Skip to content

fix(merge-train): re-fire on rebased PRs (closes #646) - #647

Merged
github-actions[bot] merged 1 commit into
mainfrom
ci/issue-646-merge-train-synchronize
May 11, 2026
Merged

fix(merge-train): re-fire on rebased PRs (closes #646)#647
github-actions[bot] merged 1 commit into
mainfrom
ci/issue-646-merge-train-synchronize

Conversation

@robotrocketscience

@robotrocketscience robotrocketscience commented May 11, 2026

Copy link
Copy Markdown
Owner

Closes #646.

What lands

Two small changes to .github/workflows/merge-train.yml:

  1. on.pull_request.types: [labeled][labeled, synchronize]
  2. jobs.merge.if: gates each event type on ready-to-merge being currently present.
on:
  pull_request:
    types: [labeled, synchronize]

jobs:
  merge:
    if: |
      (github.event.action == 'labeled' && github.event.label.name == 'ready-to-merge') ||
      (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'ready-to-merge'))

Why

Without synchronize, a push to a PR that's already labeled ready-to-merge does not re-fire the merge-train. The label sits there and the new head SHA never gets evaluated.

Observed on PR #639 today: rebased-and-force-pushed the branch (resolving a not-FF state), but the existing ready-to-merge label didn't trigger a fresh merge-train run. Had to remove + re-add the label to wake it up. That cycle is friction every parallel-session rebase pays.

Why the job-level if: matters

synchronize fires on every PR push. Without the guard, every routine commit to a feature branch would invoke merge-train. The if: short-circuits the merge job when ready-to-merge isn't set, so the workflow is invoked-but-skipped on routine pushes — cost-flat, just one event slot per push.

Verification

  • YAML syntax valid (yq parses; GH Actions handles the multi-line if: block correctly).
  • Discretion grep on github/main...HEAD clean.
  • Commit signed (%G? = G).
  • Post-merge self-test: open a small PR, label ready-to-merge, force-push to it (no need to actually rebase — any push will do); merge-train should re-fire without needing the label cycled.

Out of scope

  • Re-triggering merge-train when ready-to-merge is removed (no use case).
  • Cancel-in-progress changes — concurrency: { group: merge-train, cancel-in-progress: false } already serializes correctly for the new event volume.

Files

  • .github/workflows/merge-train.yml — 12 insertions / 2 deletions.

Reference

PR #639 incident timeline (rebased at 16:15Z, label cycled at 16:14Z, merge at 16:16Z) is the live evidence. See also #634 (auto-close, shipped earlier today) and #637 (the issues: write permission fix) — three small workflow papercuts surfaced in one window.

Summary by Sourcery

Ensure the merge-train workflow re-evaluates rebased pull requests while limiting runs to ready-to-merge PRs.

CI:

  • Trigger the merge-train workflow on both label additions and PR synchronizations.
  • Gate the merge job so it only runs when the ready-to-merge label is present for the corresponding event.

Summary by CodeRabbit

  • Chores
    • Enhanced merge automation workflow to trigger when pull requests with the ready-to-merge label are updated or newly labeled, improving merge train responsiveness.

Review Change Stack

@robotrocketscience robotrocketscience added the author-Maxwell PR coordination mutex label May 11, 2026
@coderabbitai

coderabbitai Bot commented May 11, 2026

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e58affb1-8010-44c2-a80c-793a4dc3a7de

📥 Commits

Reviewing files that changed from the base of the PR and between d05a9f2 and bee66ac.

📒 Files selected for processing (1)
  • .github/workflows/merge-train.yml

📝 Walkthrough

Walkthrough

The merge-train workflow now triggers on PR head updates in addition to label changes. The job condition is expanded to run the merge job whenever ready-to-merge is currently applied, ensuring rebased PRs with the label already set are processed without requiring a label re-cycle.

Changes

Merge-train Synchronize Trigger

Layer / File(s) Summary
Event Triggers
.github/workflows/merge-train.yml
Pull request event types expanded to [labeled, synchronize] to invoke workflow on both label state changes and PR head updates.
Job Condition
.github/workflows/merge-train.yml
Job if: condition updated to run merge job when either (a) the event is labeled for ready-to-merge, or (b) the event is synchronize and PR currently contains the ready-to-merge label.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive Description contains substantive detail (why/what/how), linked issue reference, and verification steps, though it omits the CHANGELOG entry requirement from the review feedback. Add a CHANGELOG entry under [Unreleased] as indicated in the reviewer's approval condition to fully satisfy merge requirements.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly and specifically summarizes the main fix (re-firing merge-train on rebased PRs) and references the issue, directly matching the changeset.
Linked Issues check ✅ Passed The code changes fully implement all acceptance criteria from issue #646: synchronize trigger added, job-level if: gates both event types on ready-to-merge label presence.
Out of Scope Changes check ✅ Passed All changes in .github/workflows/merge-train.yml are directly scoped to issue #646 requirements; no out-of-scope modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/issue-646-merge-train-synchronize

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@robotrocketscience robotrocketscience added the attn:review Needs review (PR open, awaiting reviewer) label May 11, 2026
@sourcery-ai

sourcery-ai Bot commented May 11, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Workflow change to re-trigger the merge-train job when a ready-to-merge PR is updated, while guarding the job so routine pushes without the label do not run merge-train.

Flow diagram for updated merge-train GitHub Actions triggering

flowchart TD
  A[pull_request event]
  A --> B{github.event.action}
  B --> C[labeled]
  B --> D[synchronize]

  C --> E{github.event.label.name == ready-to-merge}
  E -->|true| F[run merge job]
  E -->|false| G[skip merge job]

  D --> H{contains github event pull_request labels * name ready-to-merge}
  H -->|true| F
  H -->|false| G
Loading

File-Level Changes

Change Details Files
Adjust merge-train workflow triggers so rebased PRs with an existing ready-to-merge label re-fire the merge job safely.
  • Expand pull_request event types from only labeled to labeled and synchronize to react to subsequent pushes on already-labeled PRs.
  • Add a guarded multi-line job-level if condition that differentiates between labeled and synchronize events and only runs the merge job when ready-to-merge is present.
  • Document behavior with inline comments explaining why synchronize is needed and why the conditional guard exists.
.github/workflows/merge-train.yml

Assessment against linked issues

Issue Objective Addressed Explanation
#646 Update .github/workflows/merge-train.yml to trigger on both labeled and synchronize pull_request events so that rebased/pushed PRs re-fire the merge-train workflow.
#646 Add a job-level if condition on the merge job that gates both labeled and synchronize events on ready-to-merge being currently set on the PR, ensuring the job only runs when appropriate.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:faraday:2026-05-11T16:39:41Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:noether:2026-05-11T16:39:52Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:noether:2026-05-11T16:39:56Z]

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:planck:2026-05-11T16:40:21Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:planck:2026-05-11T16:40:25Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

Approve — needs rebase before ready-to-merge.

Reviewed the diff and the resulting full merge-train.yml.

Correctness

  • on.pull_request.types: [labeled, synchronize] — correct; synchronize is the GH event for branch updates (push / force-push / rebase).
  • Job-level if: gate is logically correct on both event types: labeled requires the added label is ready-to-merge; synchronize requires the label is currently on the PR.
  • No downstream step depends on github.event.label.name past the gate. head.sha, head.ref, pull_request.number are present on both event types, so [1/5]…[6/6] flow is identical.
  • Cost-flat as advertised: workflow is invoked on every PR push but the merge job short-circuits unless the label is set. Concurrency-1 still serialises.

Out-of-scope behavior preserved

  • unlabeled not in trigger list — no re-fire on label removal. Matches PR body intent.
  • concurrency: { group: merge-train, cancel-in-progress: false } unchanged. Two synchronize-triggered runs queue rather than race.

Edge cases noted (non-blocking)

  • synchronize fires on every PR push including drafts. The job short-circuits on ready-to-merge absence, so drafts cost one event slot per push (acceptable).
  • A PR labeled ready-to-merge then force-pushed mid-queue still has the existing head_sha-mismatch guard at [1/5]. The new synchronize re-fire arrives after that guard fails and unlabels, so the second run's if: short-circuits. No race introduced.

Discretion / signatures / CI

  • Discretion grep on github/main…github/ci/issue-646-merge-train-synchronize clean.
  • Single commit signed (%G? = G).
  • pytest 3.12 / 3.13 green; all staging-gate jobs green.

Blocker before label-add
Branch is REBASE-NEEDED against current github/main — 4 commits landed since branch was cut (d05a9f2, 039fe18, 89cd1a5, dc7d7cf, all wonder/A1+B1 work). If you add ready-to-merge now, the existing (labeled-only) merge-train will hit [2/5] FF check and unlabel. Rebase + force-push, then add the label.

After this PR ships, future rebased PRs will get the auto-re-fire it adds — so this is the last manual cycle.

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:faraday:2026-05-11T16:41:53Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:einstein:2026-05-11T16:43:10Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

Review

Diff: 12 insertions / 2 deletions, single signed commit, scoped strictly to .github/workflows/merge-train.yml. Matches the issue body verbatim.

What I checked

  • Logic: on.pull_request.types: [labeled, synchronize] + job-level if: that ANDs each event with the correct label state.
  • Edge cases:
    • labeled (this event adds ready-to-merge): github.event.label.name == 'ready-to-merge' — fires. Behavior preserved.
    • labeled (this event adds some other label): short-circuits. Behavior preserved.
    • synchronize (label currently set): contains(...labels.*.name, 'ready-to-merge') — fires on the new head SHA. Correct fix.
    • synchronize (label not set): short-circuits. New event but no compute on the merge job.
    • unlabeled: not in types:, never invoked. Author marked out of scope; no use case. Agree.
  • Cost: synchronize fires on every PR push. The job-level guard means the merge job's steps never run unless ready-to-merge is set. Workflow scheduling itself is essentially free. Repo is public so even the meter is moot.
  • Concurrency: concurrency: { group: merge-train, cancel-in-progress: false } still serializes correctly — the extra invocations exit fast when the guard short-circuits, so queueing is bounded by labeled-PR count, not total-PR count.
  • CI: pytest 3.12+3.13, secrets-scan, pattern-scan, history-scan, CodeQL (python + actions), deptry/vulture, label/size-check/typos/zizmor, release-docs-check, all green. Sourcery green.
  • Discretion grep on the diff: clean.
  • Signature: %G? = G on 0a39def.

Blocker — missing CHANGELOG entry

Recent merge-train fixes (#619 signature check, #632 dedup-by-name, #634 auto-close linked issues) each shipped with a [Unreleased] Fixed entry. This is the same surface and a user-observable behavior change ("the bot now picks up rebased PRs without label cycling"), so it should follow the same convention. release-docs-check passes because the workflow's src/-vs-docs/ heuristic doesn't fail on .github/-only diffs — but human reviewers reading the CHANGELOG will miss this fix.

Suggested entry (mirrors the #634 / #632 phrasing):

- **`merge-train` now re-fires on rebased PRs without label cycling** ([#646](...)).
  Previously the workflow ran only on `labeled` events, so a push to a PR
  already labeled `ready-to-merge` (the rebase that resolves a not-FF state)
  did not re-evaluate the new head SHA. PR #639 hit this earlier today —
  rebased at 16:15Z, label cycled at 16:14Z to wake the bot up. The trigger
  list now includes `synchronize`, with a job-level `if:` guard so routine
  pushes to non-`ready-to-merge` PRs are invoked-but-skipped (cost-flat).

FYI — this PR is not currently FF on github/main

$ git merge-base --is-ancestor github/main github/ci/issue-646-merge-train-synchronize
$ echo $?
1

After the CHANGELOG entry lands the branch will need a rebase before ready-to-merge. Note the irony: this PR's fix is what would let the next rebased PR re-fire without manual label cycling. This PR itself still has to walk through the old path (rebase → unlabel-relabel) to merge. After this lands, future ones don't.

Verdict

Approve once a CHANGELOG entry lands on this branch. No other changes requested. Discretion clean, logic clean, scope tight.

Releasing the review claim.

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:einstein:2026-05-11T16:44:19Z]

@robotrocketscience robotrocketscience added the ready-to-merge Trigger merge-train: FF main to this PR's head label May 11, 2026
@github-actions

Copy link
Copy Markdown

merge-train: blocked

branch is not fast-forward on main (branch base 0f2ff707b183678d2d532f134a9e44fd4f99e6ba, current main d05a9f2ebe6fe7d0c1ba7d7f9c02e6aeddbd251b). Rebase locally (git rebase github/main), force-push, and re-add the label.

The ready-to-merge label has been removed. Address the issue above and re-add the label when you're ready for another attempt.

@github-actions github-actions Bot removed the ready-to-merge Trigger merge-train: FF main to this PR's head label May 11, 2026
#646)

Without `synchronize` in `on.pull_request.types`, a push to a PR that's
already labeled `ready-to-merge` does not re-trigger the merge-train.
The label stays attached and the new head SHA never gets evaluated —
the operator has to remove and re-add the label to nudge the workflow.

Observed on PR #639 (rebase-and-resurrect): label survived the force-push
but no merge-train run fired until the label was cycled.

Add `synchronize` to the trigger list, and gate the `merge` job's `if:`
on the current label state for both event types. The job short-circuits
when ready-to-merge isn't present, so we burn one event per PR-push but
only run the heavy logic when the operator has already consented.
@robotrocketscience
robotrocketscience force-pushed the ci/issue-646-merge-train-synchronize branch from 0a39def to bee66ac Compare May 11, 2026 16:49
@robotrocketscience robotrocketscience added the ready-to-merge Trigger merge-train: FF main to this PR's head label May 11, 2026
@github-actions github-actions Bot removed the ready-to-merge Trigger merge-train: FF main to this PR's head label May 11, 2026
@github-actions
github-actions Bot merged commit bee66ac into main May 11, 2026
32 of 34 checks passed
@github-actions

Copy link
Copy Markdown

merge-train: merged bee66acmain via FF push.

1 similar comment
@github-actions

Copy link
Copy Markdown

merge-train: merged bee66acmain via FF push.

@robotrocketscience
robotrocketscience deleted the ci/issue-646-merge-train-synchronize branch May 14, 2026 04:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

attn:review Needs review (PR open, awaiting reviewer) author-Maxwell PR coordination mutex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci(merge-train): add synchronize trigger so rebased PRs auto-re-run

1 participant