fix: fail the deploy instead of masking reconcile restore errors Addresses review feedback on the concurrent-deploy reconcile logic. The authoritative restore commands in reconcile_owned_paths previously used `|| true`, so if restoring an owned documentation path failed, the action would silently stage and commit a deletion and publish broken/missing docs. - Owned purge/keep paths always exist in the deploy commit, so their `git checkout`/`git add` restores are now unmasked: a failure fails the job under `set -e` instead of committing a silent deletion. Only the best-effort pre-clean `git rm --ignore-unmatch` stays lenient. - The "latest" yield path only restores from the remote when the remote actually publishes it (guarded by `git ls-tree`); otherwise the staged removal stands, avoiding an abort on a now-absent pathspec. The `git ls-tree` check is unmasked so an invalid FETCH_HEAD fails closed. Assisted-by: claude-code:claude-4.8-opus
diff --git a/deploy-github-pages/entrypoint.sh b/deploy-github-pages/entrypoint.sh index 7075198..fe24214 100755 --- a/deploy-github-pages/entrypoint.sh +++ b/deploy-github-pages/entrypoint.sh
@@ -187,8 +187,19 @@ # remote's higher version. FETCH_HEAD is the remote tip fetched by the # preceding `git pull --rebase`, i.e. the concurrent deploy we rebased onto. git rm -rf --ignore-unmatch --quiet -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true - git checkout FETCH_HEAD -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true - git add -A -- "${LATEST_OWNED_PATH}" >/dev/null 2>&1 || true + # Restore the remote's (higher) version IF the remote actually publishes this + # path. If it does not (e.g. the higher release skipped "latest"), the + # `git rm` above already staged its removal - there is nothing to restore, and + # a `git add -A` on the now-absent pathspec would exit 128 and abort. A + # genuinely broken FETCH_HEAD makes `git ls-tree` exit nonzero, which - left + # unmasked - fails the job under `set -e` rather than being mistaken for + # "path absent". A checkout failure on a path the remote DOES have also aborts. + local remote_latest + remote_latest="$(git ls-tree -r FETCH_HEAD -- "${LATEST_OWNED_PATH}")" + if [ -n "${remote_latest}" ]; then + git checkout FETCH_HEAD -- "${LATEST_OWNED_PATH}" + git add -A -- "${LATEST_OWNED_PATH}" + fi local kept=() x for x in "${OWNED_PURGE_PATHS[@]}"; do [ "$x" = "${LATEST_OWNED_PATH}" ] || kept+=("$x") @@ -198,15 +209,20 @@ fi fi + # These owned paths are always present in DEPLOY_COMMIT (this deploy published + # them), so a restore failure means a genuinely broken repo state. Do NOT mask + # checkout/add failures with `|| true`: under `set -e` they must fail the job + # rather than silently commit a deletion and publish broken/missing docs. Only + # the best-effort pre-clean `git rm` (guarded by --ignore-unmatch) stays lenient. for p in "${OWNED_PURGE_PATHS[@]}"; do git rm -rf --ignore-unmatch --quiet -- "$p" >/dev/null 2>&1 || true - git checkout "$DEPLOY_COMMIT" -- "$p" >/dev/null 2>&1 || true - git add -A -- "$p" >/dev/null 2>&1 || true + git checkout "$DEPLOY_COMMIT" -- "$p" + git add -A -- "$p" changed=true done for p in "${OWNED_KEEP_PATHS[@]}"; do - git checkout "$DEPLOY_COMMIT" -- "$p" >/dev/null 2>&1 || true - git add -A -- "$p" >/dev/null 2>&1 || true + git checkout "$DEPLOY_COMMIT" -- "$p" + git add -A -- "$p" changed=true done if [ "$changed" = true ]; then