Skip to content

Commit 7c6bf06

Browse files
Add GoReleaser release automation with changelog generation.
Modernize GoReleaser and the Release workflow so v* tags build signed registry artifacts, publish GitHub release notes from commits, and update CHANGELOG.md automatically. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent e7803f6 commit 7c6bf06

6 files changed

Lines changed: 224 additions & 9 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env bash
2+
# Generate HashiCorp-style release notes from commits since the previous tag.
3+
# Usage: generate-release-notes.sh NEW_TAG [PREV_TAG]
4+
# Output: markdown suitable for CHANGELOG.md and GitHub release notes.
5+
set -euo pipefail
6+
7+
NEW_TAG="${1:?new tag required (e.g. v2.12.0)}"
8+
PREV_TAG="${2:-}"
9+
10+
if [[ -z "$PREV_TAG" ]]; then
11+
PREV_TAG="$(git describe --tags --abbrev=0 "${NEW_TAG}^" 2>/dev/null || true)"
12+
fi
13+
14+
VERSION="${NEW_TAG#v}"
15+
REPO="${GITHUB_REPOSITORY:-devops-rob/terraform-provider-terracurl}"
16+
17+
if [[ -n "$PREV_TAG" ]]; then
18+
RANGE="${PREV_TAG}..${NEW_TAG}"
19+
COMPARE_URL="https://github.com/${REPO}/compare/${PREV_TAG}...${NEW_TAG}"
20+
else
21+
RANGE="${NEW_TAG}"
22+
COMPARE_URL=""
23+
fi
24+
25+
should_skip() {
26+
local subject="$1"
27+
local lower="${subject,,}"
28+
29+
if [[ "$lower" =~ ^merge[[:space:]] ]]; then
30+
return 0
31+
fi
32+
if [[ "$lower" =~ ^chore: ]]; then
33+
return 0
34+
fi
35+
if [[ "$lower" =~ fix[[:space:]]gofmt ]]; then
36+
return 0
37+
fi
38+
if [[ "$lower" =~ fix[[:space:]]linter ]]; then
39+
return 0
40+
fi
41+
if [[ "$lower" =~ fix[[:space:]]ci[[:space:]]linter ]]; then
42+
return 0
43+
fi
44+
if [[ "$lower" =~ ^align[[:space:]] ]]; then
45+
return 0
46+
fi
47+
48+
return 1
49+
}
50+
51+
commit_group() {
52+
local subject="$1"
53+
local lower="${subject,,}"
54+
55+
if should_skip "$subject"; then
56+
echo "skip"
57+
return
58+
fi
59+
60+
if [[ "$lower" =~ ^add[[:space:]] ]] || \
61+
[[ "$lower" =~ ^feat: ]] || \
62+
[[ "$lower" =~ ^feat[[:space:]] ]] || \
63+
[[ "$lower" =~ ^enhancement: ]] || \
64+
[[ "$subject" == *"(Closes #"* ]] || \
65+
[[ "$subject" == *"(closes #"* ]]; then
66+
echo "enhancements"
67+
return
68+
fi
69+
70+
if [[ "$lower" =~ ^fix[[:space:]] ]] || \
71+
[[ "$lower" =~ ^fix: ]] || \
72+
[[ "$lower" =~ ^bug: ]] || \
73+
[[ "$lower" =~ ^patch: ]]; then
74+
echo "bug_fixes"
75+
return
76+
fi
77+
78+
echo "other"
79+
}
80+
81+
enhancement_lines=()
82+
bug_fix_lines=()
83+
other_lines=()
84+
85+
while IFS= read -r subject; do
86+
[[ -z "$subject" ]] && continue
87+
case "$(commit_group "$subject")" in
88+
enhancements) enhancement_lines+=("$subject") ;;
89+
bug_fixes) bug_fix_lines+=("$subject") ;;
90+
other) other_lines+=("$subject") ;;
91+
esac
92+
done < <(git log --format=%s "$RANGE" 2>/dev/null || true)
93+
94+
print_section() {
95+
local title="$1"
96+
shift
97+
if [[ $# -eq 0 ]]; then
98+
return
99+
fi
100+
printf '%s:\n\n' "$title"
101+
for line in "$@"; do
102+
printf -- '- %s\n' "$line"
103+
done
104+
printf '\n'
105+
}
106+
107+
printf '# %s\n\n' "$NEW_TAG"
108+
printf 'Terraform provider for HTTP requests via Terraform. Install from the [Terraform Registry](https://registry.terraform.io/providers/devops-rob/terracurl/latest).\n\n'
109+
110+
if [[ -n "$COMPARE_URL" ]]; then
111+
printf '**Full changelog:** [%s...%s](%s)\n\n' "$PREV_TAG" "$NEW_TAG" "$COMPARE_URL"
112+
fi
113+
114+
printf '## %s\n\n' "$VERSION"
115+
116+
print_section "ENHANCEMENTS" "${enhancement_lines[@]}"
117+
print_section "BUG FIXES" "${bug_fix_lines[@]}"
118+
print_section "OTHER" "${other_lines[@]}"
119+
120+
if [[ ${#enhancement_lines[@]} -eq 0 && ${#bug_fix_lines[@]} -eq 0 && ${#other_lines[@]} -eq 0 ]]; then
121+
printf '_No categorized commits in range %s._\n' "$RANGE"
122+
fi
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env bash
2+
# Prepend a generated release-notes section to CHANGELOG.md when absent.
3+
# Usage: update-changelog.sh NEW_TAG NOTES_FILE
4+
set -euo pipefail
5+
6+
NEW_TAG="${1:?new tag required (e.g. v2.12.0)}"
7+
NOTES_FILE="${2:?notes file required}"
8+
9+
VERSION="${NEW_TAG#v}"
10+
CHANGELOG="CHANGELOG.md"
11+
12+
if [[ ! -f "$NOTES_FILE" ]]; then
13+
echo "notes file not found: $NOTES_FILE" >&2
14+
exit 1
15+
fi
16+
17+
if [[ ! -f "$CHANGELOG" ]]; then
18+
touch "$CHANGELOG"
19+
fi
20+
21+
if grep -q "^## ${VERSION}$" "$CHANGELOG"; then
22+
echo "CHANGELOG already contains section for ${VERSION}; skipping update"
23+
exit 0
24+
fi
25+
26+
section_file="$(mktemp)"
27+
trap 'rm -f "$section_file"' EXIT
28+
29+
# Extract the HashiCorp-style section (## VERSION through end of categorized content).
30+
awk -v version="$VERSION" '
31+
/^## / {
32+
if ($0 == "## " version) {
33+
in_section = 1
34+
print
35+
next
36+
}
37+
if (in_section) {
38+
exit
39+
}
40+
}
41+
in_section { print }
42+
' "$NOTES_FILE" > "$section_file"
43+
44+
if [[ ! -s "$section_file" ]]; then
45+
echo "failed to extract changelog section for ${VERSION} from ${NOTES_FILE}" >&2
46+
exit 1
47+
fi
48+
49+
existing="$(mktemp)"
50+
trap 'rm -f "$section_file" "$existing"' EXIT
51+
cat "$CHANGELOG" > "$existing"
52+
53+
{
54+
cat "$section_file"
55+
if [[ -s "$existing" ]]; then
56+
printf '\n'
57+
cat "$existing"
58+
fi
59+
} > "$CHANGELOG"
60+
61+
echo "Updated CHANGELOG.md with section for ${VERSION}"

.github/workflows/release.yml

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
push:
88
tags:
99
- 'v*'
10+
workflow_dispatch:
1011

1112
# Releases need permissions to read and write the repository contents.
1213
# GitHub considers creating releases and uploading assets as writing contents.
@@ -15,26 +16,52 @@ permissions:
1516

1617
jobs:
1718
goreleaser:
19+
if: startsWith(github.ref, 'refs/tags/')
1820
runs-on: ubuntu-latest
1921
steps:
20-
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
22+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
2123
with:
2224
# Allow goreleaser to access older tag information.
2325
fetch-depth: 0
24-
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
26+
27+
- name: Generate release notes
28+
id: notes
29+
env:
30+
GITHUB_REPOSITORY: ${{ github.repository }}
31+
run: |
32+
notes="${RUNNER_TEMP}/release-notes.md"
33+
bash .github/scripts/generate-release-notes.sh "${{ github.ref_name }}" > "$notes"
34+
echo "path=${notes}" >> "$GITHUB_OUTPUT"
35+
echo "Release notes:"
36+
cat "$notes"
37+
38+
- name: Update CHANGELOG
39+
run: bash .github/scripts/update-changelog.sh "${{ github.ref_name }}" "${{ steps.notes.outputs.path }}"
40+
41+
- name: Commit CHANGELOG
42+
run: |
43+
git config user.name "github-actions[bot]"
44+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
45+
git add CHANGELOG.md
46+
git diff --staged --quiet || git commit -m "docs: update CHANGELOG for ${{ github.ref_name }}"
47+
git push origin HEAD:main
48+
49+
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
2550
with:
2651
go-version-file: 'go.mod'
2752
cache: true
53+
2854
- name: Import GPG key
29-
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
55+
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
3056
id: import_gpg
3157
with:
3258
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
3359
passphrase: ${{ secrets.PASSPHRASE }}
60+
3461
- name: Run GoReleaser
35-
uses: goreleaser/goreleaser-action@7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8 # v5.0.0
62+
uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3
3663
with:
37-
args: release --clean
64+
args: release --clean --release-notes=${{ steps.notes.outputs.path }}
3865
env:
3966
# GitHub sets the GITHUB_TOKEN secret automatically.
4067
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.goreleaser.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Visit https://goreleaser.com for documentation on how to customize this
22
# behavior.
3+
version: 2
34
before:
45
hooks:
56
# this is just an example and not a requirement for provider building/publishing
@@ -28,9 +29,12 @@ builds:
2829
ignore:
2930
- goos: darwin
3031
goarch: '386'
32+
- goos: windows
33+
goarch: arm
3134
binary: '{{ .ProjectName }}_v{{ .Version }}'
3235
archives:
33-
- format: zip
36+
- formats:
37+
- zip
3438
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
3539
checksum:
3640
extra_files:
@@ -41,7 +45,7 @@ checksum:
4145
signs:
4246
- artifacts: checksum
4347
args:
44-
# if you are using this in a GitHub action or some other automated pipeline, you
48+
# if you are using this in a GitHub action or some other automated pipeline, you
4549
# need to pass the batch flag to indicate its not interactive.
4650
- "--batch"
4751
- "--local-user"
@@ -57,4 +61,4 @@ release:
5761
# If you want to manually examine the release before its live, uncomment this line:
5862
# draft: true
5963
changelog:
60-
skip: true
64+
disable: false

main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var (
2323
// these will be set by the goreleaser configuration
2424
// to appropriate values for the compiled binary.
2525
version string = "dev"
26+
commit string = "unknown"
2627

2728
// goreleaser can pass other information to the main package, such as the specific commit
2829
// https://goreleaser.com/cookbooks/using-main.version/

terraform-registry-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "2.2.0",
2+
"version": 1,
33
"metadata": {
44
"protocol_versions": ["6.0"]
55
}

0 commit comments

Comments
 (0)