fix: chain Speakeasy auto-merge into Generate run#364
Conversation
The auto-merge workflow triggered on `pull_request: [labeled, opened]`. When github-actions[bot] opened the regen PR, GitHub's recursion guard refused to run a workflow triggered by another workflow's GITHUB_TOKEN, so the run landed as action_required with zero jobs executed. Regen PRs piled up unmerged and sdk_publish never fired (PyPI stuck at 0.10.0). Port the TypeScript SDK's architecture: make auto-merge a workflow_call reusable workflow chained inside the Generate run (generate -> resolve-branch -> auto-merge). No separate pull_request-triggered run exists, so there is nothing for GitHub to gate. - auto-merge-speakeasy-pr.yaml: workflow_call inputs (run_started_at, branch_name) + App-token secrets; resolve PR via branch/timestamp; .author.is_bot check; wait_for_checks before direct merge; step summaries. Keeps the SHA-pinned create-github-app-token. - sdk_generation.yaml / sdk_generation_for_spec_change.yaml: add concurrency group, resolve-branch + auto-merge jobs.
Speakeasy regen PRs are opened with the workflow GITHUB_TOKEN, which by design does not trigger downstream on: pull_request runs, so they carry zero status checks. main has no required checks either, so gh pr merge --auto no-ops and the direct-merge fallback calls wait_for_checks. The empty-rollup arm only `continue`d, so TOTAL stayed 0 until the 600s timeout and the function exit 1'd — failing auto-merge on every regen PR. Add a 60s grace window for checks to register, then treat a persistently empty rollup as "no checks to wait for" and return 0 so the direct squash merge proceeds. Matches the fix already shipped in go-sdk #318.
There was a problem hiding this comment.
⚠️ APPROVE unavailable on this installation — the maintainer GitHub App lacks
pull_requests: writeon OpenRouterTeam, so the ✅ LGTM verdict below is posted
as COMMENT. Event-level approval (for branch-protection) must be added out-of-band.
Perry's Review
Incremental re-review: this push adds a 60s grace window to the wait_for_checks empty-rollup arm so checkless Speakeasy regen PRs proceed to the direct squash-merge instead of burning the full 600s timeout and failing.
Verdict: ✅ LGTM
Details
Risk: 🟢 Low — CI/CD workflow plumbing only; no production SDK code, no secrets added.
CI: no pull_request checks registered on this PR — main carries no required checks (consistent with prior empirical finding).
Scope: incremental — 7 new lines since prior review.
Findings: my only prior open finding is resolved by this push:
- ✅ The empty-rollup arm now returns 0 after a 60s grace window instead of looping to the 600s timeout and exiting 1. This is exactly the remedy I suggested at head
186c107(matches the go-sdk #318 fix). One positive nit on the magic-number literal — see inline.
Blast radius: both reusable-workflow callers (the two Generate workflows) correctly invoke the now-workflow_call target; no other workflow still uses the old labeled/opened trigger for regen PRs.
Security: no concerns — no credentials added; the App-token plumbing is unchanged from the prior reviewed head.
Test coverage: N/A — GitHub Actions YAML; validated by reading the function control flow.
Unresolved threads: the prior wait_for_checks suggestion thread is now addressed by this push.
Review: tier=medium · model=claude-opus-latest · score=3.1
| # GITHUB_TOKEN-authored regen PRs get no pull_request checks at all, | ||
| # so TOTAL stays 0 forever. Wait a short grace window in case checks | ||
| # are merely slow to register, then proceed rather than time out. | ||
| if [ "$elapsed" -ge 60 ]; then |
There was a problem hiding this comment.
[nit] the grace threshold 60 is an inline literal; hoisting it into a named local (e.g. local empty_grace=60) alongside timeout/interval would document intent and keep the wait-tuning knobs in one place. Resolves my prior suggestion — thanks for adding the grace window.
Reviewed at 0680f01
Problem
Speakeasy regen PRs (
speakeasy-sdk-regen-*) pile up unmerged — 4 currently stuck (#347/#349/#352/#357), all wanting to ship 0.10.1, while PyPI is frozen at 0.10.0 (Jun 17).Root cause:
auto-merge-speakeasy-pr.yamltriggered onpull_request: [labeled, opened]. Whengithub-actions[bot]opens/labels the regen PR, GitHub's recursion guard refuses to run a workflow triggered by another workflow'sGITHUB_TOKEN. The runs land asaction_requiredwith zero jobs executed (e.g. runs28067963505,28032618517) — so the App-token logic inside the job never even gets a chance to run.Fix
Port the TypeScript SDK's working architecture: make auto-merge a
workflow_callreusable workflow chained inside the Generate run (generate → resolve-branch → auto-merge). No separatepull_request-triggered run exists, so there is nothing for GitHub to gate.auto-merge-speakeasy-pr.yaml→workflow_callwith inputs (run_started_at,branch_name) and App-token secrets. Resolves the regen PR by branch (with timestamp fallback), checks.author.is_bot == true(robust to theapp/github-actionsauthor change), gates direct merges behindwait_for_checks(), writes step summaries. Keeps the SHA-pinnedcreate-github-app-token.sdk_generation.yaml/sdk_generation_for_spec_change.yaml→ addconcurrencygroup plusresolve-branch+auto-mergejobs.Result
Once merged, the next Generate run merges the fresh regen PR and closes #347/#349/#352/#357 as superseded →
gen.locklands onmain→sdk_publish.yamlships 0.10.1.Verification
github.run_started_atwarning is identical in the already-working TS workflow (stale linter schema, valid property, has an API fallback) — not introduced here.pypi_tokenvsnpm_token, SHA pin vs@v3, nopnpm_version,workflow_dispatchclause in spec-changeif:).