From 5ed1e085c7cfc645b15894d531d2d23c7c0dd862 Mon Sep 17 00:00:00 2001 From: abrichr Date: Tue, 20 Oct 2026 01:34:18 -0400 Subject: [PATCH 1/3] ci: cancel superseded Packages runs on main unless the push changes Desktop A push to main whose commits mention packages/desktop/ keeps its own concurrency group and is never cancelled, because desktop-release.yml waits for the Packages run of the newest first-parent commit that changed Desktop (#1398). Every other push to main shares one group with cancel-in-progress, so a newer push cancels the older run instead of queueing behind it. Merge queue groups and dispatches are never cancelled. tests/test_packages_concurrency.py keeps the Desktop exception in place. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/packages.yml | 27 +++++++++++++++++---- tests/test_packages_concurrency.py | 38 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 tests/test_packages_concurrency.py diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 64c3da981..79c5b8212 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -49,10 +49,29 @@ permissions: contents: read concurrency: - # A pull request's newer push supersedes its older run. Runs on main are - # never cancelled: desktop-release.yml needs every main commit's own result. - group: packages-${{ github.event.pull_request.number || github.sha }} - cancel-in-progress: ${{ github.event_name == 'pull_request' }} + # A pull request's newer push supersedes its older run. + # + # On main, desktop-release.yml waits for the Packages run of the newest + # first-parent commit that changed packages/desktop (#1398). A push whose + # commits touch packages/desktop/ therefore keeps its own group and is never + # cancelled. Every other push to main shares one group, so a newer one + # cancels it instead of queueing behind it. The test is conservative: any + # mention of packages/desktop/ in the push payload (file lists or messages) + # counts as a Desktop change, and a push with no commit list keeps its own + # group. Merge queue groups and dispatches are never cancelled. + group: >- + packages-${{ + github.event.pull_request.number + || (github.event_name == 'push' + && github.event.head_commit + && !contains(toJSON(github.event.commits), 'packages/desktop/') + && 'main-without-desktop') + || github.sha }} + cancel-in-progress: >- + ${{ github.event_name == 'pull_request' + || (github.event_name == 'push' + && github.event.head_commit != null + && !contains(toJSON(github.event.commits), 'packages/desktop/')) }} env: PIP_DISABLE_PIP_VERSION_CHECK: "1" diff --git a/tests/test_packages_concurrency.py b/tests/test_packages_concurrency.py new file mode 100644 index 000000000..8bf9fdac7 --- /dev/null +++ b/tests/test_packages_concurrency.py @@ -0,0 +1,38 @@ +"""Packages runs on main: only runs the Desktop release never reads are cancelled. + +desktop-release.yml waits for the Packages push run of the newest first-parent +commit that changed packages/desktop (#1398). That run must never be cancelled. +Any other main run may be superseded by a newer push. +""" + +from __future__ import annotations + +from pathlib import Path + +import yaml + +WORKFLOW = ( + Path(__file__).resolve().parents[1] / ".github" / "workflows" / "packages.yml" +) + + +def _concurrency() -> dict[str, str]: + return yaml.safe_load(WORKFLOW.read_text(encoding="utf-8"))["concurrency"] + + +def test_desktop_changes_keep_their_own_uncancelled_group() -> None: + group = " ".join(_concurrency()["group"].split()) + cancel = " ".join(_concurrency()["cancel-in-progress"].split()) + desktop = "!contains(toJSON(github.event.commits), 'packages/desktop/')" + # Only a push without a Desktop change joins the shared, cancellable group. + assert ( + f"github.event_name == 'push' && github.event.head_commit && {desktop} && 'main-without-desktop'" + in group + ) + assert group.endswith("|| github.sha }}") + assert ( + f"github.event_name == 'push' && github.event.head_commit != null && {desktop}" + in cancel + ) + # Merge queue groups and dispatches are never cancelled. + assert "merge_group" not in cancel and "workflow_dispatch" not in cancel From 8a9c381b598a681dbeb2ef40ed184323835c4a2c Mon Sep 17 00:00:00 2001 From: abrichr Date: Tue, 20 Oct 2026 01:36:05 -0400 Subject: [PATCH 2/3] ci: keep a push of 20 or more commits in its own Packages group GitHub truncates a push payload's commit list at 20 entries, so a large push could hide a packages/desktop change from the toJSON check and have its run cancelled. Such a push now keeps its own group, like a Desktop change. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/packages.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 79c5b8212..1d346f380 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -57,13 +57,16 @@ concurrency: # cancelled. Every other push to main shares one group, so a newer one # cancels it instead of queueing behind it. The test is conservative: any # mention of packages/desktop/ in the push payload (file lists or messages) - # counts as a Desktop change, and a push with no commit list keeps its own - # group. Merge queue groups and dispatches are never cancelled. + # counts as a Desktop change. A push with no commit list, or with 20 or more + # commits (GitHub truncates the payload's list at 20, which could hide a + # Desktop change), keeps its own group. Merge queue groups and dispatches + # are never cancelled. group: >- packages-${{ github.event.pull_request.number || (github.event_name == 'push' && github.event.head_commit + && !github.event.commits[19] && !contains(toJSON(github.event.commits), 'packages/desktop/') && 'main-without-desktop') || github.sha }} @@ -71,6 +74,7 @@ concurrency: ${{ github.event_name == 'pull_request' || (github.event_name == 'push' && github.event.head_commit != null + && !github.event.commits[19] && !contains(toJSON(github.event.commits), 'packages/desktop/')) }} env: From de8d2a0cb1cff0a186a052b1a3d72202ec5c975e Mon Sep 17 00:00:00 2001 From: abrichr Date: Tue, 20 Oct 2026 01:36:36 -0400 Subject: [PATCH 3/3] test: require the 20-commit guard in the Packages concurrency test The previous commit added the guard to packages.yml but left the test asserting the old expression, so it failed. The test now requires !github.event.commits[19] in both the group and cancel-in-progress. Co-Authored-By: Claude Opus 5.5 --- tests/test_packages_concurrency.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/test_packages_concurrency.py b/tests/test_packages_concurrency.py index 8bf9fdac7..bae67ecef 100644 --- a/tests/test_packages_concurrency.py +++ b/tests/test_packages_concurrency.py @@ -24,15 +24,14 @@ def test_desktop_changes_keep_their_own_uncancelled_group() -> None: group = " ".join(_concurrency()["group"].split()) cancel = " ".join(_concurrency()["cancel-in-progress"].split()) desktop = "!contains(toJSON(github.event.commits), 'packages/desktop/')" - # Only a push without a Desktop change joins the shared, cancellable group. - assert ( - f"github.event_name == 'push' && github.event.head_commit && {desktop} && 'main-without-desktop'" - in group - ) + # GitHub truncates the payload's commit list at 20, so a push of 20 or more + # commits could hide a Desktop change: it keeps its own group. + short = "!github.event.commits[19]" + shared = f"github.event_name == 'push' && github.event.head_commit && {short} && {desktop}" + # Only a short push without a Desktop change joins the cancellable group. + assert f"{shared} && 'main-without-desktop'" in group assert group.endswith("|| github.sha }}") - assert ( - f"github.event_name == 'push' && github.event.head_commit != null && {desktop}" - in cancel - ) + pushed = "github.event_name == 'push' && github.event.head_commit != null" + assert f"{pushed} && {short} && {desktop}" in cancel # Merge queue groups and dispatches are never cancelled. assert "merge_group" not in cancel and "workflow_dispatch" not in cancel