diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9fef5ca --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,187 @@ +name: Release + +on: + push: + branches: [main] + workflow_dispatch: + inputs: + version: + description: 'Version to release (e.g., v1.0.0). Leave empty for auto-increment.' + required: false + type: string + +permissions: + contents: write + pull-requests: write + +jobs: + release: + name: Create Release + runs-on: ubuntu-latest + # Skip if commit is a release commit + if: "!startsWith(github.event.head_commit.message, 'chore(release)')" + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.22' + + - name: Get latest tag + id: get_tag + run: | + git fetch --tags + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT + echo "Latest tag: $LATEST_TAG" + + - name: Determine next version + id: next_version + run: | + LATEST="${{ steps.get_tag.outputs.latest_tag }}" + + if [ -n "${{ github.event.inputs.version }}" ]; then + NEXT="${{ github.event.inputs.version }}" + else + if [ "$LATEST" = "v0.0.0" ]; then + COMMITS=$(git log --oneline) + else + COMMITS=$(git log ${LATEST}..HEAD --oneline) + fi + + VERSION="${LATEST#v}" + MAJOR=$(echo $VERSION | cut -d. -f1) + MINOR=$(echo $VERSION | cut -d. -f2) + PATCH=$(echo $VERSION | cut -d. -f3) + + if echo "$COMMITS" | grep -qE "^[a-f0-9]+ (feat|feature)(\(.*\))?!:"; then + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + elif echo "$COMMITS" | grep -qE "^[a-f0-9]+ (feat|feature)(\(.*\))?:"; then + MINOR=$((MINOR + 1)) + PATCH=0 + else + PATCH=$((PATCH + 1)) + fi + + NEXT="v${MAJOR}.${MINOR}.${PATCH}" + fi + + echo "version=$NEXT" >> $GITHUB_OUTPUT + echo "Next version: $NEXT" + + - name: Generate changelog + id: changelog + run: | + LATEST="${{ steps.get_tag.outputs.latest_tag }}" + NEXT="${{ steps.next_version.outputs.version }}" + + echo "## What's Changed in $NEXT" > RELEASE_NOTES.md + echo "" >> RELEASE_NOTES.md + + if [ "$LATEST" = "v0.0.0" ]; then + RANGE="HEAD" + else + RANGE="${LATEST}..HEAD" + fi + + # Features + FEATURES=$(git log $RANGE --oneline --grep="^feat" --format="- %s (%h)" 2>/dev/null | head -20) + if [ -n "$FEATURES" ]; then + echo "### Added" >> RELEASE_NOTES.md + echo "$FEATURES" >> RELEASE_NOTES.md + echo "" >> RELEASE_NOTES.md + fi + + # Fixes + FIXES=$(git log $RANGE --oneline --grep="^fix" --format="- %s (%h)" 2>/dev/null | head -20) + if [ -n "$FIXES" ]; then + echo "### Fixed" >> RELEASE_NOTES.md + echo "$FIXES" >> RELEASE_NOTES.md + echo "" >> RELEASE_NOTES.md + fi + + # Other changes + OTHER=$(git log $RANGE --oneline --format="- %s (%h)" 2>/dev/null | grep -vE "^- (feat|fix)" | head -20) + if [ -n "$OTHER" ]; then + echo "### Changed" >> RELEASE_NOTES.md + echo "$OTHER" >> RELEASE_NOTES.md + echo "" >> RELEASE_NOTES.md + fi + + echo "### Downloads" >> RELEASE_NOTES.md + echo "" >> RELEASE_NOTES.md + echo "| Platform | Architecture | Binary |" >> RELEASE_NOTES.md + echo "|----------|--------------|--------|" >> RELEASE_NOTES.md + echo "| Linux | amd64 | basar-linux-amd64 |" >> RELEASE_NOTES.md + echo "| Linux | arm64 | basar-linux-arm64 |" >> RELEASE_NOTES.md + echo "| macOS | amd64 | basar-darwin-amd64 |" >> RELEASE_NOTES.md + echo "| macOS | arm64 (Apple Silicon) | basar-darwin-arm64 |" >> RELEASE_NOTES.md + echo "| Windows | amd64 | basar-windows-amd64.exe |" >> RELEASE_NOTES.md + echo "" >> RELEASE_NOTES.md + + echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST}...${NEXT}" >> RELEASE_NOTES.md + + cat RELEASE_NOTES.md + + - name: Build binaries + run: | + VERSION="${{ steps.next_version.outputs.version }}" + LDFLAGS="-s -w -X main.version=${VERSION}" + + GOOS=linux GOARCH=amd64 go build -ldflags="$LDFLAGS" -o basar-linux-amd64 ./cmd/basar + GOOS=linux GOARCH=arm64 go build -ldflags="$LDFLAGS" -o basar-linux-arm64 ./cmd/basar + GOOS=darwin GOARCH=amd64 go build -ldflags="$LDFLAGS" -o basar-darwin-amd64 ./cmd/basar + GOOS=darwin GOARCH=arm64 go build -ldflags="$LDFLAGS" -o basar-darwin-arm64 ./cmd/basar + GOOS=windows GOARCH=amd64 go build -ldflags="$LDFLAGS" -o basar-windows-amd64.exe ./cmd/basar + + sha256sum basar-* > checksums.txt + cat checksums.txt + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.next_version.outputs.version }} + name: ${{ steps.next_version.outputs.version }} + body_path: RELEASE_NOTES.md + draft: false + prerelease: false + files: | + basar-linux-amd64 + basar-linux-arm64 + basar-darwin-amd64 + basar-darwin-arm64 + basar-windows-amd64.exe + checksums.txt + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + cleanup-branches: + name: Cleanup Merged Branches + runs-on: ubuntu-latest + needs: release + if: always() + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Delete merged branches + run: | + echo "Cleaning up merged branches..." + git fetch --prune + + for branch in $(git branch -r --merged origin/main | grep -v 'main\|master\|develop\|HEAD' | sed 's/origin\///'); do + echo "Deleting merged branch: $branch" + git push origin --delete "$branch" 2>/dev/null || echo "Could not delete $branch" + done + + echo "Branch cleanup complete" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}