@orgme/semantic-release
v1.1.3
Published
A testing/demo project for **semantic-release** automation. It publishes a trivial TypeScript package to npm and demonstrates how commit messages drive automated versioning, changelog generation, and publishing.
Readme
@orgme/semantic-release
A testing/demo project for semantic-release automation. It publishes a trivial TypeScript package to npm and demonstrates how commit messages drive automated versioning, changelog generation, and publishing.
What is Semantic Release?
Semantic Release automates the entire release process — versioning, changelog generation, npm publishing, and GitHub releases — based entirely on your commit messages. You never manually bump versions or write release notes again.
How It Works
- You write commit messages following the Conventional Commits format.
- On every push to
masterornext, CI runs semantic-release. - Semantic-release analyzes the commits since the last release to determine the next version.
- It updates
package.jsonandCHANGELOG.md, publishes to npm, and creates a GitHub release — all automatically.
Under the Hood: How Versions Are Resolved
Git tags are the source of truth for semantic-release. Each release creates a tag like v1.0.2 (or v1.0.2-next.1 for prereleases):
- Semantic-release finds the most recent tag on the current branch.
- It inspects all commits between that tag and
HEAD. - Each conforming commit contributes a version bump; the highest bump wins:
- a
fix:→ patch, afeat:→ minor, aBREAKING CHANGE:→ major.
- a
- The new version is written to
package.json, appended toCHANGELOG.md, committed by the@semantic-release/gitplugin, published to npm, and tagged as a GitHub release.
This means the version field in package.json is only a starting point — never edit it manually, semantic-release overwrites it.
Key Features
- Automated Versioning — the next version is derived from commit messages (
fix→ patch,feat→ minor,BREAKING CHANGE→ major). - Changelog Generation —
CHANGELOG.mdis regenerated automatically. - Publishing — publishes the package to npm and creates a GitHub release.
- Pre-releases — the
nextbranch produces prerelease versions (e.g.1.0.2-next.1).
Prerequisites
- Node.js 22+
- pnpm 10.7.0 (this project uses pnpm — do not use npm/yarn)
- GitHub CLI (
gh) — required for dry runs. Install it withbrew install gh, then authenticate withgh auth login. - An npm account — publishing uses trusted publishing (OIDC), so no npm token is needed
- A GitHub repository with trusted publishing configured on npm for this package (map the repo + workflow file to the package at npmjs.com → package → Access)
- The
GITHUB_TOKENbuilt-in secret (used to create GitHub releases and tags)
| Secret | Purpose |
| ------ | ------- |
| GITHUB_TOKEN | Built-in token used to create GitHub releases and tags |
| id-token: write | Job permission that lets GitHub mint OIDC tokens for npm publishing — no NPM_TOKEN required |
Getting Started
1. Install dependencies
pnpm install2. Build the project
pnpm buildCompiles TypeScript from src/ to dist/ (the dist folder is gitignored and is what gets published to npm).
3. Run a release
pnpm semantic-release4. Dry run (safe to test)
Simulate a release without publishing anything:
GITHUB_TOKEN=$(gh auth token) pnpm release:dry-runThis is useful for verifying your configuration and seeing what version would be released. It requires the GitHub CLI (gh) to be installed and authenticated — otherwise the dry run fails. On macOS, install it with brew install gh && gh auth login.
Commit Message Conventions
Semantic-release only releases when your commit messages follow the Conventional Commits format. The commit type determines the version bump:
| Commit type | Example | Version bump |
| ----------- | ------- | ------------ |
| fix: | fix: correct minor typos in code | Patch (1.0.0 → 1.0.1) |
| feat: | feat: add user authentication feature | Minor (1.0.0 → 1.1.0) |
| BREAKING CHANGE: | BREAKING CHANGE: update API endpoint structure | Major (1.0.0 → 2.0.0) |
| chore: | chore: update dependencies | No release |
| docs: | docs: fix typo in README | No release |
Note: A commit message that does not conform to these conventions silently produces no release. Always use a recognized type.
Development Workflow
Doing a next (prerelease) release
The next branch is where all development happens. Pushing to it triggers a prerelease (e.g. 1.0.2-next.1).
Start from an up-to-date
nextbranch:git checkout next git pullCreate a feature/fix branch from
next:git checkout -b fix/my-bug nextMake your changes and commit them with a proper Conventional Commits message:
git add . git commit -m "fix: correct minor typos in code"Merge the branch back into
next:git checkout next git pull git merge fix/my-bug git push origin nextCI runs automatically — the push to
nexttriggers the publish workflow, which produces a prerelease like1.0.2-next.1and publishes it to npm.
Tip: If no release is needed, use
chore:ordocs:commit messages — they produce no release.
Promoting next to a stable release
When the prerelease is ready for production, merge next into master. Pushing to master triggers the stable release (e.g. 1.0.2).
git checkout master
git pull
git merge next
git push origin masterConfiguration
Release configuration lives in .releaserc.json. Here is this project's config, annotated:
{
// Which branches trigger a release, and how.
"branches": [
"master", // Stable releases (e.g. 1.0.2)
{ "name": "next", "prerelease": true } // Prereleases (e.g. 1.0.2-next.1)
],
"plugins": [
// Analyzes commits since the last tag and determines the version bump.
"@semantic-release/commit-analyzer",
// Generates the release notes text from those commits.
"@semantic-release/release-notes-generator",
// Publishes the package to npm.
"@semantic-release/npm",
// Creates the GitHub release. Comments are disabled here.
["@semantic-release/github", { "successComment": false, "failComment": false }],
// Writes the generated notes into CHANGELOG.md.
["@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" }],
// Commits the updated package.json + CHANGELOG.md. The "[skip ci]"
// suffix prevents the CI workflow from re-triggering on this commit.
["@semantic-release/git", {
"assets": ["package.json", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]"
}]
]
}Plugin execution order
Plugins run in sequence on every release. Understanding the order explains the whole pipeline:
| # | Plugin | What it does |
| - | ------ | ------------ |
| 1 | commit-analyzer | Determines the new version from commits |
| 2 | release-notes-generator | Writes the release notes |
| 3 | npm | Publishes to npm |
| 4 | github | Creates the GitHub release |
| 5 | changelog | Updates CHANGELOG.md |
| 6 | git | Commits package.json + CHANGELOG.md and tags the release |
Important:
package.jsonversion andCHANGELOG.mdare auto-managed by semantic-release. Never edit them by hand.
CI/CD Pipeline
The workflow in .github/workflows/publish.yml runs on every push to master and next:
- Checkout with full history (
fetch-depth: 0— required for semantic-release). - Set up Node.js 22 and pnpm.
pnpm installpnpm buildpnpm semantic-release(publishes to npm via trusted publishing and creates a GitHub release)
Publishing uses OIDC trusted publishing: the release job declares id-token: write, so GitHub mints an OIDC token that npm accepts — no NPM_TOKEN secret, and npm provenance is generated automatically for public packages. Note the trusted publisher on npmjs.com must reference this exact workflow file (publish.yml). Use pnpm semantic-release (not pnpx) so the release runs the lockfile-pinned versions instead of fetching the latest from pnpm's cache.
Troubleshooting
| Symptom | Cause | Fix |
| ------- | ----- | --- |
| No release created despite a push | Commit message doesn't conform to Conventional Commits (or only chore:/docs: commits) | Use fix:, feat:, or include BREAKING CHANGE: |
| Dry run fails with a token/GitHub error | gh CLI not installed or not authenticated | brew install gh && gh auth login |
| "This command requires a token" | GITHUB_TOKEN env var not set | Run GITHUB_TOKEN=$(gh auth token) pnpm release:dry-run |
| npm publish fails | NPM_TOKEN secret missing or invalid | Add the token to the repo's GitHub secrets |
| semantic-release can't see past releases | Shallow checkout | Keep fetch-depth: 0 in the checkout step |
| "Tag already exists" on a rerun | CI re-triggered on the release commit | Don't strip [skip ci] from the release commit message |
| Version not bumped as expected | Pre-release/branch logic — next always produces -next.x, only master goes stable | Check which branch you pushed to |
