Repository navigation
Restructure release-automation-reusable.yml into phase jobs with the logic in Python #476
Description
Problem description
.github/workflows/release-automation-reusable.yml is 3,015 lines: 14 inline actions/github-script blocks (~1,060 lines of JavaScript), 24 inline run: blocks (~750 lines of shell), 15 jobs with 59 job outputs and 224 needs.*.outputs references. None of the inline code has a unit test; actionlint runs with shellcheck disabled. Every command is its own job although no job boundary is forced by permissions, environments or runner profile — the YAML's own Phase comments already describe a pipeline. Adding a dimension such as the maintenance base branch (ReleaseManagement#356) would thread one more string through every job.
Possible evolution
Cut the workflow by phase instead of by command: plan (trigger detection, state derivation, command policy; one JSON plan output) → snapshot (needs the validation toolchain) or act (all other commands, dispatched in Python) → finalize (issue sync, result comment, post-release and common-file sync PRs; runs always()). The inline JavaScript and shell move into release_automation/scripts/ modules with pytest coverage; github_client.py and git_operations.py stay the only modules that touch the network. The tooling checkout uses job.workflow_repository / job.workflow_sha instead of the OIDC ref resolvers, which also removes tooling_ref_override and id-token: write.
Behaviour stays identical at every consumer-visible point: same Release Issue markers, labels, sections, bot comments and templates.
Delivery: development on the long-lived branch release-automation-refactor (see release_automation/docs/branching-model.md §3), with ReleaseTest2 consuming the branch head and a floating tag ra-v1-rc2 for pilot repositories (independent-track repositories first, then repositories needing a maintenance release once ReleaseManagement#356 is implemented on the branch). One merge into main at the end moves v1-rc.
Checklist (one PR or a few per item):
- Second release-automation test repository
ReleaseTest2(RA and validation callers, no validation regression branches); it follows the branch, whileReleaseTestkeeps bothmaincanaries untouched - RA regression canary extended with publish-free paths (
/sync-issue, a rejected command, issue-close auto-reopen) onmain; branchrelease-automation-refactorcut frommain, tagra-v1-rc2, canary on the branch targetingReleaseTest2(Release Automation canary: add publish-free paths (sync-issue, rejection, issue-close auto-reopen) #477, Release Automation canary: run on release-automation-refactor against ReleaseTest2 #478, Point the release automation caller at tooling release-automation-refactor ReleaseTest2#9) - Checkout via the
jobcontext inrelease-automation-reusable.yml(first branch PR, ci(ra): check out tooling via the job context #479); resolvers,tooling_ref_overrideandid-token: writeremoved. The same change tovalidation.ymlis a separate smallmainPR after the Sync26 release window (still pending) -
planjob:trigger.py,command_policy.py; replaces check-trigger, derive-state, handle-config-error, post-interim, post-rejection, publish-confirmation; compatibility outputs for the remaining jobs (refactor(ra): classify the trigger in trigger.py instead of inline JavaScript #480, refactor(ra): validate slash commands in command_policy.py instead of inline JavaScript #481, refactor(ra): fold the trigger, state and response jobs into one plan job #482) -
finalizejob:sync_pr.py,common_sync.py, Python issue finalisation (closes Refactor close-release-issue from inline JS to shared Python #153); replaces update-issue, post-result, create-sync-pr (refactor(ra): drop the release_plan_change trigger path #484, refactor(ra): add sync_pr.py and the common-file sync to common_sync.py #485, refactor(ra): fold update-issue, post-result and create-sync-pr into one finalize job #486) -
actandsnapshotjobs:draft_release.py,issue_events.py, publish entry point; command jobs folded, compatibility outputs removed (feat(ra): create every label release automation applies before applying it #487, refactor(ra): add draft_release.py, issue_events.py and a publish entry point in release_publisher #488, refactor(ra): replace the command jobs with act and snapshot jobs that emit one JSON outcome #489) - Snapshot glue to Python,
technical-architecture.md§2.12/§3.3 rewritten, shellcheck enabled as blocking in Tooling CI, v0 linting workflows deleted (refactor(ra): move the snapshot job glue into snapshot_prep and log bundling as a note #491, chore(linting): delete the retired v0 linting workflows, callers and docs #492, ci(tooling): make ShellCheck blocking in actionlint and fix the two validation.yml findings #493, docs(ra): describe the four-job workflow, common sync location and timings; add the refactor branch to the branching-model appendix #494) - Maintenance-branch releases (ReleaseManagement#356) on the branch
- Merge into
main,v1-rcmoved,ReleaseTest2and the pilots back to@v1-rc,ra-v1-rc2and the branch retired,branching-model.mdappendix updated
Alternative solution
Extracting each inline block into its own file while keeping the 15 jobs: gives tests for the blocks but leaves routing as untested if: expressions and the 224 output references in place. Rejected in favour of the phase cut.
Additional context
Completes the job consolidation started in #101. The validation framework is touched only by the checkout item (the validation.yml PR on main); everything else is release automation. Pre-merge coverage per slice: pytest in Tooling CI, the RA regression canary on the branch, a manual end-to-end cycle on ReleaseTest2 before each ra-v1-rc2 move.
Activity