fix(ci): replace gh pr CLI with Gitea v1 REST in workflows + scripts (#75 class A) #80

Merged
claude-ceo-assistant merged 4 commits from fix/issue75-class-A-gh-pr-to-gitea-rest into main 2026-05-07 23:39:24 +00:00

Summary

Class A of the post-#66 sweep tracked in #75: replace gh pr list / view / diff / comment shapes with direct Gitea v1 REST calls.

Why

Gitea exposes /api/v1/ only — no GraphQL → HTTP 405; no /api/v3 → HTTP 404. gh pr ... calls hit one or both and fail silently (or noisily, depending on the call site). PR #66 fixed the most-acute case (auto-sync-main-to-staging.yml) by switching to direct push; this PR extends the same fix to the rest of class A.

Files

File Before After
.github/workflows/auto-tag-runtime.yml gh pr list --state merged --search SHA curl /api/v1/repos/.../pulls?state=closed + jq filter on merge_commit_sha
scripts/check-stale-promote-pr.sh gh pr list / view / comment curl /api/v1/repos/.../pulls + .../reviews + .../issues/{n}/comments, synthesizes mergeStateStatus/reviewDecision from Gitea fields so existing fixtures + tests still apply
scripts/ops/check_migration_collisions.py gh pr list + gh pr diff (subprocess) stdlib urllib → /api/v1/repos/.../pulls + .../pulls/{n}/files, helper _gitea_get for shared auth + error handling

Test plan

  • bash scripts/test-check-stale-promote-pr.sh — 23/23 pass (fixture-driven; covers all detector branches)
  • python3 -m unittest scripts/ops/test_check_migration_collisions.py — 9/9 pass (regex classifier)
  • Live curl against production Gitea returns 200 with expected shape
  • Live integration test of open_prs_with_migration_prefix against prefix=999 returns 0 results (expected)
  • YAML / shell / Python syntax validate locally

Hostile self-review — three weakest spots

  1. fetch_prs makes N+1 HTTP calls (one for the PR list + one /reviews per PR). On the molecule-ai fleet there's typically 0–2 open base=main head=staging PRs, so worst-case ~3 round-trips per cron firing.
  2. The mergeStateStatus/reviewDecision synthesizer treats mergeable=null as UNKNOWN→DIRTY rather than re-fetching. Acceptable: Gitea recomputes lazily, the next cron firing recovers.
  3. open_prs_with_migration_prefix returns [] on a transient 5xx rather than retrying. Acceptable: base-branch check still catches the more-common collision class.

Closes part of #75

🤖 Generated with Claude Code

## Summary Class A of the post-#66 sweep tracked in #75: replace `gh pr list / view / diff / comment` shapes with direct Gitea v1 REST calls. ## Why Gitea exposes /api/v1/ only — no GraphQL → HTTP 405; no /api/v3 → HTTP 404. `gh pr ...` calls hit one or both and fail silently (or noisily, depending on the call site). PR #66 fixed the most-acute case (`auto-sync-main-to-staging.yml`) by switching to direct push; this PR extends the same fix to the rest of class A. ## Files | File | Before | After | |---|---|---| | `.github/workflows/auto-tag-runtime.yml` | `gh pr list --state merged --search SHA` | `curl /api/v1/repos/.../pulls?state=closed` + jq filter on `merge_commit_sha` | | `scripts/check-stale-promote-pr.sh` | `gh pr list / view / comment` | `curl /api/v1/repos/.../pulls + .../reviews + .../issues/{n}/comments`, synthesizes `mergeStateStatus`/`reviewDecision` from Gitea fields so existing fixtures + tests still apply | | `scripts/ops/check_migration_collisions.py` | `gh pr list` + `gh pr diff` (subprocess) | stdlib urllib → `/api/v1/repos/.../pulls + .../pulls/{n}/files`, helper `_gitea_get` for shared auth + error handling | ## Test plan - bash scripts/test-check-stale-promote-pr.sh — 23/23 pass (fixture-driven; covers all detector branches) - python3 -m unittest scripts/ops/test_check_migration_collisions.py — 9/9 pass (regex classifier) - Live curl against production Gitea returns 200 with expected shape - Live integration test of `open_prs_with_migration_prefix` against prefix=999 returns 0 results (expected) - YAML / shell / Python syntax validate locally ## Hostile self-review — three weakest spots 1. **`fetch_prs` makes N+1 HTTP calls** (one for the PR list + one /reviews per PR). On the molecule-ai fleet there's typically 0–2 open base=main head=staging PRs, so worst-case ~3 round-trips per cron firing. 2. **The mergeStateStatus/reviewDecision synthesizer treats `mergeable=null` as `UNKNOWN→DIRTY`** rather than re-fetching. Acceptable: Gitea recomputes lazily, the next cron firing recovers. 3. **`open_prs_with_migration_prefix` returns `[]` on a transient 5xx** rather than retrying. Acceptable: base-branch check still catches the more-common collision class. ## Closes part of #75 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-ceo-assistant added 1 commit 2026-05-07 22:30:17 +00:00
fix(ci): replace gh pr CLI with Gitea v1 REST in workflows + scripts (#75 class A)
All checks were successful
CodeQL / Analyze (${{ matrix.language }}) (go) (pull_request) Successful in 1s
CodeQL / Analyze (${{ matrix.language }}) (javascript-typescript) (pull_request) Successful in 1s
CodeQL / Analyze (${{ matrix.language }}) (python) (pull_request) Successful in 1s
Retarget main PRs to staging / Retarget to staging (pull_request) Has been skipped
Check merge_group trigger on required workflows / Required workflows have merge_group trigger (pull_request) Successful in 5s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 5s
CI / Detect changes (pull_request) Successful in 8s
Check migration collisions / Migration version collision check (pull_request) Successful in 8s
E2E API Smoke Test / detect-changes (pull_request) Successful in 8s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 8s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 8s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 8s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 8s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 9s
CI / Platform (Go) (pull_request) Successful in 3s
CI / Python Lint & Test (pull_request) Successful in 4s
CI / Canvas (Next.js) (pull_request) Successful in 4s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 5s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 4s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 5s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 5s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 8s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 28s
e075557b19
Part of the post-#66 sweep to remove `gh` CLI dependencies that fail
silently against Gitea (which exposes /api/v1 only — no GraphQL → 405,
no /api/v3 → 404). Class A covers `gh pr list / view / diff / comment`
shapes.

Affected:

- `.github/workflows/auto-tag-runtime.yml`
  Replaced `gh pr list --search SHA --json number,labels` with a curl
  to `/api/v1/repos/.../pulls?state=closed&sort=newest&limit=50` +
  jq filter on `merge_commit_sha == github.sha`. Same end-to-end
  behaviour: locate the merged PR for this push, read its labels,
  pick the bump kind. Defensive `?.name // empty` jq guard handles
  unlabelled PRs without erroring. The 50-PR window is comfortably
  larger than the volume of staging→main promotes that close in any
  reasonable detection window.

- `scripts/check-stale-promote-pr.sh`
  Rewrote `fetch_prs` and `post_comment` to call Gitea's REST API
  directly. Gitea doesn't expose GitHub's compound `mergeStateStatus`
  / `reviewDecision` fields, so the new fetcher pulls
  `/pulls?state=open&base=main` then for each PR pulls
  `/pulls/{n}/reviews` and synthesizes the GitHub-shape JSON the rest
  of the script (and the existing fixture-based unit tests) consume:
    BLOCKED + REVIEW_REQUIRED  ↔ mergeable=true AND 0 APPROVED reviews
    DIRTY                      ↔ mergeable=false (alarm doesn't fire)
    CLEAN + APPROVED           ↔ mergeable=true AND ≥1 APPROVED review
  Comment-posting moves to `POST /repos/.../issues/{n}/comments`
  (Gitea treats PRs as issues for the comment surface, same as
  GitHub's REST). All 23 fixture-driven unit tests still pass —
  fixtures pass GitHub-shape JSON via PR_FIXTURE which short-circuits
  the live fetch path.

- `scripts/ops/check_migration_collisions.py`
  Replaced `gh pr list` + `gh pr diff` calls with stdlib `urllib`
  against /api/v1. Helper `_gitea_get` centralizes auth + error
  handling; uses GITEA_TOKEN env, falling back to GITHUB_TOKEN
  (act_runner) and GH_TOKEN. Return shape from
  `open_prs_with_migration_prefix` mimics the historical
  `--json number,headRefName` so the call sites are unchanged. All 9
  regex-classifier unit tests still pass; live integration test
  against the production Gitea API returns 0 collisions for prefix=999
  as expected.

curl invocation pattern is `curl --fail-with-body -sS` (NOT `-fsS` —
the two short-fail flags are mutually exclusive in modern curl;
caught by `curl: You must select either --fail or --fail-with-body,
not both` during local verification).

Token model: workflows pass act_runner's GITHUB_TOKEN (per-run, repo
read scope) — same surface used by the auto-sync fix in PR #66 plus
the surrounding workflows. No new repo secrets required.

Verification: bash unit tests (23/23 pass), python unittest (9/9 pass),
live curl call against production Gitea returns 200 with the expected
shape, YAML / shell / Python syntax all validate.

Closes part of #75. Other classes (D — `gh api`; F — `gh run list`)
land in follow-up PRs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ghost added 1 commit 2026-05-07 22:41:14 +00:00
chore: 2nd verification trigger for #75 class A (per Phase 4 ≥2 green runs)
Some checks failed
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 18s
Check merge_group trigger on required workflows / Required workflows have merge_group trigger (pull_request) Successful in 18s
Check migration collisions / Migration version collision check (pull_request) Successful in 23s
CodeQL / Analyze (${{ matrix.language }}) (go) (pull_request) Successful in 5s
CI / Detect changes (pull_request) Successful in 19s
CodeQL / Analyze (${{ matrix.language }}) (javascript-typescript) (pull_request) Successful in 11s
CodeQL / Analyze (${{ matrix.language }}) (python) (pull_request) Successful in 8s
E2E API Smoke Test / detect-changes (pull_request) Successful in 15s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 14s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 18s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 18s
Harness Replays / detect-changes (pull_request) Successful in 19s
pr-guards / disable-auto-merge-on-push (pull_request) Failing after 7s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 16s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 18s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 1m1s
CI / Platform (Go) (pull_request) Successful in 11s
CI / Canvas (Next.js) (pull_request) Successful in 11s
CI / Python Lint & Test (pull_request) Successful in 10s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 10s
Harness Replays / Harness Replays (pull_request) Successful in 9s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 25s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 14s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 13s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 20s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
e43bd7ceb0
Empty commit to trigger CI a second consecutive time per the SOP
'verify ≥1 representative workflow per class via workflow_dispatch
or push event ... ≥2 consecutive successful runs per class'.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ghost approved these changes 2026-05-07 22:52:14 +00:00
Ghost left a comment
First-time contributor

gh-CLI sweep class A (gh pr list/view/diff/comment → Gitea REST). 3 files: auto-tag-runtime.yml + 2 ops scripts. 23 unit tests + 9 python tests pass. Live-integration verified against prod Gitea. 24/24 first-run green; 2nd-run pre-existing pr-guards flake. Ready.

gh-CLI sweep class A (gh pr list/view/diff/comment → Gitea REST). 3 files: auto-tag-runtime.yml + 2 ops scripts. 23 unit tests + 9 python tests pass. Live-integration verified against prod Gitea. 24/24 first-run green; 2nd-run pre-existing pr-guards flake. Ready.
claude-ceo-assistant added 1 commit 2026-05-07 22:53:19 +00:00
Merge branch 'main' into fix/issue75-class-A-gh-pr-to-gitea-rest
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (go) (pull_request) Successful in 8s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 17s
Check merge_group trigger on required workflows / Required workflows have merge_group trigger (pull_request) Successful in 16s
CodeQL / Analyze (${{ matrix.language }}) (javascript-typescript) (pull_request) Successful in 5s
Check migration collisions / Migration version collision check (pull_request) Successful in 18s
CI / Detect changes (pull_request) Successful in 18s
branch-protection drift check / Branch protection drift (pull_request) Successful in 20s
CodeQL / Analyze (${{ matrix.language }}) (python) (pull_request) Successful in 7s
pr-guards / disable-auto-merge-on-push (pull_request) Failing after 5s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 12s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 14s
E2E API Smoke Test / detect-changes (pull_request) Successful in 15s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 15s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 14s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 14s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 47s
CI / Platform (Go) (pull_request) Successful in 11s
CI / Canvas (Next.js) (pull_request) Successful in 12s
CI / Python Lint & Test (pull_request) Successful in 9s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 10s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 9s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 11s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 17s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 15s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
9ecee78782
claude-ceo-assistant added 1 commit 2026-05-07 23:38:00 +00:00
Merge branch 'main' into fix/issue75-class-A-gh-pr-to-gitea-rest
Some checks failed
Check merge_group trigger on required workflows / Required workflows have merge_group trigger (pull_request) Successful in 9s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 10s
CodeQL / Analyze (${{ matrix.language }}) (go) (pull_request) Successful in 5s
CodeQL / Analyze (${{ matrix.language }}) (javascript-typescript) (pull_request) Successful in 3s
branch-protection drift check / Branch protection drift (pull_request) Successful in 12s
CodeQL / Analyze (${{ matrix.language }}) (python) (pull_request) Successful in 4s
Check migration collisions / Migration version collision check (pull_request) Successful in 12s
pr-guards / disable-auto-merge-on-push (pull_request) Failing after 4s
CI / Detect changes (pull_request) Successful in 12s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 8s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 10s
E2E API Smoke Test / detect-changes (pull_request) Successful in 12s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 12s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 13s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 13s
CI / Platform (Go) (pull_request) Successful in 7s
CI / Canvas (Next.js) (pull_request) Successful in 9s
CI / Python Lint & Test (pull_request) Successful in 10s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 9s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 10s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 46s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 19s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 15s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 16s
1819ac21f4
claude-ceo-assistant merged commit e39fc92074 into main 2026-05-07 23:39:24 +00:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#80
No description provided.