name: release on: push: tags: - 'v*' workflow_dispatch: inputs: tag: description: 'Release tag (e.g. v1.2.3). If empty, uses current ref name.' required: false type: string permissions: contents: write jobs: build-and-package: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v5 with: go-version-file: go.mod cache: true - name: Install packaging tools run: | sudo apt-get update sudo apt-get install -y zip - name: Resolve build version id: ver run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ inputs.tag }}" ]; then raw="${{ inputs.tag }}" elif [[ "${GITHUB_REF}" == refs/tags/* ]]; then raw="${GITHUB_REF_NAME}" else raw="$(git describe --tags --always --dirty 2>/dev/null || echo dev)" fi version="${raw#v}" echo "raw=$raw" >> "$GITHUB_OUTPUT" echo "version=$version" >> "$GITHUB_OUTPUT" echo "Build version: $version (from $raw)" - name: Build release binaries (Linux minimal, others default) run: | set -euo pipefail mkdir -p build make sync-embed-workspace trap 'make cleanup-embed-workspace' EXIT # Build non-Linux targets with default flags. for target in darwin/amd64 darwin/arm64 windows/amd64 windows/arm64; do goos="${target%/*}" goarch="${target#*/}" out="build/clawgo-${goos}-${goarch}" if [ "${goos}" = "windows" ]; then out="${out}.exe"; fi CGO_ENABLED=0 GOOS="${goos}" GOARCH="${goarch}" go build \ -trimpath -buildvcs=false \ -ldflags "-X main.version=${{ steps.ver.outputs.version }} -X main.buildTime=$(date +%FT%T%z) -s -w" \ -o "${out}" ./cmd/clawgo done # Linux targets use slimmer flags without disabling channel capabilities. for arch in amd64 arm64 riscv64; do out="build/clawgo-linux-${arch}" CGO_ENABLED=0 GOOS=linux GOARCH="${arch}" go build \ -trimpath -buildvcs=false -tags "purego,netgo,osusergo" \ -ldflags "-X main.version=${{ steps.ver.outputs.version }} -X main.buildTime=$(date +%FT%T%z) -s -w -buildid=" \ -o "${out}" ./cmd/clawgo done - name: Package artifacts run: | set -euo pipefail rm -f build/checksums.txt for target in linux/amd64 linux/arm64 linux/riscv64 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64; do goos="${target%/*}" goarch="${target#*/}" bin="clawgo-${goos}-${goarch}" if [ "${goos}" = "windows" ]; then bin="${bin}.exe" zip -q -j "build/clawgo-${goos}-${goarch}.zip" "build/${bin}" else tar -czf "build/clawgo-${goos}-${goarch}.tar.gz" -C build "${bin}" fi done if command -v sha256sum >/dev/null 2>&1; then (cd build && sha256sum *.tar.gz *.zip | tee checksums.txt) else (cd build && shasum -a 256 *.tar.gz *.zip | tee checksums.txt) fi - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' cache-dependency-path: webui/package-lock.json - name: Build WebUI run: | if [ -f webui/package-lock.json ]; then npm ci --prefix webui else npm install --prefix webui fi npm run build --prefix webui tar -czf build/webui.tar.gz -C webui dist - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: release-artifacts path: | build/*.tar.gz build/*.zip build/checksums.txt if-no-files-found: error publish-release: needs: build-and-package runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' steps: - name: Download artifacts uses: actions/download-artifact@v4 with: name: release-artifacts path: build - name: Resolve tag id: tag run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ inputs.tag }}" ]; then echo "name=${{ inputs.tag }}" >> "$GITHUB_OUTPUT" else echo "name=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" fi - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.tag.outputs.name }} name: ${{ steps.tag.outputs.name }} generate_release_notes: true files: | build/*.tar.gz build/*.zip build/checksums.txt