GitHub Packages · MIT · Node ≥ 18

semver-gauge

A CI gate that checks your version bump matches what changed, and that the CHANGELOG has a real entry for it.

CI gate that checks your version bump matches the changes since the last release (Conventional Commits: breaking/feat/fix) and that CHANGELOG.md has a real entry for the new version. Text/JSON/SARIF/Markdown, allowlist with expiry, GitHub Action. Zero deps.

  1. 1 Point the @mrlouiswright scope at GitHub Packages in .npmrc

    @mrlouiswright:registry=https://npm.pkg.github.com
  2. 2 Install

    npm i -D @mrlouiswright/semver-gauge
Installing from GitHub Packages needs a token

Published to GitHub Packages, not npmjs.com. GitHub Packages needs a GitHub token with read:packages to install, even for public packages: add //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} to .npmrc or run npm login --registry=https://npm.pkg.github.com.

~/project — zsh
$ npx semver-gaugesemver-gauge — version 1.3.01.2.0 → 1.3.0 (2 commit(s) since v1.2.0; changes need: major, expected 2.0.0) HIGH     package.json 1.2.0 → 1.3.0 is a minor bump but the changes need major (e.g. "feat!: remove the legacy export") [insufficient-bump]         ↳ fix: Bump to 2.0.0, or if nothing is actually breaking, fix the commit type. 1 high✖ Failing (fail-on: high).
Sample output from the semver-gauge README.

Why it exists

semver-gauge looks at the commits since your last release tag, works out the bump they need from Conventional Commits (feat → minor, fix/perf → patch, “!” or a “BREAKING CHANGE:” footer → major) and compares that with the version in package.json. A breaking change shipped as a minor, a version that went backwards, a skipped version or a tag that already exists is reported with a severity and a concrete fix ("Bump to 2.0.0"). It also checks that CHANGELOG.md has a non-empty, correctly dated entry for the version, at the top.

CLI, library and GitHub Action. Node.js 18+, zero runtime dependencies. By Louis Wright.

Features

Bump check

the required level (major/minor/patch/none) comes from every commit since the last v* tag (or --base <ref>) that touches the package directory, so it works per-package in monorepos. Merge commits and release commits are ignored.

SemVer rules done properly

pre-release precedence (1.0.0-rc.1 → 1.0.0-rc.2 → 1.0.0), 0.x semantics (breaking → minor, feature → patch) and the 0.x → 1.0.0 graduation.

CHANGELOG check

Keep a Changelog (## [1.2.0] - 2026-01-01), ## 1.2.0 (2026-01-01) and # v1.2.0 headings; empty entries, out-of-order entries, future or impossible dates, and a forgotten [Unreleased] section.

No git needed

--commits <file> and --base-version let you feed it commit messages from anywhere.

Output

text, JSON, SARIF 2.1.0 and Markdown; --fail-on; exit codes 0/1/2; allowlist entries with expiry dates.

Usage

# check package.json against the latest v* tag and CHANGELOG.md

 npx semver-gauge

# compare with another ref

 npx semver-gauge --base origin/main

# release PRs: releasable commits must come with a bump

 npx semver-gauge --require-bump

# just check CHANGELOG.md has an entry for the current version

 npx semver-gauge --changelog-only

CI / GitHub Action

permissions:
  contents: read
  security-events: write   # only needed for the SARIF upload
jobs:
  semver-gauge:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
        with: { persist-credentials: false, fetch-depth: 0 }
      - uses: MrLouisWright/semver-gauge@v1
        with:
          fail-on: high
          sarif: semver-gauge.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with: { sarif_file: semver-gauge.sarif }

Options & flags

FlagDescription
Version
--base <ref>Git ref of the last release (default: latest v* tag reachable from HEAD)
--base-version <v>Last released version (default: from the tag name or package.json at --base)
--commits <file>Read commit messages from a file (separated by lines of "---") instead of git
--require-bumpFail (version-not-bumped) when releasable commits exist but the version is unchanged
--unknown-as <level>Treat non-conventional commits as patch | minor | major (default: ignore)
--no-tag-checkDon't check whether a git tag for the version already exists
Changelog
--changelog <file>Changelog path (default: CHANGELOG.md, HISTORY.md, CHANGES.md)
--changelog-onlyOnly check the changelog entry, not the bump
--no-changelogSkip changelog checks
Common
-c, --config <file>JSON config (default: .semver-gauge.json or "semverGauge" in package.json)
-f, --format <fmt>text (default) | json | sarif | markdown
--json <file>Also write a JSON report
--sarif <file>Also write SARIF 2.1.0
--markdown <file>Also write Markdown (e.g. for a job summary)
--fail-on <sev>critical | high | medium | low | info | none (default: high)
--list-rulesPrint rules and default severities
--no-fixesHide fix suggestions in text output
--no-colorDisable colours

Full reference, config file format and API in the README.

Support this project

Support open-source security tools

I build free, open-source tools that help developers ship safer websites. Every coffee helps keep them maintained, documented and free for everyone.

Buy me a coffee (opens Stripe in a new tab)

Secure checkout by Stripe

Portrait of Louis Wright

About the author

Louis Wright

Cyber security researcher and software engineer based in the UK.

More tools by Louis Wright

58 tools

Sentinels security scanners & CI gates · 20