Publishing to npm
This guide explains how community leads can publish the Cloud Blocks package to npm from this single-package (polyrepo). Publishing is automated via GitHub Actions using semantic-release and Conventional Commits.
Prerequisites
-
All tests passing locally and in CI:
pnpm test
-
An npm account with publish rights to the
@leighton-digital/*
scope.npm login
-
Access to the repo’s
NPM_TOKEN
secret (must be an Automation token if org requires 2FA). -
package.json
includes:{
"name": "@leighton-digital/<your-package>",
"version": "0.0.0-development",
"private": false,
"packageManager": "pnpm@9",
"publishConfig": { "access": "public" }
}version
is managed by semantic-release at publish time. For scoped public packages,publishConfig.access
must be"public"
.
Build
Build locally exactly as CI does:
pnpm install --frozen-lockfile
pnpm build
Your build should output distributable files (e.g., dist/
) referenced by package.json
fields like main
, module
, types
, exports
, etc.
Versioning & Changelog (Automated)
We use Conventional Commits + semantic-release:
feat: …
→ minorfix: …
→ patchperf:
/refactor:
may map to patch (configurable)BREAKING CHANGE:
in the commit footer (orfeat!:
/fix!:
) → major- Changelog is generated automatically into
CHANGELOG.md
.
Commit examples
feat(parser): add YAML support
fix(cli): handle empty config without crashing
feat(api)!: remove deprecated v1 endpoints
BREAKING CHANGE: The v1 /users endpoint was removed in favor of /v2/users.
How Publishing Works (GitHub Actions)
Releases are created automatically on pushes to main
that include qualifying Conventional Commits.
1) Workflow file
The release is automatically performed through the GitHub Release Workflow
2) semantic-release config
The releaserc.json provides the release configuration.
3) Dependencies
The following packages have been installed to release the package:
semantic-release @semantic-release/{npm,git,changelog,commit-analyzer,release-notes-generator}
Tip: To validate locally without publishing, run:
pnpm dlx semantic-release --dry-run
Triggering a Release
- Merge/push Conventional Commit(s) to
main
. - The workflow computes the next version, updates
CHANGELOG.md
, creates a Git tag & GitHub Release, and publishes to npm.
You don’t manually bump versions or run
pnpm publish
. CI handles it.
Manual/Emergency Publishing (avoid if possible)
If CI is unavailable and you must publish:
-
Ensure working tree is clean and built:
pnpm install --frozen-lockfile
pnpm build -
Strongly preferred: run a local dry run first:
pnpm dlx semantic-release --dry-run
-
If absolutely necessary to publish without semantic-release, you can:
pnpm version patch|minor|major
pnpm publishCaveat: This bypasses automation and will desync the next SR calculation. Afterward, reset
version
to0.0.0-development
and push a corrective commit. Use only as a last resort.
Biome & Lefthook Integration
To ensure code quality and consistency, Biome and Lefthook run locally and in CI.
Local (via Lefthook)
-
pre-commit
biome format --write
on staged filesbiome lint
on staged files
-
pre-push
pnpm typecheck
andpnpm test
-
commit-msg
non-empty: run: test -s {1} || (echo "✖ Commit message is empty" && exit 1)
commitlint: run: pnpm commitlint --edit {1}
CI (via GitHub Actions)
Every PR and push to main
should run:
pnpm format:check # biome check --formatter
pnpm lint # biome check --linter
pnpm typecheck
pnpm build
pnpm test
The release job runs these before publishing.
Troubleshooting
“No release published”
- Cause: No Conventional Commits since last release (no
feat
,fix
, orBREAKING CHANGE
). - Fix: Use proper commit types; push again.
“Semantic-release can’t find previous tag”
- Cause: Shallow clone.
- Fix: Ensure
actions/checkout
usesfetch-depth: 0
.
403 from npm / publish failed
- Cause: Token lacks permission or isn’t an Automation token (when 2FA enforced).
- Fix: Regenerate
NPM_TOKEN
with Automation type; confirm org permissions.
“Package is private”
- Cause: Missing public access for scoped package.
- Fix: Ensure
publishConfig.access: "public"
inpackage.json
.
Wrong branch
- Cause: Releasing from a non-configured branch.
- Fix: Update
.releaserc.json#branches
or usemain
.
Changelog not updated
- Cause: Missing
@semantic-release/changelog
or@semantic-release/git
. - Fix: Ensure both plugins are present in config and installed.
Checking Published Packages
View the package on npm:
npm view @leighton-digital/api-gateway-cloudfront-distribution
Check available versions:
npm view @leighton-digital/api-gateway-cloudfront-distribution versions
Best Practices
-
Before opening a PR:
pnpm format:check
pnpm lint
pnpm typecheck
pnpm test -
Use
npm pack
locally to preview the publish contents:pnpm pack
-
Prefer CI-driven releases. Avoid manual
pnpm publish
except in emergencies. -
Adopt Conventional Commits consistently across all changes.