cekanje 0.2.0

tmux notifier daemon for Claude Code sessions: track every active session, surface a native popup when one needs attention, jump to its pane via fzf
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