Skip to content

ci: skip the expensive jobs on documentation-only changes - #311

Open
harshtandiya wants to merge 1 commit into
developfrom
ci/skip-docs-only-jobs
Open

ci: skip the expensive jobs on documentation-only changes#311
harshtandiya wants to merge 1 commit into
developfrom
ci/skip-docs-only-jobs

Conversation

@harshtandiya

@harshtandiyaharshtandiya commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

ci.yml and ui-tests.yml carried paths-ignore for **.md and docs/**. That
was worse than it looks. A workflow skipped by path filtering never reports its
checks — they stay Pending. Server and Playwright E2E Tests are required
checks in the protect-develop ruleset, so a docs-only PR wasn't just skipping
CI, it could never be merged. A job skipped by a job-level if: reports Success
and satisfies a required check. Hence the shape of this change: the filter moves
off the trigger and onto the jobs.

A changes job on ubuntu-slim computes one boolean; the expensive job takes
needs: changes and an if: on it. The detection is a composite action in
.github/actions/ so four workflows share one copy. It reads the PR's file list
with gh api instead of git diff, which avoids deepening the clone. Docs paths
are **.md, docs/**, .claude/**, specs/**.

Only pull_request has a base to diff against, so every other event falls
through to running everything. The gh api call also fails open — a skipped
required check reads as Success, so a transient API failure must not look like
"docs only".

Per event, for all four gated workflows:

EventGateExpensive job
docs-only PRcode=falseskipped → check reports Success, PR is mergeable
mixed docs+code PRcode=trueruns (first non-doc file wins)
code-only PRcode=trueruns
merge_groupnot a PR → code=trueruns
push to develop/mainnot a PR → code=trueruns
workflow_dispatch (ui-tests)not a PR → code=trueruns

Deliberately unchanged:

  • linter.yml is not gated.Frappe Linter is the cheapest of the
    expensive jobs, and it's the only one that validates the non-.md doc paths —
    check-json, check-yaml and check-ast in .pre-commit-config.yaml are
    unscoped, so gating it would stop catching a malformed .claude/settings.json
    on exactly the PRs that touch it. Its schedule trigger, workflow_dispatch,
    the if: github.event_name != 'schedule' condition and the separate
    Vulnerable Dependency Check job are all untouched.
  • No job or workflow name: was renamed — the five required contexts are matched
    as strings.
  • concurrency groups and existing permissions are as they were. The changes
    jobs declare their own contents: read / pull-requests: read.
  • pr-tittle-check.yml and backport.yml are cheap or event-specific.

Verified: actionlint reports nothing new (its one SC2086 hit is pre-existing in
the untouched linter.yml and identical on develop). The run: script was
extracted from action.yml and executed against a stubbed gh for all nine
cases — docs-only, mixed, code-only, .github/**, the four non-PR events, and a
failing gh — each giving the expected code=. On this PR the gate correctly
read .github/** as code and every job ran.

Not verified: a real docs-only PR end to end, and the merge_group path, neither
of which can be exercised before this merges. Both are covered by the harness
only.

`ci.yml` and `ui-tests.yml` carried `paths-ignore` for `**.md` and `docs/**`.
A workflow skipped by path filtering never reports its checks at all: they sit
in Pending forever. `Server` and `Playwright E2E Tests` are required checks on
`develop`, so a documentation-only PR was not merely cheap to run, it was
unmergeable.
A job skipped by a job-level `if:` reports Success instead, and satisfies a
required check. So the filter moves from the workflow trigger to the jobs: a
`changes` job on `ubuntu-slim` computes one boolean, and every expensive job
takes `needs: changes` plus an `if:` on it.
The detection lives in a composite action so the four workflows share it. It
lists the PR's files via `gh api` rather than `git diff`, which keeps the
shallow clone shallow. Only `pull_request` has a base to compare against, so
every other event -- push, merge_group, workflow_dispatch, schedule -- falls
through to running everything; those guard a branch directly and must never
skip. The API call fails open for the same reason: a skipped required check
reads as success, so a transient failure must not look like "docs only".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@greptile-appsgreptile-appsBot 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.

Your trial has ended. Reactivate Greptile to resume code reviews.

Sign up for freeto 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.

1 participant

@harshtandiya