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: 6 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ jobs:
- uses: pnpm/action-setup@v4
if: steps.plan.outputs.release == 'true' && steps.plan.outputs.published == 'false'
- name: Install npm with trusted publishing support
if: steps.plan.outputs.release == 'true' && steps.plan.outputs.published == 'false'
run: npm install --global npm@11
if: steps.plan.outputs.release == 'true'
# OIDC dist-tag authentication requires npm 11.21.0 or later.
run: npm install --global 'npm@^11.21.0'
- name: Install packaging dependencies
if: steps.plan.outputs.release == 'true' && steps.plan.outputs.published == 'false'
# Packaging does not run the native renderer or need content repositories.
Expand All @@ -63,6 +64,9 @@ jobs:
env:
NPM_TAG: ${{ steps.plan.outputs.npmTag }}
run: npm publish "$RUNNER_TEMP/slides.tgz" --access public --tag "$NPM_TAG" --provenance
- name: Update npm distribution tags
if: steps.plan.outputs.release == 'true'
run: node scripts/sync-npm-tags.mjs
- name: Create and push the release tag
if: steps.plan.outputs.release == 'true'
env:
Expand Down
35 changes: 25 additions & 10 deletions .github/workflows/slides.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Slides architecture
on:
# Always report the required check; skip expensive steps for documentation-only PRs.
# Always report the required check, including documentation and version-only PRs.
pull_request:
workflow_dispatch:
jobs:
Expand All @@ -12,6 +12,9 @@ jobs:
pull-requests: read
steps:
- uses: actions/checkout@v6
with:
# Include the PR merge parents for the version-only comparison.
fetch-depth: 2
- name: Detect changes that need testing
id: changes
# Manual runs and PRs beyond the API's 3,000-file limit run all tests.
Expand All @@ -20,38 +23,50 @@ jobs:
with:
predicate-quantifier: every
filters: .github/test-paths.yml
- name: Check for version-only changes
id: version
if: >-
github.event_name == 'pull_request' &&
github.event.pull_request.changed_files <= 3000 &&
github.event.pull_request.base.ref == 'main' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.head_ref == 'changeset-release/main' &&
steps.changes.outputs.tests != 'false'
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: node scripts/check-version-only.mjs "$BASE_SHA"
- name: Documentation-only changes
if: steps.changes.outputs.tests == 'false'
run: echo "Documentation-only changes; integration tests were not needed." >> "$GITHUB_STEP_SUMMARY"
- name: Check out the integration presentation
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
run: git submodule update --init content/slides-template
- uses: pnpm/action-setup@v4
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
with:
version: 10.22.0
- uses: actions/setup-node@v6
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
with:
node-version: 24
cache: pnpm
- name: Set up native renderer
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
run: sudo sh packages/static-render/scripts/install-system-deps.sh
- run: pnpm install --frozen-lockfile
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
- name: Unit and component checks
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
run: |
pnpm -r test
pnpm --filter @allmaps/slides --filter @allmaps/iiif --filter @allmaps/static-render check
pnpm check ./content/slides-template
- name: Native pixel alignment
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
run: xvfb-run -a pnpm --filter @allmaps/static-render test:native
- name: Independent development sites
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
run: pnpm --filter @allmaps/slides test:dev
- name: Fresh installed consumer
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
run: xvfb-run -a pnpm --filter @allmaps/slides test:package
23 changes: 19 additions & 4 deletions .github/workflows/static-render.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Static renderer
on:
# Always report the required check; skip expensive steps for documentation-only PRs.
# Always report the required check, including documentation and version-only PRs.
pull_request:
workflow_dispatch:
jobs:
Expand All @@ -11,6 +11,9 @@ jobs:
pull-requests: read
steps:
- uses: actions/checkout@v6
with:
# Include the PR merge parents for the version-only comparison.
fetch-depth: 2
- name: Detect changes that need testing
id: changes
# Manual runs and PRs beyond the API's 3,000-file limit run all tests.
Expand All @@ -19,13 +22,25 @@ jobs:
with:
predicate-quantifier: every
filters: .github/test-paths.yml
- name: Check for version-only changes
id: version
if: >-
github.event_name == 'pull_request' &&
github.event.pull_request.changed_files <= 3000 &&
github.event.pull_request.base.ref == 'main' &&
github.event.pull_request.head.repo.full_name == github.repository &&
github.head_ref == 'changeset-release/main' &&
steps.changes.outputs.tests != 'false'
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: node scripts/check-version-only.mjs "$BASE_SHA"
- name: Documentation-only changes
if: steps.changes.outputs.tests == 'false'
run: echo "Documentation-only changes; container tests were not needed." >> "$GITHUB_STEP_SUMMARY"
- uses: docker/setup-buildx-action@v3
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
- name: Build image and run native smoke test
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
uses: docker/build-push-action@v6
with:
context: .
Expand All @@ -37,6 +52,6 @@ jobs:
cache-from: type=gha,scope=slides-renderer
cache-to: type=gha,mode=max,scope=slides-renderer
- name: Check container entrypoint
if: steps.changes.outputs.tests != 'false'
if: steps.changes.outputs.tests != 'false' && steps.version.outputs.only != 'true'
timeout-minutes: 1
run: docker run --rm slides-renderer:check node packages/static-render/bin/render.mjs --help
24 changes: 23 additions & 1 deletion .github/workflows/version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,34 @@ jobs:
with:
fetch-depth: 0
persist-credentials: false
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
node-version: 24
package-manager-cache: false
- name: Check for pending release changes
id: changes
run: |
node --input-type=module <<'NODE'
import { appendFile, readFile, readdir } from 'node:fs/promises';
// Consumed beta notes live in .changeset/pre/ and must not start another PR.
const pending = (await readdir('.changeset', { withFileTypes: true })).some(
entry => entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'README.md',
);
const pre = await readFile('.changeset/pre.json', 'utf8').then(JSON.parse).catch(error => {
if (error.code === 'ENOENT') return undefined;
throw error;
});
const needed = pending || pre?.mode === 'exit';
await appendFile(process.env.GITHUB_OUTPUT, `needed=${needed}\n`);
if (!needed) await appendFile(process.env.GITHUB_STEP_SUMMARY,
'No pending changesets or beta exit; no version PR needed.\n');
NODE
- uses: pnpm/action-setup@v4
if: steps.changes.outputs.needed == 'true'
- run: pnpm install --frozen-lockfile --ignore-scripts
if: steps.changes.outputs.needed == 'true'
- uses: changesets/action/version@v2
if: steps.changes.outputs.needed == 'true'
with:
script: pnpm release:version
github-token: ${{ secrets.GITHUB_TOKEN }}
16 changes: 12 additions & 4 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,18 @@ Every pull request reports the required `integration` and `container` checks.
Documentation-only changes pass after a quick file check, without installing
dependencies or building the container. The shared rules in
[`.github/test-paths.yml`](../.github/test-paths.yml) exclude guides, software
READMEs, changelogs and changeset notes. All other paths run the full checks,
including configuration, licenses, workflows and content submodules. Manual
workflow runs always run the full checks; a failed change-detection step fails
the required check.
READMEs, changelogs and changeset notes.

Automatic version PRs from this repository's `changeset-release/main` branch to
`main` also skip expensive tests when a comparison against the PR base confirms
that only the Slides package's `version` field, changelog and Changesets release
records changed. Any other manifest field, lockfile, code, configuration,
license, workflow or content change runs the full checks. The required checks
still report success with a summary explaining the shortcut. Publication keeps
its release validation and package build.

Manual workflow runs and PRs exceeding 3,000 changed files always run the full
checks; a failed change-detection step fails the required check.

```sh
pnpm -r test
Expand Down
47 changes: 32 additions & 15 deletions docs/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ Content repositories choose when to upgrade and redeploy their websites.
changesets are collected into one release.
2. **Prepare release** opens or updates a version PR with the new version,
changelog and lockfile. During beta, the next version after `0.1.0-beta.1` is
`0.1.0-beta.2`. Review the PR, let its checks pass, and merge it.
`0.1.0-beta.2`. Review the PR, let its checks pass, and merge it. For a
version-only PR, these checks verify the changed files and manifest instead
of repeating the expensive software tests. Changes to code, dependencies or
the lockfile still run the full checks.
3. **Publish release** detects the version change on `main`, checks the release,
builds and packs the software, and publishes it to npm. Beta versions use
npm's `beta` channel; stable versions use `latest`. It then creates and pushes
builds and packs the software, and publishes it to npm. Beta versions update
`beta` and also `latest` while the default version is still a beta. Once
`latest` points to a stable release, later betas leave it unchanged. Stable
versions update `latest`. It then creates and pushes
an annotated tag such as `@allmaps/slides@0.1.0-beta.2` and creates the matching
GitHub release from the changelog. Beta versions are GitHub prereleases.
No local publish command or manual tagging is needed.
Expand All @@ -36,6 +41,11 @@ publish anything. Pending changesets alone do not publish anything either:
they prepare the version PR. A release requires a clean software commit,
consumed changesets and a changelog entry matching the version.

**Prepare release** skips version preparation when there are no new changesets.
Archived beta notes in `.changeset/pre/` do not count, so merging a version PR
does not open another empty PR. Explicitly leaving beta with `changeset pre exit`
still allows a version PR without new notes. The same checks apply to manual runs.

[Software checks](development.md#checks) cover the package and application.
Content changes belong in their own repositories and need no Slides changeset.
Local content edits do not block `pnpm release:check`.
Expand All @@ -50,15 +60,17 @@ The package's npm settings must authorize this GitHub trusted publisher:
| Repository | `slides` |
| Workflow filename | `release.yml` |
| Environment name | `npm` |
| Allowed actions | Enable **npm publish** for direct publication. |
| Allowed actions | Enable **npm publish** and **npm dist-tag**. |

The publishing job uses the GitHub environment named `npm`. Under repository
**Settings → Environments → npm**, restrict deployment branches to `main`.
The job already runs only on `main`, including manual publication. Tag-triggered
GitHub release repairs do not publish to npm or use this environment.
The environment name in npm's trusted-publisher settings must match `npm`.

The publishing job has `id-token: write` permission and uses npm 11 with OIDC.
The publishing job has `id-token: write` permission and uses npm 11.21 or later
with OIDC. Tag management requires the separate **Allow npm dist-tag** permission
in the trusted-publisher settings; permission to publish alone is insufficient.
No npm token secret or interactive login is needed in Actions. pnpm prepares
the tarball so `publishConfig.exports` and bundled workspace packages are
handled correctly; npm publishes that tarball with provenance. Packaging does
Expand All @@ -72,12 +84,12 @@ silently switch to staged publishing.

| Workflow | Trigger | Result |
| --- | --- | --- |
| Prepare release (`version.yml`) | Changesets on `main`, or manual run on `main` | Opens/updates the version and changelog PR. |
| Prepare release (`version.yml`) | Changesets on `main`, or manual run on `main` | Opens/updates a version PR only for new changesets or an explicit beta exit. |
| Publish release (`release.yml`) | Package manifest changes on `main` | Publishes only when the version changes, then creates the tag and GitHub release. |
| Publish release (`release.yml`) | Manual run on `main` with an empty tag | Attempts the current prepared release, including retrying an interrupted publication. |
| Publish release (`release.yml`) | Push of `@allmaps/slides@*`, or manual run with an existing tag | Creates the GitHub release only; does not publish to npm. |
| Slides architecture (`slides.yml`) | Every pull request, or manual run | Tests the CLI, app, renderer, development server and installed package; skips tests for documentation-only PRs. |
| Static renderer (`static-render.yml`) | Every pull request, or manual run | Tests the Linux renderer container; skips tests for documentation-only PRs. |
| Slides architecture (`slides.yml`) | Every pull request, or manual run | Tests the CLI, app, renderer, development server and installed package; skips expensive tests for documentation-only and verified version-only PRs. |
| Static renderer (`static-render.yml`) | Every pull request, or manual run | Tests the Linux renderer container; uses the same documentation and version-only shortcuts. |
| Deploy to GitHub Pages (content repos) | Push to `main`, or manual run | Installs the pinned npm package, builds content and deploys the site. |
| Build and Publish Docker Image (Kattenburg) | Push to `main`, version tag, or manual run | Builds the site and publishes an Nginx image to GHCR. |

Expand Down Expand Up @@ -107,10 +119,15 @@ public Slides template.
- A manual run with an empty tag uses the selected `main` commit. Use it only
when that commit is the prepared release. If more work has landed on `main`,
rerun the original failed run instead.
- If an earlier beta publication left `latest` behind, correct it once from a
logged-in terminal: `npm dist-tag add @allmaps/slides@0.1.0-beta.2 latest`
(replace the example with the current beta version). This updates the tag
without republishing. Subsequent releases update it automatically.

GitHub supplies source ZIP/tar downloads for tagged releases. The first npm
publication also received `latest`; use an explicit version or `@beta` for beta
updates. A version already accepted by npm cannot be overwritten.
publication also received `latest`; the release workflow now keeps that default
current throughout beta. The `-beta.N` version suffix and GitHub prerelease status
remain unchanged. A version already accepted by npm cannot be overwritten.

## Local fallback

Expand All @@ -126,13 +143,13 @@ git push origin '@allmaps/slides@0.1.0-beta.2'
```

Replace the example tag with the version just published. `release:publish`
rebuilds the package, selects `beta` or `latest`, publishes and creates a local
annotated tag. Complete npm's publishing authentication when prompted. Pushing
the tag creates the GitHub release. Coordinate this fallback with any running
rebuilds the package, publishes, synchronizes npm tags using the same policy, and
creates a local annotated tag. Complete npm's publishing authentication when
prompted. Pushing the tag creates the GitHub release. Coordinate this fallback with any running
Actions publication so they do not attempt the same version concurrently.

Do not use `changeset publish` here: it can select `latest` for a package whose
first stable release has not yet been published.
Use these release commands instead of `changeset publish` to keep source
validation, npm tags and GitHub releases on the same workflow.

## Finish beta

Expand Down
Loading
Loading