name: sync-to-forgejo on: push: branches: - main - high-performance workflow_dispatch: permissions: contents: read concurrency: group: sync-to-forgejo-${{ github.ref }} cancel-in-progress: true jobs: sync: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Configure Git run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - name: Push to Forgejo env: FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} run: | set -euo pipefail BRANCH="${GITHUB_REF#refs/heads/}" REMOTE_URL="https://admin:${FORGEJO_TOKEN}@ci.nxtgauge.com/ashwin/${{ github.event.repository.name }}.git" git remote add forgejo "$REMOTE_URL" 2>/dev/null || git remote set-url forgejo "$REMOTE_URL" git fetch forgejo "$BRANCH" || true # This repo isn't a plain mirror: FluxCD's ImageUpdateAutomation # commits directly to Forgejo (the GitRepository Flux actually # watches), so Forgejo routinely has commits GitHub never sees. # A rebase here assumes Forgejo is always a fast-forward of # GitHub, which breaks the moment Flux has pushed anything - and # once one run fails, every run after it fails the same way, # silently stalling all deploys until someone notices and # reconciles history by hand. # # Merge instead. GitHub is the source of truth for human/CI # content, so conflicting hunks resolve in its favor (-X ours), # but Flux's commits are kept as merge ancestors rather than # discarded. The merge commit is only pushed to Forgejo - GitHub's # branch is left untouched - so this repeats cleanly next run # instead of accumulating rewritten history on GitHub. if git show-ref --verify --quiet "refs/remotes/forgejo/$BRANCH"; then if ! git merge -X ours --no-edit "refs/remotes/forgejo/$BRANCH"; then echo "::error::Merge with Forgejo's $BRANCH has conflicts -X ours could not resolve; manual reconciliation needed." >&2 exit 1 fi fi git push forgejo "HEAD:$BRANCH"