Skip to content

release: cut v0.3.1 #18

release: cut v0.3.1

release: cut v0.3.1 #18

Workflow file for this run

name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
release_tag:
description: "Existing release tag to build and publish (for example v0.1.7)"
required: true
type: string
permissions:
contents: write
jobs:
verify:
runs-on: ubuntu-latest
env:
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref }}
persist-credentials: false
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
- name: Verify release build
run: |
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test -q --locked
build:
needs: verify
env:
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
archive_ext: tar.gz
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
archive_ext: tar.gz
- os: macos-15-intel
target: x86_64-apple-darwin
archive_ext: tar.gz
- os: macos-14
target: aarch64-apple-darwin
archive_ext: tar.gz
- os: windows-latest
target: x86_64-pc-windows-msvc
archive_ext: zip
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install Linux ARM64 linker
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Cache cargo artifacts
uses: Swatinem/rust-cache@v2
- name: Build release binary
env:
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: ${{ matrix.target == 'aarch64-unknown-linux-gnu' && 'aarch64-linux-gnu-gcc' || '' }}
run: cargo build --locked --release --target ${{ matrix.target }}
- name: Package release archive (unix)
if: runner.os != 'Windows'
env:
TARGET: ${{ matrix.target }}
TAG: ${{ env.RELEASE_TAG }}
run: |
mkdir -p dist
cp "target/$TARGET/release/kagi" dist/kagi
tar -C dist -czf "kagi-$TAG-$TARGET.tar.gz" kagi
cp "target/$TARGET/release/kagi" "kagi-$TAG-$TARGET"
- name: Package release archive (windows)
if: runner.os == 'Windows'
shell: pwsh
env:
TARGET: ${{ matrix.target }}
TAG: ${{ env.RELEASE_TAG }}
run: |
New-Item -ItemType Directory -Path dist -Force | Out-Null
Copy-Item "target/$env:TARGET/release/kagi.exe" "dist/kagi.exe"
Compress-Archive -Path "dist/kagi.exe" -DestinationPath "kagi-$env:TAG-$env:TARGET.zip" -Force
Copy-Item "target/$env:TARGET/release/kagi.exe" "kagi-$env:TAG-$env:TARGET.exe"
- name: Upload packaged assets (unix)
if: runner.os != 'Windows'
uses: actions/upload-artifact@v7.0.0
with:
name: release-${{ matrix.target }}
path: |
kagi-${{ env.RELEASE_TAG }}-${{ matrix.target }}.${{ matrix.archive_ext }}
kagi-${{ env.RELEASE_TAG }}-${{ matrix.target }}
- name: Upload packaged assets (windows)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v7.0.0
with:
name: release-${{ matrix.target }}
path: |
kagi-${{ env.RELEASE_TAG }}-${{ matrix.target }}.${{ matrix.archive_ext }}
kagi-${{ env.RELEASE_TAG }}-${{ matrix.target }}.exe
release:
needs: build
runs-on: ubuntu-latest
env:
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }}
steps:
- name: Checkout
uses: actions/checkout@v6.0.2
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref }}
- name: Download packaged archives
uses: actions/download-artifact@v8.0.1
with:
pattern: release-*
merge-multiple: true
path: dist
- name: Generate checksums
working-directory: dist
run: |
sha256sum * > "kagi-${RELEASE_TAG}-checksums.txt"
- name: Publish GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: |
if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
gh release upload "$RELEASE_TAG" dist/* --clobber
else
gh release create "$RELEASE_TAG" dist/* --generate-notes --verify-tag
fi
- name: Sync Homebrew tap and Scoop bucket
id: sync_package_indexes
continue-on-error: true
env:
REPO_SYNC_TOKEN: ${{ secrets.REPO_SYNC_TOKEN }}
run: |
set -euo pipefail
if [ -z "${REPO_SYNC_TOKEN:-}" ]; then
echo "REPO_SYNC_TOKEN is not configured; skipping Homebrew/Scoop sync."
exit 0
fi
SYNC_TOKEN="$(printf '%s' "$REPO_SYNC_TOKEN" | tr -d '\r\n')"
export SYNC_TOKEN
VERSION="${RELEASE_TAG#v}"
CHECKSUM_FILE="dist/kagi-${RELEASE_TAG}-checksums.txt"
BASE_URL="https://github.com/Microck/kagi-cli/releases/download/${RELEASE_TAG}"
checksum_for() {
local asset="$1"
grep " ${asset}$" "$CHECKSUM_FILE" | awk '{print $1}'
}
MACOS_ARM_SHA="$(checksum_for "kagi-${RELEASE_TAG}-aarch64-apple-darwin.tar.gz")"
MACOS_INTEL_SHA="$(checksum_for "kagi-${RELEASE_TAG}-x86_64-apple-darwin.tar.gz")"
LINUX_ARM_SHA="$(checksum_for "kagi-${RELEASE_TAG}-aarch64-unknown-linux-gnu.tar.gz")"
LINUX_INTEL_SHA="$(checksum_for "kagi-${RELEASE_TAG}-x86_64-unknown-linux-gnu.tar.gz")"
WINDOWS_INTEL_SHA="$(checksum_for "kagi-${RELEASE_TAG}-x86_64-pc-windows-msvc.zip")"
TAP_DIR="$(mktemp -d)"
BUCKET_DIR="$(mktemp -d)"
ASKPASS_SCRIPT="$(mktemp)"
cat > "$ASKPASS_SCRIPT" <<'EOF'
#!/usr/bin/env bash
case "$1" in
*Username*) printf '%s\n' "x-access-token" ;;
*Password*) printf '%s\n' "$SYNC_TOKEN" ;;
esac
EOF
chmod 700 "$ASKPASS_SCRIPT"
export GIT_ASKPASS="$ASKPASS_SCRIPT"
export GIT_TERMINAL_PROMPT=0
clone_with_token() {
local repo="$1"
local dir="$2"
git clone "https://github.com/${repo}.git" "$dir"
}
push_with_token() {
local dir="$1"
git -C "$dir" push origin main
}
clone_with_token "Microck/homebrew-kagi" "$TAP_DIR"
clone_with_token "Microck/scoop-kagi" "$BUCKET_DIR"
mkdir -p "$TAP_DIR/Formula"
cat > "$TAP_DIR/Formula/kagi.rb" <<EOF
class Kagi < Formula
desc "Agent-native Rust CLI for Kagi subscribers with JSON-first output"
homepage "https://github.com/Microck/kagi-cli"
version "${VERSION}"
license "MIT"
on_macos do
if Hardware::CPU.arm?
url "${BASE_URL}/kagi-${RELEASE_TAG}-aarch64-apple-darwin.tar.gz"
sha256 "${MACOS_ARM_SHA}"
end
if Hardware::CPU.intel?
url "${BASE_URL}/kagi-${RELEASE_TAG}-x86_64-apple-darwin.tar.gz"
sha256 "${MACOS_INTEL_SHA}"
end
end
on_linux do
if Hardware::CPU.arm?
url "${BASE_URL}/kagi-${RELEASE_TAG}-aarch64-unknown-linux-gnu.tar.gz"
sha256 "${LINUX_ARM_SHA}"
end
if Hardware::CPU.intel?
url "${BASE_URL}/kagi-${RELEASE_TAG}-x86_64-unknown-linux-gnu.tar.gz"
sha256 "${LINUX_INTEL_SHA}"
end
end
def install
bin.install "kagi"
end
test do
assert_match "Usage: kagi <COMMAND>", shell_output("#{bin}/kagi --help")
end
end
EOF
cat > "$BUCKET_DIR/kagi.json" <<EOF
{
"version": "${VERSION}",
"description": "Agent-native Rust CLI for Kagi subscribers with JSON-first output.",
"homepage": "https://github.com/Microck/kagi-cli",
"license": "MIT",
"architecture": {
"64bit": {
"url": "${BASE_URL}/kagi-${RELEASE_TAG}-x86_64-pc-windows-msvc.zip",
"hash": "${WINDOWS_INTEL_SHA}"
}
},
"bin": "kagi.exe",
"checkver": {
"github": "https://github.com/Microck/kagi-cli"
},
"autoupdate": {
"architecture": {
"64bit": {
"url": "https://github.com/Microck/kagi-cli/releases/download/v\$version/kagi-v\$version-x86_64-pc-windows-msvc.zip"
}
}
}
}
EOF
git -C "$TAP_DIR" config user.name "Microck"
git -C "$TAP_DIR" config user.email "contact@micr.dev"
if ! git -C "$TAP_DIR" diff --quiet; then
git -C "$TAP_DIR" add Formula/kagi.rb
git -C "$TAP_DIR" commit -m "chore: update kagi formula for ${RELEASE_TAG}"
push_with_token "$TAP_DIR"
fi
git -C "$BUCKET_DIR" config user.name "Microck"
git -C "$BUCKET_DIR" config user.email "contact@micr.dev"
if ! git -C "$BUCKET_DIR" diff --quiet; then
git -C "$BUCKET_DIR" add kagi.json
git -C "$BUCKET_DIR" commit -m "chore: update kagi manifest for ${RELEASE_TAG}"
push_with_token "$BUCKET_DIR"
fi
- name: Report package index sync warning
if: steps.sync_package_indexes.outcome == 'failure'
run: |
echo "::warning title=Package index sync failed::GitHub release assets were published, but Homebrew/Scoop sync did not complete. Check the release job logs."