diff --git a/README.md b/README.md index 6b89c36..8af94ac 100644 --- a/README.md +++ b/README.md @@ -234,6 +234,8 @@ Want the release-please result (version bump, CHANGELOG.md, tag, GitHub Release) Replacing `semantic-release` without putting Node in the release pipeline? Same job, Node-free tooling (zipapp + `release.sh`): [semantic-release alternative without npm/Node](https://loki-inu.github.io/relnote/semantic-release-alternative.html). +Replacing `conventional-changelog` and commitizen (changelog plugins and commit prompts) without Node plugins for the release tooling? The same zipapp and `release.sh` write CHANGELOG.md, an optional version bump, and a tag offline: [conventional-changelog / commitizen alternative](https://loki-inu.github.io/relnote/conventional-changelog-alternative.html). + Releasing a Python package? [Release a Python package from conventional commits](https://loki-inu.github.io/relnote/python-package.html) bumps `version` in `pyproject.toml`, prepends CHANGELOG.md, and tags with `release.sh`, then a tag-push workflow checks the tag against `pyproject.toml`, builds, uploads to PyPI with trusted publishing, and creates the GitHub Release with relnote notes. Releasing a Rust crate? [Release a Rust crate from conventional commits](https://loki-inu.github.io/relnote/rust-crate.html) bumps `version` in `Cargo.toml`, syncs `Cargo.lock` with `release.sh --exec "cargo update --workspace"`, prepends CHANGELOG.md, and tags; a tag-push workflow checks the tag against `Cargo.toml`, publishes with `cargo publish --locked` through crates.io trusted publishing, and creates the GitHub Release with relnote notes. diff --git a/docs/changelog.html b/docs/changelog.html index c3f4409..dcb840c 100644 --- a/docs/changelog.html +++ b/docs/changelog.html @@ -224,6 +224,7 @@

relnote vs git-cliff for CHANGELOG.md

Pick git-cliff if you want custom templates, commit parsers, or a computed next version. Pick relnote if you want sensible Keep a Changelog sections and a Release body with nothing to configure.

+

Coming from the Node conventional-changelog CLI or commitizen? conventional-changelog / commitizen alternative writes the same kind of section offline, and examples/release.sh adds the version bump and tag.

diff --git a/docs/conventional-changelog-alternative.html b/docs/conventional-changelog-alternative.html new file mode 100644 index 0000000..b4210df --- /dev/null +++ b/docs/conventional-changelog-alternative.html @@ -0,0 +1,391 @@ + + + + + + + conventional-changelog / commitizen alternative without Node plugins — relnote + + + + + + + + + + + + + + + + + +
+

relnote docs · CHANGELOG.md · Next version · standard-version alternative · semantic-release alternative · release-please alternative · GitHub Action · Single-file zipapp

+

A conventional-changelog and commitizen alternative without Node plugins

+

conventional-changelog (and the conventional-changelog-* presets) turns conventional commits into CHANGELOG.md. commitizen and cz-cli prompt for the commit message. Neither command bumps a version file and tags. If you want that changelog — and the bump, commit, and tag — from commits you already wrote, without Node plugins for the release tooling, the relnote zipapp and examples/release.sh do it offline.

+ + +

conventional-changelog + commitizen, or this?

+
+ + + + + + + + + + + +
conventional-changelog + commitizenrelnote + release.sh
Runtime for release toolingNode.js and npm packagesbash, git, Python 3.11 stdlib (zipapp)
Pluginsconventional-changelog-cli, a preset (conventional-changelog-conventionalcommits, conventional-changelog-angular, …), cz-cli / commitizen, an adapter (cz-conventional-changelog)None; flags on release.sh
Commit promptgit cz asks type, scope, and subjectNone. Commits are already conventional
Changelogconventional-changelog -p angular -i CHANGELOG.md -s (preset plugin; changelog only)relnote --changelog CHANGELOG.md via release.sh
Version bump, commit, tagNot those two CLIs. conventional-recommended-bump prints a bump type; standard-version / commit-and-tag-version do the full releaseOne command: optional --bump-file, CHANGELOG.md, chore(release) commit, annotated tag
Network while writing the changelognpm install of plugins; presets resolve from the registryOffline until you push or gh release create
Configpackage.json config.commitizen, .czrc, -p presetNone
+
+

Keep commitizen if you want the questions. Keep a conventional-changelog-* preset if you depend on its writer options. This page replaces the changelog command and the separate bumper, not the prompt.

+ +

Pin the zipapp

+

Python 3.11+ and git on PATH. The download is the v0.3.7 zipapp from the GitHub Release (same pin as the single-file install), plus examples/release.sh from that tag. No npm packages.

+
mkdir -p ~/.local/bin
+curl -fsSL -o ~/.local/bin/relnote https://github.com/loki-inu/relnote/releases/download/v0.3.7/relnote
+chmod +x ~/.local/bin/relnote
+curl -fsSL -o release.sh https://raw.githubusercontent.com/loki-inu/relnote/v0.3.7/examples/release.sh
+chmod +x release.sh
+

Put ~/.local/bin on PATH. Commit release.sh into the repo (for example scripts/release.sh) so the release command does not depend on the raw URL next time. It is plain bash; read it before you run it.

+ +

One local command

+

The working tree must be clean. ./release.sh reads conventional commits since the last tag, prepends CHANGELOG.md, commits chore(release): vX.Y.Z, and creates an annotated tag. Nothing is pushed. The version rule is relnote --next-version: breaking → major, feat → minor, otherwise patch (in 0.x a breaking change bumps minor). See next version and the CHANGELOG.md guide.

+

Omit --bump-file when you have no version file. Pass it (repeatable) to set the first "version" / version = line in package.json, pyproject.toml, or Cargo.toml. --dry-run prints the plan and the notes and writes nothing. These are three separate invocations, not one script to run top to bottom:

+
./release.sh --dry-run
+./release.sh
+./release.sh --bump-file package.json
+

Afterwards: git push --follow-tags. If HEAD is already tagged, or the next tag already exists, the script exits 1 instead of guessing.

+

Changelog only, the shape of conventional-changelog -i CHANGELOG.md -s without a preset package — you choose the title, and nothing is committed:

+
relnote --next-version
+relnote --changelog CHANGELOG.md --changelog-title v1.4.0
+

Use the tag --next-version printed. ./release.sh fills that title in for you and then commits and tags.

+ +

Optional GitHub Actions release

+

When you also want a GitHub Release, save this as .github/workflows/release.yml and use Actions → Release → Run workflow. It is the same job as the semantic-release alternative and the release-please alternative: a workflow_dispatch button, a has-changes gate, then release.sh. Drop --bump-file pyproject.toml or point it at another file. No Node install for the tooling. Action inputs: GitHub Action guide.

+
name: Release
+on:
+  workflow_dispatch:
+permissions:
+  contents: write
+jobs:
+  release:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+      - id: relnote
+        uses: loki-inu/relnote@v0.3.7
+      - name: Install relnote and release.sh
+        if: steps.relnote.outputs.has-changes == 'true'
+        env:
+          V: v0.3.7
+        run: |
+          mkdir -p "$HOME/.local/bin"
+          curl -fsSL -o "$HOME/.local/bin/relnote" "https://github.com/loki-inu/relnote/releases/download/$V/relnote"
+          chmod +x "$HOME/.local/bin/relnote"
+          curl -fsSL -o "$RUNNER_TEMP/release.sh" "https://raw.githubusercontent.com/loki-inu/relnote/$V/examples/release.sh"
+          echo "$HOME/.local/bin" >> "$GITHUB_PATH"
+      - name: Bump, changelog, tag, publish
+        if: steps.relnote.outputs.has-changes == 'true'
+        env:
+          GH_TOKEN: ${{ github.token }}
+        run: |
+          set -euo pipefail
+          if [ -n "$(git tag --points-at HEAD --list 'v*')" ]; then
+            echo "HEAD is already tagged; nothing to release."
+            exit 0
+          fi
+          git config user.name "github-actions[bot]"
+          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+          bash "$RUNNER_TEMP/release.sh" --bump-file pyproject.toml
+          tag=$(git describe --tags --exact-match)
+          git push origin HEAD "refs/tags/$tag"
+          relnote --output "$RUNNER_TEMP/notes.md" --quiet
+          gh release create "$tag" --title "$tag" --notes-file "$RUNNER_TEMP/notes.md"
+

The first relnote step only checks whether anything is unreleased (has-changes). Notes go through a file and --notes-file. Never interpolate the body inside run: (backticks in commit subjects break the YAML). Pin the action and the curl URLs to the same tag.

+

A tag-push workflow can publish the same notes after you tag locally: checkout with fetch-depth: 0, run the action, write notes.md, then gh release create with --notes-file. Same rule: do not put the notes in run:. See the tag-push example on the Action guide.

+ +

What one run does

+

Start: v1.3.2 is the last tag, pyproject.toml says version = "1.3.2", and two conventional commits landed since (the kind of subjects commitizen or a squash-merged pull request title would leave). The release step log:

+
next: v1.4.0
+changelog: CHANGELOG.md
+bump: pyproject.toml -> 1.4.0
+committed: chore(release): v1.4.0
+tagged: v1.4.0
+next step: git push --follow-tags
+To https://github.com/you/project.git
+ * [new branch]      HEAD -> main
+ * [new tag]         v1.4.0 -> v1.4.0
+

pyproject.toml now says version = "1.4.0", and CHANGELOG.md gains this section above the previous one:

+
## [v1.4.0] - 2026-10-28
+
+### Features
+
+- add --json output ([#12](https://github.com/you/project/pull/12)) (`e4e9bff`) — Ada Lovelace
+
+### Fixes
+
+- handle empty config ([#13](https://github.com/you/project/pull/13)) (`8c0e206`) — Ada Lovelace
+
+**Full changelog:** https://github.com/you/project/compare/v1.3.2...v1.4.0
+

The GitHub Release v1.4.0 gets this body; on GitHub, #12 links to the pull request:

+
## What's changed
+
+### Features
+
+- add --json output (#12) (`e4e9bff`) — Ada Lovelace
+
+### Fixes
+
+- handle empty config (#13) (`8c0e206`) — Ada Lovelace
+
+---
+
+Range: `v1.3.2` → `v1.4.0`.
+
+**Full changelog:** https://github.com/you/project/compare/v1.3.2...v1.4.0
+

The CHANGELOG.md section and Release body are produced by running the workflow's last step against a scratch repository in relnote's test suite (tests/test_conventional_changelog_docs.py, with gh stubbed); your hashes and dates differ. The chore(release) commit is not listed.

+

Bumping an npm package? Use --bump-file package.json. If you also keep a package-lock.json, add --exec "npm install --package-lock-only --ignore-scripts --silent" so the lock tracks the new version. Node runs there because the product is npm. See the npm package guide. The standard-version alternative maps the rest of the flags (--release-as, --skip-commit, --skip-tag, --tag-prefix).

+ +

FAQ

+

Does relnote replace commitizen prompts?

+

No. commitizen and cz-cli (with an adapter such as cz-conventional-changelog) ask for type, scope, and subject so the commit is conventional. relnote does not prompt. It reads commits that are already conventional — from commitizen, a pull-request title, or typed by hand — and writes CHANGELOG.md, an optional version bump, and a tag. Keep commitizen if you want the prompt; you do not need it to generate the changelog.

+

What about the conventional-changelog CLI on its own?

+

conventional-changelog-cli, with a conventional-changelog-* preset, writes CHANGELOG.md and stops. It does not bump a version file, commit, or tag. relnote --changelog CHANGELOG.md is that step, offline, with no preset package. examples/release.sh adds the optional bump, the chore(release) commit, and the annotated tag. Section shape: the CHANGELOG.md guide.

+

How does this differ from standard-version and commit-and-tag-version?

+

standard-version and its fork commit-and-tag-version already combine a conventional-changelog preset with a version bump, commit, and tag, and they need Node. release.sh is that local command without Node and without .versionrc. Keep commit-and-tag-version if you need prerelease bumps, lifecycle scripts, or custom presets. Flag mapping is on the standard-version alternative page.

+

How does this differ from the semantic-release and release-please pages?

+

The semantic-release alternative page is the CI publish loop without Node in the release tooling. The release-please alternative page is the same job for people leaving a release pull request. This page is for the conventional-changelog plus commitizen stack: changelog plugins and commit prompts, with the version bump usually in another tool. The local path is release.sh; the optional Actions job matches those pages.

+

How do I dry-run?

+

Locally, release.sh --dry-run prints the next version, the changelog path, any version file it would bump, and the notes, and writes nothing. Add --bump-file only when a version file should change. Omit --bump-file when you only want a preview of the changelog, commit, and tag. In the Actions job, has-changes false skips the release steps when nothing is unreleased, and a second run whose HEAD is already tagged exits 0.

+

Are chore(release) commits included in the notes?

+

No by default. relnote skips chore(release) subjects so the release commit does not appear in its own CHANGELOG.md section or Release body. Pass --include-release-commits on the CLI, or include-release-commits: true on the action, to keep them.

+

Does an npm package still need Node?

+

Only for the product, not for this release tooling. The zipapp and release.sh stay free of Node plugins. For an npm package, pass --bump-file package.json, and if you keep a package-lock.json add --exec "npm install --package-lock-only --ignore-scripts --silent" so the lock tracks the new version. See the npm package guide.

+ + +
+ + diff --git a/docs/index.html b/docs/index.html index 83801d9..69caaa7 100644 --- a/docs/index.html +++ b/docs/index.html @@ -249,6 +249,7 @@

relnote

· Rust crate releases (Cargo.toml, Cargo.lock, crates.io) · npm package releases (package.json, package-lock.json, npmjs) · semantic-release alternative (no npm/Node) + · conventional-changelog / commitizen alternative · Windows and PowerShell diff --git a/docs/llms.txt b/docs/llms.txt index e33432e..c9fbd20 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -28,6 +28,10 @@ No release PR bot: a workflow_dispatch job runs the relnote action (has-changes Replace semantic-release's Node plugin stack with offline relnote + examples/release.sh + a workflow_dispatch (or tag-push) Actions job: has-changes gate, curl the pinned zipapp and release.sh (no npm for the tooling), --bump-file pyproject.toml or package.json, CHANGELOG.md, chore(release) commit, annotated tag, gh release create with --notes-file. Optional --exec "npm install --package-lock-only --ignore-scripts --silent" only when the product is npm. Differs from release-please-alternative (no release PR angle) and standard-version-alternative (local one-command). Guide: https://loki-inu.github.io/relnote/semantic-release-alternative.html +## conventional-changelog / commitizen alternative + +conventional-changelog (conventional-changelog-cli and conventional-changelog-* presets) writes CHANGELOG.md and stops. commitizen and cz-cli prompt for a conventional commit message; they do not bump or tag, and relnote does not prompt — commits are already conventional. The offline zipapp plus examples/release.sh (pinned v0.3.7) prepends CHANGELOG.md, optionally bumps a version file (--bump-file; omit it for changelog + commit + tag only), commits chore(release): vX.Y.Z, and creates an annotated tag. --dry-run writes nothing. chore(release) commits are skipped in the notes unless --include-release-commits. Optional workflow_dispatch job: has-changes gate, same release.sh, gh release create --notes-file (never interpolate notes in run:). Node remains appropriate for an npm product (optional --exec to refresh package-lock.json; see npm-package.html), not for the release tooling. Differs from standard-version / commit-and-tag-version (Node one-command; see standard-version-alternative), semantic-release-alternative (CI publish loop), and release-please-alternative (release pull request). Guide: https://loki-inu.github.io/relnote/conventional-changelog-alternative.html + ## Python packages (pyproject.toml, PyPI) Locally: examples/release.sh --bump-file pyproject.toml (first version = "..." line, so [project] or [tool.poetry]) → next version from commits, CHANGELOG.md section, chore(release) commit, annotated tag; git push --follow-tags. Tag-push workflow: check v$version == tag via tomllib, python -m build, pypa/gh-action-pypi-publish with trusted publishing (environment pypi, id-token: write only on that job), then gh release create TAG dist/* --notes-file with the loki-inu/relnote action's notes. Dynamic versions (setuptools-scm, hatch-vcs): skip --bump-file; the tag is the version. __version__: importlib.metadata.version("pkg"). Guide: https://loki-inu.github.io/relnote/python-package.html @@ -77,6 +81,7 @@ gh relnote prints the notes; gh relnote create TAG [gh release create flags] [-- - standard-version alternative (examples/release.sh): https://loki-inu.github.io/relnote/standard-version-alternative.html - release-please alternative without a release PR (workflow_dispatch: bump version file, CHANGELOG.md, chore(release) commit, tag, gh release create; tested example): https://loki-inu.github.io/relnote/release-please-alternative.html - semantic-release alternative without npm/Node (workflow_dispatch: zipapp + release.sh, no Node for tooling; tested example): https://loki-inu.github.io/relnote/semantic-release-alternative.html +- conventional-changelog / commitizen alternative (offline zipapp + release.sh: CHANGELOG.md, optional version bump, tag; no Node plugins; tested example): https://loki-inu.github.io/relnote/conventional-changelog-alternative.html - Release a Python package (pyproject.toml bump, CHANGELOG.md, tag, PyPI trusted publishing, GitHub Release; tested example): https://loki-inu.github.io/relnote/python-package.html - Release a Rust crate (Cargo.toml + Cargo.lock bump, CHANGELOG.md, tag, crates.io trusted publishing, GitHub Release; tested with real cargo): https://loki-inu.github.io/relnote/rust-crate.html - Release an npm package (package.json + package-lock.json bump, CHANGELOG.md, tag, npm trusted publishing, GitHub Release; tested with real npm): https://loki-inu.github.io/relnote/npm-package.html diff --git a/docs/next-version.html b/docs/next-version.html index eef74a7..eb378af 100644 --- a/docs/next-version.html +++ b/docs/next-version.html @@ -230,6 +230,7 @@

Compared to version-bump tools

Want the old npx standard-version flow (bump version files, changelog, commit, tag) in one local command? See standard-version alternative.

+

Coming from conventional-changelog and commitizen? CHANGELOG.md and a version bump without Node plugins.

If you want the whole release automated (version files, tags, PRs, npm publish), keep semantic-release or release-please. relnote is for when you want the answer and the notes, and want to do the tagging yourself.