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
105 changes: 92 additions & 13 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,109 @@
name: Publish to npm

# Only version tags can trigger a release. Do not publish from PRs.
on:
push:
tags: ["v*"]
tags:
- "v*"

permissions:
contents: read
id-token: write

concurrency:
group: npm-publish
cancel-in-progress: false

jobs:
publish:
verify:
name: Verify release
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
- name: Check out release commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "24"
registry-url: https://registry.npmjs.org
- name: Verify version tag
package-manager-cache: false

- name: Verify tag, package version, and branch
shell: bash
run: |
set -euo pipefail
expected="v$(node -p 'require("./package.json").version')"
test "$GITHUB_REF_NAME" = "$expected" || {
echo "Expected tag $expected, got $GITHUB_REF_NAME" >&2
if [[ "$GITHUB_REF_TYPE" != "tag" || "$GITHUB_REF_NAME" != "$expected" ]]; then
echo "Expected version tag $expected, received $GITHUB_REF_NAME" >&2
exit 1
fi

# Reject tags pointing to commits not reachable from main.
git fetch --no-tags origin main:refs/remotes/origin/main
if ! git merge-base --is-ancestor "$GITHUB_SHA" refs/remotes/origin/main; then
echo "Release tag must reference a commit on main" >&2
exit 1
}
- run: npm install --no-audit --no-fund
- run: npm test
- run: npm publish --access public
fi

- name: Install dependencies without lifecycle scripts
run: npm install --ignore-scripts --no-audit --no-fund

- name: Check and test
run: |
npm run check
npm test

- name: Verify npm package contents
run: npm pack --dry-run --ignore-scripts

publish:
name: Publish with npm Trusted Publishing (OIDC)
if: github.repository == 'Angular-RU/prettier-plugin-angular-comment'
needs: verify
runs-on: ubuntu-latest

# Configure required reviewers for this environment in GitHub settings.
# npm Trusted Publisher must use the same environment name.
environment: npm-publish

permissions:
contents: read
id-token: write

steps:
- name: Check out verified release commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Node.js and npm registry
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "24"
registry-url: https://registry.npmjs.org
package-manager-cache: false

- name: Require OIDC-compatible npm
shell: bash
run: |
npm --version
node -e '
const [major, minor, patch] = require("node:child_process")
.execFileSync("npm", ["--version"], { encoding: "utf8" })
.trim()
.split(".")
.map(Number);
if (major < 11 || (major === 11 && (minor < 5 || (minor === 5 && patch < 1)))) {
console.error("npm >= 11.5.1 is required for OIDC trusted publishing");
process.exit(1);
}
'

# No npm install or dependency scripts in the OIDC-enabled job.
# npm automatically generates provenance for public packages.
- name: Publish to npm via OIDC
run: npm publish --access public --ignore-scripts
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,45 @@ npm test
npm pack --dry-run
```

## npm releases
## npm releases (Trusted Publishing / OIDC)

Create the npm package first if it does not yet exist. Configure [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/) for `Angular-RU/prettier-plugin-angular-comment` and the workflow `publish.yml`; trusted publishing requires an existing npm package and matching owner access. After merging a version bump, push its matching `vX.Y.Z` Git tag. The GitHub Actions workflow tests and publishes via OIDC. Never put a long-lived npm token in the repository.
This repository uses [npm Trusted Publishing](https://docs.npmjs.com/trusted-publishers/) with GitHub Actions. No persistent `NPM_TOKEN` or `NODE_AUTH_TOKEN` secret is required.

### First release (one-time setup)

npm requires the package to exist before a Trusted Publisher can be configured. If the package has not been published yet, its npm owner must bootstrap it locally:

```sh
npm login
npm install
npm test
npm publish --access public
```

Keep the version in `package.json` synchronized with the first published version. Do **not** push a matching tag for the manually published version.

### Enable Trusted Publishing

1. Open `https://www.npmjs.com/package/prettier-plugin-angular-comment/access` or the package's npm settings, then **Trusted publishing** → **Add trusted publisher** → **GitHub Actions**.
2. Enter **Organization/user**: `Angular-RU`, **Repository**: `prettier-plugin-angular-comment`, **Workflow filename**: `publish.yml` (not a path), **Environment**: `npm-publish`.
3. Enable **Allow npm publish** in the npm trusted publisher's allowed actions. Staging-only permission is insufficient for this workflow.
4. In GitHub **Settings → Environments**, create or configure `npm-publish`. Add **required reviewers** and deployment-tag restrictions if desired, so a release requires approval.
5. Complete the first successful OIDC publication within **2 days** of creating the trusted publisher, or recreate the expired configuration.

### Publish the next version

Update `package.json` to an unpublished version (for example, `0.1.1`), merge it to `main`, and confirm CI is green. Then push the corresponding tag **from a commit on main**:

```sh
git switch main
git pull --ff-only
git tag v0.1.1
git push origin v0.1.1
```

The [publish workflow](./.github/workflows/publish.yml) verifies the exact version and that the tag commit is on `main`, runs tests without OIDC permissions, and publishes in a separate approval-gated environment. The publisher job disables npm lifecycle scripts and uses npm's short-lived OIDC authentication and automatic provenance. Pinned GitHub Action commit SHAs and disabled release-job caching reduce supply-chain risk.

**After the first successful OIDC release**, consider selecting **Require two-factor authentication and disallow tokens** under npm **Settings → Publishing access**, and protect release tags with a GitHub ruleset. Traditional npm token publishing will then be blocked while OIDC continues working.

## License

Expand Down
Loading