semantic-release-script
Semantic release in one bash script. No npm tree. Just git, bash and gh.
Requires git,
bash 4+ and the GitHub CLI
(gh), logged in when you run it locally.
$ ./scripts/release/release.sh --dry-run == Step 1 — evaluate the new version == Repository : JeremieLitzler/semantic-release-script Commit range : v0.4.0..HEAD (last tag: v0.4.0) Commits scanned : 17 feature 3ae97e8 feat: refuse a name-forced level below what the commits imply (#79) feature 08ffc72 feat: force the release level from a branch name with --level-from (#78) fix 1e09fa0 fix: restore the line continuations of the level check (#79) other df6b77c ci: pin the release workflow's release.sh to v0.4.0 (#74) Bump : minor Version : 0.4.0 -> 0.5.0 -> Continue to step 2 and build the release notes for v0.5.0? == Step 2 — release notes for v0.5.0 == ### Features - Refuse a name-forced level below what the commits imply (#79) - Force the release level from a branch name with --level-from (#78) -> Continue to step 3 and create the tag v0.5.0? == Step 3 — create and push v0.5.0 == [dry-run] git tag -a v0.5.0 -m v0.5.0 HEAD [dry-run] git push origin v0.5.0 -> Continue to step 4 and publish the GitHub release v0.5.0?
A real run on this repository, trimmed for length. Without
--dry-run, a human gate sits before each step.
Features
Conventional commits
The version bump and the release notes come from the commit messages since the last version tag.
A human gate before each step
Evaluate, write the notes, tag, publish: you answer before each one, or pass --yes to run unattended.
--dry-run
See the version and the notes without pushing a tag or creating a release. It reaches no remote.
Resume a half-published release
A run that died after pushing the tag and before creating the release is finished by the next run, not redone.
--level-from
Force the bump from a release/<major|minor|patch>/… branch name. A level below what the commits imply is refused.
--check
A setup report: every check and guard a release would weigh, each with its reason and its fix, before anything is released.
No npm
One file you vendor into your repository. No node_modules, no plugin tree to keep patched.
How it works
A run is four steps, and it can stop at the gate before any of them.
Evaluate the version
Reads the commits since the last version tag and decides major, minor or patch.
Write the release notes
Builds the Markdown notes, grouped by type, with issue and pull request titles resolved through gh.
Create and push the version tag
Creates an annotated vX.Y.Z tag and pushes it to origin.
Publish the release
Creates the GitHub release on that tag, with the notes as its body.
Quick start
Vendor release.sh at the latest version tag, then run it from your trunk.
curl -fsSL https://raw.githubusercontent.com/JeremieLitzler/semantic-release-script/<latest-tag>/scripts/release/release.sh -o release.sh && chmod +x release.sh
The latest version could not be fetched. Replace
<latest-tag> with the tag on the
releases page.
./release.sh --dry-run # preview the version and the notes
./release.sh # the real thing, one gate per step
The command pins a version tag: pin it, don't track a branch.
Options
| Flag | What it does |
|---|---|
-y, --yes | Skip every human gate (unattended run). |
-n, --dry-run | Do everything but push the tag and create the release. |
-l, --local | Create the tag locally, but neither push nor publish. |
--since <ref> | Read commits since a ref instead of the last version tag. |
--to <ref> | Read commits up to a ref instead of HEAD, and tag that ref. |
--trunk <name> | The branch releases are cut from. Defaults to the repository's default branch. |
--level <level> | Force the bump: major, minor or patch. |
--level-from <ref> | Force the bump from a release branch name. |
--notes <file> | Also write the release notes to a file. |
--changelog <file> | Prepend the release to a changelog, newest first. |
--summary <file> | Write what the run decided, as key=value lines. |
--check | Print the setup report instead of releasing. |
-h, --help | Show the help. |
In CI
A dry run reaches no remote, so a runner can preview a release without a terminal. A real run on a runner passes --yes.
# preview the pending release
GH_TOKEN="$GITHUB_TOKEN" ./release.sh --dry-run
# cut it
GH_TOKEN="$GITHUB_TOKEN" ./release.sh --yes