GitHub is the source of truth; Gitea (origin) is a just-in-case copy that had drifted two commits behind. Rather than require a credential on GitHub's side or convert the repo to a read-only Gitea mirror, wire it into the local workflow: - scripts/mirror-gitea.sh — pushes prod + all tags to the Gitea remote (--branches for every branch). Refuses to push to a GitHub remote, prints what it did, exits non-zero when the mirror could not be updated. - scripts/hooks/pre-push — git has no post-push hook, so the mirror runs before a push that includes prod/main or a tag; skips other remotes, deletions and its own recursion. - scripts/hooks/post-merge — refreshes the mirror after `git pull`/merge on prod, which is how a PR squash-merged on GitHub reaches the mirror. - scripts/install-git-hooks.sh — one-time per clone; sets core.hooksPath=scripts/hooks so the hooks stay versioned with the repo. Mirror failures are warnings: a Gitea outage never blocks a push to GitHub. AGENTS.md documents the setup plus the GitHub-only release flow. Verified: script + hooks exercised for the prod/tag case, the feature-branch skip, the Gitea-remote skip and the recursion guard; the mirror is idempotent (no-op when already in sync).
91 lines
2.9 KiB
Bash
Executable File
91 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Keep the Gitea "just in case" mirror (git.ranio.xyz) in step with GitHub.
|
|
#
|
|
# GitHub (`AdrianBonpin/gridline`, remote `github`) is the source of truth; the
|
|
# Gitea remote (`origin`) exists only as a fallback copy of the code, so this
|
|
# mirrors the trunk branch and every tag — not feature branches.
|
|
#
|
|
# Run it manually after a merge that happened on GitHub, or let the repo's git
|
|
# hooks call it (`scripts/install-git-hooks.sh` wires up `core.hooksPath`):
|
|
# * pre-push — before pushing prod/tags to GitHub
|
|
# * post-merge — after `git pull`/merge while on prod
|
|
#
|
|
# Exit status is non-zero when the mirror could not be updated, so callers can
|
|
# decide whether that is fatal. The hooks treat it as a warning: a Gitea outage
|
|
# must never block a push to GitHub.
|
|
#
|
|
# Usage:
|
|
# scripts/mirror-gitea.sh # mirror prod + all tags
|
|
# GRIDLINE_GITEA_REMOTE=mirror scripts/… # use another remote name
|
|
# scripts/mirror-gitea.sh --branches # also mirror every local branch
|
|
|
|
set -uo pipefail
|
|
|
|
GITEA_REMOTE="${GRIDLINE_GITEA_REMOTE:-origin}"
|
|
MIRROR_BRANCHES=0
|
|
TRUNK_BRANCH="${GRIDLINE_TRUNK_BRANCH:-prod}"
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--branches) MIRROR_BRANCHES=1 ;;
|
|
-h|--help) sed -n '2,25p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
|
*) echo "mirror-gitea: unknown argument '$arg' (try --help)" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
|
|
echo "mirror-gitea: not inside a git repository" >&2
|
|
exit 1
|
|
}
|
|
cd "$repo_root" || exit 1
|
|
|
|
url="$(git remote get-url "$GITEA_REMOTE" 2>/dev/null || true)"
|
|
if [ -z "$url" ]; then
|
|
echo "mirror-gitea: remote '$GITEA_REMOTE' not found — nothing to mirror" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Safety: never push to GitHub through this script (it is the source, and a
|
|
# mis-pointed remote could otherwise rewrite the wrong repository).
|
|
case "$url" in
|
|
*github.com*)
|
|
echo "mirror-gitea: '$GITEA_REMOTE' points at GitHub ($url) — refusing to mirror" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
status=0
|
|
note() { printf 'mirror-gitea: %s\n' "$1" >&2; }
|
|
|
|
# Trunk branch. Only mirror it when it exists locally; a fresh clone with just
|
|
# the feature branch checked out still mirrors the tags below.
|
|
if git show-ref --verify --quiet "refs/heads/$TRUNK_BRANCH"; then
|
|
if ! git push "$GITEA_REMOTE" "refs/heads/$TRUNK_BRANCH:refs/heads/$TRUNK_BRANCH"; then
|
|
status=1
|
|
note "could not update $TRUNK_BRANCH"
|
|
fi
|
|
fi
|
|
|
|
# Every local tag, so release tags appear on the mirror too (`--tags` is
|
|
# idempotent — already-present tags are skipped).
|
|
if [ -n "$(git tag --list)" ]; then
|
|
if ! git push "$GITEA_REMOTE" --tags; then
|
|
status=1
|
|
note "could not update tags"
|
|
fi
|
|
fi
|
|
|
|
# Optional: every local branch (off by default — feature branches are ephemeral).
|
|
if [ "$MIRROR_BRANCHES" = "1" ]; then
|
|
if ! git push "$GITEA_REMOTE" --all; then
|
|
status=1
|
|
note "could not update branches"
|
|
fi
|
|
fi
|
|
|
|
if [ "$status" = "0" ]; then
|
|
note "mirror up to date ($url)"
|
|
fi
|
|
exit "$status"
|