1- name : Build and Release
1+ name : Release
22
33on :
44 push :
5- tags :
6- - ' v*.*.*'
5+ branches : [main]
76 workflow_dispatch :
87
8+ # Prevent concurrent releases
9+ concurrency :
10+ group : release
11+ cancel-in-progress : false
12+
913jobs :
14+ check :
15+ runs-on : ubuntu-latest
16+ outputs :
17+ should_release : ${{ steps.check.outputs.should_release }}
18+ next_version : ${{ steps.version.outputs.next_version }}
19+ changelog : ${{ steps.changelog.outputs.changelog }}
20+ steps :
21+ - name : Checkout code
22+ uses : actions/checkout@v4
23+ with :
24+ fetch-depth : 0
25+
26+ - name : Check if release needed
27+ id : check
28+ run : |
29+ # Skip if the last commit is a release commit (avoid infinite loop)
30+ LAST_MSG=$(git log -1 --pretty=%s)
31+ if [[ "$LAST_MSG" == chore:\ release* ]]; then
32+ echo "should_release=false" >> $GITHUB_OUTPUT
33+ exit 0
34+ fi
35+
36+ # Skip if no meaningful changes since last tag
37+ LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
38+ if [ -z "$LAST_TAG" ]; then
39+ echo "should_release=true" >> $GITHUB_OUTPUT
40+ exit 0
41+ fi
42+
43+ # Check for feat/fix/refactor commits since last tag
44+ COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=%s)
45+ if echo "$COMMITS" | grep -qE '^(feat|fix|refactor|perf|breaking)'; then
46+ echo "should_release=true" >> $GITHUB_OUTPUT
47+ else
48+ echo "should_release=false" >> $GITHUB_OUTPUT
49+ fi
50+
51+ - name : Determine next version
52+ if : steps.check.outputs.should_release == 'true'
53+ id : version
54+ run : |
55+ LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
56+ echo "Last tag: $LAST_TAG"
57+
58+ # Parse semver
59+ VERSION=${LAST_TAG#v}
60+ MAJOR=$(echo $VERSION | cut -d. -f1)
61+ MINOR=$(echo $VERSION | cut -d. -f2)
62+ PATCH=$(echo $VERSION | cut -d. -f3)
63+
64+ # Determine bump type from commits
65+ COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=%s 2>/dev/null || git log --pretty=%s)
66+ if echo "$COMMITS" | grep -qiE '^breaking|BREAKING CHANGE'; then
67+ MAJOR=$((MAJOR + 1))
68+ MINOR=0
69+ PATCH=0
70+ elif echo "$COMMITS" | grep -qE '^feat'; then
71+ MINOR=$((MINOR + 1))
72+ PATCH=0
73+ else
74+ PATCH=$((PATCH + 1))
75+ fi
76+
77+ NEXT="v${MAJOR}.${MINOR}.${PATCH}"
78+ echo "Next version: $NEXT"
79+ echo "next_version=$NEXT" >> $GITHUB_OUTPUT
80+
81+ - name : Generate changelog
82+ if : steps.check.outputs.should_release == 'true'
83+ id : changelog
84+ run : |
85+ LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
86+ if [ -z "$LAST_TAG" ]; then
87+ RANGE="HEAD"
88+ else
89+ RANGE="${LAST_TAG}..HEAD"
90+ fi
91+
92+ {
93+ echo 'changelog<<CHANGELOG_EOF'
94+
95+ # Features
96+ FEATS=$(git log $RANGE --pretty="- %s (%h)" --grep="^feat" --extended-regexp 2>/dev/null)
97+ if [ -n "$FEATS" ]; then
98+ echo "### Features"
99+ echo "$FEATS"
100+ echo ""
101+ fi
102+
103+ # Fixes
104+ FIXES=$(git log $RANGE --pretty="- %s (%h)" --grep="^fix" --extended-regexp 2>/dev/null)
105+ if [ -n "$FIXES" ]; then
106+ echo "### Bug Fixes"
107+ echo "$FIXES"
108+ echo ""
109+ fi
110+
111+ # Other changes (refactor, perf, etc.)
112+ OTHERS=$(git log $RANGE --pretty="- %s (%h)" --grep="^refactor\|^perf\|^chore\|^ci\|^docs\|^test\|^build" --extended-regexp 2>/dev/null)
113+ if [ -n "$OTHERS" ]; then
114+ echo "### Other Changes"
115+ echo "$OTHERS"
116+ echo ""
117+ fi
118+
119+ echo "### Platforms"
120+ echo "- Linux (amd64, arm64)"
121+ echo "- macOS (amd64, arm64)"
122+ echo "- Windows (amd64, arm64)"
123+
124+ echo 'CHANGELOG_EOF'
125+ } >> $GITHUB_OUTPUT
126+
10127 build :
128+ needs : check
129+ if : needs.check.outputs.should_release == 'true'
11130 strategy :
12131 matrix :
13132 include :
@@ -51,17 +170,22 @@ jobs:
51170 - name : Install dependencies
52171 run : go mod download
53172
54- - name : Build codes
173+ - name : Build
55174 shell : bash
56175 env :
57176 GOOS : ${{ matrix.goos }}
58177 GOARCH : ${{ matrix.goarch }}
59178 CGO_ENABLED : ' 0'
60179 run : |
180+ VERSION=${{ needs.check.outputs.next_version }}
181+ COMMIT=$(git rev-parse --short HEAD)
182+ DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
183+ LDFLAGS="-s -w -X codes/internal/commands.Version=${VERSION} -X codes/internal/commands.Commit=${COMMIT} -X codes/internal/commands.Date=${DATE}"
184+
61185 if [ "${{ matrix.goos }}" = "windows" ]; then
62- go build -o codes.exe ./cmd/codes
186+ go build -ldflags "$LDFLAGS" - o codes.exe ./cmd/codes
63187 else
64- go build -o codes ./cmd/codes
188+ go build -ldflags "$LDFLAGS" - o codes ./cmd/codes
65189 fi
66190
67191 - name : Test
@@ -74,30 +198,22 @@ jobs:
74198 ./codes version
75199 fi
76200
77- - name : Set binary name
78- id : binary
79- shell : bash
80- run : |
81- if [ "${{ matrix.goos }}" = "windows" ]; then
82- echo "name=codes.exe" >> $GITHUB_OUTPUT
83- else
84- echo "name=codes" >> $GITHUB_OUTPUT
85- fi
86-
87201 - name : Upload artifact
88202 uses : actions/upload-artifact@v4
89203 with :
90204 name : codes-${{ matrix.goos }}-${{ matrix.goarch }}
91- path : ${{ steps.binary.outputs.name }}
205+ path : codes ${{ matrix.goos == 'windows' && '.exe' || '' }}
92206 retention-days : 7
93207
94208 release :
95- needs : build
209+ needs : [check, build]
96210 runs-on : ubuntu-latest
97- if : startsWith(github.ref, 'refs/tags/v')
98211 permissions :
99212 contents : write
100213 steps :
214+ - name : Checkout code
215+ uses : actions/checkout@v4
216+
101217 - name : Download all artifacts
102218 uses : actions/download-artifact@v4
103219 with :
@@ -112,19 +228,18 @@ jobs:
112228 mv "$dir/codes.exe" "release/codes-$platform.exe"
113229 elif [ -f "$dir/codes" ]; then
114230 mv "$dir/codes" "release/codes-$platform"
231+ chmod +x "release/codes-$platform"
115232 fi
116233 done
117234 ls -la release/
118235
119236 - name : Create release
120237 uses : softprops/action-gh-release@v2
121238 with :
239+ tag_name : ${{ needs.check.outputs.next_version }}
240+ name : ${{ needs.check.outputs.next_version }}
241+ body : ${{ needs.check.outputs.changelog }}
122242 files : release/*
123243 draft : false
124244 prerelease : false
125- body : |
126- Cross-platform builds for codes CLI tool
127-
128- - Linux (amd64, arm64)
129- - Windows (amd64, arm64)
130- - macOS (amd64, arm64)
245+ make_latest : true
0 commit comments