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
10 changes: 5 additions & 5 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/bin/sh
# Pre-commit: the quick checks, on what is staged, so a commit never carries what CI would reject. The slow ones (the tests, and the
# values check that runs every module in `numbat`) stay in `npm run check` and CI. The style check takes about 20 seconds, so it
# values check that runs every module in `numbat`) stay in `pnpm run check` and CI. The style check takes about 20 seconds, so it
# runs only when a module is staged.
#
# This file is version-controlled. `npm install` points git at this folder (`prepare` in package.json:
# This file is version-controlled. `pnpm install` points git at this folder (`prepare` in package.json:
# `git config core.hooksPath .githooks`). Skip it once with `git commit --no-verify`.
set -e
cd "$(git rev-parse --show-toplevel)"
Expand All @@ -18,18 +18,18 @@ modules=$(staged 'modules/*' 'unitpad.json' 'api.json')
if [ -n "$formatted" ]; then
echo "pre-commit: formatting"
# shellcheck disable=SC2086
npx --no-install prettier --check --ignore-unknown $formatted
pnpm exec prettier --check --ignore-unknown $formatted
fi

if [ -n "$scripts" ]; then
echo "pre-commit: eslint"
# shellcheck disable=SC2086
npx --no-install eslint --no-warn-ignored $scripts
pnpm exec eslint --no-warn-ignored $scripts
fi

if [ -n "$docs" ]; then
echo "pre-commit: markdown"
npx --no-install markdownlint-cli2
pnpm exec markdownlint-cli2
echo "pre-commit: documents"
node tools/check-docs.mjs >/dev/null || { node tools/check-docs.mjs | grep -v '^ok'; exit 1; }
fi
Expand Down
16 changes: 4 additions & 12 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
# Only the Actions are updated here: it bumps the commit that each action is pinned to, and the version in the comment beside it.
# There is no `npm` block on purpose. Dependabot's documentation lists pnpm 7 to 10, and this repository uses pnpm 12, whose lockfile it
# may not read; it also ignores `minimumReleaseAge`, so it could propose a version younger than two weeks. The packages are updated by
# hand, as `docs/maintaining.md` says.
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
open-pull-requests-limit: 5
groups:
# Minor and patch together: they are one review. A major stays its own pull request.
minor-and-patch:
patterns: ['*']
update-types: ['minor', 'patch']

- package-ecosystem: github-actions
directory: /
schedule:
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,21 @@ jobs:
# Pinned to the commits that the `v7` tags pointed at on 2026-10-07: a tag can be moved to other code.
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

# Pinned to the commit that the `v6.1.0` tag pointed at on 2026-10-11, like the actions above it. It reads the pnpm version from
# `packageManager` in package.json, and goes before `setup-node` so that `cache: pnpm` finds it.
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
with:
node-version: 22
cache: npm
cache: pnpm

- run: npm ci
- run: pnpm install --frozen-lockfile

# The official `numbat` program, at the version and checksum in `numbat-version.json`.
- run: node tools/install-numbat.mjs

# Prettier, ESLint, markdownlint, the tests, the documents check, the names and values checks, and the package contents.
- run: npm run check
- run: pnpm run check
env:
REQUIRE_NUMBAT: '1'
11 changes: 8 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

# Pinned to the commit that the `v6.1.0` tag pointed at on 2026-10-11, like the actions above it. It reads the pnpm version from
# `packageManager` in package.json, and goes before `setup-node` so that `cache: pnpm` finds it.
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0

- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
with:
node-version: 22
cache: npm
cache: pnpm
registry-url: https://registry.npmjs.org

- run: npm ci
- run: pnpm install --frozen-lockfile
- run: node tools/install-numbat.mjs
- run: npm run check
- run: pnpm run check
env:
REQUIRE_NUMBAT: '1'

Expand All @@ -48,4 +52,5 @@ jobs:
- run: npm install -g [email protected]

# No token: npm trusts this workflow of this repository (the package's settings on npmjs.com), through `id-token: write`.
# The packages are installed and checked with pnpm, and published with npm on purpose: the trust and the provenance are npm's.
- run: npm publish --provenance --access public
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node_modules
package-lock.json
pnpm-lock.yaml
# prose and modules are written by hand: not for a code formatter
*.md
*.nbt
Expand Down
10 changes: 6 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ it. The numbers are facts. The descriptions are your words, so paraphrase the so

## What you can run

The packages are installed with [pnpm](https://pnpm.io), at the version that `packageManager` in `package.json` names. With Node 22 or newer, `corepack enable pnpm` makes that version the one you get. The settings of pnpm are in `pnpm-workspace.yaml`: no dependency version younger than 14 days is installed.

| Command | What it does |
|---|---|
| `node tools/pack-check.mjs` | Checks that a release would hold only the package's files |
| `npm ci`, then `npm run check` | Runs everything below, the formatter, the linters and the tests |
| `npm test` | Runs the tests of the checks below |
| `pnpm install --frozen-lockfile`, then `pnpm run check` | Runs everything below, the formatter, the linters and the tests |
| `pnpm test` | Runs the tests of the checks below |
| `node tools/check-docs.mjs` | Checks the documents here against [`docs/writing.md`](docs/writing.md) |
| `node tools/install-numbat.mjs` | Installs the official `numbat` program, at the pinned version and checksum, into `.numbat/` |
| `node tools/style.mjs` | Holds every module to the rules of `docs/style.md` |
Expand All @@ -52,12 +54,12 @@ it. The numbers are facts. The descriptions are your words, so paraphrase the so
| `node tools/stale.mjs` | Lists the modules that are older than a year or `unverified` |
| `node tools/links.mjs` | Lists the sources that no longer answer |

Each needs only Node. `npm run check` also holds every module to the rules of [`docs/style.md`](docs/style.md). A reviewer reads for the numbers and their
Each needs only Node, and pnpm for the first two. `pnpm run check` also holds every module to the rules of [`docs/style.md`](docs/style.md). A reviewer reads for the numbers and their
sources.

## The commit hook

`npm install` points git at `.githooks/`. Its `pre-commit` runs the quick checks on what you staged: formatting, ESLint, markdownlint,
`pnpm install` points git at `.githooks/`. Its `pre-commit` runs the quick checks on what you staged: formatting, ESLint, markdownlint,
the documents check, the names and version check, and the package contents. When a module is staged, it also runs the style check,
which takes about 20 seconds. The tests and the values check run in CI. Skip the hook once with `git commit --no-verify`.

Expand Down
23 changes: 18 additions & 5 deletions docs/maintaining.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,33 @@ edited by hand.

| File | Runs | What it does |
|---|---|---|
| `.github/workflows/check.yml` | Each pull request and each push to `main` | `npm ci`, installs `numbat`, then `npm run check` |
| `.github/workflows/release.yml` | A tag `vX.Y.Z` | The same check, then the tag, `api.json` and `values.json` must match the version, then `npm publish` with provenance |
| `.github/workflows/check.yml` | Each pull request and each push to `main` | `pnpm install --frozen-lockfile`, installs `numbat`, then `pnpm run check` |
| `.github/workflows/release.yml` | A tag `vX.Y.Z` | The same check, then the tag, `api.json` and `values.json` must match the version, then `npm publish` with provenance (npm, not pnpm: see below) |
| `.github/workflows/maintenance.yml` | Each Monday | Lists the modules that are due a check, and fails when a source no longer answers |
| `.github/dependabot.yml` | Each Monday | Opens pull requests for npm and Actions updates |
| `.github/dependabot.yml` | Each Monday | Opens pull requests for Actions updates only |

The release workflow holds no secret. The package's settings on npmjs.com name `UnitPad/modules` and `release.yml` as its trusted
publisher, so npm accepts the publish from that workflow alone. If a release fails with an authentication error, check that setting first.

The packages are installed and checked with pnpm, and the release publishes with `npm publish` on purpose. Trusted publishing and provenance are
features of the npm command line, and the trust on npmjs.com is tied to the file name `release.yml`. The workflow installs npm 11.21.0 for it,
because Node 22 ships npm 10. Keep the file name, the job name, the tag trigger and `id-token: write` as they are.

## Updating dependencies

The five packages are development tools, and nothing runs at runtime. Dependabot does not update them. Update them by hand:

1. Run `pnpm outdated` to list what has a newer version.
2. Run `pnpm update --interactive` and choose what to move. pnpm refuses a version younger than 14 days (`minimumReleaseAge` in `pnpm-workspace.yaml`), which is the rule of this repository.
3. Run `pnpm run check`, then commit `package.json` and `pnpm-lock.yaml` together.
4. After 2026-10-16, delete the two `minimumReleaseAgeExclude` lines in `pnpm-workspace.yaml`: `[email protected]` and `[email protected]` have matured by then, and the lines do nothing.

## Make a release

1. Choose the version by the table in `CONTRIBUTING.md`. `node tools/api.mjs` tells you the least step that the names need.
2. Run `npm run api:update` and `npm run values:update`. They write the names and the values of this release to `api.json` and
2. Run `pnpm run api:update` and `pnpm run values:update`. They write the names and the values of this release to `api.json` and
`values.json`, in the formatter's layout. Commit them with the version.
3. Run `npm run check`. It must pass.
3. Run `pnpm run check`. It must pass.
4. Tag `vX.Y.Z`, equal to the version in `package.json`, and push the tag.
5. The release workflow publishes the tag with npm provenance. A published version then names the commit it came from. Nobody publishes
from a laptop. npm takes a minute or two to show the new version.
Expand Down
Loading