diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 09e5964a3..a6658fba2 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -4,8 +4,9 @@ name: CodeQL on: push: branches: [main] + # Every pull request, whatever its base, plus each merge queue group. pull_request: - branches: [main] + merge_group: schedule: - cron: "23 5 * * 1" diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 2756e4bad..00e93c022 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -2,8 +2,11 @@ name: Dependency Review # SOC 2: dependency-review (OA-C-24). Flags vulnerable/denied deps on PRs. on: + # Every pull request, whatever its base, so a stacked PR reaches main with + # this required check already reported. pull_request: - branches: [main] + # The merge queue tests each group before it lands on main. + merge_group: permissions: contents: read @@ -22,6 +25,16 @@ jobs: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Dependency Review + if: github.event_name != 'merge_group' uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 with: fail-on-severity: high + # A queue group has no pull request in its payload: compare the group's + # head with the main commit it was built on. + - name: Dependency Review (merge queue group) + if: github.event_name == 'merge_group' + uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 + with: + fail-on-severity: high + base-ref: ${{ github.event.merge_group.base_sha }} + head-ref: ${{ github.event.merge_group.head_sha }} diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index 4d71509e2..a6ad7c6b9 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -35,12 +35,19 @@ jobs: env: BEFORE_SHA: ${{ github.event.before }} EVENT_NAME: ${{ github.event_name }} + GROUP_BASE_SHA: ${{ github.event.merge_group.base_sha }} shell: bash run: | set -euo pipefail changed_paths="${RUNNER_TEMP}/openadapt-desktop-changed-paths.txt" : > "${changed_paths}" - if [ "${EVENT_NAME}" = "push" ]; then + if [ "${EVENT_NAME}" = "merge_group" ]; then + # A queue group is scoped like a push to main: diff the group's + # head against the main commit it was built on. + BEFORE_SHA="${GROUP_BASE_SHA}" + git fetch --no-tags --depth=1 origin "${GROUP_BASE_SHA}" || true + fi + if [ "${EVENT_NAME}" = "push" ] || [ "${EVENT_NAME}" = "merge_group" ]; then before="${BEFORE_SHA}" if [ -z "${before}" ] || [ "${before}" = "0000000000000000000000000000000000000000" ]; then before="$(git rev-parse HEAD^)" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c59dcf0dd..ad5d5dfde 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,6 +4,8 @@ on: pull_request: branches: - '**' + # The merge queue tests each group before it lands on main. + merge_group: push: branches: - main diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 5018e7046..e2d05bec4 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -46,6 +46,8 @@ name: Packages on: pull_request: + # The merge queue tests each group before it lands on main. + merge_group: push: branches: [main] workflow_dispatch: @@ -86,6 +88,7 @@ jobs: env: EVENT_NAME: ${{ github.event_name }} BEFORE_SHA: ${{ github.event.before }} + GROUP_BASE_SHA: ${{ github.event.merge_group.base_sha }} run: | set -euo pipefail all() { @@ -95,6 +98,13 @@ jobs: case "$EVENT_NAME" in workflow_dispatch) all ;; pull_request) base="HEAD^1" ;; # the PR merge commit's first parent is the base tip + # A queue group runs the full matrix (the PR tier ran one lane) + # for every package the group's PRs touch, measured from the main + # commit the group was built on. + merge_group) + base="$GROUP_BASE_SHA" + git cat-file -e "$base^{commit}" 2>/dev/null || all + ;; *) if [ -z "${BEFORE_SHA:-}" ] || [ "$BEFORE_SHA" = 0000000000000000000000000000000000000000 ] \ || ! git cat-file -e "$BEFORE_SHA^{commit}" 2>/dev/null; then diff --git a/.github/workflows/platform-manifest.yml b/.github/workflows/platform-manifest.yml index 3b2083625..ac47179ec 100644 --- a/.github/workflows/platform-manifest.yml +++ b/.github/workflows/platform-manifest.yml @@ -8,6 +8,8 @@ on: pull_request: branches: - '**' + # The merge queue tests each group before it lands on main. + merge_group: push: branches: - main diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml index 2d5db93f0..02212b5f3 100644 --- a/.github/workflows/secret-scan.yml +++ b/.github/workflows/secret-scan.yml @@ -6,6 +6,8 @@ name: Secret Scan # invoke it directly and pin the version. Scans full git history on PRs + main. on: pull_request: + # The merge queue tests each group before it lands on main. + merge_group: push: branches: [main] diff --git a/packages/desktop/scripts/classify_build_changes.py b/packages/desktop/scripts/classify_build_changes.py index 2c41eb576..308d51518 100644 --- a/packages/desktop/scripts/classify_build_changes.py +++ b/packages/desktop/scripts/classify_build_changes.py @@ -4,9 +4,10 @@ request that changes the Tauri shell or its JavaScript locks also builds the Linux installer, so a native dependency bump compiles before it merges. Release candidates and explicit dispatches keep the complete platform matrix. A push -to protected ``main`` repeats the expensive matrix only when a dependency, -toolchain, packaging, or native-runtime input changed. The immutable native -release workflow always rebuilds every installer from its release tag. +to protected ``main``, and a merge queue group about to become ``main``, +repeats the expensive matrix only when a dependency, toolchain, packaging, or +native-runtime input changed. The immutable native release workflow always +rebuilds every installer from its release tag. """ from __future__ import annotations @@ -123,7 +124,8 @@ def classify_build_scope(event: str, changed_paths: Iterable[str]) -> BuildScope if native: return BuildScope(True, True, f"pull request changes the native shell: {native[0]}") return BuildScope(True, False, "representative pull-request sidecar") - if event != "push": + # A merge queue group is about to become main, so it gets main's scope. + if event not in ("push", "merge_group"): return BuildScope(True, True, f"unknown event {event!r}; fail toward full evidence") if not paths: diff --git a/packages/desktop/tests/test_build_change_classifier.py b/packages/desktop/tests/test_build_change_classifier.py index 8e87ddd4b..fb39a156a 100644 --- a/packages/desktop/tests/test_build_change_classifier.py +++ b/packages/desktop/tests/test_build_change_classifier.py @@ -85,3 +85,10 @@ def test_empty_push_fails_toward_the_complete_matrix() -> None: def test_absolute_or_parent_path_is_refused() -> None: with pytest.raises(ValueError, match="repository-relative"): classify_build_scope("push", ["../outside"]) + + +def test_merge_queue_group_is_scoped_like_main() -> None: + assert classify_build_scope("merge_group", ["src/App.tsx"]) == classify_build_scope( + "push", ["src/App.tsx"] + ) + assert classify_build_scope("merge_group", []).run_native is True