fix: Push to public mirrors after merge (#614)

Add fire-and-forget mirror push support so merges to the primary branch
are automatically pushed to configured public mirrors (GitHub, Codeberg,
etc.). Mirror failures are logged but never block the pipeline.

- lib/mirrors.sh: new shared mirror_push() helper
- lib/load-project.sh: parse [mirrors] TOML section into MIRROR_* env vars
- dev/phase-handler.sh: call mirror_push after do_merge() success
- dev/dev-poll.sh: call mirror_push after try_direct_merge() success
- gardener/gardener-run.sh: call mirror_push after _gardener_merge() success
- bin/disinto: set up mirror remotes during init, add commented mirrors to
  generated TOML
- projects/*.toml.example: show [mirrors] section (commented out)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-23 19:19:16 +00:00
parent a4cbe1e8c6
commit 7bc74caa63
9 changed files with 102 additions and 1 deletions

View file

@ -8,7 +8,8 @@
# PROJECT_NAME, FORGE_REPO, FORGE_API, FORGE_WEB, FORGE_URL,
# PROJECT_REPO_ROOT, PRIMARY_BRANCH, WOODPECKER_REPO_ID,
# PROJECT_CONTAINERS, CHECK_PRS, CHECK_DEV_AGENT,
# CHECK_PIPELINE_STALL, CI_STALE_MINUTES
# CHECK_PIPELINE_STALL, CI_STALE_MINUTES,
# MIRROR_NAMES, MIRROR_URLS, MIRROR_<NAME> (per configured mirror)
# (plus backwards-compat aliases: CODEBERG_REPO, CODEBERG_API, CODEBERG_WEB)
#
# If no argument given, does nothing (allows poll scripts to work with
@ -71,6 +72,14 @@ mon = cfg.get('monitoring', {})
for key in ['check_prs', 'check_dev_agent', 'check_pipeline_stall']:
if key in mon:
emit(key.upper(), mon[key])
# [mirrors] section
mirrors = cfg.get('mirrors', {})
for name, url in mirrors.items():
emit(f'MIRROR_{name.upper()}', url)
if mirrors:
emit('MIRROR_NAMES', list(mirrors.keys()))
emit('MIRROR_URLS', list(mirrors.values()))
" "$_PROJECT_TOML" 2>/dev/null) || {
echo "WARNING: failed to parse project TOML: $_PROJECT_TOML" >&2
return 1 2>/dev/null || exit 1

30
lib/mirrors.sh Normal file
View file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# mirrors.sh — Push primary branch + tags to configured mirror remotes.
#
# Usage: source lib/mirrors.sh; mirror_push
# Requires: PROJECT_REPO_ROOT, PRIMARY_BRANCH, MIRROR_* vars from load-project.sh
# shellcheck disable=SC2154 # globals set by load-project.sh / calling script
mirror_push() {
[ -z "${MIRROR_NAMES:-}" ] && return 0
[ -z "${PROJECT_REPO_ROOT:-}" ] && return 0
[ -z "${PRIMARY_BRANCH:-}" ] && return 0
local name url
for name in $MIRROR_NAMES; do
url=$(eval "echo \"\$MIRROR_$(echo "$name" | tr '[:lower:]' '[:upper:]')\"") || true
[ -z "$url" ] && continue
# Ensure remote exists with correct URL
if git -C "$PROJECT_REPO_ROOT" remote get-url "$name" &>/dev/null; then
git -C "$PROJECT_REPO_ROOT" remote set-url "$name" "$url" 2>/dev/null || true
else
git -C "$PROJECT_REPO_ROOT" remote add "$name" "$url" 2>/dev/null || true
fi
# Fire-and-forget push (background, no failure propagation)
git -C "$PROJECT_REPO_ROOT" push "$name" "$PRIMARY_BRANCH" --tags 2>/dev/null &
log "mirror: pushed to ${name} (pid $!)"
done
}