Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "fix/195-auto-promote-staging-gitea-rest"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Root-cause fix for the persistent broken
auto-promote-staging.ymlworkflow on Gitea. Same root-cause class as #65 / PR #66 (auto-sync rewrite), inverse direction.Root cause (full Phase 1 in #73): the workflow used
gh pr create,gh pr merge --auto,gh run list, andgh workflow runagainst Gitea. Each call hits an endpoint that does not exist or returns 405:gh pr create / merge / view / list→/api/graphql→ 405 (Gitea has no GraphQL)gh run list→ 405 (same root cause)gh workflow run X.yml→POST /actions/workflows/{id}/dispatchesdoes not exist on Gitea 1.22.6 (verified viaswagger.v1.json)Fix shape:
gh run listwith Gitea-native combined-status endpoint (GET /repos/{owner}/{repo}/commits/{ref}/status) — combined state encodes the AND across every check context. Simpler than the per-workflow loop and immune to workflow-name collisions (the GitHub-era footgun #2 was workflow-name disambiguation between explicit YAML and UI default-setup).gh pr createwithPOST /api/v1/repos/.../pulls(idempotent: GET-existing-by-base/head first).gh pr merge --autowithPOST /api/v1/repos/.../pulls/{N}/mergebody{Do:"merge", merge_when_checks_succeed:true}. Gitea waits for both required-status-checks AND required-approvals (1 onmain).workflow_dispatchREST endpoint. Thepublish-workspace-server-image.ymlworkflow fires automatically via itson: push: branches: [main]trigger when this promote PR merges.Why this is the proper fix (not a workaround)
feedback_fix_root_not_symptom: fixes the mechanism mismatch with Gitea, not the symptom.feedback_long_term_robust_automated: simpler, fewer external API dependencies, no GraphQL probes, no missing-endpoint footgun.feedback_prod_apply_needs_hongming_chat_go: preserves Hongming's approval gate onmain.merge_when_checks_succeeddoes NOT bypassrequired_approvals: 1. Gitea waits for approval + green checks before landing.Critical constraint discovered:
maincannot be direct-pushedUnlike PR #66 (which direct-pushes staging as
devops-engineerwhitelisted on staging),mainhasenable_push: falsewith no whitelist:Direct push is impossible for any persona, including admins. PR-mediated merge is the only path. This is intentional — staging→main is a prod state mutation. Auto-merge fires on Hongming approval + green checks, never bypassing the gate.
Identity & security (anti-bot-ring)
Per
feedback_per_agent_gitea_identity_default: this workflow usesAUTO_SYNC_TOKEN(devops-engineer persona), NOT founder PAT. Same persona as PR #66, keeping the identity model coherent. Token scope:push: true(read+write); CANNOT bypass branch protection.Backwards compat
name:unchanged → required-check name (if any) is identical.workflow_run(4 gate workflows) +workflow_dispatch(withforce).AUTO_PROMOTE_ENABLEDrepo variable still gates the rollout.auto-promote-stagingunchanged.Rejected alternatives
feedback_prod_apply_needs_hongming_chat_go. Removes Hongming's approval gate. Requires branch-protection edit (Discuss-with-Hongming territory).feedback_github_botring_fingerprint. Founder-approves-bot-PR-at-machine-speed got us GH-banned 2026-05-06.External pattern reference
Mirrors GitLab's "Merge when pipeline succeeds" feature (
PUT /projects/:id/merge_requests/:iid/merge?merge_when_pipeline_succeeds=true). Gitea'smerge_when_checks_succeedis the same idea — pre-arm a merge that fires on gate-green, with the maintainer-approval gate orthogonal.Also consistent with Cloud-Native CI/CD playbooks (Argo Rollouts, Spinnaker promote pipelines): "auto-create promotion artifact, human-in-the-loop on approval, machine-merge on approval+green."
Test plan
python3 -c "import yaml; yaml.safe_load(...)").GET /commits/{ref}/status,POST /pulls,GET /pulls/{base}/{head},POST /pulls/{N}/merge(probed againstswagger.v1.json).merge_when_checks_succeedfield inMergePullRequestOptionschema.push: truepermissions on the repo.name:declarations match whatworkflow_run.workflows:references (CI,E2E Staging Canvas (Playwright),E2E API Smoke Test,CodeQL).publish-workspace-server-image.ymlfires naturally on the resulting main push.Hostile self-review (3 weakest spots)
merge_when_checks_succeed405 confusion: the schedule-success response is HTTP 405 "Please try again later". A reader might mistake this for a Method-Not-Allowed error and think the workflow is broken. Mitigation: the workflow code explicitly comments this and the step summary uses friendly language ("auto-merge scheduled", not "got 405"). Long-term: file an upstream Gitea doc clarification request.POST /pullscould return 502/503 and the workflow fails red. Re-running the workflow_dispatch on the next gate-completion picks up. Could add retry-with-backoff later, but the simpler path is robust enough; transient 5xx is rare and a manual re-trigger is one click. Documented as failure mode B.pendingforever. Mitigation:feedback_branch_protection_check_name_parityalready covers this; if it surfaces, file a cleanup issue to delete the stale external status. Not blocking this PR.Refs
feedback_per_agent_gitea_identity_default,feedback_fix_root_not_symptom,feedback_gitea_actions_migration_audit_pattern,feedback_prod_apply_needs_hongming_chat_go,feedback_long_term_robust_automated,feedback_curl_status_capture_pollutionRoot cause: same as #65/PR-#66 — gh CLI calls Gitea GraphQL (/api/graphql) which returns HTTP 405. Additionally, gh workflow run calls /actions/workflows/{id}/dispatches which does not exist on Gitea 1.22.6 (verified via swagger.v1.json). Fix: - Replace gh run list with Gitea REST combined-status endpoint (GET /repos/{owner}/{repo}/commits/{ref}/status). Combined state encodes the AND across every check context — simpler than the per-workflow loop and immune to workflow-name collisions. - Replace gh pr create / merge --auto with direct curl calls to POST /pulls and POST /pulls/{N}/merge with merge_when_checks_succeed. - Remove the post-merge polling tail entirely. The GitHub-era GITHUB_TOKEN no-recursion rule does not apply on Gitea Actions (verified empirically: PR #66 merge fired downstream pushes naturally). Even if we wanted to dispatch, Gitea has no workflow_dispatch REST endpoint. Critical constraint: main has enable_push: false with no whitelist; direct push is impossible for any persona. PR-mediated merge is the only path. main has required_approvals: 1 — auto-merge waits for Hongming's approval before landing, preserving the feedback_prod_apply_needs_hongming_chat_go contract. Identity: AUTO_SYNC_TOKEN (devops-engineer persona). Not founder PAT. Per feedback_per_agent_gitea_identity_default. Same persona used by auto-sync (PR #66) — keeps identity model coherent. Header comment block fully rewritten with 4 failure-mode runbooks (A: gates not green, B: PR-create non-201, C: merge schedule fails, D: token rotated/scope wrong) per PR #66's pattern. Refs: #65, #73, #195, PR #66 (canonical reference) Closes #73 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Auto-promote-staging.yml rewrite. Removes ~60 lines of polling+dispatch (Gitea fires on:push naturally on token-merge). Uses Gitea merge_when_checks_succeed (preserves required_approvals=1 on main). Same persona+token as PR #66. 22/22 green. Ready.