diff --git a/.github/workflows/auto-release.yaml b/.github/workflows/auto-release.yaml index 907f71199..ec81a7788 100644 --- a/.github/workflows/auto-release.yaml +++ b/.github/workflows/auto-release.yaml @@ -1,146 +1,146 @@ --- # yamllint disable rule:truthy -name: Auto Release +# Push-based release tagger + release-page publisher. +# +# Runs on push to main (normal releases) and to release-* branches (backports +# / maintenance releases). Inspects conventional commits reachable from the +# pushed ref since the latest reachable v*.*.* tag via git-cliff, and: +# +# 1. creates a new vX.Y.Z git tag if a bump is warranted +# 2. creates the matching GitHub Release with notes generated by git-cliff +# +# The tag push then triggers downstream publishing (for chart/service/CLI +# repos, this is the CircleCI architect pipeline firing on the same /^v.*/ +# tag filter — go-build + push-to-registries + push-to-app-catalog + +# upload-release-assets as appropriate for the repo type). Architect appends +# any binary artifacts to the release we just created here. +# +# No release PR. No human approval step. The mechanism that protects against +# bad releases is the pre-merge CI on the feature PRs that landed these +# commits — once they're on the branch, they ship. +name: Auto-release + on: - pull_request: - types: [closed] + push: branches: - main + - 'release-*' # maintenance branches for backports, e.g. release-2.x permissions: - contents: write # Needed to create releases and tags - pull-requests: read # Needed to read PR information + contents: write # push tags and create the GitHub Release + # git-cliff's GitHub API lookups (commit.remote.pr_number / username + # in release notes) need PR read access via GITHUB_TOKEN. + pull-requests: read + +# Scope the concurrency lock per branch so a backport tag on release-2.x +# doesn't block (or get blocked by) a main release, and vice versa. A second +# push to the same branch while a tag is being computed still waits. +concurrency: + group: auto-release-${{ github.ref_name }} + cancel-in-progress: false jobs: - auto_release: - name: Auto Release - if: >- - github.event.pull_request.merged && - !startsWith(github.event.pull_request.title, 'Release v') - runs-on: ubuntu-latest + tag: + name: Tag + runs-on: ubuntu-24.04 steps: - - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - # Fetch all history and tags for version calculation and changelog - fetch-depth: 0 - # Use PAT to allow pushing tags for commits with workflow changes - # GITHUB_TOKEN cannot push tags that modify .github/workflows/ - token: ${{ secrets.RELEASE_PAT }} - - # yamllint disable rule:line-length - - name: Check if commit already tagged - id: check_tag - run: | - # Check if HEAD already has a version tag - # This prevents duplicate releases on workflow re-run - EXISTING_TAG=$(git tag --points-at HEAD \ - | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1 || true) - if [[ -n "$EXISTING_TAG" ]]; then - echo "Commit already has version tag: $EXISTING_TAG" - echo "Skipping release to prevent duplicate tags" - echo "skip=true" >> "$GITHUB_OUTPUT" - echo "existing_tag=$EXISTING_TAG" >> "$GITHUB_OUTPUT" - else - echo "No existing version tag found, proceeding" - echo "skip=false" >> "$GITHUB_OUTPUT" - fi + fetch-depth: 0 # full history so git-cliff sees every commit + fetch-tags: true # ensure tags are present (shallow runners drop them by default) - - name: Report skipped release - if: steps.check_tag.outputs.skip == 'true' - run: | - TAG="${{ steps.check_tag.outputs.existing_tag }}" - echo "::notice::Release skipped - already tagged as $TAG" - echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY - echo "Commit already has version tag \`$TAG\`." \ - >> $GITHUB_STEP_SUMMARY - echo "Re-running on an already-tagged commit is safe." \ - >> $GITHUB_STEP_SUMMARY - # yamllint enable rule:line-length - - - name: Set up Go - if: steps.check_tag.outputs.skip != 'true' - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + # Install git-cliff once and call it from shell so we can do all the + # expensive work (commits walk + GitHub API PR lookups) in a single + # invocation, then cheaply re-render from the cached JSON context. + # Replaces two separate orhun/git-cliff-action invocations that each + # re-installed git-cliff and re-paid the API-lookup cost. + - name: Install git-cliff + uses: giantswarm/install-binary-action@5bef88f65012037dd836117c8d344b21bb559854 # v4.1.0 with: - go-version: '1.26' # Specify Go version - cache: true # Cache Go modules and build cache + binary: git-cliff + version: "2.13.1" + # yamllint disable-line rule:line-length + download_url: 'https://github.com/orhun/git-cliff/releases/download/v${version}/git-cliff-${version}-x86_64-unknown-linux-gnu.tar.gz' + tarball_binary_path: 'git-cliff-${version}/git-cliff' + smoke_test: '${binary} --version' - - name: Install GoReleaser - if: steps.check_tag.outputs.skip != 'true' - uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 - with: - # either 'goreleaser' (default) or 'goreleaser-pro' - distribution: goreleaser - version: "~> v2" - args: --version # Print version for verification - - - name: Configure Git - if: steps.check_tag.outputs.skip != 'true' + - name: Compute next version and render release notes + id: cliff + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - git config user.name "${{ github.actor }}" - git config user.email "${{ github.actor }}@users.noreply.github.com" + set -euo pipefail + # Single expensive call: walks commits, queries the GitHub API for + # per-commit PR lookups, emits the JSON context for ONLY the bumped + # release. + # + # Flag choice matters here. Both `--latest` and `--unreleased` + # *look* like single-release filters, but only one composes with + # `--bump`: + # --latest --bump : returns the latest EXISTING tag — drops the + # bump silently. We don't want this (it caused + # #15 to never produce a new tag). + # --unreleased --bump : filters to commits that aren't in any tag + # yet, computes the bumped version from + # them, returns JSON for that bumped + # release only. This is what we want. + # + # Without either filter, --bump --context returns the full release + # history in JSON and the render below would concatenate every + # past release into each new release's notes (the #13 → #15 bug). + git-cliff --unreleased --bump --context > cliff-context.json + NEXT=$(jq -r '.[0].version // empty' cliff-context.json) + echo "next computed: ${NEXT:-}" + echo "version=${NEXT}" >> "$GITHUB_OUTPUT" + # Cheap render from the cached context — no API calls, no git walk. + # `--strip all` drops header/footer; body-only is what gh release + # create --notes-file expects. + git-cliff --from-context cliff-context.json --strip all --output release-notes.md - - name: Determine Next Version - if: steps.check_tag.outputs.skip != 'true' - id: version + - name: Decide whether to tag + id: decide + env: + NEXT: ${{ steps.cliff.outputs.version }} run: | - set -e - # Use version-aware sorting to find the semantically highest tag, - # not just the nearest reachable one. git describe can pick the - # wrong tag when multiple tags point to the same commit. - LATEST_TAG=$(git tag --sort=-version:refname | head -1) - if [ -z "$LATEST_TAG" ]; then - LATEST_TAG="v0.0.0" + set -euo pipefail + # `git describe --tags --abbrev=0` returns the closest tag reachable + # from HEAD — NOT the highest tag in the repo overall. This matters + # for backports: on release-2.x, HEAD's reachable history terminates + # before v3.0.0 was tagged, so describe correctly returns v2.3.5 + # (the baseline of the 2.x line) and we end up tagging v2.3.6 rather + # than something nonsensical relative to v3.0.0. + last=$(git describe --tags --abbrev=0 --match='v*.*.*' 2>/dev/null || echo "") + echo "branch: ${GITHUB_REF_NAME}" + echo "last reachable tag: ${last:-}" + if [ -z "${NEXT}" ] || [ "${NEXT}" = "${last}" ]; then + echo "No releasable commits since ${last:-inception}; skipping tag." + echo "tag=" >> "$GITHUB_OUTPUT" + else + echo "tag=${NEXT}" >> "$GITHUB_OUTPUT" fi - # Remove 'v' prefix - LATEST_VERSION=${LATEST_TAG#v} - # Split into major, minor, patch - IFS='.' read -r -a VERSION_PARTS <<< "$LATEST_VERSION" - # Increment patch version - NEXT_PATCH=$((VERSION_PARTS[2] + 1)) - # Construct next version string - NEXT_VERSION="v${VERSION_PARTS[0]}.${VERSION_PARTS[1]}.$NEXT_PATCH" - echo "Latest tag: $LATEST_TAG" - echo "Next version: $NEXT_VERSION" - # Set output for subsequent steps - echo "next_version=$NEXT_VERSION" >> "$GITHUB_OUTPUT" - - name: Create Tag - if: steps.check_tag.outputs.skip != 'true' - run: | - NEXT_VERSION="${{ steps.version.outputs.next_version }}" - git tag "$NEXT_VERSION" - git push origin "$NEXT_VERSION" - echo "Created and pushed tag $NEXT_VERSION" - - - name: Run GoReleaser - if: steps.check_tag.outputs.skip != 'true' - continue-on-error: true - id: goreleaser - uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 - with: - distribution: goreleaser - version: "~> v2" - args: release --clean + # Create the tag AND the GitHub Release in one atomic API call. GitHub's + # release-create endpoint accepts a tag_name + target_commitish and, if + # the tag doesn't already exist, creates it pointing at that commitish + # as part of the same operation. Either both exist or neither does — + # no risk of a tag-without-release "stuck" state, no race window with + # CircleCI's `upload-release-assets` job that starts polling the + # release the instant it sees the tag. + # + # Trade-off: the tag created this way is **lightweight** (just a ref), + # not annotated. For our use — git describe, architect's tag filter, + # gitsemver, gh release view — both behave identically. Nothing in the + # giantswarm stack distinguishes them. + - name: Create release (and the tag, atomically) + if: steps.decide.outputs.tag != '' env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} - - - name: Check release result - if: steps.check_tag.outputs.skip != 'true' - env: - TAG: ${{ steps.version.outputs.next_version }} - GR_OUTCOME: ${{ steps.goreleaser.outcome }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + TAG: ${{ steps.decide.outputs.tag }} run: | - if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" \ - > /dev/null 2>&1; then - echo "Release $TAG published successfully" - if [[ "$GR_OUTCOME" == "failure" ]]; then - echo "::warning::GoReleaser had non-fatal errors" \ - "(e.g. homebrew tap update). Release artifacts are fine." - fi - else - echo "::error::Release $TAG was not published" - exit 1 - fi + set -euo pipefail + gh release create "$TAG" \ + --title "$TAG" \ + --notes-file release-notes.md \ + --target "$GITHUB_SHA" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f03c4aab0..13d990100 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -69,16 +69,3 @@ jobs: - name: Run muster integration tests run: ./muster test --parallel 50 --base-port 30000 - - - name: Install GoReleaser - uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 - with: - distribution: goreleaser - version: "~> v2" - install-only: true - - - name: Run Release Dry-Run - if: github.event_name == 'pull_request' - run: make release-dry-run-fast - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/zz_generated.release-please.yaml b/.github/workflows/zz_generated.release-please.yaml deleted file mode 100644 index e6b9701f3..000000000 --- a/.github/workflows/zz_generated.release-please.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# DO NOT EDIT. Generated with: -# -# devctl -# -# https://github.com/giantswarm/devctl/blob/4129e812666c6bf5584d68d971dc6ce6c6eb5cc9/pkg/gen/input/workflows/internal/file/release_please.yaml.template -# -name: Release Please - -on: - push: - branches: - - main - - master - -permissions: {} - -jobs: - release_please: - uses: giantswarm/github-workflows/.github/workflows/release.yaml@main - permissions: - contents: write - pull-requests: write - with: - auto-merge-level: minor - secrets: - RELEASE_PLEASE_CLIENT_ID: ${{ secrets.RELEASE_PLEASE_CLIENT_ID }} - RELEASE_PLEASE_PRIVATE_KEY: ${{ secrets.RELEASE_PLEASE_PRIVATE_KEY }} - RELEASE_PLEASE_APPROVER_CLIENT_ID: ${{ secrets.RELEASE_PLEASE_APPROVER_CLIENT_ID }} - RELEASE_PLEASE_APPROVER_PRIVATE_KEY: ${{ secrets.RELEASE_PLEASE_APPROVER_PRIVATE_KEY }} diff --git a/.goreleaser.ci.yaml b/.goreleaser.ci.yaml deleted file mode 100644 index 4b3c09b25..000000000 --- a/.goreleaser.ci.yaml +++ /dev/null @@ -1,56 +0,0 @@ ---- -# yamllint disable rule:truthy -# .goreleaser.ci.yaml -# Minimal GoReleaser config for CI dry-run validation. -# Only builds linux/amd64 to validate the release config works. -# The full release uses .goreleaser.yaml which builds all platforms. -version: 2 - -before: - hooks: - - go mod tidy - -builds: - - id: muster - main: ./main.go - binary: muster - # Only build linux/amd64 for CI validation - saves ~6 minutes - goos: - - linux - goarch: - - amd64 - env: - - CGO_ENABLED=0 - mod_timestamp: '{{ .CommitTimestamp }}' - flags: - - -trimpath - ldflags: - - >- - -s -w - -X github.com/giantswarm/muster/pkg/project.version={{.Version}} - -X github.com/giantswarm/muster/pkg/project.gitSHA={{.ShortCommit}} - -X github.com/giantswarm/muster/pkg/project.buildTimestamp={{.Date}} - -archives: - - id: default - formats: [tar.gz] - name_template: >- - {{ .ProjectName }}_ {{- title .Os }}_ {{- if eq .Arch "amd64" }}x86_64 - {{- else if eq .Arch "386" }}i386 - {{- else }}{{ .Arch }}{{ end }} - {{- if .Arm }}v{{ .Arm }}{{ end }} - wrap_in_directory: true - files: - - LICENSE - - README.md - -checksum: - algorithm: sha256 - name_template: '{{ .ProjectName }}_checksums.txt' - -# Skip changelog generation in CI - not needed for validation -changelog: - disable: true - -# Modelines -# vim: set ts=2 sw=2 tw=0 fo=cnqoj diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index 3979d7283..000000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,156 +0,0 @@ ---- -# yamllint disable rule:truthy -# .goreleaser.yaml -# Make sure to check the documentation at https://goreleaser.com -version: 2 # Explicitly set GoReleaser configuration version - -before: - hooks: - # You may remove this if you don't use go modules. - - go mod tidy - # you may remove this if you don't need go generate - # - go generate ./... - -builds: - - id: muster - # Path to main.go file or main package. - main: ./main.go - # Binary name. - # Defaults to the project name. - binary: muster - # GOOS list to build for. - # Defaults to linux, windows and darwin. - goos: - - linux - - windows - - darwin - # GOARCH list to build for. - # Defaults to 386, amd64 and arm64. - goarch: - - amd64 - - arm64 - # GOARM list to build for when GOARCH is arm. - # Defaults to 6. - # goarm: - # - "6" - # Environment variables that will be passed to the build process. - env: - - CGO_ENABLED=0 - # Set the modified timestamp on the output binary, typically - # you would do this to ensure reproducible builds. - mod_timestamp: '{{ .CommitTimestamp }}' - # Flags to pass to the go build command. - # Defaults to -trimpath. - flags: - - -trimpath - # Ldflags inject build metadata into pkg/project. Same vars are populated - # by architect-orb's go-build job for container images. - ldflags: - - >- - -s -w - -X github.com/giantswarm/muster/pkg/project.version={{.Version}} - -X github.com/giantswarm/muster/pkg/project.gitSHA={{.ShortCommit}} - -X github.com/giantswarm/muster/pkg/project.buildTimestamp={{.Date}} - -archives: - - id: default - # Default formats for all platforms (can be overridden per OS) - formats: [tar.gz] - name_template: >- - {{ .ProjectName }}_ {{- title .Os }}_ {{- if eq .Arch "amd64" }}x86_64 - {{- else if eq .Arch "386" }}i386 - {{- else }}{{ .Arch }}{{ end }} - {{- if .Arm }}v{{ .Arm }}{{ end }} - # Wrap the binary in a directory structure when extracted. - # Defaults to false. - wrap_in_directory: true - # Format overrides per OS (using new plural 'formats' syntax) - format_overrides: - - goos: windows - formats: [zip] - - goos: darwin - formats: [zip] - # Files to include in the archive. - # Defaults to license*, readme*, etc. - files: - - LICENSE - - README.md - -checksum: - # Algorithm to use. Valid options are sha256, sha512, sha1, crc32, md5, etc. - # Default is sha256. - algorithm: sha256 - # Name template for the checksums file. - # Default is `{{ .ProjectName }}_{{ .Version }}_checksums.txt`. - name_template: '{{ .ProjectName }}_checksums.txt' - -changelog: - # Use GitHub's native release notes generation. - # This automatically uses PRs merged since the last tag. - # Disables sort, groups, filters, etc. - use: github-native - -release: - # Repo in format "owner/name". - # Defaults to the origin remote. - # repo: - # owner: user - # name: repo - # If set to true, will not auto-publish the release. - # Default is false. - draft: false - # If set to true, will mark the release as not ready for production. - # Default is false. - prerelease: auto - # You can change the name of the GitHub release. - # Default is `{{.Tag}}` - name_template: "{{.ProjectName}} v{{.Version}}" - # Header to add to the release notes. - # Default is empty. - # header: | - # This is the header - # Footer to add to the release notes. - # Default is empty. - # footer: | - # This is the footer - # Add back the extra_files section with corrected globs - extra_files: - - glob: ./dist/muster_darwin_amd64*/muster - name_template: muster_darwin_amd64 - - glob: ./dist/muster_darwin_arm64*/muster - name_template: muster_darwin_arm64 - - glob: ./dist/muster_linux_amd64*/muster - name_template: muster_linux_amd64 - - glob: ./dist/muster_linux_arm64*/muster - name_template: muster_linux_arm64 - - glob: ./dist/muster_windows_amd64*/muster.exe - name_template: muster_windows_amd64.exe - - glob: ./dist/muster_windows_arm64*/muster.exe - name_template: muster_windows_arm64.exe - -brews: - - name: muster - repository: - owner: giantswarm - name: homebrew-muster - branch: main - token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}" - url_template: >- - https://github.com/giantswarm/muster/releases/download/{{ .Tag }}/ - {{- .ArtifactName }} - commit_author: - name: giantswarm-bot - email: bot@giantswarm.io - commit_msg_template: "Update {{ .ProjectName }} to {{ .Tag }}" - directory: Formula - homepage: "https://github.com/giantswarm/muster" - description: "Universal Control Plane for AI Agents - MCP server aggregator" - license: "Apache-2.0" - skip_upload: auto - install: | - bin.install "muster" - test: | - system "#{bin}/muster", "version" - -# Modelines -# vim: set ts=2 sw=2 tw=0 fo=cnqoj diff --git a/.release-please-manifest.json b/.release-please-manifest.json deleted file mode 100644 index 2be9c43c8..000000000 --- a/.release-please-manifest.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - ".": "0.2.0" -} diff --git a/CLAUDE.md b/CLAUDE.md index ed0a066ed..c4d9e3138 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,9 +27,6 @@ make vet # go vet # Helm make helm-lint # Lint Helm chart make helm-test # Helm unit tests - -# Release -make release-dry-run-fast # Quick release test (linux/amd64 only) ``` ## Architecture diff --git a/Makefile.custom.mk b/Makefile.custom.mk index 34eebf1a5..cf907b4de 100644 --- a/Makefile.custom.mk +++ b/Makefile.custom.mk @@ -1,27 +1,13 @@ # Custom Makefile targets for muster # This file is included by the main Makefile via `include Makefile.*.mk` -##@ Release - -.PHONY: release-dry-run -release-dry-run: ## Test the release process without publishing (all platforms) - goreleaser release --snapshot --clean --skip=announce,publish,validate - -.PHONY: release-dry-run-fast -release-dry-run-fast: ## Fast release dry-run for CI (linux/amd64 only, ~6min faster) - goreleaser release --config .goreleaser.ci.yaml --snapshot --clean --skip=announce,publish,validate - -.PHONY: release-local -release-local: ## Create a release locally - goreleaser release --clean - ##@ Development .PHONY: lint-yaml lint-yaml: ## Run YAML linter @echo "Running YAML linter..." @# Exclude zz_generated files - @yamllint .github/workflows/auto-release.yaml .github/workflows/ci.yaml .goreleaser.yaml .goreleaser.ci.yaml + @yamllint .github/workflows/auto-release.yaml .github/workflows/ci.yaml .PHONY: helm-lint helm-lint: ## Run Helm linter @@ -63,10 +49,3 @@ test-ci-pr: ## Run 'act' to simulate CI checks for a pull request test-ci-push: ## Run 'act' to simulate CI checks for a push to main @echo "Simulating CI workflow (push event)..." @act push --job check - -.PHONY: test-auto-release -test-auto-release: ## Run 'act' to simulate the auto-release workflow - @echo "Simulating Auto-Release workflow (merged pull_request event)..." - @echo "NOTE: Requires 'merged_pr_event.json' in the project root." - @echo "NOTE: Git push steps within the workflow are expected to fail locally." - @act pull_request --job auto_release --eventpath merged_pr_event.json diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 000000000..646681d1f --- /dev/null +++ b/cliff.toml @@ -0,0 +1,107 @@ +# git-cliff config for the push-based PoC. +# +# Two jobs: +# 1. Decide the next semver from conventional commits (`--bumped-version`, +# used by .github/workflows/auto-tag.yaml). +# 2. Render the release notes posted on the GitHub Release (`--latest`, +# also used by auto-tag.yaml after the tag is pushed). + +[bump] +# `feat:` always bumps minor (not patch). Matches conventional-commits spec. +features_always_bump_minor = true +# `feat!:`/`BREAKING CHANGE` always bumps major. +breaking_always_bump_major = true + +[git] +conventional_commits = true +# Drop non-conventional commits silently rather than counting them as +# unclassified work — the bump-decider should only act on intent-bearing +# commits. +filter_unconventional = true +# Highest-version tag (not creation date) is the baseline when computing what +# changed since last release. +topo_order = false +sort_commits = "oldest" + +# Strip the trailing " (#N)" that GitHub appends to squash-merge commit +# messages. Our template renders the PR link explicitly via cliff's GitHub +# integration (commit.remote.pr_number — see [changelog].body), so the +# auto-appended reference would duplicate it. +# +# `(?m)` enables multi-line mode so `$` matches end-of-line (the squash +# `(#N)` lives at the end of the subject line, not the end of the full +# commit text — git-cliff's default regex mode is single-line). This +# anchoring keeps `(#N)` references that appear inside commit bodies +# untouched. +commit_preprocessors = [ + { pattern = '(?m) \(#\d+\)$', replace = "" }, +] + +# Map commit types to changelog groups. Mirrors the section structure from +# the old release-please-config.json (Keep-a-Changelog convention): feat → +# Added, fix → Fixed, all "internal change" types → Changed, security → +# Security. +# +# `style` is the only type marked skip — release-please-config.json didn't +# include it anywhere either. Bump decision is unaffected by these group +# names: git-cliff only bumps on feat / fix / breaking regardless. +commit_parsers = [ + { message = "^feat", group = "Added" }, + { message = "^fix", group = "Fixed" }, + { message = "^refactor", group = "Changed" }, + { message = "^perf", group = "Changed" }, + { message = "^docs", group = "Changed" }, + { message = "^chore", group = "Changed" }, + { message = "^test", group = "Changed" }, + { message = "^build", group = "Changed" }, + { message = "^ci", group = "Changed" }, + { message = "^security", group = "Security" }, + { message = "^style", skip = true }, +] + +# GitHub repo coordinates — required for the API lookups that populate +# `commit.github.pr_number` and `commit.github.username` in the template +# below. The token is passed automatically by git-cliff-action from the +# workflow's GITHUB_TOKEN. +# +# Note for devctl when templating this file: owner / repo need to come from +# the consuming repo's identity, not be hard-coded. +[remote.github] +owner = "giantswarm" +repo = "muster" + +# Template for the rendered release notes. Body is what gets posted to the +# GitHub Release; header and footer are empty so the release page shows only +# the section list. +# +# Each bullet ends with " in [#N](pr-url) by [@user](user-url)" when +# git-cliff successfully resolves the PR for the commit via the GitHub API. +# `commit.remote` is the post-2.x replacement for the per-platform fields +# (commit.github / commit.gitlab / etc.) — using it future-proofs the +# template against git-cliff dropping the old names. +# Backslashes at line ends escape the newline so the bullet stays on one +# line in the rendered Markdown. +[changelog] +header = "" +# `{%-` / `-%}` strip the surrounding newline so the rendered Markdown is +# tight: one blank line before each "### " header, no leading blank, no +# double-blank between header and bullets. Without the whitespace control +# the output picks up two extra blank lines per loop iteration. +body = """ +{% for group, commits in commits | group_by(attribute="group") -%} +### {{ group }} + +{% for commit in commits -%} +- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ +{% if commit.breaking %}[**breaking**] {% endif %}\ +{{ commit.message | split(pat="\n") | first | upper_first }}\ +{% if commit.remote.pr_number %} in [#{{ commit.remote.pr_number }}](https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}/pull/{{ commit.remote.pr_number }}){% endif %}\ +{% if commit.remote.username %} by [@{{ commit.remote.username }}](https://github.com/{{ commit.remote.username }}){% endif %} +{% endfor %} +{% endfor -%} +{% if previous.version %} +**Full Changelog**: https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}/compare/{{ previous.version }}...{{ version }} +{% endif -%} +""" +trim = true +footer = "" diff --git a/release-please-config.json b/release-please-config.json deleted file mode 100644 index d69d6c3a2..000000000 --- a/release-please-config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "release-type": "simple", - "packages": { - ".": {} - }, - "extra-files": [ - {"type": "generic", "path": "pkg/project/project.go"} - ], - "changelog-sections": [ - {"type": "feat", "section": "Added"}, - {"type": "fix", "section": "Fixed"}, - {"type": "refactor", "section": "Changed"}, - {"type": "perf", "section": "Changed"}, - {"type": "docs", "section": "Changed"}, - {"type": "chore", "section": "Changed"}, - {"type": "test", "section": "Changed"}, - {"type": "build", "section": "Changed"}, - {"type": "ci", "section": "Changed"}, - {"type": "security", "section": "Security"} - ] -}