name: Release
on:
workflow_dispatch:
inputs:
bump:
description: "Semver bump"
required: false
default: "patch"
type: choice
options:
- patch
- minor
- major
env:
CARGO_TERM_COLOR: always
permissions:
contents: write
jobs:
bump-and-tag:
name: Bump version + tag
runs-on: ubuntu-latest
outputs:
version: ${{ steps.bump.outputs.version }}
tag: ${{ steps.bump.outputs.tag }}
steps:
- name: Checkout main
uses: actions/checkout@v6
with:
ref: main
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- name: Bump Cargo.toml + Cargo.lock
id: bump
env:
BUMP: ${{ inputs.bump }}
run: |
old=$(grep '^version' Cargo.toml | head -1 | cut -d'"' -f2)
ma=$(echo "$old" | cut -d. -f1)
mi=$(echo "$old" | cut -d. -f2)
pa=$(echo "$old" | cut -d. -f3)
case "$BUMP" in
major) ma=$((ma+1)); mi=0; pa=0;;
minor) mi=$((mi+1)); pa=0;;
patch) pa=$((pa+1));;
*) echo "Unknown bump '$BUMP'." >&2; exit 1;;
esac
new="$ma.$mi.$pa"
echo "Bumping $old -> $new ($BUMP)"
sed -i.bak -E "s/^version = \"[^\"]+\"/version = \"$new\"/" Cargo.toml
rm Cargo.toml.bak
cargo update -p cekanje --precise "$new" --offline >/dev/null 2>&1 || cargo check --quiet
echo "version=$new" >> "$GITHUB_OUTPUT"
echo "tag=v$new" >> "$GITHUB_OUTPUT"
- name: Commit, tag, push
env:
NEW_VERSION: ${{ steps.bump.outputs.version }}
NEW_TAG: ${{ steps.bump.outputs.tag }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Cargo.toml Cargo.lock
git commit -m "chore: release ${NEW_TAG}"
git tag "${NEW_TAG}"
git push origin HEAD:main
git push origin "${NEW_TAG}"
create-release:
name: Create GitHub Release
needs: bump-and-tag
runs-on: ubuntu-latest
steps:
- name: Generate release notes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
TAG: ${{ needs.bump-and-tag.outputs.tag }}
VERSION: ${{ needs.bump-and-tag.outputs.version }}
run: |
gh api "repos/${REPO}/releases/generate-notes" \
-f tag_name="${TAG}" \
--jq .body > /tmp/notes.md
cat >> /tmp/notes.md <<EOF
## Installation
### Homebrew
\`\`\`bash
brew tap ${REPO} https://github.com/${REPO}
brew install cekanje
\`\`\`
### Cargo
\`\`\`bash
cargo install cekanje
\`\`\`
### macOS (Apple Silicon)
\`\`\`bash
curl -L "https://github.com/${REPO}/releases/download/${TAG}/cekanje-${VERSION}-aarch64-apple-darwin.tar.gz" | tar xz
\`\`\`
### macOS (Intel)
\`\`\`bash
curl -L "https://github.com/${REPO}/releases/download/${TAG}/cekanje-${VERSION}-x86_64-apple-darwin.tar.gz" | tar xz
\`\`\`
### Linux (x86_64)
\`\`\`bash
curl -L "https://github.com/${REPO}/releases/download/${TAG}/cekanje-${VERSION}-x86_64-unknown-linux-gnu.tar.gz" | tar xz
\`\`\`
EOF
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
TAG: ${{ needs.bump-and-tag.outputs.tag }}
run: |
gh release create "${TAG}" \
--repo "${REPO}" \
--title "Release ${TAG}" \
--notes-file /tmp/notes.md
build-release:
name: Build ${{ matrix.target }}
needs: [bump-and-tag, create-release]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
target: aarch64-apple-darwin
- os: macos-15-intel
target: x86_64-apple-darwin
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{ needs.bump-and-tag.outputs.tag }}
- name: Install Linux build deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libdbus-1-dev pkg-config
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
target: ${{ matrix.target }}
- name: Build release binary
env:
TARGET: ${{ matrix.target }}
run: cargo build --release --target "${TARGET}"
- name: Smoke test --version
env:
TARGET: ${{ matrix.target }}
VERSION: ${{ needs.bump-and-tag.outputs.version }}
run: |
out=$("./target/${TARGET}/release/cekanje" --version)
echo "${out}"
echo "${out}" | grep -F "${VERSION}"
- name: Create archive
env:
TARGET: ${{ matrix.target }}
VERSION: ${{ needs.bump-and-tag.outputs.version }}
run: |
archive="cekanje-${VERSION}-${TARGET}.tar.gz"
tar -C "target/${TARGET}/release" -czf "${archive}" cekanje
ls -la "${archive}"
echo "ARCHIVE=${archive}" >> "$GITHUB_ENV"
- name: Upload release asset
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
TAG: ${{ needs.bump-and-tag.outputs.tag }}
run: gh release upload "${TAG}" --repo "${REPO}" "${ARCHIVE}" --clobber
update-homebrew-formula:
name: Update Homebrew Formula
needs: [bump-and-tag, build-release]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
ref: main
fetch-depth: 0
- name: Compute SHA256 hashes
id: sha
env:
REPO: ${{ github.repository }}
TAG: ${{ needs.bump-and-tag.outputs.tag }}
VERSION: ${{ needs.bump-and-tag.outputs.version }}
run: |
base="https://github.com/${REPO}/releases/download/${TAG}"
aarch64_mac=$(curl -fsSL "${base}/cekanje-${VERSION}-aarch64-apple-darwin.tar.gz" | sha256sum | cut -d' ' -f1)
x86_mac=$(curl -fsSL "${base}/cekanje-${VERSION}-x86_64-apple-darwin.tar.gz" | sha256sum | cut -d' ' -f1)
x86_linux=$(curl -fsSL "${base}/cekanje-${VERSION}-x86_64-unknown-linux-gnu.tar.gz" | sha256sum | cut -d' ' -f1)
echo "aarch64_mac=${aarch64_mac}" >> "$GITHUB_OUTPUT"
echo "x86_mac=${x86_mac}" >> "$GITHUB_OUTPUT"
echo "x86_linux=${x86_linux}" >> "$GITHUB_OUTPUT"
- name: Regenerate Formula/cekanje.rb
env:
REPO: ${{ github.repository }}
TAG: ${{ needs.bump-and-tag.outputs.tag }}
VERSION: ${{ needs.bump-and-tag.outputs.version }}
AARCH64_MAC_SHA: ${{ steps.sha.outputs.aarch64_mac }}
X86_MAC_SHA: ${{ steps.sha.outputs.x86_mac }}
X86_LINUX_SHA: ${{ steps.sha.outputs.x86_linux }}
run: |
mkdir -p Formula
cat > Formula/cekanje.rb <<EOF
class Cekanje < Formula
desc "tmux notifier daemon for Claude Code sessions"
homepage "https://github.com/${REPO}"
version "${VERSION}"
license "MIT"
on_macos do
if Hardware::CPU.arm?
url "https://github.com/${REPO}/releases/download/${TAG}/cekanje-${VERSION}-aarch64-apple-darwin.tar.gz"
sha256 "${AARCH64_MAC_SHA}"
else
url "https://github.com/${REPO}/releases/download/${TAG}/cekanje-${VERSION}-x86_64-apple-darwin.tar.gz"
sha256 "${X86_MAC_SHA}"
end
end
on_linux do
url "https://github.com/${REPO}/releases/download/${TAG}/cekanje-${VERSION}-x86_64-unknown-linux-gnu.tar.gz"
sha256 "${X86_LINUX_SHA}"
end
def install
bin.install "cekanje"
bin.install_symlink "cekanje" => "cek"
end
test do
assert_match version.to_s, shell_output("#{bin}/cekanje --version")
end
end
EOF
echo "Generated formula:"
cat Formula/cekanje.rb
- name: Commit and push
env:
VERSION: ${{ needs.bump-and-tag.outputs.version }}
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/cekanje.rb
if git diff --staged --quiet; then
echo "No formula changes."
exit 0
fi
git commit -m "chore: update homebrew formula to ${VERSION}"
for i in 1 2 3; do
if git push origin HEAD:main; then
exit 0
fi
echo "Push rejected; rebasing and retrying ($i/3)…"
git pull --rebase origin main
done
echo "Push failed after retries." >&2
exit 1
publish-crates:
name: Publish to crates.io
needs: [bump-and-tag, build-release]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{ needs.bump-and-tag.outputs.tag }}
- name: Install Linux build deps
run: |
sudo apt-get update
sudo apt-get install -y libdbus-1-dev pkg-config
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- name: Publish
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
run: cargo publish