diff --git a/.goreleaser.yml b/.goreleaser.yml index b9f562e..b13316e 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -31,3 +31,13 @@ checksum: changelog: use: git + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + - "^chore:" + - "^ci:" + - "merge conflict" + - "^Merge pull request" + - "^Merge branch" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..90bb0fa --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +.PHONY: tag-next tag-patch tag-minor tag-major + +tag-next: + @if [ -z "$(TYPE)" ]; then \ + echo "TYPE is required (patch|minor|major)"; \ + echo "example: make tag-next TYPE=patch"; \ + exit 2; \ + fi + @./scripts/tag-next-version.sh "$(TYPE)" + +tag-patch: + @./scripts/tag-next-version.sh patch + +tag-minor: + @./scripts/tag-next-version.sh minor + +tag-major: + @./scripts/tag-next-version.sh major diff --git a/README.md b/README.md index c3cfc10..9922b92 100644 --- a/README.md +++ b/README.md @@ -95,9 +95,36 @@ jq -e '.estimatedBranchCoverage >= 70' gobce.json For stable CI behavior, prefer pinned versions (`@vX.Y.Z`) over `@latest`. +## Versioning Policy + +`gobce` follows [Semantic Versioning](https://semver.org/). + +During the pre-1.0 phase, this project is versioned as `0.x` while coverage logic is validated in a real project. + +- `PATCH` (`0.1.0` -> `0.1.1`): bug fixes only +- `MINOR` (`0.1.1` -> `0.2.0`): new features, behavior changes, and potentially breaking changes +- `MAJOR` (`1.x`): used after the interface and output become stable + +Please assume that interfaces and output formats may change between `0.x` minor versions. + +Version tags use the `vX.Y.Z` format (for example, `v0.1.0`). + ## Release Flow This repository is configured to publish GitHub Releases via GoReleaser when a version tag is pushed. +Release notes are generated automatically from git commits between tags using GoReleaser changelog support. + +You can create the next SemVer tag with: + +```bash +make tag-patch +make tag-minor +make tag-major +# or +make tag-next TYPE=patch +make tag-next TYPE=minor +make tag-next TYPE=major +``` ```bash git tag v0.1.0 @@ -107,8 +134,11 @@ git push origin v0.1.0 After push: - GitHub Actions workflow `release` runs automatically - GitHub Release is created for `v0.1.0` +- Release notes are generated from commit history - OS/arch archives and `checksums.txt` are uploaded +To keep generated release notes clean, prefer commit prefixes such as `feat:`, `fix:`, `refactor:`, and `perf:`. + ## Design Design notes are available in: diff --git a/scripts/tag-next-version.sh b/scripts/tag-next-version.sh new file mode 100755 index 0000000..bdfe966 --- /dev/null +++ b/scripts/tag-next-version.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env sh + +set -eu + +usage() { + echo "usage: $0 " + echo "example: $0 patch" +} + +if [ "${1-}" = "" ]; then + usage + exit 2 +fi + +bump_type="$1" +case "$bump_type" in + patch|minor|major) ;; + *) + echo "unsupported bump type: $bump_type" >&2 + usage + exit 2 + ;; +esac + +if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + echo "this command must run inside a git repository" >&2 + exit 1 +fi + +latest_tag="$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-version:refname | sed -n '1p')" + +if [ -z "$latest_tag" ]; then + major=0 + minor=0 + patch=0 +else + version="${latest_tag#v}" + major="$(echo "$version" | cut -d. -f1)" + minor="$(echo "$version" | cut -d. -f2)" + patch="$(echo "$version" | cut -d. -f3)" +fi + +case "$bump_type" in + patch) + patch=$((patch + 1)) + ;; + minor) + minor=$((minor + 1)) + patch=0 + ;; + major) + major=$((major + 1)) + minor=0 + patch=0 + ;; +esac + +next_tag="v${major}.${minor}.${patch}" + +if git rev-parse -q --verify "refs/tags/${next_tag}" >/dev/null 2>&1; then + echo "tag already exists: ${next_tag}" >&2 + exit 1 +fi + +git tag "${next_tag}" +echo "created tag: ${next_tag}" +echo "push with: git push origin ${next_tag}"