commit 78575bf44d136638156eb188890834543c237c38
parent 165aed2c24d76472a2a9a6396df397ec5cc19f4e
Author: mtmn <miro@haravara.org>
Date: Sun, 3 May 2026 00:03:04 +0200
feat(ci): add git-cliff
Diffstat:
3 files changed, 105 insertions(+), 0 deletions(-)
diff --git a/cliff.toml b/cliff.toml
@@ -0,0 +1,51 @@
+[changelog]
+header = "# Changelog\n\n"
+body = """
+{% if version -%}
+## [{{ version | trim_start_matches(pat="v") }}]{% if previous.version %} - {{ timestamp | date(format="%Y-%m-%d") }}{% endif %}
+
+{% if previous.version -%}
+[compare](https://git.sr.ht/~mtmn/corpus/log/{{ previous.version }}..{{ version }})
+
+{% endif -%}
+{% else -%}
+## [Unreleased]
+
+{% endif -%}
+{% for group, commits in commits | group_by(attribute="group") -%}
+### {{ group }}
+
+{% for commit in commits -%}
+- {% if commit.breaking %}**breaking:** {% endif -%}
+{% if commit.scope %}**{{ commit.scope }}:** {% endif -%}
+{{ commit.message | upper_first }} \
+([`{{ commit.id | truncate(length=7, end="") }}`](https://git.sr.ht/~mtmn/corpus/commit/{{ commit.id }}))
+{% endfor %}
+{% endfor %}
+"""
+footer = ""
+trim = true
+
+[git]
+conventional_commits = true
+filter_unconventional = true
+split_commits = false
+commit_parsers = [
+ { message = "^feat", group = "Features" },
+ { message = "^fix", group = "Bug Fixes" },
+ { message = "^perf", group = "Performance" },
+ { message = "^refactor", group = "Refactor" },
+ { message = "^revert", group = "Reverts" },
+ { message = "^doc", group = "Documentation" },
+ { message = "^test", group = "Testing" },
+ { message = "^chore\\(deps\\)", group = "Dependencies" },
+ { message = "^chore", skip = true },
+ { message = "^ci", skip = true },
+ { message = "^style", skip = true },
+ { message = "^build", skip = true },
+]
+protect_breaking_commits = true
+filter_commits = true
+tag_pattern = "v[0-9].*"
+topo_order = false
+sort_commits = "oldest"
diff --git a/hack/git-release b/hack/git-release
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+require() { command -v "$1" &>/dev/null || {
+ echo "error: $1 not found"
+ exit 1
+}; }
+require git
+require git-cliff
+require jq
+
+# --- pre-flight ---
+
+if [ -n "$(git status --porcelain)" ]; then
+ echo "error: working tree is dirty"
+ exit 1
+fi
+
+current=$(jq -r .version package.json)
+next=$(git-cliff --bumped-version 2>/dev/null | sed 's/^v//')
+
+if [ "$current" = "$next" ]; then
+ echo "no releasable commits since v$current"
+ exit 0
+fi
+
+echo "releasing $current -> $next"
+
+# --- update files ---
+
+jq --arg v "$next" '.version = $v' package.json >package.json.tmp
+mv package.json.tmp package.json
+
+git-cliff --tag "v$next" --output CHANGELOG.md
+
+# update npmDepsHash if nix and prefetch-npm-deps are available
+if command -v nix &>/dev/null; then
+ hash=$(nix run nixpkgs#prefetch-npm-deps -- package-lock.json 2>/dev/null)
+ sed -i "s|npmDepsHash = \"sha256-[^\"]*\"|npmDepsHash = \"$hash\"|" flake.nix
+fi
+
+# --- commit, tag, push ---
+
+git add package.json CHANGELOG.md flake.nix
+git commit -m "chore: release v$next"
+git tag -a "v$next" -m "release v$next"
+git push
+git push --tags
+
+echo "released v$next"
diff --git a/justfile b/justfile
@@ -1,6 +1,10 @@
help:
@just --list
+# Bump version, update CHANGELOG, tag, and push (requires git-cliff)
+bump:
+ @hack/release
+
# Setup npm and spago
setup: