ci: add go vet, unit tests and smoke tests to CI matrix #12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| # Prevent concurrent releases | |
| concurrency: | |
| group: release | |
| cancel-in-progress: false | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_release: ${{ steps.check.outputs.should_release }} | |
| next_version: ${{ steps.version.outputs.next_version }} | |
| changelog: ${{ steps.changelog.outputs.changelog }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check if release needed | |
| id: check | |
| run: | | |
| # Skip if the last commit is a release commit (avoid infinite loop) | |
| LAST_MSG=$(git log -1 --pretty=%s) | |
| if [[ "$LAST_MSG" == chore:\ release* ]]; then | |
| echo "should_release=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Skip if no meaningful changes since last tag | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
| if [ -z "$LAST_TAG" ]; then | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Check for feat/fix/refactor commits since last tag | |
| COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=%s) | |
| if echo "$COMMITS" | grep -qE '^(feat|fix|refactor|perf|breaking)'; then | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "should_release=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Determine next version | |
| if: steps.check.outputs.should_release == 'true' | |
| id: version | |
| run: | | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") | |
| echo "Last tag: $LAST_TAG" | |
| # Parse semver | |
| VERSION=${LAST_TAG#v} | |
| MAJOR=$(echo $VERSION | cut -d. -f1) | |
| MINOR=$(echo $VERSION | cut -d. -f2) | |
| PATCH=$(echo $VERSION | cut -d. -f3) | |
| # Determine bump type from commits | |
| COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=%s 2>/dev/null || git log --pretty=%s) | |
| if echo "$COMMITS" | grep -qiE '^breaking|BREAKING CHANGE'; then | |
| MAJOR=$((MAJOR + 1)) | |
| MINOR=0 | |
| PATCH=0 | |
| elif echo "$COMMITS" | grep -qE '^feat'; then | |
| MINOR=$((MINOR + 1)) | |
| PATCH=0 | |
| else | |
| PATCH=$((PATCH + 1)) | |
| fi | |
| NEXT="v${MAJOR}.${MINOR}.${PATCH}" | |
| echo "Next version: $NEXT" | |
| echo "next_version=$NEXT" >> $GITHUB_OUTPUT | |
| - name: Generate changelog | |
| if: steps.check.outputs.should_release == 'true' | |
| id: changelog | |
| run: | | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
| if [ -z "$LAST_TAG" ]; then | |
| RANGE="HEAD" | |
| else | |
| RANGE="${LAST_TAG}..HEAD" | |
| fi | |
| { | |
| echo 'changelog<<CHANGELOG_EOF' | |
| # Features | |
| FEATS=$(git log $RANGE --pretty="- %s (%h)" --grep="^feat" --extended-regexp 2>/dev/null) | |
| if [ -n "$FEATS" ]; then | |
| echo "### Features" | |
| echo "$FEATS" | |
| echo "" | |
| fi | |
| # Fixes | |
| FIXES=$(git log $RANGE --pretty="- %s (%h)" --grep="^fix" --extended-regexp 2>/dev/null) | |
| if [ -n "$FIXES" ]; then | |
| echo "### Bug Fixes" | |
| echo "$FIXES" | |
| echo "" | |
| fi | |
| # Other changes (refactor, perf, etc.) | |
| OTHERS=$(git log $RANGE --pretty="- %s (%h)" --grep="^refactor\|^perf\|^chore\|^ci\|^docs\|^test\|^build" --extended-regexp 2>/dev/null) | |
| if [ -n "$OTHERS" ]; then | |
| echo "### Other Changes" | |
| echo "$OTHERS" | |
| echo "" | |
| fi | |
| echo "### Platforms" | |
| echo "- Linux (amd64, arm64)" | |
| echo "- macOS (amd64, arm64)" | |
| echo "- Windows (amd64, arm64)" | |
| echo 'CHANGELOG_EOF' | |
| } >> $GITHUB_OUTPUT | |
| build: | |
| needs: check | |
| if: needs.check.outputs.should_release == 'true' | |
| strategy: | |
| matrix: | |
| include: | |
| - platform: ubuntu-latest | |
| goos: linux | |
| goarch: amd64 | |
| can_test: true | |
| - platform: ubuntu-latest | |
| goos: linux | |
| goarch: arm64 | |
| can_test: false | |
| - platform: windows-latest | |
| goos: windows | |
| goarch: amd64 | |
| can_test: true | |
| - platform: windows-latest | |
| goos: windows | |
| goarch: arm64 | |
| can_test: false | |
| - platform: macos-latest | |
| goos: darwin | |
| goarch: amd64 | |
| can_test: false | |
| - platform: macos-latest | |
| goos: darwin | |
| goarch: arm64 | |
| can_test: true | |
| runs-on: ${{ matrix.platform }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: '1.24.x' | |
| cache: false | |
| - name: Install dependencies | |
| run: go mod download | |
| - name: Build | |
| shell: bash | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| CGO_ENABLED: '0' | |
| run: | | |
| VERSION=${{ needs.check.outputs.next_version }} | |
| COMMIT=$(git rev-parse --short HEAD) | |
| DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) | |
| LDFLAGS="-s -w -X codes/internal/commands.Version=${VERSION} -X codes/internal/commands.Commit=${COMMIT} -X codes/internal/commands.Date=${DATE}" | |
| if [ "${{ matrix.goos }}" = "windows" ]; then | |
| go build -ldflags "$LDFLAGS" -o codes.exe ./cmd/codes | |
| else | |
| go build -ldflags "$LDFLAGS" -o codes ./cmd/codes | |
| fi | |
| - name: Test | |
| if: matrix.can_test | |
| shell: bash | |
| run: | | |
| if [ "${{ matrix.goos }}" = "windows" ]; then | |
| ./codes.exe version | |
| else | |
| ./codes version | |
| fi | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: codes-${{ matrix.goos }}-${{ matrix.goarch }} | |
| path: codes${{ matrix.goos == 'windows' && '.exe' || '' }} | |
| retention-days: 7 | |
| release: | |
| needs: [check, build] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Prepare release files | |
| run: | | |
| mkdir -p release | |
| for dir in artifacts/codes-*; do | |
| platform=$(basename $dir | sed 's/codes-//') | |
| if [ -f "$dir/codes.exe" ]; then | |
| mv "$dir/codes.exe" "release/codes-$platform.exe" | |
| elif [ -f "$dir/codes" ]; then | |
| mv "$dir/codes" "release/codes-$platform" | |
| chmod +x "release/codes-$platform" | |
| fi | |
| done | |
| ls -la release/ | |
| - name: Create release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.check.outputs.next_version }} | |
| name: ${{ needs.check.outputs.next_version }} | |
| body: ${{ needs.check.outputs.changelog }} | |
| files: release/* | |
| draft: false | |
| prerelease: false | |
| make_latest: true |