Skip to content

Commit 14e910a

Browse files
Julianclaude
andcommitted
Modernize CI, harden workflows, swap pyright for ty.
Make zizmor --pedantic clean by pinning actions to SHAs, scoping permissions, setting persist-credentials: false, and routing matrix / github.ref_name through env vars. Add zizmor (pedantic) to pre-commit. Move the noxfile to a uv-native layout (uv sync + dependency-groups), drop the virtualenv fallback, and let uv install Pythons in CI in place of actions/setup-python. Drop Python 3.9 and 3.10, add 3.14, bump PyPy to 3.11. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1a3db30 commit 14e910a

7 files changed

Lines changed: 116 additions & 662 deletions

File tree

.github/workflows/ci.yml

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,95 +12,98 @@ on:
1212
- cron: "33 8 * * *"
1313
workflow_dispatch:
1414

15+
permissions: {}
16+
17+
concurrency:
18+
group: ${{ github.workflow }}-${{ github.ref }}
19+
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
20+
1521
jobs:
1622
list:
23+
name: List nox sessions
1724
runs-on: ubuntu-latest
25+
permissions:
26+
contents: read # checkout
1827
outputs:
1928
noxenvs: ${{ steps.noxenvs-matrix.outputs.noxenvs }}
2029
steps:
21-
- uses: actions/checkout@v6
30+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.0
31+
with:
32+
persist-credentials: false
2233
- name: Set up uv
23-
uses: astral-sh/setup-uv@v7
34+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v7.1.0
2435
with:
25-
enable-cache: true
36+
enable-cache: false
2637
- id: noxenvs-matrix
2738
run: |
2839
echo >>$GITHUB_OUTPUT noxenvs=$(
2940
uvx nox --list-sessions --json | jq '[.[].session]'
3041
)
3142
3243
ci:
44+
name: Run nox session
3345
needs: list
3446
runs-on: ubuntu-latest
47+
permissions:
48+
contents: read # checkout
3549

3650
strategy:
3751
fail-fast: false
3852
matrix:
3953
noxenv: ${{ fromJson(needs.list.outputs.noxenvs) }}
4054
posargs: [""]
4155
include:
42-
- noxenv: tests-3.12
56+
- noxenv: tests-3.14
4357
posargs: coverage github
4458

4559
steps:
46-
- uses: actions/checkout@v6
60+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.0
4761
with:
4862
submodules: "recursive"
49-
- name: Install dependencies
50-
run: sudo apt-get update && sudo apt-get install -y libenchant-2-dev
51-
if: runner.os == 'Linux' && startsWith(matrix.noxenv, 'docs')
52-
- name: Install dependencies
53-
run: brew install enchant
54-
if: runner.os == 'macOS' && startsWith(matrix.noxenv, 'docs')
55-
- name: Set up Python
56-
uses: actions/setup-python@v6
57-
with:
58-
python-version: |
59-
3.9
60-
3.10
61-
3.11
62-
3.12
63-
3.13
64-
pypy3.10
65-
allow-prereleases: true
66-
63+
persist-credentials: false
6764
- name: Set up uv
68-
uses: astral-sh/setup-uv@v7
65+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v7.1.0
6966
with:
70-
enable-cache: true
67+
enable-cache: false
7168

7269
- name: Run nox
73-
run: uvx nox -s "${{ matrix.noxenv }}" -- ${{ matrix.posargs }}
70+
env:
71+
NOXENV: ${{ matrix.noxenv }}
72+
POSARGS: ${{ matrix.posargs }}
73+
run: uvx nox -s "$NOXENV" -- $POSARGS
7474

7575
packaging:
76+
name: Package and release
7677
needs: ci
7778
runs-on: ubuntu-latest
7879
environment:
7980
name: PyPI
8081
url: https://pypi.org/p/schemastore
8182

8283
permissions:
83-
contents: write
84-
id-token: write
84+
contents: write # gh release create
85+
id-token: write # OIDC for trusted publishing to PyPI
8586

8687
steps:
87-
- uses: actions/checkout@v6
88+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.0
8889
with:
8990
submodules: "recursive"
91+
persist-credentials: false
9092

9193
- name: Set up uv
92-
uses: astral-sh/setup-uv@v7
94+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v7.1.0
9395
with:
94-
enable-cache: true
96+
enable-cache: false
9597

9698
- name: Build our distributions
9799
run: uv run --frozen --with 'build[uv]' -m build --installer=uv
98100

99101
- name: Publish to PyPI
100102
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
101-
uses: pypa/gh-action-pypi-publish@release/v1
103+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
102104
- name: Create a Release
103105
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
104-
run: gh release create ${{ github.ref_name }} dist/* --generate-notes
105106
env:
106107
GH_TOKEN: ${{ github.token }}
108+
REF_NAME: ${{ github.ref_name }}
109+
run: gh release create "$REF_NAME" dist/* --generate-notes

.pre-commit-config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,8 @@ repos:
3939
alias: ruff
4040
- id: ruff-check
4141
alias: ruff
42+
- repo: https://github.com/zizmorcore/zizmor-pre-commit
43+
rev: v1.24.1
44+
hooks:
45+
- id: zizmor
46+
args: [--pedantic]

noxfile.py

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,10 @@
88
PYPROJECT = ROOT / "pyproject.toml"
99
PACKAGE = ROOT / "schemastore"
1010

11-
REQUIREMENTS = dict(
12-
tests=ROOT / "test-requirements.txt",
13-
)
14-
REQUIREMENTS_IN = [ # this is actually ordered, as files depend on each other
15-
(path.parent / f"{path.stem}.in", path) for path in REQUIREMENTS.values()
16-
]
17-
18-
SUPPORTED = ["3.9", "3.10", "pypy3.10", "3.11", "3.12", "3.13"]
11+
SUPPORTED = ["3.11", "pypy3.11", "3.12", "3.13", "3.14"]
1912
LATEST = SUPPORTED[-1]
2013

21-
nox.options.default_venv_backend = "uv|virtualenv"
14+
nox.options.default_venv_backend = "uv"
2215
nox.options.sessions = []
2316

2417

@@ -36,7 +29,12 @@ def tests(session):
3629
"""
3730
Run the test suite with a corresponding Python version.
3831
"""
39-
session.install("-r", REQUIREMENTS["tests"])
32+
session.run_install(
33+
"uv",
34+
"sync",
35+
f"--python={session.virtualenv.location}",
36+
env={"UV_PROJECT_ENVIRONMENT": session.virtualenv.location},
37+
)
4038

4139
if session.posargs and session.posargs[0] == "coverage":
4240
if len(session.posargs) > 1 and session.posargs[1] == "github":
@@ -102,24 +100,5 @@ def typing(session):
102100
"""
103101
Check static typing.
104102
"""
105-
session.install("pyright", ROOT)
106-
session.run("pyright", *session.posargs, PACKAGE)
107-
108-
109-
@session(default=False)
110-
def requirements(session):
111-
"""
112-
Update the project's pinned requirements.
113-
114-
You should commit the result afterwards.
115-
"""
116-
if session.venv_backend == "uv":
117-
cmd = ["uv", "pip", "compile"]
118-
else:
119-
session.install("pip-tools")
120-
cmd = ["pip-compile", "--resolver", "backtracking", "--strip-extras"]
121-
122-
for each, out in REQUIREMENTS_IN:
123-
# otherwise output files end up with silly absolute path comments...
124-
relative = each.relative_to(ROOT)
125-
session.run(*cmd, "--upgrade", "--output-file", out, relative)
103+
session.install("ty", ROOT)
104+
session.run("ty", "check", *session.posargs, PACKAGE)

pyproject.toml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ source = "vcs"
88
[project]
99
name = "schemastore"
1010
description = "Easy use of the JSON SchemaStore from Python, as a referencing.Registry"
11-
requires-python = ">=3.8"
11+
requires-python = ">=3.11"
1212
readme = "README.md"
1313
keywords = ["schemastore", "json", "yaml", "schemas", "referencing", "jsonschema"]
1414
authors = [
@@ -21,11 +21,10 @@ classifiers = [
2121
"License :: OSI Approved :: Apache Software License",
2222
"Operating System :: OS Independent",
2323
"Programming Language :: Python",
24-
"Programming Language :: Python :: 3.9",
25-
"Programming Language :: Python :: 3.10",
2624
"Programming Language :: Python :: 3.11",
2725
"Programming Language :: Python :: 3.12",
2826
"Programming Language :: Python :: 3.13",
27+
"Programming Language :: Python :: 3.14",
2928
"Programming Language :: Python :: Implementation :: CPython",
3029
"Programming Language :: Python :: Implementation :: PyPy",
3130
"Topic :: File Formats :: JSON",
@@ -42,6 +41,11 @@ Homepage = "https://github.com/python-jsonschema/schemastore"
4241
Issues = "https://github.com/python-jsonschema/schemastore/issues/"
4342
Source = "https://github.com/python-jsonschema/schemastore"
4443

44+
[dependency-groups]
45+
dev = [
46+
"pytest>=8.3.4",
47+
]
48+
4549
[tool.coverage.html]
4650
show_contexts = true
4751
skip_covered = false
@@ -65,9 +69,7 @@ ignore = [
6569
"D001", # one sentence per line, so max length doesn't make sense
6670
]
6771

68-
[tool.pyright]
69-
reportUnnecessaryTypeIgnoreComment = true
70-
strict = ["**/*"]
72+
[tool.ty.src]
7173
exclude = [
7274
"**/tests/__init__.py",
7375
"**/tests/test_*.py",
@@ -120,7 +122,6 @@ ignore = [
120122
"SIM300", # Not sure what heuristic this uses, but it's easily incorrect
121123
"SLF001", # Private usage within this package itself is fine
122124
"TD", # These TODO style rules are also silly
123-
"UP007", # We support 3.9
124125
]
125126

126127
[tool.ruff.lint.flake8-pytest-style]

test-requirements.in

Lines changed: 0 additions & 2 deletions
This file was deleted.

test-requirements.txt

Lines changed: 0 additions & 43 deletions
This file was deleted.

0 commit comments

Comments
 (0)