Skip to content

ci: skip unnecessary jobs based on change detection#892

Merged
sirtimid merged 10 commits into
mainfrom
sirtimid/ci-skip-unnecessary-jobs
Mar 26, 2026
Merged

ci: skip unnecessary jobs based on change detection#892
sirtimid merged 10 commits into
mainfrom
sirtimid/ci-skip-unnecessary-jobs

Conversation

@sirtimid

@sirtimid sirtimid commented Mar 23, 2026

Copy link
Copy Markdown
Member

Description

Adds a detect-changes job to the main CI workflow that classifies changed files and conditionally skips expensive jobs when they aren't needed. This reduces CI time and resource usage for documentation, config, and CI-only PRs.

Changes

  • Added a detect-changes job that categorizes files into: docs, config/tooling, CI, and code
  • Docs-only PRs (.md, .txt, docs/, .claude/, LICENSE): run lint only, skip build, test, integration, e2e, and security scan
    • This could be further optimized in the future by not running eslint unnecessarily
  • Config-only PRs (.eslintrc, .prettierrc, .editorconfig, etc.): run lint only, skip build/test/e2e
  • CI-only PRs (.github/workflows/, .github/actions/): run actionlint only, skip everything else
  • Code PRs: run everything as before (no change)
  • Added a lint-only job for config-only changes that don't need the full build/test pipeline
  • Updated all-jobs-complete gate to dynamically verify success based on what was expected to run
  • Pushes to main always run the full pipeline regardless of file types
  • Added a step summary with change detection results for easy debugging

Testing

This is a CI workflow change. It can be validated by observing the GitHub Actions run on this PR itself — since the only changed file is .github/workflows/main.yml, the detect-changes job should classify it as CI-only and skip lint/build/test jobs. The workflow is also self-testing through its own merge queue integration.


Note

Medium Risk
Medium risk because it changes CI gating logic and could unintentionally skip required checks or misclassify changes, affecting merge protection and security scanning coverage.

Overview
Adds a new detect-changes job that diffs against the PR/merge-queue base SHA and classifies changes into has-code, has-ci, and has-lint-targets, publishing a step summary for debugging.

Updates the main workflow to conditionally run check-workflows, analyse-code, and lint-build-test only when relevant (while always running the full pipeline on pushes to main), and introduces a lint-only job for non-code changes.

Refactors all-jobs-complete to dynamically enforce success based on the detected change category (including requiring detect-changes to succeed) so the final gate accurately reflects what was expected to run.

Written by Cursor Bugbot for commit 6ac945e. This will update automatically on new commits. Configure here.

@sirtimid
sirtimid requested a review from a team as a code owner March 23, 2026 20:57
Comment thread .github/workflows/main.yml
Comment thread .github/workflows/main.yml
Comment thread .github/workflows/main.yml Outdated
Comment thread .github/workflows/main.yml Outdated
@sirtimid
sirtimid requested a review from rekmarks March 23, 2026 21:49
Comment thread .github/workflows/main.yml
Comment thread .github/workflows/main.yml
@sirtimid
sirtimid enabled auto-merge March 23, 2026 22:20
@sirtimid
sirtimid force-pushed the sirtimid/ci-skip-unnecessary-jobs branch from 1eea7ec to ee5166b Compare March 24, 2026 16:59
Comment thread .github/workflows/main.yml Outdated
sirtimid and others added 8 commits March 26, 2026 09:27
Add a `detect-changes` job that classifies files into categories and
conditionally skips expensive CI jobs:

- docs-only (.md, .txt, docs/, .claude/, LICENSE): skip all jobs
- config/tooling-only (.eslintrc, .prettierrc, etc.): run lint only
- CI-only (.github/): run actionlint only
- code changes: run everything as before

The `all-jobs-complete` gate is updated to verify the right jobs
succeeded based on what actually changed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove redundant AGENTS.md pattern (already matched by *.md)
- Group redirects to $GITHUB_OUTPUT and $GITHUB_STEP_SUMMARY

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address two gaps in the all-jobs-complete gate:
- Fail if detect-changes itself fails (prevents empty outputs from
  letting the gate pass with zero validation)
- Verify check-workflows succeeded for CI-only PRs (has-ci=true)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Docs files (.md, .txt, etc.) now set HAS_LINT_TARGETS=true since
  prettier runs on them via lint:misc (rekmarks review)
- analyse-code and lint-build-test handle skipped check-workflows
  via explicit result guard to prevent cascade-skip issues
- Gate now requires check-workflows for code changes too (not just CI)
- Dead else branch now fails explicitly instead of using github.event.before

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The implicit success() in GitHub Actions if: conditions short-circuits
when an upstream job is skipped, making the '== skipped' check dead
code. Use always() with '!= failure' instead so analyse-code and
lint-build-test can run when check-workflows is legitimately skipped.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CI workflow files (.yml) go through prettier via lint:misc, so they
need HAS_LINT_TARGETS=true to trigger the lint-only job.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The always() pattern on analyse-code and lint-build-test bypassed
the merge queue skip optimization. Add check-skip-merge-queue to
their needs and condition so they don't run when the merge queue
determines the PR is already up-to-date.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sirtimid
sirtimid force-pushed the sirtimid/ci-skip-unnecessary-jobs branch from ee5166b to c9901ec Compare March 26, 2026 08:28
@sirtimid
sirtimid requested a review from rekmarks March 26, 2026 08:29
Comment thread .github/workflows/main.yml
Changes to .github/actions/* (e.g. playwright-install) were classified
as CI-only, skipping build/test validation. Split into its own case
that also sets HAS_CODE=true so the lint-build-test pipeline runs.

Also removes .claude/* from the doc-only pattern so it falls through
to the code catch-all, future-proofing for executable skills/plugins.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment thread .github/workflows/main.yml Outdated
LICENSE only matched a bare LICENSE file, but the repo uses
LICENSE.APACHE2 and LICENSE.MIT. Change to LICENSE* so license-only
changes are correctly classified as documentation, not code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@rekmarks rekmarks 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.

LGTM!

@sirtimid
sirtimid added this pull request to the merge queue Mar 26, 2026
Merged via the queue into main with commit 05f513c Mar 26, 2026
20 checks passed
@sirtimid
sirtimid deleted the sirtimid/ci-skip-unnecessary-jobs branch March 26, 2026 18:00
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