name: Release
on:
push:
tags:
- 'v[0-9]+*'
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
BINARY_NAME: cmt
jobs:
release:
name: Build and Release
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
asset_name: cmt-linux-amd64
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
asset_name: cmt-linux-arm64
- os: macos-latest
target: x86_64-apple-darwin
asset_name: cmt-darwin-amd64
- os: macos-latest
target: aarch64-apple-darwin
asset_name: cmt-darwin-arm64
- os: windows-latest
target: x86_64-pc-windows-msvc
asset_name: cmt-windows-amd64.exe
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: "Build Changelog"
id: build_changelog
uses: mikepenz/release-changelog-builder-action@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
mode: COMMIT
configurationJson: |
{
"template": "#{{CHANGELOG}}\n\n## Other\n#{{UNCATEGORIZED}}",
"categories": [
{
"title": "## ✨ Features",
"labels": ["feature", "enhancement", "feat"]
},
{
"title": "## 🐛 Fixes",
"labels": ["fix", "bug"]
},
{
"title": "## 📝 Documentation",
"labels": ["documentation", "docs"]
},
{
"title": "## 🔨 Maintenance",
"labels": ["chore", "dependencies"]
}
],
"commit_template": "- #{{TITLE}} (#{{HASH_7}})",
"pr_template": "- #{{TITLE}} (#{{NUMBER}})",
"empty_template": "- No changes",
"transformers": [
{
"pattern": "\\b\\(0\\)\\b",
"target": ""
},
],
"label_extractor": [
{
"pattern": "(.) (.+)",
"target": "$1",
"flags": "gu"
}
],
"max_tags_to_fetch": 200,
"max_pull_requests": 200,
"max_back_track_time_days": 90,
"exclude_merge_branches": ["main"],
"sort": "DESC"
}
- name: Build binary
uses: houseabsolute/actions-rust-cross@v1
with:
command: build
target: ${{ matrix.target }}
args: "--release"
strip: true
- name: Prepare asset
shell: bash
run: |
if [ "${{ matrix.os }}" = "windows-latest" ]; then
cp target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}.exe ${{ matrix.asset_name }}
else
cp target/${{ matrix.target }}/release/${{ env.BINARY_NAME }} ${{ matrix.asset_name }}
fi
- name: Upload Release Asset
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
body: ${{ steps.build_changelog.outputs.changelog }}
files: ${{ matrix.asset_name }}
draft: false
prerelease: false
make_latest: true
update-homebrew:
name: Update Homebrew Formula
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get version from tag
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Download release assets and compute SHA256
id: sha256
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION=${{ steps.get_version.outputs.VERSION }}
# Wait for all assets to be available
echo "Waiting for release assets..."
for i in {1..30}; do
ASSET_COUNT=$(gh release view "v$VERSION" --json assets --jq '.assets | length')
if [ "$ASSET_COUNT" -ge 4 ]; then
echo "Found $ASSET_COUNT assets"
break
fi
echo "Found $ASSET_COUNT assets, waiting... ($i/30)"
sleep 10
done
# Download and compute SHA256 for each binary
gh release download "v$VERSION" -p "cmt-darwin-arm64" -D /tmp
gh release download "v$VERSION" -p "cmt-darwin-amd64" -D /tmp
gh release download "v$VERSION" -p "cmt-linux-arm64" -D /tmp || true
gh release download "v$VERSION" -p "cmt-linux-amd64" -D /tmp || true
echo "SHA_DARWIN_ARM64=$(sha256sum /tmp/cmt-darwin-arm64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT
echo "SHA_DARWIN_AMD64=$(sha256sum /tmp/cmt-darwin-amd64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT
if [ -f /tmp/cmt-linux-arm64 ]; then
echo "SHA_LINUX_ARM64=$(sha256sum /tmp/cmt-linux-arm64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT
fi
if [ -f /tmp/cmt-linux-amd64 ]; then
echo "SHA_LINUX_AMD64=$(sha256sum /tmp/cmt-linux-amd64 | cut -d' ' -f1)" >> $GITHUB_OUTPUT
fi
- name: Update Homebrew formula
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
VERSION=${{ steps.get_version.outputs.VERSION }}
SHA_DARWIN_ARM64=${{ steps.sha256.outputs.SHA_DARWIN_ARM64 }}
SHA_DARWIN_AMD64=${{ steps.sha256.outputs.SHA_DARWIN_AMD64 }}
SHA_LINUX_ARM64=${{ steps.sha256.outputs.SHA_LINUX_ARM64 }}
SHA_LINUX_AMD64=${{ steps.sha256.outputs.SHA_LINUX_AMD64 }}
# Clone the tap repo
git clone https://x-access-token:${GH_TOKEN}@github.com/clifton/homebrew-tap.git /tmp/homebrew-tap
cd /tmp/homebrew-tap
mkdir -p Formula
# Generate the formula
cat > Formula/cmt.rb << 'FORMULA'
# typed: false
# frozen_string_literal: true
class Cmt < Formula
desc "CLI tool that generates commit messages using AI"
homepage "https://github.com/clifton/cmt"
FORMULA
# Add version and platform-specific URLs (these need variable expansion)
cat >> Formula/cmt.rb << EOF
version "$VERSION"
license "MIT"
on_macos do
on_arm do
url "https://github.com/clifton/cmt/releases/download/v#{version}/cmt-darwin-arm64"
sha256 "$SHA_DARWIN_ARM64"
end
on_intel do
url "https://github.com/clifton/cmt/releases/download/v#{version}/cmt-darwin-amd64"
sha256 "$SHA_DARWIN_AMD64"
end
end
on_linux do
on_arm do
url "https://github.com/clifton/cmt/releases/download/v#{version}/cmt-linux-arm64"
sha256 "$SHA_LINUX_ARM64"
end
on_intel do
url "https://github.com/clifton/cmt/releases/download/v#{version}/cmt-linux-amd64"
sha256 "$SHA_LINUX_AMD64"
end
end
EOF
# Add the rest (no variable expansion needed, use single quotes to preserve #{})
cat >> Formula/cmt.rb << 'FORMULA'
def install
binary_name = "cmt-#{OS.kernel_name.downcase}-#{Hardware::CPU.arch == :arm64 ? "arm64" : "amd64"}"
bin.install binary_name => "cmt"
end
test do
assert_match version.to_s, shell_output("#{bin}/cmt --version")
end
end
FORMULA
# Fix indentation (remove leading spaces from heredoc)
sed -i 's/^ //' Formula/cmt.rb
# Commit and push
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A
git diff --staged --quiet || git commit -m "Update cmt to v$VERSION"
git push