Skip to content

feat: stevedore-release-scope hook, and make python hooks actually installable - #4

Merged
blairham merged 5 commits into
mainfrom
feat/stevedore-release-scope-hook
Aug 13, 2026
Merged

feat: stevedore-release-scope hook, and make python hooks actually installable#4
blairham merged 5 commits into
mainfrom
feat/stevedore-release-scope-hook

Conversation

@blairham

Copy link
Copy Markdown
Contributor

Adds the shared stevedore-release-scope hook, and fixes the packaging bug that meant no language: python hook in this repo has ever run.

Part of trading#3362 — moving static CI guards to pre-commit. This PR must merge and be tagged v0.3.0 before the trading side lands: trading's config pins rev: v0.3.0, and pre-commit resolves all repos before running any hook, so until the tag exists trading's hooks cannot run locally at all.

service-yaml-check was never runnable

language: python makes pre-commit pip-install this repo and run the hook's entry as a command. service-yaml-check shipped with entry: hooks/service-yaml-check.py and the repo had no build definition, so every consumer's install failed with Directory '.' is not installable. Nothing exercised the install path, so it went unnoticed.

Fixed by adding a pyproject.toml that packages the hooks as pinpredict_hooks with console-script entry points, moving the module into the package, and pointing the hook at the script name. The additional_dependencies: ["pyyaml>=6"] pin goes away — the package declares PyYAML for real.

stevedore-release-scope

Asserts that onboarding or retiring a service does not silently widen the image build contract so that every image in the catalog re-releases. Three surfaces:

  • a named service is an image id in .stevedore.yaml and has a sibling chart whose Chart.yaml name matches, keeping a manual services: <id> dispatch resolvable on both release paths;
  • docker-release and chart-release receive the same only: selector, so a manual dispatch can never release a different set of images than charts;
  • change_detection.shared_paths carries the explicit all-image contract signal and not the paths every onboarding touches anyway (Dockerfile, .dockerignore, *.sln).

Every assertion is opt-in via args, so a repo missing a surface skips it instead of failing, and a repo with no .stevedore.yaml is a clean no-op. All violations are collected and reported in one run rather than failing on the first.

The manual-dispatch selector expression is deliberately not uniform across the org — most repos map services: all to an empty selector, trading maps it to all on purpose — so --expect-selector is opt-in per repo. The docker/chart consistency check runs either way.

Guardrails so this doesn't recur

  • .github/workflows/ci.yml — unit tests on 3.9 and 3.13, plus a hook-install job that pip-installs the package, resolves each console script, and pre-commit try-repos every hook against a fixture consumer. That job is the direct regression guard for the failure above.
  • .pre-commit-config.yaml — the repo now dogfoods its own gate, including the unit tests. A hook whose tests only run in CI is exactly how service-yaml-check stayed broken.
  • README records the repository layout and the console-script rule, and backfills the check-go-version-sync row that landed without one.

Verification

python -m unittest discover -s tests — 15 tests, green. pre-commit run --all-files — all hooks pass.

`language: python` makes pre-commit pip-install this repo and then run the
hook's `entry` as a command, so a repo-relative path entry can never resolve.
`service-yaml-check` shipped with `entry: hooks/service-yaml-check.py` and no
build definition, so every consumer's install failed with "Directory '.' is
not installable" — the hook has never run anywhere.

Add a pyproject.toml that packages the hooks as `pinpredict_hooks`, move the
module into the package, and point the hook at the console script. The
`additional_dependencies: [pyyaml]` pin goes away because the package now
declares PyYAML as a real dependency.
…uild contract

Onboarding or retiring a service must not silently make every image in the
stevedore catalog re-release. The hook checks the three surfaces where that
widening happens:

  - a named service is an image id in .stevedore.yaml and has a sibling chart
    whose Chart.yaml name matches, so a manual `services: <id>` dispatch stays
    resolvable on both release paths;
  - docker-release and chart-release receive the same `only:` selector, so a
    manual dispatch can never release a different set of images than charts;
  - change_detection.shared_paths carries the explicit all-image contract
    signal and not the paths every onboarding touches anyway (Dockerfile,
    .dockerignore, the solution file).

Every assertion is opt-in via args, so a repo missing a surface skips it
rather than failing, and a repo with no .stevedore.yaml is a clean no-op. All
violations are collected and reported in one run instead of failing on the
first, so a single `pre-commit run` shows the whole picture.
The repo had no CI and no pre-commit config of its own — nothing exercised the
`language: python` install path, which is exactly how `service-yaml-check`
stayed uninstallable without anyone noticing.

Add a tests job across the supported python range, a `hook-install` job that
pip-installs the package and `try-repo`s each hook against a fixture consumer,
and a .pre-commit-config.yaml so the repo dogfoods its own gate (unit tests,
whitespace/EOF/merge-conflict/yaml checks, yamllint, gitleaks).
Add stevedore-release-scope (with its flag reference and the note that the
manual-dispatch selector expression is not uniform across the org) and backfill
check-go-version-sync, which landed without a table row. Record the repository
layout and the packaging rule that Python hooks must be console scripts, so the
next hook does not repeat the service-yaml-check install failure. Bump the
documented rev to v0.3.0.
The fixture's .platform/services/oms.yaml carried only a name, so
service-yaml-check correctly failed on the missing repositories block and took
the hook-install job red. That job asserts each hook installs and runs, so the
fixture has to satisfy the checks the hook enforces.
@blairham
blairham merged commit 405c7e2 into main Aug 13, 2026
3 checks passed
@blairham
blairham deleted the feat/stevedore-release-scope-hook branch August 13, 2026 20:35
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