name: Release on: push: tags: - 'v*.*.*' concurrency: group: release-${{ github.ref }} cancel-in-progress: false jobs: # ============================================================ # Job 1: Build jsc binaries for all 6 platforms (matrix) # ============================================================ build-jsc: name: Build jsc (${{ matrix.goos }}/${{ matrix.goarch }}) runs-on: ubuntu-latest strategy: matrix: include: - goos: linux goarch: amd64 npm_pkg: jsc-linux-x64 binary: jsc - goos: linux goarch: arm64 npm_pkg: jsc-linux-arm64 binary: jsc - goos: darwin goarch: amd64 npm_pkg: jsc-darwin-x64 binary: jsc - goos: darwin goarch: arm64 npm_pkg: jsc-darwin-arm64 binary: jsc - goos: windows goarch: amd64 npm_pkg: jsc-win32-x64 binary: jsc.exe - goos: windows goarch: arm64 npm_pkg: jsc-win32-arm64 binary: jsc.exe steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: '1.26' cache-dependency-path: packages/jsc/go.sum - name: Build working-directory: packages/jsc env: CGO_ENABLED: '0' GOOS: ${{ matrix.goos }} GOARCH: ${{ matrix.goarch }} run: | mkdir -p ../../dist/${{ matrix.npm_pkg }}/bin go build -ldflags="-s -w" -o "../../dist/${{ matrix.npm_pkg }}/bin/${{ matrix.binary }}" . - name: Upload artifact uses: actions/upload-artifact@v4 with: name: ${{ matrix.npm_pkg }} path: dist/${{ matrix.npm_pkg }}/bin/${{ matrix.binary }} # ============================================================ # Job 2: Publish all packages (depends on jsc build) # ============================================================ publish: name: Publish to npm and GitHub needs: build-jsc runs-on: ubuntu-latest permissions: contents: write # 创建 GitHub Release id-token: write # npm Trusted Publishing (OIDC) steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # 需要全部历史,用于生成 release notes - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: pnpm registry-url: https://registry.npmjs.org/ - name: Install dependencies run: pnpm install --no-frozen-lockfile - name: Ensure npm supports Trusted Publishing (OIDC) run: npm install -g npm@latest - name: Build all packages run: pnpm --filter "./packages/*" build - name: Verify version matches tag id: ver run: | set -e TAG="${GITHUB_REF_NAME}" VERSION="${TAG#v}" echo "tag=$TAG" >> "$GITHUB_OUTPUT" echo "version=$VERSION" >> "$GITHUB_OUTPUT" for pkg in plugin-sdk plugin-builder create-songloft-plugin jsc; do PKG_VER=$(node -p "require('./packages/$pkg/package.json').version") if [ "$PKG_VER" != "$VERSION" ]; then echo "❌ packages/$pkg/package.json version=$PKG_VER does not match tag=$VERSION" exit 1 fi done echo "✅ all packages aligned at $VERSION" - name: Download jsc artifacts uses: actions/download-artifact@v4 with: path: artifacts/ - name: Prepare jsc platform packages env: VERSION: ${{ steps.ver.outputs.version }} run: | set -e for pkg in jsc-linux-x64 jsc-linux-arm64 jsc-darwin-x64 jsc-darwin-arm64 jsc-win32-x64 jsc-win32-arm64; do PKG_DIR="packages/$pkg" # Copy binary from artifact mkdir -p "$PKG_DIR/bin" cp artifacts/$pkg/* "$PKG_DIR/bin/" chmod +x "$PKG_DIR/bin/"* 2>/dev/null || true echo "✅ $pkg prepared (v$VERSION)" done - name: Publish all packages to npm # 先发布 jsc 平台子包(被 @songloft/jsc 主包 optionalDependencies 引用) # 再发布其他所有包(含 @songloft/jsc 主包) run: | set -e # 1. Publish jsc platform sub-packages first for pkg in jsc-linux-x64 jsc-linux-arm64 jsc-darwin-x64 jsc-darwin-arm64 jsc-win32-x64 jsc-win32-arm64; do echo "Publishing @songloft/$pkg..." cd "packages/$pkg" npm publish --access public --provenance || echo "⚠️ $pkg publish failed (may already exist)" cd ../.. done # 2. Publish remaining packages (plugin-sdk, plugin-builder, create-songloft-plugin, jsc) pnpm --filter "./packages/plugin-sdk" publish --access public --no-git-checks pnpm --filter "./packages/plugin-builder" publish --access public --no-git-checks pnpm --filter "./packages/create-songloft-plugin" publish --access public --no-git-checks pnpm --filter "./packages/jsc" publish --access public --no-git-checks env: NPM_CONFIG_PROVENANCE: 'true' - name: Generate release notes id: notes env: TAG: ${{ steps.ver.outputs.tag }} run: | set -e PREV=$(git tag --list 'v*.*.*' --sort=-v:refname | grep -v "^${TAG}$" | head -n 1 || true) { echo "## What's Changed" echo if [ -n "$PREV" ]; then echo "**Full Changelog**: https://github.com/${GITHUB_REPOSITORY}/compare/${PREV}...${TAG}" echo git log "${PREV}..${TAG}" --pretty=format:'- %s (%h)' --no-merges else echo "Initial release." echo git log "${TAG}" --pretty=format:'- %s (%h)' --no-merges -n 50 fi echo echo echo "## Published Packages" echo VER="${TAG#v}" echo "- \`@songloft/plugin-sdk@${VER}\`" echo "- \`@songloft/plugin-builder@${VER}\`" echo "- \`create-songloft-plugin@${VER}\`" echo "- \`@songloft/jsc@${VER}\`" echo "- \`@songloft/jsc-linux-x64@${VER}\`" echo "- \`@songloft/jsc-linux-arm64@${VER}\`" echo "- \`@songloft/jsc-darwin-x64@${VER}\`" echo "- \`@songloft/jsc-darwin-arm64@${VER}\`" echo "- \`@songloft/jsc-win32-x64@${VER}\`" echo "- \`@songloft/jsc-win32-arm64@${VER}\`" } > RELEASE_NOTES.md cat RELEASE_NOTES.md - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.ver.outputs.tag }} name: ${{ steps.ver.outputs.tag }} body_path: RELEASE_NOTES.md draft: false prerelease: false