From 96be5fc40c4ecb2892d0a01c00a13f31927e92f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Fri, 6 Nov 2026 14:23:58 -0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(workflows):=20run=20every=20ho?= =?UTF-8?q?ok=20under=20the=20cooldown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pre-commit.ci builds hook environments from the newest releases, while the scheduled maintenance pull requests and release preparation build them under the seven-day cutoff. A hook bumped to a younger release, or one that rewrites files when built fresh, passed its pull request and then failed those jobs (simplint#55, simplint#58). cooled-hooks.yaml runs `prek run --all-files` with the release-prepare prek and cooled hook environments, for a caller to add to its gate. This repository's own formatting check now uses it. --- .github/workflows/ci.yaml | 29 +---------------- .github/workflows/cooled-hooks.yaml | 48 ++++++++++++++++++++++++++++ README.md | 1 + changelog.d/+cooled-hooks.feature.md | 2 ++ docs/pr-checks.md | 29 +++++++++++++++++ 5 files changed, 81 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/cooled-hooks.yaml create mode 100644 changelog.d/+cooled-hooks.feature.md diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 54c9a9a..c7a9c12 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,36 +9,9 @@ concurrency: jobs: check: name: ๐Ÿงน Check formatting - runs-on: ubuntu-26.04 + uses: $/.github/workflows/cooled-hooks.yaml permissions: contents: read - steps: - - name: ๐Ÿ“ฅ Check out repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 1 - persist-credentials: false - - name: ๐Ÿ’พ Restore prek cache - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 - with: - path: ~/.cache/prek - key: prek-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.pre-commit-config.yaml') }} - - name: ๐Ÿ Install uv and Python - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 - with: - version: latest-known - python-version: "3.15" - enable-cache: true - cache-suffix: ${{ github.job }} - cache-dependency-glob: pyproject.toml - - name: ๐Ÿ“ฆ Install release tools - env: - EXCLUDE_NEWER: 7 days - run: | - tools/install_live_tools.sh .release-tools 'prek>=0.2' - uv run --no-project --python .release-tools python tools/expose_locked_commands.py .release-tools - - name: ๐Ÿงน Check repository formatting - run: tools/cooled_prek.sh run --all-files shell: name: ๐Ÿงน Check inline shell runs-on: ubuntu-26.04 diff --git a/.github/workflows/cooled-hooks.yaml b/.github/workflows/cooled-hooks.yaml new file mode 100644 index 0000000..833bacc --- /dev/null +++ b/.github/workflows/cooled-hooks.yaml @@ -0,0 +1,48 @@ +name: Cooled hooks +on: + workflow_call: + inputs: + exclude-newer: + description: Upload cutoff for the lock reader the shared Actions install from PyPI + type: string + default: 7 days + exclude-newer-package: + description: Newline-separated name=date cutoffs that override exclude-newer for single packages + type: string + default: "" +permissions: {} +jobs: + hooks: + name: ๐Ÿงน Hooks under the cooldown + runs-on: ubuntu-26.04 + permissions: + contents: read + steps: + - name: ๐Ÿ“ฅ Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 1 + persist-credentials: false + - name: ๐Ÿ’พ Restore prek cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/prek + # A changed hook or cutoff exception misses the cache, so its environment builds under the cutoff again. + key: prek-cooled-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.pre-commit-config.yaml', 'pyproject.toml') }} + - name: ๐Ÿ Install uv and Python + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + python-version: "3.15" + enable-cache: false + - name: ๐Ÿ“ฆ Install locked release tools + uses: $/install-locked-tools + with: + groups: release-prepare + venv: ${{ runner.temp }}/release-tools + exclude-newer: ${{ inputs.exclude-newer }} + exclude-newer-package: ${{ inputs.exclude-newer-package }} + - name: ๐Ÿงน Run every hook under the cooldown + uses: $/cooled-prek + with: + args: run --all-files --show-diff-on-failure diff --git a/README.md b/README.md index 4eb0647..1bb6989 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ at least the listed permissions; "App key" means it also passes the `RELEASE_APP | Workflow | Purpose | Caller grants | Docs | | --------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------------------------------------------------ | | `check.yaml` | Run tox environments, one job per row, with a gate. | `contents: read` | [PR checks](docs/pr-checks.md#run-tox-environments-checkyaml) | +| `cooled-hooks.yaml` | Run every prek hook over the tree, environments built under the cutoff. | `contents: read` | [PR checks](docs/pr-checks.md#run-hooks-under-the-cooldown-cooled-hooksyaml) | | `prepare-towncrier-release.yaml` | Build the Towncrier changelog, push the release commit and tag; or dry run. | `contents: read`, `pull-requests: read`; App key | [Prepare](docs/release-prepare.md#prepare-towncrier-releaseyaml) | | `prepare-release-creator.yaml` | Same for multi-package or Rust repositories with a caller-assembled changelog. | `contents: read`, `pull-requests: read`; App key | [Prepare](docs/release-prepare.md#prepare-release-creatoryaml) | | `validate-python-release.yaml` | Build a wheel and sdist from the tag against locked build constraints. | `contents: read` | [Publish](docs/release-publish.md#validate-python-releaseyaml) | diff --git a/changelog.d/+cooled-hooks.feature.md b/changelog.d/+cooled-hooks.feature.md new file mode 100644 index 0000000..e7b23a8 --- /dev/null +++ b/changelog.d/+cooled-hooks.feature.md @@ -0,0 +1,2 @@ +`cooled-hooks.yaml` runs every prek hook over the tree with environments built under the seven-day cutoff, so a pull +request fails when a hook would break the scheduled maintenance pull requests or release preparation. diff --git a/docs/pr-checks.md b/docs/pr-checks.md index 58d9abf..f859a69 100644 --- a/docs/pr-checks.md +++ b/docs/pr-checks.md @@ -76,6 +76,35 @@ Check names are ` / ๐Ÿงช on `; with the example's ` `๐Ÿงช Test / ๐Ÿงช 3.15 on ubuntu-26.04`. The reusable gate shows up as `๐Ÿงช Test / ๐Ÿšฆ Required checks pass`; require the caller's gate, not that one. The test jobs run project code, so grant them `contents: read` only. +## Run hooks under the cooldown: `cooled-hooks.yaml` + +pre-commit.ci and a contributor's machine build hook environments from the newest releases. The scheduled maintenance +pull requests and release preparation build them with packages from the last seven days held back. A hook bumped to a +release younger than that, or one that rewrites files when its environment is built fresh, passes the pull request and +then fails those scheduled jobs. This workflow runs every hook over the whole tree the way they do, so the pull request +fails instead. + +```yaml + hooks: + name: ๐Ÿงน Hooks under the cooldown + uses: tox-dev/github-workflows/.github/workflows/cooled-hooks.yaml@SHA # 6.7.0 + permissions: + contents: read + gate: + name: ๐Ÿšฆ Required checks pass + if: ${{ !cancelled() }} + needs: [test, hooks] +``` + +| Input | Default | Meaning | +| ----------------------- | -------- | -------------------------------------------------------------------------------------- | +| `exclude-newer` | `7 days` | Upload cutoff for the lock reader that installs the caller's locked `release-prepare`. | +| `exclude-newer-package` | empty | Newline-separated `name=date` cutoffs that override `exclude-newer` for one package. | + +prek comes from the caller's `release-prepare` lock group. Hook environments read cutoff exceptions from `[tool.nab]` in +`pyproject.toml`, as [`cooled-prek`](locked-tools.md#run-prek-under-the-cutoff-cooled-prek) describes. The prek cache is +keyed on `.pre-commit-config.yaml` and `pyproject.toml`, so a changed hook or exception rebuilds its environment. + ## Release dry run Add the caller's prepare workflow as a job with `dry-run: true` and list it in the gate's `needs`. The pull request then