Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .github/workflows/prepare-release-creator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,6 @@ jobs:
with:
crate: cargo-edit
version: 0.13.13
- name: 🧹 Install prek hooks
id: hooks
uses: $/cooled-prek
with:
args: install-hooks
background: true
- name: 🏷️ Select release version
id: version
env:
Expand Down Expand Up @@ -203,8 +197,6 @@ jobs:
args+=(--package "$PACKAGE")
fi
release-creator contributors "${args[@]}"
- name: ⏳ Wait for prek hooks
wait: hooks
- name: 🧹 Format changelog
id: format
continue-on-error: true
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/prepare-towncrier-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,6 @@ jobs:
venv: .venv
exclude-newer: ${{ inputs.exclude-newer }}
exclude-newer-package: ${{ inputs.exclude-newer-package }}
- name: 🧹 Install prek hooks
id: hooks
uses: $/cooled-prek
with:
args: install-hooks
background: true
- id: prepare
name: 📝 Build changelog
uses: $/prepare-towncrier
Expand All @@ -87,8 +81,6 @@ jobs:
tag-prefix: ${{ inputs.tag-prefix }}
changelog-prefix: ${{ inputs.changelog-prefix }}
phase: build
- name: ⏳ Wait for prek hooks
wait: hooks
- name: 📝 Finalize release patch
uses: $/prepare-towncrier
with:
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -586,8 +586,8 @@ these examples means that commit.

Assembly needs release history to select a tag. The writer can check out the source commit with `fetch-depth: 1`. All
jobs use `persist-credentials: false`. Assembly installs the caller's locked release tools and needs `contents: read`
and `pull-requests: read` to resolve PR authors. It starts `prek install-hooks` while building the changelog, then waits
for the hooks before formatting and uploading the patch. The writer uses the `release-auth` environment with
and `pull-requests: read` to resolve PR authors. It installs only the changelog formatter's hook, when it formats, so a
hook the release never runs cannot fail it. The writer uses the `release-auth` environment with
`RELEASE_APP_PRIVATE_KEY` and `RELEASE_APP_CLIENT_ID`. Restrict that environment to `main`. Install the App on this
repository only, with Contents write and Metadata read, and grant the necessary branch and tag ruleset bypass.

Expand Down Expand Up @@ -653,11 +653,11 @@ token exists. Trigger the caller on `push`, `schedule`, `workflow_dispatch`, or

### Dry run on pull requests

A release assembles under rules a pull request's own checks never apply: hooks install with packages from the last seven
days held back, fragments link to their pull requests, and the changelog builds and formats. A pull request that breaks
any of these merges green and fails the next release. `dry-run: true` runs `assemble` alone and skips `push`, so the
pull request fails instead. A dry run needs no App key and uses its own concurrency group per ref, so it never queues
behind a real release.
A release assembles under rules a pull request's own checks never apply: the changelog formatter's hook installs with
packages from the last seven days held back, fragments link to their pull requests, and the changelog builds and
formats. A pull request that breaks any of these merges green and fails the next release. `dry-run: true` runs
`assemble` alone and skips `push`, so the pull request fails instead. A dry run needs no App key and uses its own
concurrency group per ref, so it never queues behind a real release.

Make the caller's prepare workflow callable and run it from the workflow that holds the required gate, so the dry run
uses the same inputs as the release:
Expand Down Expand Up @@ -747,8 +747,8 @@ formatting must all succeed.
whose release headings use `v1.2.3`.
- `version`: Explicit version for a caller with its own version selector. It takes precedence over `bump`.
- `phase`: `all` (default) runs the complete Action. The reusable workflow uses `build` to select the version, link
authors, and build the changelog while hooks install; it then uses `finalize` to format, render, and write the patch.
Pass the version selected by `build` to `finalize`.
authors, and build the changelog; it then uses `finalize` to format, render, and write the patch. Pass the version
selected by `build` to `finalize`.

The committed `tool.towncrier` configuration gives the `filename` and `directory`. `docstrfmt` formats a `.rst`
changelog and `mdformat` any other; the formatter must be a configured `prek` hook. The Action writes the patch at
Expand Down
3 changes: 3 additions & 0 deletions changelog.d/+install-one-hook.performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
`prepare-towncrier-release` and `prepare-release-creator` install only the changelog formatter's hook instead of every
hook, so release preparation and its pull request dry run finish faster, and a hook the release never runs cannot fail
it.
10 changes: 5 additions & 5 deletions tests/cooled_prek/test_cooled_prek.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import subprocess
from pathlib import Path

import pytest
import yaml
from conftest import action

Expand All @@ -31,14 +32,13 @@ def test_no_hook_run_bypasses_cooled_prek() -> None:
assert not commands, commands


def test_prepare_hook_install_uses_cooled_prek() -> None:
@pytest.mark.parametrize("name", ["prepare-towncrier-release.yaml", "prepare-release-creator.yaml"])
def test_prepare_installs_no_hook_it_does_not_run(name: str) -> None:
workflow = yaml.load(
(Path(__file__).resolve().parents[2] / ".github/workflows/prepare-towncrier-release.yaml").read_text(),
Loader=yaml.BaseLoader,
(Path(__file__).resolve().parents[2] / ".github/workflows" / name).read_text(), Loader=yaml.BaseLoader
)
step = next(step for step in workflow["jobs"]["assemble"]["steps"] if step.get("id") == "hooks")

assert (step["uses"], step["with"]) == ("$/cooled-prek", {"args": "install-hooks"})
assert "install-hooks" not in str(workflow["jobs"]["assemble"]["steps"])


def test_cooled_prek_action_passes_each_argument(tmp_path: Path, action_scripts: Path) -> None:
Expand Down