name: release on: push: tags: ['v*'] workflow_dispatch: inputs: dry_run: description: Build and verify the artifacts without publishing a release type: boolean default: true concurrency: group: release-${{ github.ref }} cancel-in-progress: false permissions: contents: write jobs: verify: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 with: bun-version: 1.3.14 - name: Cache the bun install store uses: actions/cache@v4 with: path: ~/.bun/install/cache key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: | bun-${{ runner.os }}- - run: bun install --frozen-lockfile - run: bun run typecheck - run: bun test build: needs: verify runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 with: bun-version: 1.3.14 - name: Cache the bun install store uses: actions/cache@v4 with: path: ~/.bun/install/cache key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} restore-keys: | bun-${{ runner.os }}- - run: bun install --frozen-lockfile # Bun cross-compiles every target from one host, so no build matrix is needed. # release.ts also fails the build when the tag and src/version.ts disagree. - run: bun run release - name: Check the binaries report the right version and are non-empty run: | for f in dist/release/shiro-linux-x64 dist/release/shiro-linux-arm64 \ dist/release/shiro-darwin-x64 dist/release/shiro-darwin-arm64; do [ -s "$f" ] || { echo "$f is missing or empty"; exit 1; } done chmod +x dist/release/shiro-linux-x64 ./dist/release/shiro-linux-x64 --version ./dist/release/shiro-linux-x64 --version | grep -q "$(bun -e 'console.log((await import("./src/version.ts")).VERSION)')" - uses: actions/upload-artifact@v4 with: name: shiro-binaries path: dist/release/ retention-days: 7 publish: needs: build # Tag pushes always publish. A manual dispatch publishes only when dry_run is # unchecked (false); the default true builds and verifies without a release. if: >- startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && inputs.dry_run == false) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 with: bun-version: 1.3.14 - uses: actions/download-artifact@v4 with: name: shiro-binaries path: dist/release # Release body: a short summary plus the artifact inventory, so the release # page reads like a hand-written one instead of the raw PR list. The changelog # is the prose; scripts/make-release-notes.ts extracts the section for this tag # and fails if the heading is missing, rather than publishing an empty body. - name: Compose release notes env: RELEASE_TAG: ${{ github.ref_name }} run: bun run scripts/make-release-notes.ts - name: Publish the release env: GH_TOKEN: ${{ github.token }} run: | gh release create "${{ github.ref_name }}" \ --title "shiro-neko ${{ github.ref_name }}" \ --notes-file release_notes.md \ $([[ "${{ github.ref_name }}" == *-* ]] && echo --prerelease) \ dist/release/*