Repository navigation
ci: npm trusted publishing and GitHub releases - #473
Conversation
Remove the changesets versioning workflow (changesets/action without a publish input, which only added a Release check to every commit on main), the generated .changeset/README.md and the root CHANGELOG.md stub. changeset publish stays the publish command. Refs #465 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The builder stage of the docs image copies the whole build context. Send only what the build needs (allow list: workspaces, build scripts, root manifests), so that local .env* files and other local files never reach the image, and drop dependencies and build output within. Closes #463 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pin every action to a full commit SHA on its current major version (checkout v7, setup-node v7, cache v6, semantic PR title v6, ssh-agent v0.10, push action v1.3.0 instead of master), with Dependabot keeping the pins up to date. Replace the node_modules caches, whose key hashed a file that doesn't exist and which used ::set-output, by the npm cache of setup-node in CI; releases use no dependency cache. Drop the force-with-lease input of the push action, which doesn't exist (the input is force_with_lease) and so never had an effect. Refs #465 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Give Dependabot pull requests a ci: prefix, so that their titles pass the PR title check. Keep the commented-out release tests job as it was and state the release cache comment once. Refs #465 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ubuntu-latest now is Ubuntu 26.04, on which Playwright 1.56 can't install its browsers, so every test job fails (unrelated to the other changes). Pin the test job to ubuntu-24.04 until Playwright is upgraded. Refs #465 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node.js 18 and 20 are end of life. Test on 22 and 24, lint and release on 24 (npm 11, needed for trusted publishing), build the docs image on node:24-alpine and update the development prerequisites in the README. engines and packageManager stay as they are. Closes #466 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rename publish.yml to release.yml (Release), as in the organization's other repositories, with job names Lint release, Bump version, Publish packages. The publish job gets id-token: write (and only it), checks for npm 11.5.1 or later and publishes through OIDC with provenance. NPM_TOKEN stays as a fallback: npm tries OIDC first and uses the token only if the exchange fails; remove it after the first OIDC release. A new job creates a GitHub release with generated notes from the previous version tag, as a prerelease for versions with a suffix. Closes #467 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Order version tags by semver when looking up the previous tag for the release notes (sort -V puts v2.0.0 before v2.0.0-alpha.1). Configure the NPM_TOKEN fallback only right before publishing, say in the log when it is configured, and warn about released versions without provenance (published with the token). Name the jobs Release packages and Release on GitHub. Refs #467 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Reviewer's GuideModernizes tag-based releases around npm trusted publishing with narrowly scoped OIDC permissions, provenance validation, and automated GitHub releases, while updating the project and CI to Node.js 24 and removing obsolete release artifacts. Sequence diagram for the trusted npm and GitHub release flowsequenceDiagram
participant Maintainer
participant Actions as GitHub Actions
participant Bump as Bump version job
participant Publish as Release packages job
participant NPM as npm registry
participant GitHub as GitHub Releases
Maintainer->>Actions: Push v* tag on main
Actions->>Bump: Run after lint succeeds
Bump->>Bump: Push bump: v<version> to main via SSH
Bump->>Publish: Start publish job with id-token: write
Publish->>NPM: Exchange OIDC identity for trusted publishing
NPM-->>Publish: Publish packages with provenance
alt OIDC exchange fails
Publish->>NPM: Publish using NPM_TOKEN fallback
end
Publish->>NPM: Check dist.attestations.provenance
Publish->>GitHub: Create release with generated notes
GitHub-->>Publish: Mark prerelease when tag contains -
Flow diagram for the tag-based release pipelineflowchart LR
Tag[Push v* tag on main] --> Lint[Lint release]
Lint --> Bump[Bump version]
Bump --> Publish[Release packages]
Publish --> Provenance[Check npm provenance]
Provenance --> GitHub[Release on GitHub]
Publish -. OIDC with id-token: write .-> NPM[npm trusted publishing]
Publish -. fallback .-> Token[NPM_TOKEN]
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've reviewed your changes and they look great!
Sourcery assessment
Needs a human reviewer. If the tag, version selection, or build is wrong, this workflow can publish an unintended package version to npm, where consumers may install it and reverting the workflow cannot undo that exposure. Reverting stops future releases, but an already-published version may remain in use.
Add scripts/release.js, which sets and checks the shared version of the root and of all public packages in packages/*, prints their dist-tag and pins their internal dependencies for publishing (with tests). @elixir-cloud/tes is deprecated (no build, so a release would have no code): mark it private, so that it is no longer released. Give @elixir-cloud/eslint-config a repository URL for provenance. Drop the unused `release` script (changeset publish). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rework release.yml for the branch model of the other repositories: the version bump is a pull request to `dev`, a maintainer tags `v<version>` on `dev`, and the workflow builds from the tag and pushes nothing (no bump job, no deploy key). It checks that all package versions match the tag and that the tag is on the default branch before anything else. The publish job runs in the `npm` environment and stages each public package with `npm stage publish --provenance --tag <dist-tag>` (trusted publishing; npm 11.15.0 or later); maintainers approve the staged versions on npmjs.com. The NPM_TOKEN fallback and the provenance check are gone. Outside the main repository, staging is a dry run. PR Evaluation now runs on pull requests to `dev`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the review: check out the tagged commit (github.sha) in all jobs, check the tag against `dev`, fail if the package list is empty or an npm lookup fails for another reason than "not found", and warn in the summary not to approve versions while others failed to stage. Test the command line of scripts/release.js and clean up test fixtures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep Node.js 24 (and 22/24 in the test matrix) in the conflicting setup-node steps, and run PR Evaluation on pull requests to `dev`, the default branch now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the second review: `npm view` doesn't see staged versions, so a re-run tried to stage them again and failed on the conflict (E409) forever. Count those as staged (the same commit, as tags are immutable), keep stdin away from npm in the loop, and say in the header that tags must be on `dev`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decided by the maintainer: as before, the 2.0.0 alphas go to `latest`. Prereleases of a major version without a release yet (no tag v<major>.x.y without suffix) get `latest`; once the major is released, prereleases get their identifier (`rc` for 2.1.0-rc.1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From the review: without any release tag (e.g. a clone without tags), every prerelease would get `latest`. Fail instead, also in the workflow (the dist-tag is no longer computed inside `echo`), wrap git errors, and tidy the tests and comments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Third of the stacked pull requests for #464. Stacked on #470: merge it first; until then this diff also shows its commits.
Reworks the npm release for the branch model of the organization's other repositories (
devis the default branch,mainpoints at the latest release) and for npm trusted publishing with staged publishing only (the trusted publishers allownpm stage publish, notnpm publishor dist-tag changes; package publishing access is "require 2FA, disallow tokens").main: the bump job, the deploy key (DEPLOY_KEY) and theNPM_TOKENfallback are gone. The version bump happens in a normal pull request todev(node scripts/release.js set <version>, which also updatespackage-lock.json).release.yml/Releaseon tagsv*, all jobs on the tagged commit (github.sha):readiness/Release readiness: fails early unless the tag is a version, the root and all public packages have exactly that version, and the commit is ondev. Computes the dist-tag from the git tags.lint/Lint release:npm ci,npm run lint.publish/Release packages: environmentnpm(required reviewer),id-token: writeonly here. Node.js 24 withcheck-latestand a check for npm 11.15.0 or later (the first withnpm stage; Node.js 24.22 bundles 11.19.1). Pins the internal@elixir-cloud/*dependencies to the version (as before, not committed), builds, then runsnpm stage publish --provenance --tag <dist-tag>in each public package. Versions already on npm are skipped. A version staged by an earlier attempt fails with a conflict (E409) and counts as staged, so the job can be re-run. The run summary lists the staged versions to approve on npmjs.com; if any failed, it warns not to approve yet.github/Release on GitHub: unchanged (generated notes from the previous version tag, prerelease for-versions).elixir-cloud-aai/cloud-components: staging gets--dry-run, for a test in a fork.latestfor releases and for prereleases of a major version without a release tag yet, so the2.0.0-alpha.Nseries keeps going tolatestas before (there is nov2.x.ytag). Once 2.0.0 is out, prereleases get their identifier (2.1.0-rc.1→rc). Without any release tag (e.g. a clone without tags) the step fails instead of defaulting tolatest. npm requires--tagfor prereleases, and the tag of a staged version can't be changed later.packages/without"private": true.@elixir-cloud/teshas no build (all its scripts aredepricated-*), so a release would contain no code: it is nowprivateand no longer released. Its trusted publisher on npm will expire (it can't be validated by a publish before 2026-10-29); recreate it if tes is ever released again.@elixir-cloud/eslint-configis released with the shared version (0.0.1 → 2.0.0-alpha.N) and gets arepositoryURL for provenance.scripts/release.js(set,check,packages,dist-tag,pin), with tests inscripts/release.test.js(node --test; ci: single CI gate and contribution docs #474 runs them in CI).dev; the unusedreleasescript (changeset publish) is removed (ci: single CI gate and contribution docs #474 removes changesets).The release docs (version bump PR → tag on
dev→ approve thenpmenvironment → approve the staged versions → fast-forwardmain) are inCONTRIBUTING.mdin #474.Closes #467
Closes #471
Verification
node --test scripts/release.test.js: 9 tests pass.node scripts/release.js dist-tag 2.0.0-alpha.49→latest,dist-tag 1.1.0-rc.1→rc; in a repository without tags it fails ("No release tags").node scripts/release.js check 2.0.0-alpha.49lists all mismatches and exits 1;check v1exits 1 ("Not a version").npm version 2.0.0-alpha.49 --no-git-tag-version --include-workspace-root -w …(whatsetruns) changes only the versions in the root, the given packages andpackage-lock.json(tried, then reverted).npm stage publish --provenance --tag alpha --dry-run(npm 11.19.1) ineslint-configat2.0.0-alpha.49: "Staging … with tag alpha … (dry-run)". Without--tag: "You must specify a tag using --tag when publishing a prerelease version". At an existing version: "You cannot publish over the previously published versions".npm stage publishsubclassesnpm publish(same flags) and enables provenance automatically with OIDC;--provenancemakes it explicit.npm(a lookup timing out, a staging failure, an E409, a version already on npm; dry run and real): it continues, lists all results in the summary and exits 1 on failures.actionlint1.7.12: no findings.zizmor1.31.1 (offline): no findings forrelease.yml(findings only in the oldpr_evaluation.yml, which ci: single CI gate and contribution docs #474 replaces).npm run lint: passes locally.devwith build: move CI and Docker to Node.js 22 and 24 #470 and test: drop test scripts of packages without tests #478, head 2eda27f): PR Evaluation passes (conflicts, linting, title, tests on Node.js 22 and 24); the second, skipped PR Evaluation run is theeditedevent. The RTD check fails here because.readthedocs.yamlcomes with docs: host the docs on Read the Docs #476.uniqueg/cloud-components) is prepared for the maintainer.github.sha, a failing package list no longer hidden, npm lookups failing for other reasons than E404 count as failures, re-runs after partial staging (E409), summary warning, stdin of npm in the loop, CLI tests, fixture cleanup, dead filter, comments.Declined review findings
scripts/release.js: both were checked by hand (previous tags for alpha/rc/release sequences; npm versions); kept inline to keep this change small before the release.Decided
latest, as before (maintainer, 2026-10-27); prerelease dist-tags start once 2.0.0 is out.Open questions
None.
🤖 Generated with Claude Code