Files
codewhale/.github/workflows/sync-cnb.yml
T
Hunter Bown c188cade88 ci(cnb): use plain --force on main push, drop misleading --force-with-lease
`--force-with-lease` without an explicit value uses
`refs/remotes/<remote>/main` as the lease ref. The CNB push remote
is added fresh inside each workflow run (`git remote add cnb …`)
without a prior fetch, so that lease ref never exists in the
runner's local clone. The lease check then misfires with
`! [rejected] HEAD -> main (stale info)` even when CNB is correctly
behind GitHub.

Plain `--force` is the right primitive here: the CNB mirror is
one-way by design, so there's no contributor work on the CNB side
to protect against. The lease safety would only matter in a
multi-writer scenario, which we explicitly don't run.

Confirmed via failing run 25714171752 (2026-05-12T04:53:13Z) where
all three retry attempts failed with the same stale-info error
even though CNB was simply behind GitHub by two scrub commits.
2026-05-11 23:54:05 -05:00

111 lines
4.5 KiB
YAML

name: Sync to CNB
# Mirror commits and release tags to cnb.cool/deepseek-tui.com/DeepSeek-TUI
# so users behind GitHub-blocking networks can fetch the source and tagged
# releases from the Tencent-hosted mirror.
#
# Triggers:
# * push to main → mirrors that commit to CNB main
# * tag matching v* → mirrors that tag to CNB
# * workflow_dispatch → manual fallback if either of the above fails
#
# Why the rewrite (v0.8.31):
# The previous implementation used the opaque tencentcom/git-sync Docker
# action, which discovered every local ref via fetch-depth: 0 and tried
# to push them all — including dependabot/* branches that GitHub had
# locally. Those follow-on pushes ran without the configured credential
# helper in scope and failed with
# `fatal: could not read Username for 'https://cnb.cool'`
# No concurrency block meant the main-push and tag-push workflow runs
# that auto-tag.yml fires within seconds of each other raced. About
# half of recent runs failed for those two reasons combined.
on:
push:
branches: [main]
tags: ['v*']
workflow_dispatch: {}
# Serialize runs so the back-to-back main-push + tag-push from auto-tag.yml
# don't race each other rebasing onto CNB. cancel-in-progress: false so
# every commit actually arrives — we'd rather queue than drop.
concurrency:
group: cnb-sync
cancel-in-progress: false
permissions:
contents: read
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Push triggering ref to CNB
env:
CNB_TOKEN: ${{ secrets.CNB_GIT_TOKEN }}
shell: bash
run: |
set -euo pipefail
if [ -z "${CNB_TOKEN:-}" ]; then
echo "::error::CNB_GIT_TOKEN secret is not set; cannot push to CNB." >&2
exit 1
fi
# URL-encode any '%' in the token so basic-auth doesn't break on
# special characters. CNB tokens are typically alphanumeric so
# this is belt-and-suspenders.
ENCODED_TOKEN="$(printf '%s' "${CNB_TOKEN}" | python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.stdin.read(), safe=""))')"
REMOTE_URL="https://cnb:${ENCODED_TOKEN}@cnb.cool/deepseek-tui.com/DeepSeek-TUI.git"
# Use a masked alias so the token never appears in log lines.
git remote add cnb "${REMOTE_URL}"
# Push with retry on transient failures (CNB rate-limits, DNS
# blips, etc.). Args after `kind` are forwarded to `git push`
# so callers can pass `--force-with-lease`, multiple refspecs,
# etc. without quoting them into one string.
push_with_retry() {
local kind="$1"
shift
local attempt
for attempt in 1 2 3; do
echo "Attempt ${attempt}: pushing ${kind} to CNB"
if git push cnb "$@" 2>&1; then
echo "Successfully pushed ${kind} to CNB"
return 0
fi
if [ "${attempt}" -lt 3 ]; then
sleep $((attempt * 5))
fi
done
echo "::error::Failed to push ${kind} to CNB after 3 attempts" >&2
return 1
}
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
TAG="${GITHUB_REF#refs/tags/}"
push_with_retry "tag ${TAG}" "refs/tags/${TAG}:refs/tags/${TAG}"
elif [[ "${GITHUB_REF}" == refs/heads/main ]]; then
# Plain --force. The CNB mirror is one-way by design —
# nothing else pushes to it, so there's no contributor work
# to protect against. `--force-with-lease` would be safer
# in a multi-writer scenario, but in our setup the lease
# check requires `refs/remotes/cnb/main` to exist in the
# runner's local clone, which it never does (we add `cnb`
# as a fresh remote in this step and don't fetch first).
# That made the lease check spuriously fail with
# `! [rejected] HEAD -> main (stale info)` even when CNB
# was actually behind GitHub.
push_with_retry "main" HEAD:refs/heads/main --force
else
# workflow_dispatch from a non-main branch — push that branch
# too, but never force. Useful for testing the mirror against
# a feature branch before merging.
BRANCH="${GITHUB_REF#refs/heads/}"
push_with_retry "branch ${BRANCH}" "HEAD:refs/heads/${BRANCH}"
fi