Add check-upstream.sh, generated status artifacts, merge guide, and a scheduled Forgejo job to refresh upstream sync visibility. Co-authored-by: Cursor <cursoragent@cursor.com>
196 lines
5.4 KiB
Bash
Executable file
196 lines
5.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Compare this fork against upstream and optionally write UPSTREAM_STATUS.md.
|
|
set -euo pipefail
|
|
|
|
UPSTREAM_REMOTE="${UPSTREAM_REMOTE:-upstream}"
|
|
UPSTREAM_URL="${UPSTREAM_URL:-https://github.com/komikku-app/komikku.git}"
|
|
UPSTREAM_BRANCH="${UPSTREAM_BRANCH:-master}"
|
|
FORK_BRANCH="${FORK_BRANCH:-main}"
|
|
BEHIND_WARN="${BEHIND_WARN:-10}"
|
|
OUTPUT_MD="${OUTPUT_MD:-UPSTREAM_STATUS.md}"
|
|
OUTPUT_JSON="${OUTPUT_JSON:-docs/upstream-status.json}"
|
|
FETCH="${FETCH:-1}"
|
|
WRITE="${WRITE:-0}"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: scripts/check-upstream.sh [options]
|
|
|
|
Options:
|
|
--no-fetch Skip git fetch upstream
|
|
--write Write UPSTREAM_STATUS.md and docs/upstream-status.json
|
|
--json Print JSON status to stdout
|
|
-h, --help Show this help
|
|
|
|
Environment:
|
|
UPSTREAM_REMOTE Git remote name (default: upstream)
|
|
UPSTREAM_BRANCH Upstream branch (default: master)
|
|
FORK_BRANCH Local fork branch (default: main)
|
|
BEHIND_WARN Warn when behind by this many commits (default: 10)
|
|
EOF
|
|
}
|
|
|
|
print_json=0
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--no-fetch) FETCH=0 ;;
|
|
--write) WRITE=1 ;;
|
|
--json) print_json=1 ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "Unknown option: $1" >&2; usage >&2; exit 2 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
repo_root="$(git rev-parse --show-toplevel)"
|
|
cd "$repo_root"
|
|
|
|
if ! git rev-parse --verify "$FORK_BRANCH" >/dev/null 2>&1; then
|
|
echo "Fork branch not found: $FORK_BRANCH" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! git remote get-url "$UPSTREAM_REMOTE" >/dev/null 2>&1; then
|
|
echo "Adding upstream remote: $UPSTREAM_REMOTE -> $UPSTREAM_URL" >&2
|
|
git remote add "$UPSTREAM_REMOTE" "$UPSTREAM_URL"
|
|
fi
|
|
|
|
if [[ "$FETCH" == "1" ]]; then
|
|
git fetch "$UPSTREAM_REMOTE" "$UPSTREAM_BRANCH" --prune
|
|
fi
|
|
|
|
upstream_ref="$UPSTREAM_REMOTE/$UPSTREAM_BRANCH"
|
|
if ! git rev-parse --verify "$upstream_ref" >/dev/null 2>&1; then
|
|
echo "Upstream ref not found: $upstream_ref" >&2
|
|
exit 1
|
|
fi
|
|
|
|
merge_base="$(git merge-base "$FORK_BRANCH" "$upstream_ref")"
|
|
behind="$(git rev-list --count "$FORK_BRANCH".."$upstream_ref")"
|
|
ahead="$(git rev-list --count "$upstream_ref".."$FORK_BRANCH")"
|
|
fork_head="$(git rev-parse --short "$FORK_BRANCH")"
|
|
upstream_head="$(git rev-parse --short "$upstream_ref")"
|
|
checked_at="$(date -u +"%Y-%m-%d %H:%M UTC")"
|
|
|
|
if [[ "$behind" -eq 0 ]]; then
|
|
status="up_to_date"
|
|
status_label="Up to date"
|
|
status_emoji="✅"
|
|
elif [[ "$behind" -le "$BEHIND_WARN" ]]; then
|
|
status="slightly_behind"
|
|
status_label="Slightly behind"
|
|
status_emoji="🟡"
|
|
else
|
|
status="behind"
|
|
status_label="Behind upstream"
|
|
status_emoji="🔴"
|
|
fi
|
|
|
|
upstream_sample="$(git log --oneline "$FORK_BRANCH".."$upstream_ref" -10)"
|
|
fork_sample="$(git log --oneline "$upstream_ref".."$FORK_BRANCH" -10)"
|
|
|
|
if [[ "$print_json" == "1" ]]; then
|
|
python3 - <<PY
|
|
import json
|
|
print(json.dumps({
|
|
"checked_at": "$checked_at",
|
|
"status": "$status",
|
|
"status_label": "$status_label",
|
|
"behind": $behind,
|
|
"ahead": $ahead,
|
|
"fork_branch": "$FORK_BRANCH",
|
|
"upstream_remote": "$UPSTREAM_REMOTE",
|
|
"upstream_branch": "$UPSTREAM_BRANCH",
|
|
"upstream_url": "$UPSTREAM_URL",
|
|
"merge_base": "$(git rev-parse --short "$merge_base")",
|
|
"fork_head": "$fork_head",
|
|
"upstream_head": "$upstream_head",
|
|
"behind_warn": $BEHIND_WARN,
|
|
}, indent=2))
|
|
PY
|
|
fi
|
|
|
|
echo "Upstream: $UPSTREAM_REMOTE ($UPSTREAM_URL) @ $UPSTREAM_BRANCH"
|
|
echo "Fork: $FORK_BRANCH @ $fork_head"
|
|
echo "Merge base: $(git rev-parse --short "$merge_base")"
|
|
echo "Behind upstream: $behind commits"
|
|
echo "Ahead of upstream: $ahead commits"
|
|
echo "Status: $status_emoji $status_label"
|
|
|
|
if [[ "$WRITE" != "1" ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$OUTPUT_JSON")"
|
|
|
|
python3 - <<PY
|
|
import json
|
|
from pathlib import Path
|
|
Path("$(dirname "$OUTPUT_JSON")").mkdir(parents=True, exist_ok=True)
|
|
json.dump({
|
|
"schemaVersion": 1,
|
|
"checked_at": "$checked_at",
|
|
"status": "$status",
|
|
"status_label": "$status_label",
|
|
"behind": $behind,
|
|
"ahead": $ahead,
|
|
"fork_branch": "$FORK_BRANCH",
|
|
"upstream_remote": "$UPSTREAM_REMOTE",
|
|
"upstream_branch": "$UPSTREAM_BRANCH",
|
|
"upstream_url": "$UPSTREAM_URL",
|
|
"merge_base": "$(git rev-parse "$merge_base")",
|
|
"fork_head": "$(git rev-parse "$FORK_BRANCH")",
|
|
"upstream_head": "$(git rev-parse "$upstream_ref")",
|
|
"behind_warn": $BEHIND_WARN,
|
|
}, open("$OUTPUT_JSON", "w"), indent=2)
|
|
PY
|
|
|
|
{
|
|
cat <<EOF
|
|
# Upstream sync status
|
|
|
|
> Auto-generated by [\`scripts/check-upstream.sh\`](scripts/check-upstream.sh). Last check: **$checked_at**.
|
|
|
|
| | |
|
|
|---|---|
|
|
| Status | $status_emoji **$status_label** |
|
|
| Behind upstream | **$behind** commits on [\`$UPSTREAM_REMOTE/$UPSTREAM_BRANCH\`]($UPSTREAM_URL) |
|
|
| Ahead of upstream | **$ahead** fork-only commits on \`$FORK_BRANCH\` |
|
|
| Merge base | \`$(git rev-parse --short "$merge_base")\` |
|
|
| Fork HEAD | \`$fork_head\` |
|
|
| Upstream HEAD | \`$upstream_head\` |
|
|
|
|
EOF
|
|
|
|
if [[ "$behind" -gt 0 ]]; then
|
|
cat <<EOF
|
|
## Action recommended
|
|
|
|
This fork is **$behind commits behind** [komikku-app/komikku]($UPSTREAM_URL). Consider merging upstream soon.
|
|
|
|
See [docs/upstream-sync.md](docs/upstream-sync.md) for the manual sync procedure.
|
|
|
|
EOF
|
|
else
|
|
echo "## No merge needed"
|
|
echo
|
|
echo "The fork includes all commits from upstream \`$UPSTREAM_BRANCH\`."
|
|
echo
|
|
fi
|
|
|
|
cat <<EOF
|
|
## Recent upstream commits not in fork
|
|
|
|
\`\`\`
|
|
$(printf '%s\n' "$upstream_sample")
|
|
\`\`\`
|
|
|
|
## Recent fork-only commits
|
|
|
|
\`\`\`
|
|
$(printf '%s\n' "$fork_sample")
|
|
\`\`\`
|
|
EOF
|
|
} >"$OUTPUT_MD"
|
|
|
|
echo "Wrote $OUTPUT_MD and $OUTPUT_JSON"
|