diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 874478d0..796091e6 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -3,6 +3,10 @@ name: CD permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + on: workflow_dispatch: pull_request: @@ -15,20 +19,23 @@ on: jobs: dist: + name: Create dist runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - uses: hynek/build-and-inspect-python-package@fe0a0fb1925ca263d076ca4f2c13e93a6e92a33e # v2.17.0 publish: + name: Publish needs: [dist] environment: pypi permissions: - id-token: write - attestations: write + id-token: write # for trusted publishing + attestations: write # for trusted publishing contents: read runs-on: ubuntu-latest if: github.event_name == 'release' && github.event.action == 'published' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb35ed0f..37bb21c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - uses: prefix-dev/setup-pixi@1b2de7f3351f171c8b4dfeb558c639cb58ed4ec0 # v0.9.5 with: @@ -52,10 +53,13 @@ jobs: - tests-nogil runs-on: [ubuntu-latest] + environment: ci-checks + steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false - uses: prefix-dev/setup-pixi@1b2de7f3351f171c8b4dfeb558c639cb58ed4ec0 # v0.9.5 with: @@ -66,7 +70,9 @@ jobs: - name: Test package # Save some time; also at the moment of writing coverage crashes on python 3.13t if: ${{ matrix.environment != 'tests-nogil' }} - run: pixi run -e ${{ matrix.environment }} tests-ci + run: pixi run -e "${TASK_ENV}" tests-ci + env: + TASK_ENV: ${{ matrix.environment }} - name: Test free-threading if: ${{ matrix.environment == 'tests-nogil' }} diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml deleted file mode 100644 index dc05bed4..00000000 --- a/.github/workflows/docs-build.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Docs Build - -permissions: - contents: read - -on: [push, pull_request] - -jobs: - docs-build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - uses: prefix-dev/setup-pixi@1b2de7f3351f171c8b4dfeb558c639cb58ed4ec0 # v0.9.5 - with: - pixi-version: v0.62.0 - cache: true - environments: docs - - - name: Build Docs - run: pixi run -e docs docs - - - name: Upload Artifact - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: docs-build - path: docs/build/ diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml deleted file mode 100644 index 9cbbf8b7..00000000 --- a/.github/workflows/docs-deploy.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Docs Deploy - -permissions: - contents: write # needed for the deploy step - -on: - workflow_run: - workflows: ["Docs Build"] - types: [completed] - branches: - - "main" - -jobs: - docs-deploy: - runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.event == 'push' }} - environment: - name: docs-deploy - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Download Artifact - uses: dawidd6/action-download-artifact@8a338493df3d275e4a7a63bcff3b8fe97e51a927 # v19 - with: - workflow: docs-build.yml - name: docs-build - path: docs/build/ - - # Note, the gh-pages deployment requires setting up a SSH deploy key. - # See - # https://github.com/JamesIves/github-pages-deploy-action/tree/dev#using-an-ssh-deploy-key- - - name: Deploy - uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0 - with: - folder: docs/build/ - ssh-key: ${{ secrets.DEPLOY_KEY }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..1aaf22bb --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,66 @@ +name: Docs + +on: [push, pull_request] + +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + docs-build: + name: Build + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - uses: prefix-dev/setup-pixi@1b2de7f3351f171c8b4dfeb558c639cb58ed4ec0 # v0.9.5 + with: + pixi-version: v0.62.0 + cache: true + environments: docs + + - name: Build Docs + run: pixi run -e docs docs + + - name: Upload Artifact + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: docs-build + path: docs/build/ + + docs-deploy: + name: Deploy + if: ${{ github.event.workflow_run.event == 'push' }} + needs: docs-build + runs-on: ubuntu-latest + + permissions: + contents: write # needed for the deploy step + + environment: + name: docs-deploy + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Download Artifact + uses: actions/download-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: docs-build + path: docs/build/ + + - name: Deploy + uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0 + with: + folder: docs/build/ + ssh-key: ${{ secrets.DEPLOY_KEY }} diff --git a/lefthook.yml b/lefthook.yml index bff9beec..57fdcc5d 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -47,6 +47,8 @@ pre-commit: run: pixi {run} typos - name: actionlint run: pixi {run} actionlint + - name: zizmor + run: pixi {run} zizmor - name: blacken-docs glob: "*.md" stage_fixed: true diff --git a/pixi.lock b/pixi.lock index 9c471120..5f92ad68 100644 --- a/pixi.lock +++ b/pixi.lock @@ -319,6 +319,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/zizmor-1.24.1-hb17b654_0.conda - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - conda: . osx-64: @@ -507,6 +508,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/zizmor-1.24.1-h19f9e61_0.conda - conda: https://prefix.dev/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda - conda: . osx-arm64: @@ -690,6 +692,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/zizmor-1.24.1-h6fdd925_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - conda: . win-64: @@ -855,6 +858,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/win-64/zizmor-1.24.1-h18a1a76_0.conda - conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda - conda: . dev-cuda: @@ -1098,6 +1102,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/zizmor-1.24.1-hb17b654_0.conda - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - conda: . osx-64: @@ -1286,6 +1291,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/zizmor-1.24.1-h19f9e61_0.conda - conda: https://prefix.dev/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda - conda: . osx-arm64: @@ -1469,6 +1475,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/wcwidth-0.6.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/zizmor-1.24.1-h6fdd925_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - conda: . win-64: @@ -1654,6 +1661,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/win-64/zizmor-1.24.1-h18a1a76_0.conda - conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda - conda: . docs: @@ -2178,6 +2186,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/validate-pyproject-0.25-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/zizmor-1.24.1-hb17b654_0.conda - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - conda: . osx-64: @@ -2302,6 +2311,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/validate-pyproject-0.25-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-64/yaml-0.2.5-h4132b18_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/osx-64/zizmor-1.24.1-h19f9e61_0.conda - conda: https://prefix.dev/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda - conda: . osx-arm64: @@ -2426,6 +2436,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/validate-pyproject-0.25-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/zizmor-1.24.1-h6fdd925_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - conda: . win-64: @@ -2546,6 +2557,7 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda + - conda: https://prefix.dev/conda-forge/win-64/zizmor-1.24.1-h18a1a76_0.conda - conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda - conda: . tests: @@ -14566,6 +14578,55 @@ packages: - pkg:pypi/zipp?source=hash-mapping size: 24194 timestamp: 1764460141901 +- conda: https://prefix.dev/conda-forge/linux-64/zizmor-1.24.1-hb17b654_0.conda + sha256: 58dbfa4f5fca801edebac6d5e770cb6b37816cb73c0016088a0d55b35d8cba4f + md5: ecd23f3e1de203a92991edf69fd61e14 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + purls: [] + size: 7003303 + timestamp: 1776165056488 +- conda: https://prefix.dev/conda-forge/osx-64/zizmor-1.24.1-h19f9e61_0.conda + sha256: 0d12cbb3df3f1eac06c1d1b1bddb64ba49ecd066ebfe934c641bdc8c0b4d00b2 + md5: 191eefc55f8c28718ca835fdc580d044 + depends: + - __osx >=11.0 + constrains: + - __osx >=10.13 + license: MIT + license_family: MIT + purls: [] + size: 6949272 + timestamp: 1776165102204 +- conda: https://prefix.dev/conda-forge/osx-arm64/zizmor-1.24.1-h6fdd925_0.conda + sha256: 7a3379d2439e846568396c31f66e01ff0bb89bf9165f637ad581ea29c2be97ff + md5: d8ba3448fc0872fb84467e6eed423e5f + depends: + - __osx >=11.0 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 6443748 + timestamp: 1776165113536 +- conda: https://prefix.dev/conda-forge/win-64/zizmor-1.24.1-h18a1a76_0.conda + sha256: 05170f009bd5ce7dbef27a0eb6086068ea926ae5bdad3f406351fed2695b2994 + md5: f7a36b70b4c27fccdab381b28c4d53b8 + depends: + - vc >=14.3,<15 + - vc14_runtime >=14.44.35208 + - ucrt >=10.0.20348.0 + license: MIT + license_family: MIT + purls: [] + size: 7213873 + timestamp: 1776165138591 - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 diff --git a/pyproject.toml b/pyproject.toml index 34f7451a..7f97dea0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,6 +109,7 @@ blacken-docs = ">=1.20.0,<2" pytest = ">=9.0.2,<10" validate-pyproject = ">=0.25,<0.26" pyrefly = ">=0.61.1,<0.62" +zizmor = ">=1.24.1,<1.25" # NOTE: don't add cupy, jax, pytorch, or sparse here, # as they slow down mypy and are not portable across target OSs @@ -125,6 +126,7 @@ ruff-format = { cmd = "ruff format", description = "Format with ruff" } dprint = { cmd = "dprint fmt", description = "Format with dprint" } typos = { cmd = "typos --write-changes --force-exclude", description = "Fix typos" } actionlint = { cmd = "actionlint", description = "Lint actions with actionlint" } +zizmor = { cmd = "zizmor .github -p", description = "GHA static analysis with zizmor" } blacken-docs = { cmd = "blacken-docs", description = "Format Python markdown blocks with Black" } validate-pyproject = { cmd = "validate-pyproject pyproject.toml", description = "Validate pyproject.toml" } numpydoc = { cmd = "numpydoc lint", description = "Validate docstrings with numpydoc" }