chore: harden install script for preview releases (#18) #27
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: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*.*.*" | |
| branches: | |
| - main | |
| permissions: | |
| contents: write | |
| id-token: write | |
| packages: write | |
| jobs: | |
| build-linux: | |
| name: Build Linux Executables | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version.outputs.VERSION }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Set version in package.json | |
| id: version | |
| run: | | |
| if [[ "$GITHUB_REF" == refs/tags/v* ]]; then | |
| # For tagged releases, use the tag version | |
| VERSION="${GITHUB_REF#refs/tags/v}" | |
| else | |
| # For main branch, generate prerelease version | |
| CURRENT_VERSION=$(bun -e "console.log(require('./package.json').version)") | |
| COMMIT_SHA=${GITHUB_SHA::7} | |
| VERSION="${CURRENT_VERSION}-preview.${COMMIT_SHA}" | |
| fi | |
| echo "Setting version to: ${VERSION}" | |
| echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT | |
| npm version "${VERSION}" --no-git-tag-version --allow-same-version | |
| - name: Build for Linux x64 | |
| run: bun run build:linux-x64 | |
| - name: Build for Linux ARM64 | |
| run: bun run build:linux-arm64 | |
| - name: Upload Linux executables | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: grove-linux-executables | |
| path: | | |
| grove-linux-x64 | |
| grove-linux-arm64 | |
| build-macos: | |
| name: Build and Sign macOS Executables | |
| runs-on: macos-latest | |
| needs: build-linux | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Set version in package.json | |
| run: npm version "${{ needs.build-linux.outputs.version }}" --no-git-tag-version --allow-same-version | |
| - name: Build for macOS x64 | |
| run: bun run build:darwin-x64 | |
| - name: Build for macOS ARM64 | |
| run: bun run build:darwin-arm64 | |
| - name: Import Code Signing Certificate | |
| env: | |
| MACOS_CERT_P12_BASE64: ${{ secrets.MACOS_CERT_P12_BASE64 }} | |
| MACOS_CERT_P12_PASSWORD: ${{ secrets.MACOS_CERT_P12_PASSWORD }} | |
| run: | | |
| # Create a temporary keychain | |
| KEYCHAIN_PATH=$RUNNER_TEMP/signing.keychain-db | |
| KEYCHAIN_PASSWORD=$(openssl rand -base64 32) | |
| # Decode the certificate | |
| echo "$MACOS_CERT_P12_BASE64" | base64 --decode > $RUNNER_TEMP/certificate.p12 | |
| # Create and configure keychain | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| # Import certificate | |
| security import $RUNNER_TEMP/certificate.p12 -P "$MACOS_CERT_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| # Clean up certificate file | |
| rm $RUNNER_TEMP/certificate.p12 | |
| - name: Sign macOS Binaries | |
| run: | | |
| # Find the signing identity | |
| IDENTITY=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk -F'"' '{print $2}') | |
| echo "Signing with identity: $IDENTITY" | |
| # Sign both binaries with JIT entitlements | |
| codesign --force --options runtime --timestamp --entitlements .github/workflows/assets/entitlements.plist --sign "$IDENTITY" grove-darwin-x64 | |
| codesign --force --options runtime --timestamp --entitlements .github/workflows/assets/entitlements.plist --sign "$IDENTITY" grove-darwin-arm64 | |
| # Verify signatures | |
| codesign --verify --verbose grove-darwin-x64 | |
| codesign --verify --verbose grove-darwin-arm64 | |
| - name: Notarize macOS Binaries | |
| env: | |
| APPLE_ID_EMAIL: ${{ secrets.APPLE_ID_EMAIL }} | |
| APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} | |
| run: | | |
| # Create zip files for notarization | |
| zip grove-darwin-x64.zip grove-darwin-x64 | |
| zip grove-darwin-arm64.zip grove-darwin-arm64 | |
| # Get team ID from signing identity | |
| TEAM_ID=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | sed -n 's/.*(\([A-Z0-9]*\)).*/\1/p') | |
| # Notarize x64 binary | |
| xcrun notarytool submit grove-darwin-x64.zip \ | |
| --apple-id "$APPLE_ID_EMAIL" \ | |
| --password "$APPLE_APP_SPECIFIC_PASSWORD" \ | |
| --team-id "$TEAM_ID" \ | |
| --wait | |
| # Notarize ARM64 binary | |
| xcrun notarytool submit grove-darwin-arm64.zip \ | |
| --apple-id "$APPLE_ID_EMAIL" \ | |
| --password "$APPLE_APP_SPECIFIC_PASSWORD" \ | |
| --team-id "$TEAM_ID" \ | |
| --wait | |
| # Clean up zip files | |
| rm grove-darwin-x64.zip grove-darwin-arm64.zip | |
| - name: Upload macOS executables | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: grove-macos-executables | |
| path: | | |
| grove-darwin-x64 | |
| grove-darwin-arm64 | |
| prerelease: | |
| name: Prerelease | |
| runs-on: ubuntu-latest | |
| needs: [build-linux, build-macos] | |
| if: github.ref == 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download Linux executables | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: grove-linux-executables | |
| path: ./executables | |
| - name: Download macOS executables | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: grove-macos-executables | |
| path: ./executables | |
| - name: Create GitHub Preview Release | |
| uses: softprops/action-gh-release@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: v${{ needs.build-linux.outputs.version }} | |
| name: Preview v${{ needs.build-linux.outputs.version }} | |
| body: | | |
| ## Preview Release | |
| This is an automated preview release from the `main` branch. | |
| **Commit:** ${{ github.sha }} | |
| ## Installation | |
| ```bash | |
| curl -fsSL https://safia.rocks/grove/install.sh | sh -s -- v${{ needs.build-linux.outputs.version }} | |
| ``` | |
| ## Manual Downloads | |
| | Platform | Architecture | Download | | |
| |----------|--------------|----------| | |
| | Linux | x64 | `grove-linux-x64` | | |
| | Linux | ARM64 | `grove-linux-arm64` | | |
| | macOS | x64 | `grove-darwin-x64` (signed & notarized) | | |
| | macOS | ARM64 | `grove-darwin-arm64` (signed & notarized) | | |
| draft: false | |
| prerelease: true | |
| files: | | |
| ./executables/grove-linux-x64 | |
| ./executables/grove-linux-arm64 | |
| ./executables/grove-darwin-x64 | |
| ./executables/grove-darwin-arm64 | |
| release: | |
| name: Release | |
| runs-on: ubuntu-latest | |
| needs: [build-linux, build-macos] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| registry-url: "https://registry.npmjs.org" | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Extract version from tag | |
| id: version | |
| run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT | |
| - name: Update package.json version | |
| run: npm version ${{ steps.version.outputs.VERSION }} --no-git-tag-version --allow-same-version | |
| - name: Build | |
| run: bun run build | |
| - name: Publish to npm | |
| run: npm publish --provenance --access public | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Set up Node.js for GitHub Packages | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| registry-url: "https://npm.pkg.github.com" | |
| scope: "@captainsafia" | |
| - name: Publish to GitHub Packages | |
| run: npm publish | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download Linux executables | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: grove-linux-executables | |
| path: ./executables | |
| - name: Download macOS executables | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: grove-macos-executables | |
| path: ./executables | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: ${{ github.ref_name }} | |
| name: Release ${{ github.ref_name }} | |
| body: | | |
| ## Installation | |
| ```bash | |
| curl -fsSL https://safia.rocks/grove/install.sh | sh -s -- ${{ github.ref_name }} | |
| ``` | |
| ## Manual Downloads | |
| | Platform | Architecture | Download | | |
| |----------|--------------|----------| | |
| | Linux | x64 | `grove-linux-x64` | | |
| | Linux | ARM64 | `grove-linux-arm64` | | |
| | macOS | x64 | `grove-darwin-x64` (signed & notarized) | | |
| | macOS | ARM64 | `grove-darwin-arm64` (signed & notarized) | | |
| ## Changes | |
| See the [commits](https://github.com/captainsafia/grove/compare/v${{ steps.version.outputs.VERSION }}...HEAD) for details. | |
| draft: false | |
| prerelease: false | |
| files: | | |
| ./executables/grove-linux-x64 | |
| ./executables/grove-linux-arm64 | |
| ./executables/grove-darwin-x64 | |
| ./executables/grove-darwin-arm64 |