Repository navigation
ci(lint-python): split linting into code, docs, and linkcheck jobs - #199
Conversation
Run the three lint stages as separate jobs so that a failure points at the stage that broke, and so link checking is no longer bundled with the documentation linters. - Rename the Makefile `lint` target to `lint-code`. - Drop `linkcheck` from `docs-lint`. It runs in its own job through the existing `docs-%` passthrough, so no new target is needed. - Gate the new `docs` and `linkcheck` jobs on a `docs-files` path filter covering the docs directory, Markdown files, and reStructuredText files. - Treat an unset `source-files` input as "not docs-only". Outside of `workflow_call` the input is empty, so the previous `== 'true'` comparison meant that pushes and pull requests to main only ever ran the documentation linters.
There was a problem hiding this comment.
🟡 Changes recommended
Critical workflow and compatibility issues remain unresolved.
4 open findings
What changed in this PR
Splits Python linting into independent code, documentation, and link-check workflow jobs.
Changes:
- Renames
linttolint-codeand separates documentation link checking. - Adds path-filtered
docsandlinkcheckjobs. - Updates source-file gating for push, pull request, and reusable workflow runs.
| File | Review findings |
|---|---|
Makefile |
Critical (4 votes): Renaming lint breaks the documented reusable-workflow contract; retain a compatibility alias or update/version the contract. |
.github/workflows/lint-python.yaml |
Critical (2 votes): The linkcheck setup reference uses a truncated SHA. Moderate: Job gating remains step-level, .readthedocs.yaml is omitted from documentation filters, and RST changes are not excluded from the source filter. |
🧠 Review effort: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Move the paths filter into its own job that exposes `source-files` and `docs-files` as job outputs, so the `files`, `docs`, and `linkcheck` jobs can be gated at job level. Previously the conditions sat on the final step, which meant a source-only change still started a runner for both documentation jobs, checked out the repository, and installed `uv` before the filter decided there was nothing to do. - Add `.readthedocs.yaml` to the documentation filter. It was already excluded from the source filter, so a change touching only that file previously ran no linters at all. - Drop `pull-requests: read` from the three linting jobs. Only the filter job reads the pull request API. Document the renamed target and the documentation targets in the README, and describe the `source-files` input.
The previous commit rewrote the whole workflow file and reverted the rename from "Lint Python" to "Lint" in f360004.
The filter job only checks out the repository and classifies changed files, so it does not need the full runner image. The three linting jobs are unchanged and still use ubuntu-latest.
The starflow lint workflow is being split so that the code linters run as their own job, and it calls the code linters as `make -k lint-code` (see canonical/starflow#199). Split the aggregate `lint` target so the code linters can be addressed as `lint-code`, matching the repositories that already provide it. `lint` still runs everything for local use.
The starflow lint workflow is being split so that the code linters run as their own job, and it calls the code linters as `make -k lint-code` (see canonical/starflow#199). Split the aggregate `lint` target so the code linters can be addressed as `lint-code`, matching the repositories that already provide it. `lint` still runs everything for local use.
|
@mr-cal I believe canonical/starbase#632 is what you're looking for. |
|
@mr-cal and here's one that skips the code linting but runs the docs/linkcheck: LoweRAM/charmcraft#1 |
|
Thanks for the runs, interesting failure on the linkchecker: https://github.com/LoweRAM/charmcraft/actions/runs/39987431539/job/120530361084?pr=1#step:4:339 |
|
Odd that it did that in that charmcraft one but not in craft-application. Looking... |
|
@mr-cal ok I've added |


Summary
Splits the lint workflow into jobs so that a red run identifies which lint stage broke, and so link checking no longer blocks or delays the rest of the documentation linting.
filterfilesmake -k lint-codedocsmake -k docs-lintlinkcheckmake -k docs-linkcheckDraft: the workflow shape is settled, but nothing has run against a real runner yet.
Related starbase change
The starbase side of this split is canonical/starbase#625, which adds an
explicit
docs-linkchecktarget. Itsdocs-%passthrough routesdocs-linkcheckthe same way, so this workflow works either way, but #625makes the target explicit and keeps
make lintrunning link checking.Merge order matters. Both orders are being tested:
merged first.
starflow merged first. The
linkcheckjob is expected to fail there.Changes
Makefile
linttarget tolint-code.linkcheckfromdocs-lint. No new target was added: the existingdocs-%passthrough already routesdocs-linkchecktomake -C docs linkcheck.lint-python.yaml
filterjob that runsdorny/paths-filteronce and exportssource-filesanddocs-filesas job outputs. The three linting jobs takeneeds: filterand gate at job level.docs-filesfilter coveringdocs/**,**/*.md,**/*.rst, and.readthedocs.yaml.docsandlinkcheckjobs keep only thesetup-uvstep, since neither the documentation linters nor Sphinx's linkchecker need the snap-installed linters.pull-requests: readnow exists only onfilter, which is the only job that calls the pull request API.README
lint-codetarget, the previously undocumenteddocs-lintanddocs-linkchecktargets, and thesource-filesinput.Review responses
All four Copilot findings and the zizmor alert were addressed:
setup-uvSHA (2c77769)..readthedocs.yaml(46f37bc).lintagainst the documented contract (46f37bc). This one is a deliberate breaking change for consumers, discussed below.Behaviour changes worth reviewing
The
source-filesinput only exists forworkflow_call. Onpushandpull_requestevents it is empty, so the old conditioninputs.source-files == 'true'never matched and self-linting runs of this repository only ever executed the documentation linters. Thefilesjob now usesinputs.source-files != 'false', so an unset input counts as "not docs-only" and the code linters run on pushes and pull requests tomain. Callers that passsource-files: 'false'still skip them.Mixed changes now run both code and documentation linting. A pull request touching source files and documentation runs all three linting jobs, where the previous exclusive either/or would have run only the code linters. Gating both documentation jobs on a single shared filter also means a pull request that changes only source files no longer starts a runner for
docsandlinkcheck, which previously checked out the repository and installeduvbefore the final step's condition was evaluated.Consumers must rename
linttolint-code. Any repository calling this workflow needs the renamed target. An alias in this repository's Makefile would not help, since callers supply their own. If a non-breaking change is preferred, the alternative is to keep invokinglintand drop the rename.Testing
make -n lint-code,make -n docs-lint, andmake -n docs-linkcheckall resolve to the expected recipes.prettier --checkpasses over the repository glob.uses:reference in the workflow is pinned to a 40-character commit SHA.Not yet verified against a real runner.