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
4 changes: 2 additions & 2 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ jobs:
uses: actions/setup-node@v7
with:
node-version: 22
registry-url: https://registry.npmjs.org

- name: Set up pnpm
run: |
Expand All @@ -49,11 +48,12 @@ jobs:
- name: Validate release gate
run: pnpm validate

# npm trusted publishing: pnpm exchanges this job's OIDC identity for a short-lived publish
# token, so no long-lived npm token is stored in GitHub.
- name: Semantic release
run: pnpm exec semantic-release
env:
GITHUB_TOKEN: ${{ github.token }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Upload release verification artifacts
uses: actions/upload-artifact@v7
Expand Down
6 changes: 6 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ The workflow runs `pnpm validate`, then semantic-release derives the next versio
Conventional Commits. It prepares and publishes `@jcode.labs/ragmir` with npm provenance.
The landing is private and is not published to npm.

Publishing uses npm trusted publishing: `pnpm publish` exchanges the release job's GitHub OIDC
identity for a short-lived token, so the repository stores no npm token. The npm package settings
must list one trusted publisher with these values: organization `jcode-works`, repository
`jcode-ragmir`, workflow `npm-publish.yml`, and environment `npm-publish`. Renaming the workflow,
the environment, or the repository requires updating that entry on npmjs.com first.

The repository intentionally contains no cloud-vendor landing configuration and the npm workflow
does not deploy the site. The external deployment must build with the released version in
`PUBLIC_RAGMIR_VERSION`. Production must use `PUBLIC_RAGMIR_LANDING_URL=https://ragmir.com`; staging
Expand Down
4 changes: 1 addition & 3 deletions scripts/semantic-release-publish.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ for (const directory of packageDirs) {
if (checkOnly) {
console.log(`Semantic release publish check passed for ${version}`)
} else {
if (!process.env.NODE_AUTH_TOKEN) {
throw new Error("NODE_AUTH_TOKEN is required for npm publish")
}
// pnpm authenticates through npm trusted publishing with the workflow's OIDC identity.
for (const directory of packageDirs) {
run("pnpm", [
"--dir",
Expand Down
20 changes: 5 additions & 15 deletions scripts/semantic-release-verify.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { spawnSync } from "node:child_process"
import { readFile } from "node:fs/promises"
import path from "node:path"
import { fileURLToPath } from "node:url"
Expand Down Expand Up @@ -36,19 +35,10 @@ for (const packageName of optionalCorePackages) {
if (checkOnly) {
console.log("Semantic release verify check passed.")
} else if (process.env.GITHUB_ACTIONS === "true") {
if (!process.env.NODE_AUTH_TOKEN) {
throw new Error("NODE_AUTH_TOKEN is required before semantic-release can create a tag")
}
run("npm", ["whoami", "--registry=https://registry.npmjs.org"])
}

function run(command, args) {
const result = spawnSync(command, args, {
cwd: repoRoot,
encoding: "utf8",
stdio: "inherit",
})
if (result.status !== 0) {
throw new Error(`Command failed: ${command} ${args.join(" ")}`)
// Trusted publishing needs the job's OIDC request credentials before a tag is created.
if (!process.env.ACTIONS_ID_TOKEN_REQUEST_URL || !process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN) {
throw new Error(
"npm trusted publishing requires the release job's id-token: write permission before semantic-release can create a tag",
)
}
}
Loading