Skip to content

Create Tag and Release #42

Create Tag and Release

Create Tag and Release #42

Workflow file for this run

name: Create Tag and Release
on:
workflow_dispatch:
inputs:
tag:
description: "Release tag (required, e.g. v0.2.0)"
required: true
type: string
prerelease:
description: "Mark as pre-release"
required: false
type: boolean
default: false
draft:
description: "Create as draft"
required: false
type: boolean
default: false
concurrency:
group: ${{ github.workflow }}-${{ inputs.tag }}
cancel-in-progress: false
env:
TAP_REPO: drpedapati/homebrew-tap
FORMULA_RELATIVE_PATH: Formula/sciclaw.rb
jobs:
create-tag:
name: Create Git Tag
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create and push tag
shell: bash
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -a "${{ inputs.tag }}" -m "Release ${{ inputs.tag }}"
git push origin "${{ inputs.tag }}"
build-binaries:
name: Build Release Binaries
needs: create-tag
runs-on: ubuntu-latest
steps:
- name: Checkout tag
uses: actions/checkout@v4
with:
ref: ${{ inputs.tag }}
- name: Setup Go from go.mod
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Build all binaries
run: make build-all
- name: Generate checksums
shell: bash
run: |
shasum -a 256 build/sciclaw-* build/picoclaw-* > build/sha256sums.txt
- name: Upload release binaries artifact
uses: actions/upload-artifact@v4
with:
name: sciclaw-binaries
path: |
build/sciclaw-*
build/picoclaw-*
build/sha256sums.txt
if-no-files-found: error
create-release:
name: Create GitHub Release
needs: [create-tag, build-binaries]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: release-artifacts
- name: Show downloaded files
run: ls -R release-artifacts
- name: Create release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.tag }}
name: ${{ inputs.tag }}
draft: ${{ inputs.draft }}
prerelease: ${{ inputs.prerelease }}
files: |
release-artifacts/**/*
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
update-homebrew-tap:
name: Update Homebrew Tap Formula
needs: [create-tag, build-binaries, create-release]
if: ${{ !inputs.prerelease && !inputs.draft }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check Homebrew tap token
id: tap-token
shell: bash
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
if [ -z "${HOMEBREW_TAP_TOKEN}" ]; then
echo "available=false" >> "${GITHUB_OUTPUT}"
echo "HOMEBREW_TAP_TOKEN is not configured; skipping tap update."
else
echo "available=true" >> "${GITHUB_OUTPUT}"
fi
- name: Compute checksums for binaries and source
if: ${{ steps.tap-token.outputs.available == 'true' }}
id: checksums
shell: bash
run: |
tag="${{ inputs.tag }}"
version="${tag#v}"
base="https://github.com/${{ github.repository }}/releases/download/${tag}"
# Download binaries and compute SHA-256
for target in darwin-arm64 linux-arm64 linux-amd64; do
curl -fsSL -o "sciclaw-${target}" "${base}/sciclaw-${target}"
sha=$(shasum -a 256 "sciclaw-${target}" | awk '{print $1}')
# Normalize target name for output keys (dash to underscore)
key=$(echo "$target" | tr '-' '_')
echo "sha_${key}=${sha}" >> "${GITHUB_OUTPUT}"
done
# Source archive (for skills and workspace templates)
source_url="https://github.com/${{ github.repository }}/archive/refs/tags/${tag}.tar.gz"
curl -fsSL -o source.tar.gz "${source_url}"
echo "sha_source=$(shasum -a 256 source.tar.gz | awk '{print $1}')" >> "${GITHUB_OUTPUT}"
echo "source_url=${source_url}" >> "${GITHUB_OUTPUT}"
echo "version=${version}" >> "${GITHUB_OUTPUT}"
- name: Checkout tap repository
if: ${{ steps.tap-token.outputs.available == 'true' }}
uses: actions/checkout@v4
with:
repository: ${{ env.TAP_REPO }}
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: tap
- name: Render formula
if: ${{ steps.tap-token.outputs.available == 'true' }}
shell: bash
run: |
tag="${{ inputs.tag }}"
version="${{ steps.checksums.outputs.version }}"
source_url="${{ steps.checksums.outputs.source_url }}"
sha_source="${{ steps.checksums.outputs.sha_source }}"
sha_darwin_arm64="${{ steps.checksums.outputs.sha_darwin_arm64 }}"
sha_linux_arm64="${{ steps.checksums.outputs.sha_linux_arm64 }}"
sha_linux_amd64="${{ steps.checksums.outputs.sha_linux_amd64 }}"
base="https://github.com/${{ github.repository }}/releases/download/${tag}"
mkdir -p "tap/Formula"
cat > "tap/${{ env.FORMULA_RELATIVE_PATH }}" <<FORMULA
class Sciclaw < Formula
desc "Autonomous paired scientist CLI forked from PicoClaw"
homepage "https://github.com/drpedapati/sciclaw"
version "${version}"
license "MIT"
on_macos do
on_arm do
url "${base}/sciclaw-darwin-arm64"
sha256 "${sha_darwin_arm64}"
end
end
on_linux do
on_arm do
url "${base}/sciclaw-linux-arm64"
sha256 "${sha_linux_arm64}"
end
on_intel do
url "${base}/sciclaw-linux-amd64"
sha256 "${sha_linux_amd64}"
end
depends_on "sciclaw-quarto"
end
# Source archive provides skills and workspace templates
resource "source" do
url "${source_url}"
sha256 "${sha_source}"
end
depends_on "irl"
depends_on "imagemagick"
depends_on "pandoc"
depends_on "ripgrep"
depends_on "uv"
depends_on "sciclaw-docx-review"
depends_on "sciclaw-pubmed-cli"
def install
# Install pre-compiled binary
if OS.mac?
bin.install "sciclaw-darwin-arm64" => "sciclaw"
elsif OS.linux? && Hardware::CPU.arm?
bin.install "sciclaw-linux-arm64" => "sciclaw"
else
bin.install "sciclaw-linux-amd64" => "sciclaw"
end
(bin/"picoclaw").make_symlink bin/"sciclaw"
# Install skills and workspace templates from source
resource("source").stage do
pkgshare.install "skills"
(pkgshare/"templates"/"workspace").install Dir["pkg/workspacetpl/templates/workspace/*.md"]
end
end
def post_install
return unless service_definition_installed?
unless quiet_system(bin/"sciclaw", "service", "refresh")
opoo "sciClaw service refresh could not be applied automatically. Run: sciclaw service refresh"
end
end
def service_definition_installed?
if OS.mac?
(Pathname.new(Dir.home)/"Library"/"LaunchAgents"/"io.sciclaw.gateway.plist").exist?
elsif OS.linux?
(Pathname.new(Dir.home)/".config"/"systemd"/"user"/"sciclaw-gateway.service").exist?
else
false
end
end
def caveats
<<~EOS
If you use the sciClaw background gateway service, this formula attempts
to refresh the service automatically on upgrade.
If your environment blocks that step (no user service session), run:
sciclaw service refresh
EOS
end
test do
assert_match "Usage:", shell_output("#{bin}/sciclaw 2>&1", 1)
assert_match "Usage:", shell_output("#{bin}/picoclaw 2>&1", 1)
assert_match "v#{version}", shell_output("#{bin}/sciclaw --version")
assert_match "ripgrep", shell_output("#{Formula["ripgrep"].opt_bin}/rg --version")
assert_match "ImageMagick", shell_output("#{Formula["imagemagick"].opt_bin}/magick -version")
assert_match "irl", shell_output("#{Formula["irl"].opt_bin}/irl --version 2>&1")
if OS.linux?
assert_match(/\\d+\\.\\d+\\.\\d+/, shell_output("#{Formula["sciclaw-quarto"].opt_bin}/quarto --version").strip)
end
assert_match "docx-review", shell_output("#{Formula["sciclaw-docx-review"].opt_bin}/docx-review --version")
assert_match "PubMed", shell_output("#{Formula["sciclaw-pubmed-cli"].opt_bin}/pubmed --help")
ENV["HOME"] = testpath
system bin/"sciclaw", "onboard", "--yes"
assert_path_exists testpath/"sciclaw/AGENTS.md"
assert_path_exists testpath/"sciclaw/HOOKS.md"
assert_path_exists testpath/"sciclaw/skills/scientific-writing/SKILL.md"
end
end
FORMULA
- name: Commit and push formula update
if: ${{ steps.tap-token.outputs.available == 'true' }}
shell: bash
run: |
cd tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if git diff --quiet -- "${{ env.FORMULA_RELATIVE_PATH }}"; then
echo "No tap formula changes detected."
exit 0
fi
git add "${{ env.FORMULA_RELATIVE_PATH }}"
git commit -m "sciclaw ${{ inputs.tag }}"
git push origin main