Skip to content

[build] merge the release PR automatically once required checks pass - #18018

Merged
titusfortner merged 2 commits into
trunkfrom
auto-merge-release-pr
Sep 10, 2026
Merged

titusfortner merged 2 commits into
trunkfrom
auto-merge-release-pr

Conversation

@titusfortner

Copy link
Copy Markdown
Member

💥 What does this PR do?

  • Merges the release preparation PR automatically if required checks pass, so a release runs end to end from the Release Preparation dispatch.
  • Notifies selenium-tlc in Slack as soon as a required check fails, or if the merge itself errors.

🔧 Implementation Notes

  • GitHub's auto-merge runs as the enabling user and cannot use ruleset bypass, and trunk is locked by a ruleset during a release, so the bot (a bypass actor) merges from a workflow_run workflow instead.
  • --admin only skips the gh CLI preflight that refuses a PR whose merge state is blocked; GitHub still requires the bot to be a ruleset bypass actor.
  • Triggers on CI and CI - RBE only; CI - Lint always finishes well before either, so its checks are verified but never waited on.
  • Only the PR authored by selenium-ci is eligible, so no other release-preparation-* branch can be merged through the lock.
  • selenium-ci is added to the get-approval allowlist because the bot is now the actor on the merge event that starts the release workflow; without it every release would stop at the production environment approval.

🤖 AI assistance

  • AI assisted (complete below)
    • Tool(s): Claude Code (Fable 5.1)
    • What was generated: review of the merge workflow, the notification and author-filter hardening, and this description
    • I reviewed all AI output and can explain the change

💡 Additional Considerations

  • After this, the last manual step in a release is dispatching Release Preparation; the generated changelogs are published without anyone reading the PR.
  • The bot merging through the trunk lock is exercised for the first time on the next release.

🔄 Types of changes

  • New feature (non-breaking change which adds functionality and tests!)

@selenium-ci selenium-ci added the B-build Includes scripting, bazel and CI integrations label Sep 10, 2026
@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Automatically merge validated release preparation PRs

✨ Enhancement ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Automatically merges selenium-ci release preparation PRs after every required check passes.
• Alerts selenium-tlc when required checks or the privileged merge fail.
• Exempts selenium-ci-triggered releases from redundant production approval.
Diagram

graph TD
  A["Release Prep"] --> B["Bot Release PR"] --> C["CI Workflows"] --> D{"Checks pass?"}
  D -- Yes --> E["Privileged Merge"] --> F["Release Workflow"] --> G["Approval Allowlist"]
  D -- No --> H["Slack Alert"]
  E -- Error --> H
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. GitHub native auto-merge
  • ➕ Uses built-in pull-request merge orchestration.
  • ➕ Requires less custom workflow logic.
  • ➖ Runs as the enabling user, which cannot bypass the release trunk lock.
  • ➖ Does not provide the same targeted Slack failure handling.
2. Poll from release preparation
  • ➕ Keeps release creation and merging within one workflow.
  • ➕ Avoids coordinating multiple workflow completion events.
  • ➖ Consumes a runner while waiting for independent checks.
  • ➖ Introduces timeout and polling complexity for long-running CI.
  • ➖ Couples release preparation more tightly to CI implementation details.
3. Temporarily unlock trunk
  • ➕ Allows ordinary GitHub auto-merge behavior.
  • ➕ Avoids a privileged merge command.
  • ➖ Weakens trunk protection during a sensitive release window.
  • ➖ Creates race conditions where unrelated changes could merge.

Recommendation: Keep the workflow_run-based approach. It preserves the release trunk lock, uses the designated bypass actor only for a bot-authored PR at the exact checked commit, and reacts to independent CI completion without holding a runner. The repository and author filters materially reduce the risk of exposing privileged merging to unrelated branches.

Files changed (2) +73 / -1

Enhancement (1) +72 / -0
merge-release-pr.ymlMerge validated bot-authored release PRs automatically +72/-0

Merge validated bot-authored release PRs automatically

• Adds a workflow_run-driven release merge workflow that locates the selenium-ci PR, evaluates every required check, and squash-merges the validated head commit through the trunk ruleset. It serializes evaluations per release branch and alerts selenium-tlc when required checks or the merge fail.

.github/workflows/merge-release-pr.yml

Other (1) +1 / -1
get-approval.ymlAuthorize selenium-ci-triggered release workflows +1/-1

Authorize selenium-ci-triggered release workflows

• Adds selenium-ci to the trusted actor allowlist. Releases initiated by the bot's merge can proceed without waiting for redundant production-environment approval.

.github/workflows/get-approval.yml

@qodo-code-review

qodo-code-review Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📜 Skill insights (0)

Grey Divider


Action required

1. Rerun lint leaves releases unmerged ✗ Dismissed 🐞 Bug ≡ Correctness
Description
The workflow_run trigger excludes CI - Lint even though two checks from that workflow are
required before the release PR can merge. If lint finishes after both listed workflows or is rerun
after a failure, its successful completion starts no new merge attempt and the PR remains open.
Code

.github/workflows/merge-release-pr.yml[R4-7]

+  workflow_run:
+    workflows: ["CI", "CI - RBE"]
+    types: [completed]
+    branches: ["release-preparation-*"]
Evidence
The release ruleset requires Validate workflows and Format / Check Format, both supplied by `CI
- Lint, but the new workflow listens only for CI and CI - RBE`. GitHub therefore has no matching
completion event that retries the merge when lint is the last required workflow to pass.

.github/workflows/merge-release-pr.yml[4-7]
.github/rulesets/release-require-passing.json[19-35]
.github/workflows/ci-lint.yml[18-26]
.github/workflows/ci-lint.yml[49-55]
.github/workflows/merge-release-pr.yml[45-60]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Required lint checks can become successful after both currently listed trigger workflows have completed, but lint completion does not initiate another merge attempt.

## Fix Focus Areas
- .github/workflows/merge-release-pr.yml[4-7]
- .github/workflows/merge-release-pr.yml[47-54]

## Recommended Fix
Add `CI - Lint` to the `workflow_run.workflows` list and to the trigger-workflow set used by the notification calculation, so delayed and rerun lint checks can initiate merging.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Release merge regressions go undetected 📘 Rule violation ☼ Reliability
Description
The required-check decision and notification policy are implemented as an inline jq program
without regression coverage for its pass, pending, and failure branches. Changes in check buckets,
trigger workflow ordering, or failure combinations can therefore alter whether a release is merged
or Slack is notified without being caught before deployment.
Code

.github/workflows/merge-release-pr.yml[R47-50]

+          echo "notify=$(jq --arg conclusion "$CONCLUSION" --arg workflow "$WORKFLOW" --argjson triggers '["CI", "CI - RBE"]' '
+            def failed: .bucket != "pass" and .bucket != "pending";
+            def trigger: .workflow | IN($triggers[]);
+            length > 0 and
Evidence
Compliance rule 5 requires appropriately scoped regression coverage for changed behavior. The cited
workflow lines introduce multi-branch release decisions, while the PR adds no test or fixture
covering those decisions.

AGENTS.md: Prefer Small Reliable Tests and Avoid Contract-Misrepresenting Mocks
.github/workflows/merge-release-pr.yml[47-54]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new release merge workflow contains branching check and notification logic without an applicable regression test, leaving its merge and alert decisions unverified.

## Fix Focus Areas
- .github/workflows/merge-release-pr.yml[47-54]

## Recommended Fix
Extract the check-evaluation logic into a small testable script and add table-driven tests covering all checks passing, pending checks, each triggering workflow failing, non-trigger required checks failing, empty required-check results, and mixed terminal results. Invoke that tested script from the workflow while preserving the existing outputs.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Bot actions bypass production approval ✗ Dismissed 🐞 Bug ⛨ Security
Description
The shared authorization workflow now marks every run whose github.actor is selenium-ci as
preapproved rather than limiting the exception to the intended release-PR merge event. A workflow
dispatch performed as that account can consequently publish an arbitrary release tag or unlock trunk
without passing through the production environment approval.
Code

.github/workflows/get-approval.yml[25]

+      required: ${{ !contains(fromJSON('["AutomatedTester","selenium-ci","jimevans","p0deje","titusfortner","bonigarcia","diemol","pujagani","harsha509"]'), github.actor) }}
Evidence
The changed expression controls whether the production-environment authorization job runs for all
reusable-workflow callers. Release Selenium accepts a manually supplied tag and gates tag creation
on this workflow, while the manually dispatched trunk workflow uses the same approval workflow
before deleting release rulesets.

.github/workflows/get-approval.yml[20-55]
.github/workflows/release.yml[3-16]
.github/workflows/release.yml[67-103]
.github/workflows/unlock-trunk.yml[3-15]
.github/workflows/restrict-trunk.yml[39-56]
.github/workflows/restrict-trunk.yml[78-89]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Adding `selenium-ci` to the global actor allowlist bypasses approval for every caller of the reusable workflow, including manually dispatched release and trunk-management operations.

## Fix Focus Areas
- .github/workflows/get-approval.yml[20-55]
- .github/workflows/release.yml[41-87]
- .github/workflows/restrict-trunk.yml[39-56]

## Recommended Fix
Replace the global bot allowlist entry with an explicit, narrowly scoped input or condition supplied only by the merged release-PR path. Keep approval required when `selenium-ci` is the actor for `workflow_dispatch` and unrelated trunk-management callers.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Healthy releases send failure alerts ✗ Dismissed 🐞 Bug ☼ Reliability
Description
The check step treats every nonzero gh pr checks result except “no required checks reported” as an
execution error, even though the command returns exit code 8 while checks are pending. When either
triggering workflow finishes before another required check, line 42 fails the job and failure()
immediately sends the release-failure Slack notification.
Code

.github/workflows/merge-release-pr.yml[R41-42]

+          if ! checks=$(gh pr checks "$PR" --required --json name,bucket,workflow 2>"$RUNNER_TEMP/checks.err"); then
+            grep -q 'no required checks reported' "$RUNNER_TEMP/checks.err" || { cat "$RUNNER_TEMP/checks.err"; exit 1; }
Evidence
The official CLI documentation assigns exit code 8 to pending checks, while this workflow rejects
every nonzero result other than one stderr string. The two independently triggered CI workflows and
the required lint checks make a normal pending state reachable, and the notification step runs
whenever that rejection fails the job.

.github/workflows/merge-release-pr.yml[4-7]
.github/workflows/merge-release-pr.yml[41-54]
.github/workflows/merge-release-pr.yml[61-70]
.github/rulesets/release-require-passing.json[19-35]
🌐 The gh pr checks manual documents exit code 8 for checks that are still pending.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`gh pr checks` returns a nonzero status for normal pending and failed-check states, so the first completed workflow can generate a false workflow failure and Slack alert while other checks are still running.

## Fix Focus Areas
- .github/workflows/merge-release-pr.yml[41-54]
- .github/workflows/merge-release-pr.yml[61-70]

## Recommended Fix
Capture the command output and exit status separately. Continue into the existing JSON evaluation for documented check-result statuses such as pending, and fail the step only for genuine CLI/API errors or invalid JSON.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Web pages:
  +2 more
Review mode: ⚖️ Balanced: This changes security-sensitive release automation, ruleset-bypass merging, workflow triggers, required-check evaluation, and Slack failure handling, so a careful full review is warranted.

Grey Divider

Tip of the day
💡 Did you know, you can turn these tips off under Display preferences

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread .github/workflows/merge-release-pr.yml
Comment thread .github/workflows/merge-release-pr.yml
Comment thread .github/workflows/merge-release-pr.yml
Comment thread .github/workflows/get-approval.yml
@titusfortner
titusfortner merged commit 133a66a into trunk Sep 10, 2026
29 checks passed
@titusfortner
titusfortner deleted the auto-merge-release-pr branch September 10, 2026 15:54
This was referenced Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-build Includes scripting, bazel and CI integrations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants