diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c54a9e..2adb222 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,12 +16,12 @@ jobs: strategy: matrix: # The oldest and the newest Python that the scripts support. - python: ["3.10.22", "3.15.1"] + python: ["3.10.22", "3.15.2"] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 with: python-version: ${{ matrix.python }} - run: python -m unittest discover tests -v diff --git a/.github/workflows/org.yml b/.github/workflows/org.yml index 7901398..2d9ae03 100644 --- a/.github/workflows/org.yml +++ b/.github/workflows/org.yml @@ -222,7 +222,7 @@ jobs: # The credential helper supplies fresh tokens. persist-credentials: false - - uses: anthropics/claude-code-action@f27be6b65a4652f08a2ba3cff79114829b588967 # v1.0.252 + - uses: anthropics/claude-code-action@d535f5172dec02b204866b393d6b20b9b2aaf98d # v1.0.266 env: SEMGREP_APP_TOKEN: ${{ secrets.semgrep_app_token }} SADR_APP_TOKEN: ${{ steps.app.outputs.app-token }} diff --git a/.github/workflows/run.yml b/.github/workflows/run.yml index a502e92..4d720f8 100644 --- a/.github/workflows/run.yml +++ b/.github/workflows/run.yml @@ -158,7 +158,7 @@ jobs: git config --global user.name 'github-actions[bot]' git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' - - uses: anthropics/claude-code-action@f27be6b65a4652f08a2ba3cff79114829b588967 # v1.0.252 + - uses: anthropics/claude-code-action@d535f5172dec02b204866b393d6b20b9b2aaf98d # v1.0.266 env: SEMGREP_APP_TOKEN: ${{ secrets.semgrep_app_token }} SADR_APP_TOKEN: ${{ steps.app.outputs.app-token }} diff --git a/CHANGELOG.md b/CHANGELOG.md index ff9baa9..fc5e1d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ adopter's repos. So each release lists its policy changes: - The org report reads check status in private repos. Its token now asks for Checks and Commit statuses (read), so the report no longer fails on an organization with private repos. - A `Sadr: off` line in the owner's `.github` repo opts out that repo only. `repos.py` leaves it out of the owner's defaults, so other repos never read it as their own. - Sadr marks its draft PRs ready. When a repo asks for drafts, Sadr waits for the PR's checks and marks it ready when they pass, and each run readies any of its drafts that turned green later. Before, its drafts stayed drafts. +- A Known traps line in policy.md says how to verify locally when `uv python install` lacks a CPython patch release that `actions/setup-python` already ships. ## v2.0.0 (2026-10-23) diff --git a/plugins/sadr/skills/sadr/references/policy.md b/plugins/sadr/skills/sadr/references/policy.md index 1362b92..b0a9e42 100644 --- a/plugins/sadr/skills/sadr/references/policy.md +++ b/plugins/sadr/skills/sadr/references/policy.md @@ -316,6 +316,7 @@ These notes are examples from earlier runs. They do not limit what Sadr handles. - Poetry 2.4 and later reads `min-release-age` in days under `[solver]` in `poetry.toml`. - A bare `requirements.txt` with pip has no usable cooldown. Move it to `pyproject.toml` with a lockfile, unless AGENTS.md says not to. - `astral-sh/setup-uv` without an exact `version:` installs the newest uv. Pin it. +- `uv python install` can lack a CPython patch release that `actions/setup-python` already ships. When it does, run the local tests on the newest patch of the same line that uv has, and say under `## Verification` which version CI runs. - When Python moves, update `.python-version`, `requires-python`, the Dockerfile, CI `python-version`, and the targets of ruff and mypy. **Go, Rust, Swift and others without a cooldown setting** diff --git a/tests/test_pins.py b/tests/test_pins.py index 2f007a3..61b60a5 100644 --- a/tests/test_pins.py +++ b/tests/test_pins.py @@ -208,12 +208,12 @@ def test_resolver_caches_tags(self): self.assertEqual(len(api.calls), 2) def test_main_exit_codes_and_json_before_subcommand(self): - with mock.patch.object(_gh, "api", FakeApi(tag_routes())), \ + with mock.patch.object(_gh, "api", FakeApi(tag_routes())), mock.patch.object(_gh, "now", lambda: NOW), \ mock.patch.object(_registry, "Client", registry), mock.patch("sys.stdout", io.StringIO()) as out: self.assertEqual(pins.main(["check", WORKFLOW]), 1) self.assertIn("9 pins checked, 6 with problems, 0 not checked, 1 skipped.", out.getvalue()) self.assertIn("skipped, local action", out.getvalue()) - with mock.patch.object(_gh, "api", FakeApi(tag_routes())), \ + with mock.patch.object(_gh, "api", FakeApi(tag_routes())), mock.patch.object(_gh, "now", lambda: NOW), \ mock.patch.object(_registry, "Client", registry), mock.patch("sys.stdout", io.StringIO()) as out: self.assertEqual(pins.main(["--json", "check", WORKFLOW]), 1) data = json.loads(out.getvalue())