From 8fefbf1997d836d26aa7f525f2e10be27c8b2168 Mon Sep 17 00:00:00 2001 From: Micheal Wilkinson Date: Fri, 20 Mar 2026 19:16:51 +0000 Subject: [PATCH] refactor: rename releaseprep to vociferate --- .gitea/workflows/prepare-release.yml | 43 ++++++++++++------ .gitea/workflows/push-validation.yml | 2 +- README.md | 17 ++++--- action.yml | 45 +++++++++++-------- changelog.md | 7 ++- cmd/{releaseprep => vociferate}/main.go | 10 ++--- .../version/version.go | 0 .../vociferate.go} | 4 +- .../vociferate_test.go} | 32 ++++++------- justfile | 2 +- script/prepare-release.sh | 4 +- 11 files changed, 99 insertions(+), 67 deletions(-) rename cmd/{releaseprep => vociferate}/main.go (70%) rename internal/{releaseprep => vociferate}/version/version.go (100%) rename internal/{releaseprep/releaseprep.go => vociferate/vociferate.go} (98%) rename internal/{releaseprep/releaseprep_test.go => vociferate/vociferate_test.go} (81%) diff --git a/.gitea/workflows/prepare-release.yml b/.gitea/workflows/prepare-release.yml index 560405d..298038d 100644 --- a/.gitea/workflows/prepare-release.yml +++ b/.gitea/workflows/prepare-release.yml @@ -4,13 +4,14 @@ on: workflow_dispatch: inputs: version: - description: Semantic version to release, with or without leading v. - required: true + description: Optional semantic version override, with or without leading v. When omitted, the recommended version is used. + required: false workflow_call: inputs: version: - description: Semantic version to release, with or without leading v. - required: true + description: Optional semantic version override, with or without leading v. When omitted, the recommended version is used. + required: false + default: '' type: string jobs: @@ -36,9 +37,29 @@ jobs: cache: true cache-dependency-path: go.sum - - name: Prepare release files + - name: Resolve release version + id: resolve-version env: - RELEASE_VERSION: ${{ inputs.version }} + INPUT_VERSION: ${{ inputs.version }} + run: | + set -euo pipefail + + provided_version="$(printf '%s' "${INPUT_VERSION:-}" | sed 's/^[[:space:]]\+//; s/[[:space:]]\+$//')" + + if [[ -n "$provided_version" ]]; then + release_version="$provided_version" + else + if ! release_version="$(go run ./cmd/vociferate --recommend --root . 2>release-recommendation.err)"; then + recommendation_error="$(tr '\n' ' ' < release-recommendation.err | sed 's/[[:space:]]\+/ /g' | sed 's/^ //; s/ $//')" + echo "Resolve release version: ${recommendation_error}" >&2 + exit 1 + fi + fi + + echo "RELEASE_VERSION=$release_version" >> "$GITHUB_ENV" + echo "version=$release_version" >> "$GITHUB_OUTPUT" + + - name: Prepare release files run: | set -euo pipefail ./script/prepare-release.sh "$RELEASE_VERSION" @@ -55,8 +76,6 @@ jobs: git config user.email "gitea-actions[bot]@users.noreply.local" - name: Commit release changes and push tag - env: - RELEASE_VERSION: ${{ inputs.version }} run: | set -euo pipefail @@ -82,15 +101,13 @@ jobs: esac git remote set-url origin "$authed_remote" - git add changelog.md internal/releaseprep/version/version.go + git add changelog.md internal/vociferate/version/version.go git commit -m "release: prepare ${tag}" git tag "$tag" git push origin HEAD git push origin "$tag" - name: Create release with changelog notes - env: - RELEASE_VERSION: ${{ inputs.version }} run: | set -euo pipefail @@ -158,8 +175,6 @@ jobs: echo "RELEASE_ID=$release_id" >> "$GITHUB_ENV" - name: Build release binaries - env: - RELEASE_VERSION: ${{ inputs.version }} run: | set -euo pipefail @@ -175,7 +190,7 @@ jobs: fi bin="vociferate_${normalized_version}_${os}_${arch}${ext}" - GOOS="$os" GOARCH="$arch" go build -trimpath -ldflags="-s -w" -o "dist/${bin}" ./cmd/releaseprep + GOOS="$os" GOARCH="$arch" go build -trimpath -ldflags="-s -w" -o "dist/${bin}" ./cmd/vociferate done ( diff --git a/.gitea/workflows/push-validation.yml b/.gitea/workflows/push-validation.yml index cc4c723..96a7f6a 100644 --- a/.gitea/workflows/push-validation.yml +++ b/.gitea/workflows/push-validation.yml @@ -37,7 +37,7 @@ jobs: run: | set -euo pipefail - if recommended_tag="$(go run ./cmd/releaseprep --recommend --root . 2>release-recommendation.err)"; then + if recommended_tag="$(go run ./cmd/vociferate --recommend --root . 2>release-recommendation.err)"; then { echo echo '## Release Recommendation' diff --git a/README.md b/README.md index 0dd8742..1507aa5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ just go-build Or directly with Go: ```bash -go build -o dist/releaseprep ./cmd/releaseprep +go build -o dist/vociferate ./cmd/vociferate ``` ## Usage @@ -21,13 +21,15 @@ go build -o dist/releaseprep ./cmd/releaseprep Prepare release files: ```bash -go run ./cmd/releaseprep --version v1.2.3 --date 2026-03-20 --root . +go run ./cmd/vociferate --version v1.2.3 --date 2026-03-20 --root . ``` +In the provided workflow and composite action, `version` is optional. When it is omitted, vociferate computes and uses the recommended next version automatically. + Recommend next release tag from changelog content: ```bash -go run ./cmd/releaseprep --recommend --root . +go run ./cmd/vociferate --recommend --root . ``` ### Flags @@ -42,7 +44,7 @@ go run ./cmd/releaseprep --recommend --root . Defaults: -- `version-file`: `internal/releaseprep/version/version.go` +- `version-file`: `internal/vociferate/version/version.go` - `version-pattern`: `const String = "([^"]+)"` - `changelog`: `changelog.md` @@ -76,12 +78,13 @@ Use the composite action directly: - name: Prepare release files uses: git.hrafn.xyz/aether/vociferate@main with: - version: v1.2.3 version-file: internal/myapp/version/version.go version-pattern: 'const Version = "([^"]+)"' changelog: changelog.md ``` +Set `version` only when you want to override the recommended version. + Call the reusable release workflow: ```yaml @@ -91,8 +94,8 @@ on: workflow_dispatch: inputs: version: - description: Semantic version to release. - required: true + description: Optional semantic version override. + required: false jobs: release: diff --git a/action.yml b/action.yml index f0e681b..5425934 100644 --- a/action.yml +++ b/action.yml @@ -1,9 +1,9 @@ -name: releaseprep +name: vociferate description: Prepare release files or recommend a next semantic version tag. inputs: version: - description: Semantic version to release. + description: Optional semantic version override. When omitted, the recommended version is used. required: false version-file: description: Path to version file relative to repository root. @@ -22,6 +22,11 @@ inputs: required: false default: 'false' +outputs: + version: + description: Resolved version used for prepare mode, or the emitted recommended version for recommend mode. + value: ${{ steps.run-vociferate.outputs.version }} + runs: using: composite steps: @@ -31,33 +36,37 @@ runs: with: go-version: '1.26.1' - - name: Run releaseprep + - name: Run vociferate + id: run-vociferate shell: bash run: | set -euo pipefail - args=(--root .) - - if [[ "${{ inputs.recommend }}" == "true" ]]; then - args+=(--recommend) - else - if [[ -z "${{ inputs.version }}" ]]; then - echo "input 'version' is required when recommend is false" >&2 - exit 2 - fi - args+=(--version "${{ inputs.version }}" --date "$(date -u +%F)") - fi + common_args=(--root .) if [[ -n "${{ inputs.version-file }}" ]]; then - args+=(--version-file "${{ inputs.version-file }}") + common_args+=(--version-file "${{ inputs.version-file }}") fi if [[ -n "${{ inputs.version-pattern }}" ]]; then - args+=(--version-pattern "${{ inputs.version-pattern }}") + common_args+=(--version-pattern "${{ inputs.version-pattern }}") fi if [[ -n "${{ inputs.changelog }}" ]]; then - args+=(--changelog "${{ inputs.changelog }}") + common_args+=(--changelog "${{ inputs.changelog }}") fi - go run git.hrafn.xyz/aether/vociferate/cmd/releaseprep@latest "${args[@]}" + if [[ "${{ inputs.recommend }}" == "true" ]]; then + resolved_version="$(go run git.hrafn.xyz/aether/vociferate/cmd/vociferate@latest "${common_args[@]}" --recommend)" + echo "$resolved_version" + echo "version=$resolved_version" >> "$GITHUB_OUTPUT" + exit 0 + else + resolved_version="$(printf '%s' "${{ inputs.version }}" | sed 's/^[[:space:]]\+//; s/[[:space:]]\+$//')" + if [[ -z "$resolved_version" ]]; then + resolved_version="$(go run git.hrafn.xyz/aether/vociferate/cmd/vociferate@latest "${common_args[@]}" --recommend)" + fi + fi + + echo "version=$resolved_version" >> "$GITHUB_OUTPUT" + go run git.hrafn.xyz/aether/vociferate/cmd/vociferate@latest "${common_args[@]}" --version "$resolved_version" --date "$(date -u +%F)" diff --git a/changelog.md b/changelog.md index 3f5471a..89c27a1 100644 --- a/changelog.md +++ b/changelog.md @@ -9,6 +9,11 @@ A `### Breaking` section is used in addition to Keep a Changelog's standard sect ## [Unreleased] +### Changed + +- The CLI entrypoint, internal package paths, build outputs, and automation references now use the `vociferate` name instead of the earlier `releaseprep` naming. +- The release workflow and composite action now treat a provided `version` as an override and otherwise fall back to the recommended next version automatically. + ## [1.0.0] - 2026-03-20 ### Breaking @@ -18,7 +23,7 @@ A `### Breaking` section is used in addition to Keep a Changelog's standard sect - Reusable `workflow_call` support for the `Prepare Release` workflow, enabling other repositories to invoke it directly. - Automated release artifact publishing in the release workflow for `darwin`, `linux`, and `windows` binaries plus `checksums.txt`. - README guidance for release artifacts and examples for reusing vociferate as a composite action or reusable workflow. -- Initial standalone releaseprep migration into vociferate. +- Initial standalone vociferate migration from its earlier internal naming. - Configurable version source and parser via `--version-file` and `--version-pattern`. - Configurable changelog path via `--changelog`. - Composite action (`action.yml`) for release preparation and recommendation flows. diff --git a/cmd/releaseprep/main.go b/cmd/vociferate/main.go similarity index 70% rename from cmd/releaseprep/main.go rename to cmd/vociferate/main.go index 1884d7e..81de004 100644 --- a/cmd/releaseprep/main.go +++ b/cmd/vociferate/main.go @@ -6,7 +6,7 @@ import ( "os" "path/filepath" - "git.hrafn.xyz/aether/vociferate/internal/releaseprep" + "git.hrafn.xyz/aether/vociferate/internal/vociferate" ) func main() { @@ -25,14 +25,14 @@ func main() { os.Exit(1) } - opts := releaseprep.Options{ + opts := vociferate.Options{ VersionFile: *versionFile, VersionPattern: *versionPattern, Changelog: *changelog, } if *recommend { - tag, err := releaseprep.RecommendedTag(absRoot, opts) + tag, err := vociferate.RecommendedTag(absRoot, opts) if err != nil { fmt.Fprintf(os.Stderr, "recommend release: %v\n", err) os.Exit(1) @@ -42,11 +42,11 @@ func main() { } if *version == "" || *date == "" { - fmt.Fprintln(os.Stderr, "usage: releaseprep --version --date [--root ] [--version-file ] [--version-pattern ] [--changelog ] | --recommend [--root ] [--version-file ] [--version-pattern ] [--changelog ]") + fmt.Fprintln(os.Stderr, "usage: vociferate --version --date [--root ] [--version-file ] [--version-pattern ] [--changelog ] | --recommend [--root ] [--version-file ] [--version-pattern ] [--changelog ]") os.Exit(2) } - if err := releaseprep.Prepare(absRoot, *version, *date, opts); err != nil { + if err := vociferate.Prepare(absRoot, *version, *date, opts); err != nil { fmt.Fprintf(os.Stderr, "prepare release: %v\n", err) os.Exit(1) } diff --git a/internal/releaseprep/version/version.go b/internal/vociferate/version/version.go similarity index 100% rename from internal/releaseprep/version/version.go rename to internal/vociferate/version/version.go diff --git a/internal/releaseprep/releaseprep.go b/internal/vociferate/vociferate.go similarity index 98% rename from internal/releaseprep/releaseprep.go rename to internal/vociferate/vociferate.go index 03d3577..baf27a6 100644 --- a/internal/releaseprep/releaseprep.go +++ b/internal/vociferate/vociferate.go @@ -1,4 +1,4 @@ -package releaseprep +package vociferate import ( "fmt" @@ -10,7 +10,7 @@ import ( ) const ( - defaultVersionFile = "internal/releaseprep/version/version.go" + defaultVersionFile = "internal/vociferate/version/version.go" defaultVersionExpr = `const String = "([^"]+)"` defaultChangelog = "changelog.md" ) diff --git a/internal/releaseprep/releaseprep_test.go b/internal/vociferate/vociferate_test.go similarity index 81% rename from internal/releaseprep/releaseprep_test.go rename to internal/vociferate/vociferate_test.go index f68df13..58d51d8 100644 --- a/internal/releaseprep/releaseprep_test.go +++ b/internal/vociferate/vociferate_test.go @@ -1,11 +1,11 @@ -package releaseprep_test +package vociferate_test import ( "os" "path/filepath" "testing" - "git.hrafn.xyz/aether/vociferate/internal/releaseprep" + "git.hrafn.xyz/aether/vociferate/internal/vociferate" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -21,7 +21,7 @@ func TestPrepareSuite(t *testing.T) { func (s *PrepareSuite) SetupTest() { s.rootDir = s.T().TempDir() - versionDir := filepath.Join(s.rootDir, "internal", "releaseprep", "version") + versionDir := filepath.Join(s.rootDir, "internal", "vociferate", "version") require.NoError(s.T(), os.MkdirAll(versionDir, 0o755)) require.NoError(s.T(), os.WriteFile( @@ -38,11 +38,11 @@ func (s *PrepareSuite) SetupTest() { } func (s *PrepareSuite) TestPrepare_UpdatesVersionAndPromotesUnreleasedNotes() { - err := releaseprep.Prepare(s.rootDir, "v1.1.7", "2026-03-20", releaseprep.Options{}) + err := vociferate.Prepare(s.rootDir, "v1.1.7", "2026-03-20", vociferate.Options{}) require.NoError(s.T(), err) - versionBytes, err := os.ReadFile(filepath.Join(s.rootDir, "internal", "releaseprep", "version", "version.go")) + versionBytes, err := os.ReadFile(filepath.Join(s.rootDir, "internal", "vociferate", "version", "version.go")) require.NoError(s.T(), err) require.Equal(s.T(), "package version\n\nconst String = \"1.1.7\"\n", string(versionBytes)) @@ -58,7 +58,7 @@ func (s *PrepareSuite) TestPrepare_ReturnsErrorWhenUnreleasedSectionMissing() { 0o644, )) - err := releaseprep.Prepare(s.rootDir, "1.1.7", "2026-03-20", releaseprep.Options{}) + err := vociferate.Prepare(s.rootDir, "1.1.7", "2026-03-20", vociferate.Options{}) require.ErrorContains(s.T(), err, "unreleased section") } @@ -70,13 +70,13 @@ func (s *PrepareSuite) TestPrepare_ReturnsErrorWhenUnreleasedSectionIsEmpty() { 0o644, )) - err := releaseprep.Prepare(s.rootDir, "1.1.7", "2026-03-20", releaseprep.Options{}) + err := vociferate.Prepare(s.rootDir, "1.1.7", "2026-03-20", vociferate.Options{}) require.ErrorContains(s.T(), err, "unreleased section is empty") } func (s *PrepareSuite) TestRecommendedTag_UsesMajorBumpWhenBreakingHeadingExists() { - tag, err := releaseprep.RecommendedTag(s.rootDir, releaseprep.Options{}) + tag, err := vociferate.RecommendedTag(s.rootDir, vociferate.Options{}) require.NoError(s.T(), err) require.Equal(s.T(), "v2.0.0", tag) @@ -89,7 +89,7 @@ func (s *PrepareSuite) TestRecommendedTag_UsesPatchBumpForFixOnlyChanges() { 0o644, )) - tag, err := releaseprep.RecommendedTag(s.rootDir, releaseprep.Options{}) + tag, err := vociferate.RecommendedTag(s.rootDir, vociferate.Options{}) require.NoError(s.T(), err) require.Equal(s.T(), "v1.1.7", tag) @@ -102,7 +102,7 @@ func (s *PrepareSuite) TestRecommendedTag_UsesMajorBumpWhenRemovedEntriesExist() 0o644, )) - tag, err := releaseprep.RecommendedTag(s.rootDir, releaseprep.Options{}) + tag, err := vociferate.RecommendedTag(s.rootDir, vociferate.Options{}) require.NoError(s.T(), err) require.Equal(s.T(), "v2.0.0", tag) @@ -115,7 +115,7 @@ func (s *PrepareSuite) TestRecommendedTag_UsesMajorBumpWhenBreakingEntriesExist( 0o644, )) - tag, err := releaseprep.RecommendedTag(s.rootDir, releaseprep.Options{}) + tag, err := vociferate.RecommendedTag(s.rootDir, vociferate.Options{}) require.NoError(s.T(), err) require.Equal(s.T(), "v2.0.0", tag) @@ -130,7 +130,7 @@ func (s *PrepareSuite) TestPrepare_UsesCustomVersionFileAndPattern() { 0o644, )) - err := releaseprep.Prepare(s.rootDir, "1.1.8", "2026-03-20", releaseprep.Options{ + err := vociferate.Prepare(s.rootDir, "1.1.8", "2026-03-20", vociferate.Options{ VersionFile: customVersionFile, VersionPattern: `VERSION=([^\n]+)`, }) @@ -144,16 +144,16 @@ func (s *PrepareSuite) TestPrepare_UsesCustomVersionFileAndPattern() { func (s *PrepareSuite) TestPrepare_AllowsUnchangedVersionValue() { require.NoError(s.T(), os.WriteFile( - filepath.Join(s.rootDir, "internal", "releaseprep", "version", "version.go"), + filepath.Join(s.rootDir, "internal", "vociferate", "version", "version.go"), []byte("package version\n\nconst String = \"1.1.6\"\n"), 0o644, )) - err := releaseprep.Prepare(s.rootDir, "1.1.6", "2026-03-20", releaseprep.Options{}) + err := vociferate.Prepare(s.rootDir, "1.1.6", "2026-03-20", vociferate.Options{}) require.NoError(s.T(), err) - versionBytes, readErr := os.ReadFile(filepath.Join(s.rootDir, "internal", "releaseprep", "version", "version.go")) + versionBytes, readErr := os.ReadFile(filepath.Join(s.rootDir, "internal", "vociferate", "version", "version.go")) require.NoError(s.T(), readErr) require.Equal(s.T(), "package version\n\nconst String = \"1.1.6\"\n", string(versionBytes)) } @@ -172,7 +172,7 @@ func (s *PrepareSuite) TestRecommendedTag_UsesCustomVersionFileAndPattern() { 0o644, )) - tag, err := releaseprep.RecommendedTag(s.rootDir, releaseprep.Options{ + tag, err := vociferate.RecommendedTag(s.rootDir, vociferate.Options{ VersionFile: customVersionFile, VersionPattern: `VERSION=([^\n]+)`, }) diff --git a/justfile b/justfile index 18f41d4..11e22f4 100644 --- a/justfile +++ b/justfile @@ -5,7 +5,7 @@ default: go-build: @mkdir -p dist - go build -o dist/releaseprep ./cmd/releaseprep + go build -o dist/vociferate ./cmd/vociferate go-test: go test ./... diff --git a/script/prepare-release.sh b/script/prepare-release.sh index 3c5863a..1d355c0 100755 --- a/script/prepare-release.sh +++ b/script/prepare-release.sh @@ -9,10 +9,10 @@ fi repo_root="$(cd "$(dirname "$0")/.." && pwd)" release_date="$(date -u +%F)" -go run ./cmd/releaseprep \ +go run ./cmd/vociferate \ --root "$repo_root" \ --version "$1" \ --date "$release_date" \ - --version-file internal/releaseprep/version/version.go \ + --version-file internal/vociferate/version/version.go \ --version-pattern 'const String = "([^"]+)"' \ --changelog changelog.md