Skip to content

Fix Read the Docs build, add Docker dev environment and standards sync - #24

Open
jtdub wants to merge 6 commits into
developfrom
docker-dev-and-shared-standards
Open

Fix Read the Docs build, add Docker dev environment and standards sync#24
jtdub wants to merge 6 commits into
developfrom
docker-dev-and-shared-standards

Conversation

@jtdub

@jtdub jtdub commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Read the Docs

The build produced nothing usable. .readthedocs.yaml ran poetry install without pointing VIRTUAL_ENV at the environment Read the Docs runs mkdocs from, so Poetry created its own virtualenv and mkdocs was never installed where the build could find it. It also declared a second, conflicting install path via docs/requirements.txt.

Fixed by installing into $READTHEDOCS_VIRTUALENV_PATH and deleting docs/requirements.txt, leaving pyproject.toml as the single source of docs dependencies. Note this deliberately does not copy hier_config's simpler requirements-only approach: the mkdocstrings reference pages import hier_config_api, so the package itself has to be installed in the docs environment.

Docker development environment

Dockerfile is multi-stage — development carries the full toolchain, production only runtime dependencies. docker-compose.yml bind-mounts the repo for hot reload, with an opt-in docs profile for live-reload mkdocs on :8001.

Driven by invoke tasks (tasks.py), matching the task names used across the hier-config projects:

invoke build / serve / docs / pytest / lint / lint-and-test / cli / sync-standards / destroy

serve is this repo's addition to the shared set, since a library has no process to serve.

Shared standards

Adopts the model added in netdevops/hier_config#298. scripts/build.py, scripts/sync_standards.py, .yamllint.yml, and .dockerignore are now pulled from that repository via the .standards.yml manifest, with hier_config rewritten to hier_config_api as files are fetched. .github/workflows/sync-standards.yml applies the sync weekly and opens a PR, so CI validates canonical changes before they land.

⚠️ Depends on netdevops/hier_config#298 — the sync fetches from master, so sync-standards reports the new files as unpublished until that merges. Everything else here stands alone.

The ruff pin

Worth a careful look, as it is the largest behavioral change. This repo pinned ruff >=0.14.14,<0.15; the canonical repo tracks 0.16. That pin was the cause of the build.py divergence — ruff 0.14 does not understand the # ruff: ignore[...] directive the canonical file uses, so this repo's copy had been rewritten to # noqa and the two could never converge.

Relaxing to ^0.16 flips the relationship: under 0.16's preview rules that directive is not merely accepted but required, so the pre-existing # noqa comments in main.py and platform_service.py were converted. Also adds pytest-profiling for the --profile option the canonical build.py exposes.

With those aligned, invoke sync-standards reports zero drift on scripts/build.py.

Verification

  • poetry run python scripts/build.py lint — clean on ruff 0.16
  • 51 tests pass, 96% coverage (gate is 95%)
  • poetry run mkdocs build --strict — clean
  • Both Docker targets build; the dev container serves /api/openapi.json
  • poetry run python scripts/sync_standards.py check — zero drift on the already-published files

🤖 Generated with Claude Code

jtdub and others added 6 commits August 6, 2026 09:38
Switch the hier-config dependency from the git checkout / 3.x range to
the 4.0.0b1 beta from PyPI, using a specifier that explicitly includes
the prerelease so pip and poetry resolve it. v4 removes the module-level
constructor functions, so replace all get_hconfig(platform, text) calls
in the service layer with the v4 classmethod HConfig.from_text(platform,
text) per the official v3-to-v4 migration guide. No other v3-only APIs
(config_to_get_to, dump_simple, tags_add/tags_remove, v2 compatibility
helpers, negation rule models) were in use, and WorkflowRemediation is
unchanged in v4, so no further code changes are required. poetry.lock is
regenerated against the new pin; all 21 tests plus ruff, ruff format,
and mypy strict pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adopt the development standards from the hier_config repository so both
projects share one toolchain: ruff (ALL rules, preview, line length 88),
mypy strict with the pydantic plugin, pyright strict, pylint with
extension plugins and pylint_pydantic, yamllint, and flynt, all driven
by the parallel runner in scripts/build.py. Coverage is enforced at 95%
via 'build.py pytest --coverage' (--cov=hier_config_api).

Dev dependencies gain pyright, pylint-pydantic, pytest-xdist, yamllint,
flynt, and typer; pytest-asyncio is dropped because the test suite has
no async tests. The mypy ignore_missing_imports overrides for
hier_config are removed since hier_config 4.x ships py.typed.

CI now mirrors hier_config: a Python 3.10-3.14 matrix running
'build.py lint' and 'build.py pytest --coverage' on push/PR to develop
and next, and the docs job builds with 'mkdocs build --strict' and
deploys to GitHub Pages on push to develop (the default branch; it
previously only triggered on the nonexistent main branch).

This repo has no CHANGELOG.md, so the change is recorded here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fix all violations surfaced by the hier_config lint stack (64 ruff
errors, 22 pyright errors, and 12 pylint messages beyond ruff's fixes):

- Routers: drop redundant response_model arguments (FAST001), move to
  Annotated[..., Query()] dependencies (FAST002/B008), rename the
  export 'format' parameter to export_format with a query alias to
  avoid shadowing the builtin (A002), and restructure try blocks so
  each guards a single statement (pylint too-many-try-statements),
  extracting small orchestration helpers where several calls must be
  error-wrapped together.
- Services: replace typing.Any parameters with HConfig | HConfigChild
  (ANN401), pass MatchRule/GenerateRemediationRequest models instead of
  long argument lists (PLR0913/PLR0917), split boolean-heavy matching
  into a helper (PLR0916), mark PLATFORMS as ClassVar (RUF012),
  restructure batch processing so the per-device try/except lives
  outside the loop body (PERF203), and assign exception messages to a
  variable before raising (EM102/TRY003).
- Models: use keyword 'default=' in Field() calls so pyright's strict
  dataclass_transform handling recognizes optional fields, and use a
  named module-level default factory for the ordering field.
- Annotate empty-list literals so pyright strict can infer element
  types.

Justified suppressions, each with an explanatory comment:
- BLE001/broad-exception-caught in validate_config and batch device
  processing, where any failure must be reported as data, not raised.
- S104 on the dev/container uvicorn entry point binding 0.0.0.0.
- T201/S404/S603 in scripts/build.py (a console tool that prints and
  spawns the lint/test processes), replacing the upstream file's
  invalid 'ruff:ignore' comments with real noqa directives.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Coverage sat at 89.4% once the hier_config coverage gate was enforced.
Add function-based, fully annotated tests for the previously uncovered
paths: the root and health endpoints, 404 responses for unknown
remediations, reports, and batch jobs, 400 responses when parsing fails
(via monkeypatched HConfig.from_text) or a search regex is invalid, the
invalid export format guard, YAML export and tag-filtered change
queries, per-device failure recording in batch jobs, storage updates
for unknown IDs, remediation tag include/exclude filtering, and
merge/search service edge cases. Total coverage is now 95.9% with no
'# pragma: no cover' exclusions.

Update CLAUDE.md and the README development section to document the
scripts/build.py commands, the lint/typing stack, the coverage floor,
and the new CI matrix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Releases were previously manual with no defined process. Add two
GitHub Actions workflows: Prepare Release (admin-gated
workflow_dispatch that bumps the version with poetry, opens a
release/vX.Y.Z PR against the dispatched branch, and creates a draft
GitHub release) and Release (publishes to PyPI via poetry publish
when a release is published — the published event, not created, so
publishing a draft triggers it). Document the three-step process in
the README.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Read the Docs produced no usable build. The config ran `poetry install`
without pointing VIRTUAL_ENV at the environment Read the Docs runs mkdocs
from, so Poetry created its own virtualenv and mkdocs was never installed
where the build could find it. It also declared a second, conflicting
install path via docs/requirements.txt. Point the install at
$READTHEDOCS_VIRTUALENV_PATH and drop the requirements file, leaving
pyproject.toml as the single source of docs dependencies. The package
itself must be installed because the mkdocstrings reference pages import
it, so the simpler requirements-only approach used by hier_config does
not work here.

Add a Docker development environment driven by invoke tasks, and adopt
the shared standards published by netdevops/hier_config: build.py,
sync_standards.py, .yamllint.yml, and .dockerignore now come from there
via the .standards.yml manifest, with hier_config rewritten to
hier_config_api as they are fetched. A scheduled workflow applies the
sync weekly and opens a PR so CI validates the update before it merges.

Relax the ruff pin from <0.15 to ^0.16 to match the canonical repository.
The old pin was the reason scripts/build.py had diverged: ruff 0.14 does
not understand the `# ruff: ignore[...]` directive the canonical file
uses. On 0.16 that directive is not merely accepted but required, so the
existing `# noqa` comments were converted. Add pytest-profiling for the
--profile option the canonical build.py exposes. With those aligned,
`invoke sync-standards` reports zero drift.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant