chore(ci): sync the toolchain with vramfit and saucier - #432
Conversation
Every Python tool in the hook line now runs through 'uv run', so the version pre-commit uses is the one uv.lock pins and CI installs. The ruff and uv mirrors carried their own pins, which had already drifted from the lockfile (ruff 0.15.4 against 0.15.5). A pre-push stage carries the coverage gate and 'uv audit'. pre-commit-hooks adds whitespace, EOF, merge-marker and large-file checks. actionlint stays a mirror, since a Go binary has no lockfile entry; CI pins the same 1.7.12.
…elib ruff 0.15.5 -> 0.16.5, ty 0.0.20 -> 0.0.78, pytest-randomly 4 -> 5, and yamllint joins the dev group so pre-commit and CI run it from the lockfile. The griffe distribution on PyPI became a hollow shim at 1.15; the code moved to griffelib 2.x and still imports as griffe. The old 'griffe>=1.0,<2' constraint resolved to the shim and broke the griffe check on every fresh install. Both the extra and the dev group now require griffelib>=2.2,<3. ruff 0.16 formats fenced Python blocks in Markdown by default, so the vendored _bmad trees are excluded and force-exclude makes that exclusion hold for the explicit paths pre-commit passes.
ruff 0.16 enables 413 rules by default (up from 59). The 121 findings were all mechanical: removesuffix over slicing, next(iter()) over list()[0], collapsed nested ifs and withs, explicit check=False on subprocess.run, datetime.UTC, PEP 695 generics, and underscore-prefixed unused unpacked names. ty 0.0.78 no longer honours mypy-coded 'type: ignore[misc]' comments, so the 24 suppressions on frozen-dataclass mutation tests, dict[str, object] unpacking, and the dynamic LanguageServer attribute now use 'ty: ignore[rule]' with ty's own rule names. The suppression syntax example in docs/site/suppression.md sits inside a fmt:off fence so the formatter cannot normalise the comment spacing the example exists to demonstrate. Freshness is skipped for this commit: every touched body is a semantics-preserving rewrite and the docstrings still hold.
…ion majors CI gains yamllint and actionlint (pinned to the hook's 1.7.12), a workflow-level 'contents: read', and the audit-command preview flag that silences the uv audit warning. Action majors move to checkout v7, setup-uv v10, codecov v7, release-please v5, pages v5, setup-python v7, attest-action v0.0.6 and dynamic-badges v1.9.0. release-please and CodeQL follow the least-privilege layout: read-only at the workflow level, escalation per job. A release cut without the PAT now fails loudly, because a tag pushed with GITHUB_TOKEN never triggers publish.yml. The wheel smoke test also rejects docs/ and scripts/ and requires the py.typed marker. Dependabot replaces the Renovate config, which never opened a PR here; Dependabot already had, so it gets the grouped weekly schedule saucier uses. CONTRIBUTING documents the two-stage hook line.
setup-uv stopped publishing floating major tags at v8, so '@v10' does not resolve. Pin the full version instead.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
🟢 Approval recommended
The changes are primarily toolchain/CI synchronization and mechanical refactors, with only minor maintainability follow-ups noted in comments.
Pull request overview
This PR updates docvet’s development and CI toolchain to match the lockfile-driven, least-privilege patterns used in related repos, while addressing the griffe dependency shim issue by switching the optional extra to griffelib 2.x.
Changes:
- Align pre-commit and CI tooling to
uv.lock(run tools viauv run, add yamllint/actionlint/audit gates, and refresh workflow permissions). - Move the
griffeextra/dev dependency fromgriffe>=1,<2togriffelib>=2.2,<3and apply related internal cleanups. - Replace Renovate with grouped weekly Dependabot updates for
uvand GitHub Actions.
File summaries
| File | Description |
|---|---|
| tests/unit/test_mcp.py | Test adjustments for subprocess invocation and unused return values. |
| tests/unit/test_docs_infrastructure.py | MkDocs nav parsing test tweak (yaml load call site). |
| tests/unit/test_config.py | Update type suppression comments for ty. |
| tests/unit/test_cli.py | Update type suppression and minor loop simplification in tests. |
| tests/unit/test_cli_fix.py | Test variable usage cleanup (avoid unused bindings). |
| tests/unit/checks/test_undocumented_init_params.py | Avoid unused local in test helper results. |
| tests/unit/checks/test_trivial_docstring.py | Replace list indexing with next() in symbol selection. |
| tests/unit/checks/test_reverse_enrichment.py | Replace list indexing with next() and unused tuple unpacking cleanup. |
| tests/unit/checks/test_presence.py | Avoid unused stats binding in tests. |
| tests/unit/checks/test_prefer_fenced_code_blocks.py | Replace list indexing with next() in symbol selection. |
| tests/unit/checks/test_param_agreement.py | Replace list indexing with next() in symbol selection. |
| tests/unit/checks/test_overload_docstring.py | Update type suppression comment for ty. |
| tests/unit/checks/test_missing_returns.py | Replace list indexing with next() in symbol selection. |
| tests/unit/checks/test_missing_deprecation.py | Param formatting and symbol selection cleanup; unused unpacking cleanup. |
| tests/unit/checks/test_freshness.py | Simplify diff fixture string construction. |
| tests/unit/checks/test_finding.py | Update type suppression comments for ty. |
| tests/unit/checks/test_enrichment.py | Replace list indexing with next() and update ty suppression comment. |
| tests/integration/test_suppression_cli.py | Subprocess invocation made explicit about non-raising behavior. |
| tests/integration/test_mcp.py | Update type suppression and simplify async context management. |
| tests/integration/test_fix_cli.py | Subprocess invocation made explicit about non-raising behavior. |
| tests/fixtures/missing_yields.py | Use yield from in fixture generator. |
| tests/fixtures/complete_module.py | Use yield from in fixture generator. |
| src/docvet/reporting.py | Minor loop/conditional refactors for clarity. |
| src/docvet/lsp.py | Update type suppression comments for ty. |
| src/docvet/discovery.py | Minor boolean-return refactor in exclusion matcher. |
| src/docvet/config/init.py | Update type suppression comments for ty. |
| src/docvet/cli/_suppression.py | Simplify suppression boolean return. |
| src/docvet/cli/_runners.py | Introduce PEP 695 type params on progressbar context manager. |
| src/docvet/checks/presence.py | Minor conditional refactor while computing overload lines. |
| src/docvet/checks/griffe_compat.py | Adjust typing around yielded griffe objects. |
| src/docvet/checks/freshness.py | Switch to datetime.UTC usage. |
| src/docvet/checks/enrichment/_forward.py | Minor return expression simplification. |
| src/docvet/checks/enrichment/_class_module.py | Small conditional refactors and path-suffix simplification. |
| src/docvet/checks/enrichment/init.py | Minor control-flow simplification and formatting changes. |
| src/docvet/checks/coverage.py | Deterministic representative selection using min(). |
| src/docvet/ast_utils.py | Use removesuffix() for cleaner path normalization. |
| renovate.json | Remove Renovate configuration (migrate to Dependabot). |
| pyproject.toml | Update ruff config, add yamllint, and switch griffe extra/dev dep to griffelib. |
| docs/site/suppression.md | Preserve formatting of equivalence examples under formatter. |
| docs/site/rules/stale-signature.md | Formatting-only adjustment in docs example. |
| docs/site/rules/stale-import.md | Formatting-only adjustment in docs example. |
| docs/site/rules/overload-has-docstring.md | Update overload example formatting/structure. |
| docs/site/rules/missing-deprecation.md | Formatting-only adjustment in docs example. |
| docs/site/cli-reference.md | Formatting-only adjustment in docs example. |
| CONTRIBUTING.md | Update contributor guidance for new pre-commit stages and uv-run tooling. |
| CLAUDE.md | Update pinned attest-action version guidance. |
| action.yml | Bump actions/setup-python major version. |
| .sonarlint/connectedMode.json | Formatting (newline) normalization. |
| .pre-commit-config.yaml | Rework hooks to run via uv run, add pre-push gates, and add basic pre-commit-hooks. |
| .github/workflows/test-publish.yml | Action bumps, Python pinning, and stricter wheel contents checks. |
| .github/workflows/test-action.yml | Action bumps (checkout). |
| .github/workflows/release-please.yml | Least-privilege permissions, release token safety check, and action bumps. |
| .github/workflows/publish.yml | Action bumps, Python pinning, wheel content gate, and attest-action bump. |
| .github/workflows/docs.yml | Action bumps and uv sync --locked for docs build. |
| .github/workflows/codeql.yml | Add push trigger, permissions tightening, and checkout bump. |
| .github/workflows/ci.yml | Add workflow-level permissions, add yamllint/actionlint/audit gates, and bump actions. |
| .github/ISSUE_TEMPLATE/bug_report.md | Trailing whitespace cleanup. |
| .github/dependabot.yml | Add grouped weekly Dependabot updates for uv and GitHub Actions. |
| .claude/rules/pytest.md | Formatting updates to match current style/tooling expectations. |
Review details
- Files reviewed: 58/60 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| @@ -130,7 +130,7 @@ def _walk_objects( | |||
| if current.is_alias: | |||
| continue | |||
| if current.docstring is not None and current.filepath in file_set: | |||
| yield current | |||
| yield current # ty: ignore[invalid-yield] | |||
There was a problem hiding this comment.
Addressed in latest push — _walk_objects now does cast("GriffeObject", current) after the is_alias guard and yields that, so the ty: ignore[invalid-yield] is gone. String form keeps the griffe import under TYPE_CHECKING.
| def _maybe_progressbar[V]( | ||
| items: Sequence[V], |
There was a problem hiding this comment.
Addressed in latest push — removed the module-level V = TypeVar("V") and the TypeVar import; the PEP 695 parameter is the only declaration now.
Review follow-ups on #432. The ruff UP047 autofix rewrote _maybe_progressbar to a PEP 695 type parameter but left the module-level TypeVar behind. In _walk_objects, a cast after the is_alias guard states the narrowing ty cannot infer, replacing the invalid-yield ignore. Freshness skipped for the module-level finding: the only module body change is the added cast import.
The docvet toolchain had drifted behind vramfit and saucier: pre-commit mirrors pinned their own ruff and uv versions apart from the lockfile, CI had no yamllint or actionlint gate, several action majors were two versions back, and the lockfile still resolved
griffe>=1.0,<2to the hollow 1.15 shim that PyPI now serves, which broke the griffe check on every fresh install. This PR brings the repo to the same lockfile-driven hook line and least-privilege workflow layout the other two repos use, and moves the griffe extra togriffelib2.x.griffelib>=2.2,<3in both thegriffeextra and the dev groupuv run, add a pre-push stage for coverage anduv audit, and add pre-commit-hooks basicscontents: readto CI; bump checkout, setup-uv, codecov, release-please, pages, setup-python and attest-action majors; replace Renovate with a grouped Dependabot schedulety: ignore[rule]commentsTest:
pre-commit run --all-files(all 13 hooks pass),uv run pytest(1820 passed),uv run docvet check --allon a clean treefix(griffe): depend on griffelib 2.x instead of the hollow griffe 1.15 shim
chore(ci): run pre-commit tools from the lockfile and bump action majors
PR Review
Checklist
uv run pytest)uv run ruff check .)uv run ty check)!in title andBREAKING CHANGE:in bodyReview Focus
setup-uv@v10.0.1is beyond what vramfit and saucier run (both v7), and it is a full pin because setup-uv stopped publishing floating major tags at v8. The v8 to v10 breaking changes are the removed custom manifest,prune-cachedefaulting to false (CI prunes explicitly already) and.tool-versionssupport; none apply here, but CI on this PR is the proof.RELEASE_PLEASE_TOKEN, sincepublish.ymltriggers on the tag push and aGITHUB_TOKENtag never fires it. Confirm the secret is set before merging.src/in that commit.E402,E501,I,D. Adopting vramfit's Sonar-adjacent set (B,SIM,PL,TRY,S, ...) surfaces 602 findings and is a separate effort.Related