Skip to content

ci: build master changes through a merge queue - #1560

Merged
joaodinissf merged 1 commit into
masterfrom
ci/merge-queue
Oct 9, 2026
Merged

joaodinissf merged 1 commit into
masterfrom
ci/merge-queue

Conversation

@joaodinissf

@joaodinissf joaodinissf commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Why the change

Master should only ever move to a commit that was built exactly as the snapshot build will build it, so two PRs that are green on their own can no longer break master together or share a version.

Special things to note

  • Needs a repository admin after merging: add a merge queue rule to the master ruleset, with rebase merges, one PR per group, one group building at a time, all-green grouping and a 60-minute check timeout. Adding it first would leave queued PRs waiting for checks that never run. The rule must not be bypassable, by admins or direct pushes, or same-minute merges become possible again.
  • Merge-queue builds use the published snapshot like the snapshot build does, and fail on a mismatch. -Dtycho.baseline=failCommon fails the build when an artifact has a version the published snapshot already has, with different content. Tycho's default only warns and swaps in the published copy. On 28 Sep, fix(xtext): match case-sensitive pattern lookups against the candidate name #1551 and fix(xtext.ui): iterate a snapshot of the matches when showing a running search #1552 were merged 9 s apart, so the runtime feature got one version for two contents. The snapshot build swapped in fix(xtext): match case-sensitive pattern lookups against the candidate name #1551's feature, which pins xtext.ui 17.3.3, and failed to resolve. The last good snapshot swapped 36 artifacts, all identical, so the guard has no false positives there. Because the queue builds one PR at a time and each takes a full CI run, two merges to master can no longer land in the same minute. Pushes to version branches (v*) don't go through the queue; their snapshot builds are covered by failCommon.
  • PR builds still check versions against the last release, but no longer compare with the published snapshot.
    • The release version check, tycho-p2-extras:compare-version-with-baselines against p2/releases/latest, doesn't read the tycho.baseline properties and runs as before. This PR's own build ran it in 61 modules.
    • -Dtycho.baseline=disable -Dtycho.baseline.replace=none only switch off tycho-p2-plugin's comparison with p2/snapshots/latest.
    • A PR build only has to show that the PR is correct; the queue checks it against master. Today one bad snapshot fails every open PR, and so does a PR whose commits are older than master's last change to the same feature.

Change outline

 .github/workflows/verify.yml
+  on: merge_group
   maven-verify:
+    pull_request → -Dtycho.baseline=disable -Dtycho.baseline.replace=none
+    merge_group  → -Dtycho.baseline=failCommon
 .github/workflows/snapshot.yml
+  -Dtycho.baseline=failCommon
flowchart LR
  PR[PR build: release version check,<br/>no snapshot comparison] -->|approved + auto-merge| Q[merge queue: one PR at a time]
  Q --> B[queue build = snapshot build<br/>swap + failCommon]
  B -->|green| M[master fast-forwards]
  B -->|red| X[PR leaves the queue, master untouched]
  M --> S[snapshot build publishes]
Loading

🤖 Generated with Claude Code

@joaodinissf
joaodinissf enabled auto-merge (rebase) September 30, 2026 10:41

@rubenporras rubenporras left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think

PR builds no longer read the published snapshot (-Dtycho.baseline=disable -Dtycho.baseline.replace=none).

is not correct, the PR should still read the last released version to know that a plugin version must be updated. So I think the flags -Dtycho.baseline=disable -Dtycho.baseline.replace=none should not be applied like that. Can we change it so that the check stays but against the release and not the snapshot?

@joaodinissf

Copy link
Copy Markdown
Collaborator Author

(Comment left by Claude at João's request.)

@rubenporras, the check against the last release stays in PR builds; those two flags only switch off the comparison with the published snapshot:

  • -Dtycho.baseline / -Dtycho.baseline.replace are the baselineMode / baselineReplace of tycho-p2-plugin:p2-metadata, whose baseline repository is p2/snapshots/latest.
  • The version check is tycho-p2-extras-plugin:compare-version-with-baselines against p2/releases/latest. It reads only baselines, skip and onIllegalVersion, so it isn't affected.
  • This PR's own build (run 36703946394) ran compare-version-with-baselines in 61 modules against p2/releases/latest, and never loaded p2/snapshots/latest.

The description made that unclear. I've reworded it, the workflow comment and the commit message to say that PR builds still compare versions with the last release; the behaviour is unchanged.

@joaodinissf

Copy link
Copy Markdown
Collaborator Author

(Comment left by Claude at João's request.)

@rubenporras, on why LSP4E has never hit this although its setup is the same as ours (minute-resolution jgit qualifiers, the swap against its published snapshot, no merge queue):

  • Same-minute collisions do happen there. At least five times since 2022, two PRs touching the same bundle landed within a minute, most recently in January, 15 s apart, and got the same qualifier.
  • They stay harmless for two reasons:
    • No features. The update site lists bundles directly, and the bundles require each other with lower bounds only, so a swapped-in older jar still resolves. Our failure needed a feature pinning an exact bundle version the new build no longer had.
    • Its snapshot job cancels the running build when a newer push arrives (since 2024). The first of two quick merges never publishes, so the next build never finds its own qualifier already published.
  • Our snapshot builds queue instead of cancelling, so the second build read the first one's freshly published snapshot.

That's why this PR keeps the swap. The merge queue keeps merges from landing in the same minute, and failCommon makes any collision that still gets through fail the build instead of publishing a stale artifact.

Run the verify checks on merge_group so master can be gated by a merge
queue that builds one PR at a time on top of the current master.

Merge-queue and snapshot builds keep replacing artifacts with the
published snapshot's, but now fail when a version the snapshot already
has comes with different content (-Dtycho.baseline=failCommon) instead
of silently swapping in the published copy. Two merges within one
minute gave the runtime feature one version for two contents; the
snapshot build then took #1551's feature, which pins xtext.ui 17.3.3,
and failed to resolve the umbrella feature.

PR builds still compare versions with the last release
(compare-version-with-baselines reads none of these properties) but no
longer replace anything with the published snapshot, so a bad or newer
snapshot cannot fail an unrelated PR; the queue build checks the PR
against master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@joaodinissf
joaodinissf merged commit 010e843 into master Oct 9, 2026
4 checks passed
@joaodinissf
joaodinissf deleted the ci/merge-queue branch October 9, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants