Skip to content

ci: reduce PR test matrix, run full matrix in merge queue#830

Merged
mangelajo merged 3 commits into
mainfrom
ci/optimize-pr-matrix
Jun 23, 2026
Merged

ci: reduce PR test matrix, run full matrix in merge queue#830
mangelajo merged 3 commits into
mainfrom
ci/optimize-pr-matrix

Conversation

@mangelajo

Copy link
Copy Markdown
Member

Problem

PR CI runs the full test matrix (3 Python versions x 2 OSes = 6 pytest jobs, plus 2 architectures for e2e), which is slow and expensive. Most of this coverage is redundant for validating a PR — the full matrix only needs to pass before merging.

Changes

Python tests (python-tests.yaml)

  • PRs: Run only Python 3.12 on Ubuntu (1 job, down from 6)
  • Merge queue / push / dispatch: Full matrix — 3.11, 3.12, 3.13 on both Ubuntu and macOS

E2E tests (e2e.yaml)

  • PRs: Build and test only amd64 (down from amd64 + arm64)
  • Merge queue / push / dispatch: Both architectures

Implementation

Both workflows compute the matrix dynamically in the changes job based on github.event_name, outputting JSON arrays consumed by fromJson() in the matrix strategy.

Impact

PRs (before) PRs (after) Merge queue
pytest-matrix 6 jobs 1 job 6 jobs
e2e builds 4 jobs (2 images x 2 arch) 2 jobs (2 images x 1 arch) 4 jobs
e2e tests 2 jobs 1 job 2 jobs
Total ~12 jobs ~4 jobs ~12 jobs

No reduction in pre-merge coverage — the merge queue runs everything.

PRs now run a minimal CI matrix to save time and resources:
- Python tests: only Python 3.12 on Ubuntu (was 3 versions x 2 OSes)
- E2E tests: only amd64 (was amd64 + arm64)

The merge queue runs the full matrix before merging to main:
- Python tests: 3.11, 3.12, 3.13 on both Ubuntu and macOS
- E2E tests: both amd64 and arm64

This reduces PR CI from ~12 parallel jobs to ~4, while maintaining
full coverage before merge.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Two GitHub Actions workflows gain event-driven matrix computation. In e2e.yaml, a new step in the changes job emits an e2e-matrix JSON (amd64-only for PRs, amd64+arm64 otherwise) consumed by the controller build, operator build, and e2e-tests jobs. The compatibility test jobs add explicit PR-skip conditions. A new e2e aggregator job enforces workflow failure when dependent jobs fail, are cancelled, or skip despite should_run being true. In python-tests.yaml, a similar step emits python-versions and runners (Python 3.12/Ubuntu for PRs, 3.11–3.13/Ubuntu+macOS otherwise) consumed by pytest-matrix.

Changes

Dynamic CI Matrix Computation and Execution Control

Layer / File(s) Summary
Dynamic e2e architecture matrix
.github/workflows/e2e.yaml
changes job gains e2e-matrix output from a new computation step that emits amd64-only JSON for pull_request events and amd64+arm64 JSON for other event types. Controller image build, operator image build, and e2e-tests jobs switch their strategy include from hardcoded entries to fromJson(needs.changes.outputs.e2e-matrix).
Dynamic Python test matrix
.github/workflows/python-tests.yaml
changes job gains python-versions and runners outputs from a new computation step that emits Python 3.12/Ubuntu for pull_request events and Python 3.11–3.13 across Ubuntu and macOS for other event types. pytest-matrix derives runs-on and python-version from those outputs instead of hardcoded lists.
e2e compatibility jobs PR-only execution gating
.github/workflows/e2e.yaml
e2e-compat-old-controller and e2e-compat-old-client jobs add explicit github.event_name != 'pull_request' conditions to their if statements, ensuring they skip on pull requests while preserving existing should_run == 'true' || workflow_dispatch logic.
e2e aggregator job and failure detection
.github/workflows/e2e.yaml
A new e2e job runs unconditionally with if: always(), depends on changes, e2e-tests, and both compatibility jobs, and executes a failing step (exit 1) when any dependent job is failure or cancelled, or when e2e-tests is skipped while changes.should_run == 'true'.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • jumpstarter-dev/jumpstarter#239: Originally created the e2e.yaml workflow, which this PR modifies to introduce dynamic architecture matrix computation and execution control.
  • jumpstarter-dev/jumpstarter#489: Modified .github/workflows/e2e.yaml e2e job execution logic; this PR adds an always-running e2e aggregator job with failure detection to the same workflow.
  • jumpstarter-dev/jumpstarter#176: Modified .github/workflows/python-tests.yaml by using a changes job to compute outputs and drive test execution, similar to the dynamic matrix pattern introduced here.

Suggested reviewers

  • raballew
  • kirkbrauer

Poem

🐇 Hop hop, the matrix grows and shrinks with care,
On pull requests only amd64 builds with flair,
But merge and push unleash arm64's might,
Python 3.11–3.13, running day and night,
The e2e aggregator hops to catch each failing sight! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main changes: reducing the PR test matrix while maintaining full coverage in the merge queue.
Description check ✅ Passed The description comprehensively explains the problem, changes, and impact across both workflows with clear examples and metrics.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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/optimize-pr-matrix

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.

Move e2e-compat-old-controller and e2e-compat-old-client to only run
on merge queue, push to main, and workflow_dispatch. These cross-version
compatibility tests are important but don't need to gate every PR.
Add a rollup job (like pytest already has) so GitHub branch protection
can use a single 'e2e' required check that works for both PRs and
merge queue, regardless of which matrix jobs ran.

The rollup tolerates intentionally-skipped compat jobs on PRs but
fails if e2e-tests itself was skipped when changes were detected.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/e2e.yaml (1)

19-23: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard matrix consumers when changes can be skipped.

Line 19 can skip changes, but Lines 61/100/185 still parse needs.changes.outputs.e2e-matrix. On fork workflow_dispatch/push runs, this can become fromJson('') and fail before jobs start.

Suggested fix
 build-controller-image:
   needs: changes
-  if: needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
+  if: github.repository_owner == 'jumpstarter-dev' && (needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main'))
   strategy:
     matrix:
       include: ${{ fromJson(needs.changes.outputs.e2e-matrix) }}

 build-operator-image:
   needs: changes
-  if: needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
+  if: github.repository_owner == 'jumpstarter-dev' && (needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main'))
   strategy:
     matrix:
       include: ${{ fromJson(needs.changes.outputs.e2e-matrix) }}

Also applies to: 61-61, 100-100, 182-185

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e.yaml around lines 19 - 23, The jobs at lines 61, 100,
and 185 that consume the `needs.changes.outputs.e2e-matrix` output lack guards
to handle when the "changes" job is skipped on fork repositories. Add
conditional checks to these consuming jobs (typically using `if:
needs.changes.result == 'success'` or similar) to ensure they only attempt to
parse the e2e-matrix output when the upstream changes job has actually executed,
preventing fromJson('') failures on fork workflow_dispatch and push runs.
.github/workflows/python-tests.yaml (1)

18-24: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Align pytest-matrix gating with changes output dependency.

Line 18 may skip changes, but Lines 61/67 always parse its outputs. With Line 57 allowing workflow_dispatch, this can fail as fromJson('') instead of cleanly skipping.

Suggested fix
 pytest-matrix:
   needs: changes
-  if: needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch'
+  if: github.repository_owner == 'jumpstarter-dev' && (needs.changes.outputs.should_run == 'true' || github.event_name == 'workflow_dispatch')
   runs-on: ${{ matrix.runs-on }}
   strategy:
     matrix:
       runs-on: ${{ fromJson(needs.changes.outputs.runners) }}
       python-version: ${{ fromJson(needs.changes.outputs.python-versions) }}

Also applies to: 55-67

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/python-tests.yaml around lines 18 - 24, The pytest-matrix
job references outputs from the changes job (steps.filter.outputs.python,
steps.filter.outputs.renode_driver) on lines 61/67, but the changes job may be
skipped due to the conditional on line 18 when github.repository_owner is not
'jumpstarter-dev'. Since workflow_dispatch can trigger the workflow regardless
of this condition, the pytest-matrix job will fail trying to parse empty outputs
with fromJson(''). Add an explicit dependency by including needs: changes in the
pytest-matrix job definition and apply the same repository owner conditional
(if: github.repository_owner == 'jumpstarter-dev') to ensure pytest-matrix only
runs when changes has successfully produced outputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/e2e.yaml:
- Around line 19-23: The jobs at lines 61, 100, and 185 that consume the
`needs.changes.outputs.e2e-matrix` output lack guards to handle when the
"changes" job is skipped on fork repositories. Add conditional checks to these
consuming jobs (typically using `if: needs.changes.result == 'success'` or
similar) to ensure they only attempt to parse the e2e-matrix output when the
upstream changes job has actually executed, preventing fromJson('') failures on
fork workflow_dispatch and push runs.

In @.github/workflows/python-tests.yaml:
- Around line 18-24: The pytest-matrix job references outputs from the changes
job (steps.filter.outputs.python, steps.filter.outputs.renode_driver) on lines
61/67, but the changes job may be skipped due to the conditional on line 18 when
github.repository_owner is not 'jumpstarter-dev'. Since workflow_dispatch can
trigger the workflow regardless of this condition, the pytest-matrix job will
fail trying to parse empty outputs with fromJson(''). Add an explicit dependency
by including needs: changes in the pytest-matrix job definition and apply the
same repository owner conditional (if: github.repository_owner ==
'jumpstarter-dev') to ensure pytest-matrix only runs when changes has
successfully produced outputs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4d411be1-2ad9-460b-bc17-50fadc4a377c

📥 Commits

Reviewing files that changed from the base of the PR and between 86c308e and bc563d8.

📒 Files selected for processing (2)
  • .github/workflows/e2e.yaml
  • .github/workflows/python-tests.yaml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.github/workflows/e2e.yaml (1)

338-338: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Pin the rollup runner for consistency.

The rest of this workflow pins runners (e.g. ubuntu-24.04), but the aggregator uses the floating ubuntu-latest. Pinning avoids surprise behavior changes when GitHub rolls the latest label.

♻️ Optional consistency tweak
   e2e:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-24.04
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e.yaml at line 338, The aggregator job at line 338 uses
the floating `ubuntu-latest` runner while other jobs in the workflow use pinned
versions like `ubuntu-24.04`. Replace the `runs-on: ubuntu-latest` value with a
specific pinned version (e.g., `ubuntu-24.04`) to match the consistency of other
jobs in the workflow and prevent unexpected behavior changes when GitHub updates
what the `latest` tag points to.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/e2e.yaml:
- Line 338: The aggregator job at line 338 uses the floating `ubuntu-latest`
runner while other jobs in the workflow use pinned versions like `ubuntu-24.04`.
Replace the `runs-on: ubuntu-latest` value with a specific pinned version (e.g.,
`ubuntu-24.04`) to match the consistency of other jobs in the workflow and
prevent unexpected behavior changes when GitHub updates what the `latest` tag
points to.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c16c1cef-0f0b-4bae-a98d-c58619351ce2

📥 Commits

Reviewing files that changed from the base of the PR and between bc563d8 and 348185c.

📒 Files selected for processing (1)
  • .github/workflows/e2e.yaml

@mangelajo mangelajo added this pull request to the merge queue Jun 23, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 23, 2026
@mangelajo mangelajo added this pull request to the merge queue Jun 23, 2026
Merged via the queue into main with commit b38ff9a Jun 23, 2026
21 checks passed
@mangelajo mangelajo deleted the ci/optimize-pr-matrix branch June 23, 2026 19:51
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