Create Tag and Release #39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 "ripgrep" | |
| 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 | |
| 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 "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 |