Merge pull request #283 from cooklang/release-please--branches--main-… #217
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
| # based on https://github.com/starship/starship workflow | |
| name: Release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| env: | |
| CARGO_INCREMENTAL: 0 | |
| CARGO_NET_RETRY: 10 | |
| RUST_BACKTRACE: short | |
| RUSTUP_MAX_RETRIES: 5 | |
| MACOSX_DEPLOYMENT_TARGET: 10.7 | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| packages: write | |
| id-token: write | |
| jobs: | |
| # Update release PR | |
| release_please: | |
| name: Release Please | |
| runs-on: ubuntu-latest | |
| if: github.repository == 'cooklang/cookcli' | |
| outputs: | |
| release_created: ${{ steps.release.outputs.release_created }} | |
| tag_name: ${{ steps.release.outputs.tag_name }} | |
| steps: | |
| - uses: googleapis/release-please-action@v4 | |
| id: release | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| release-type: rust | |
| draft: true | |
| # Build sources for every OS | |
| github_build: | |
| name: Build release binaries | |
| needs: release_please | |
| if: ${{ needs.release_please.outputs.release_created == 'true' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: x86_64-unknown-linux-gnu | |
| os: ubuntu-latest | |
| name: cook-x86_64-unknown-linux-gnu.tar.gz | |
| - target: x86_64-unknown-linux-musl | |
| os: ubuntu-latest | |
| name: cook-x86_64-unknown-linux-musl.tar.gz | |
| - target: i686-unknown-linux-musl | |
| os: ubuntu-latest | |
| name: cook-i686-unknown-linux-musl.tar.gz | |
| - target: aarch64-unknown-linux-musl | |
| os: ubuntu-latest | |
| name: cook-aarch64-unknown-linux-musl.tar.gz | |
| - target: arm-unknown-linux-musleabihf | |
| os: ubuntu-latest | |
| name: cook-arm-unknown-linux-musleabihf.tar.gz | |
| - target: x86_64-apple-darwin | |
| os: macos-15-intel | |
| name: cook-x86_64-apple-darwin.tar.gz | |
| notarize: true | |
| - target: aarch64-apple-darwin | |
| os: macos-14 | |
| name: cook-aarch64-apple-darwin.tar.gz | |
| notarize: true | |
| - target: x86_64-pc-windows-msvc | |
| os: windows-latest | |
| name: cook-x86_64-pc-windows-msvc.zip | |
| rustflags: -C target-feature=+crt-static | |
| - target: i686-pc-windows-msvc | |
| os: windows-latest | |
| name: cook-i686-pc-windows-msvc.zip | |
| rustflags: -C target-feature=+crt-static | |
| - target: aarch64-pc-windows-msvc | |
| os: windows-latest | |
| name: cook-aarch64-pc-windows-msvc.zip | |
| rustflags: -C target-feature=+crt-static | |
| - target: x86_64-unknown-freebsd | |
| os: ubuntu-latest | |
| name: cook-x86_64-unknown-freebsd.tar.gz | |
| runs-on: ${{ matrix.os }} | |
| continue-on-error: true | |
| env: | |
| RUSTFLAGS: ${{ matrix.rustflags || '' }} | |
| steps: | |
| - name: Setup | Checkout | |
| uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18' | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Build CSS | |
| run: npm run build-css | |
| - name: Build JS | |
| run: npm run build-js | |
| - name: Setup | Rust | |
| uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: stable | |
| target: ${{ matrix.target }} | |
| - name: Setup | Cache | |
| uses: Swatinem/rust-cache@v2 | |
| - name: Setup | Install cargo-wix [Windows] | |
| continue-on-error: true | |
| # aarch64 is only supported in wix 4.0 development builds | |
| if: matrix.os == 'windows-latest' && matrix.target != 'aarch64-pc-windows-msvc' | |
| run: cargo install --version 0.3.4 cargo-wix | |
| env: | |
| # cargo-wix does not require static crt | |
| RUSTFLAGS: "" | |
| - name: Setup | Install cross [Linux] | |
| if: matrix.os == 'ubuntu-latest' | |
| uses: taiki-e/install-action@cross | |
| - name: Build | Build [Cargo] | |
| if: matrix.os != 'ubuntu-latest' | |
| run: cargo build --release --locked --target ${{ matrix.target }} | |
| - name: Build | Build [Cross] | |
| if: matrix.os == 'ubuntu-latest' | |
| run: cross build --release --locked --target ${{ matrix.target }} | |
| - name: Build | Installer [Windows] | |
| continue-on-error: true | |
| if: matrix.os == 'windows-latest' && matrix.target != 'aarch64-pc-windows-msvc' | |
| run: > | |
| cargo wix -v --no-build --nocapture -I install/windows/main.wxs | |
| --target ${{ matrix.target }} | |
| --output target/wix/cook-${{ matrix.target }}.msi | |
| # Sign and notarize macOS binaries before packaging | |
| - name: Notarize | Sign and Notarize [macOS] | |
| if: matrix.notarize == true | |
| env: | |
| APP_CERTIFICATE_BASE64: ${{ secrets.APPLEDEV_APPSIGNKEY_BASE64 }} | |
| P12_PASSWORD: ${{ secrets.APPLEDEV_SIGNKEY_PASS }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.APPLEDEV_SIGNKEY_PASS }} | |
| APPLEID_USERNAME: ${{ secrets.APPLEDEV_ID_NAME }} | |
| APPLEID_TEAMID: ${{ secrets.APPLEDEV_TEAM_ID }} | |
| APPLEID_PASSWORD: ${{ secrets.APPLEDEV_PASSWORD }} | |
| APPLICATION_KEY_IDENT: ${{ secrets.APPLEDEV_KEY_IDENT }} | |
| run: | | |
| # Setup variables | |
| BINARY_PATH="target/${{ matrix.target }}/release/cook" | |
| KEYCHAIN_FILENAME="app-signing.keychain-db" | |
| KEYCHAIN_ENTRY="AC_PASSWORD" | |
| APP_CERTIFICATE_PATH="$RUNNER_TEMP/app_certificate.p12" | |
| KEYCHAIN_PATH="$RUNNER_TEMP/$KEYCHAIN_FILENAME" | |
| # Import certificates from secrets | |
| echo -n "$APP_CERTIFICATE_BASE64" | base64 --decode -o $APP_CERTIFICATE_PATH | |
| # Create temporary 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 certificates to keychain | |
| security import $APP_CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| # Add Apple Developer ID credentials to keychain | |
| xcrun notarytool store-credentials "$KEYCHAIN_ENTRY" \ | |
| --team-id "$APPLEID_TEAMID" \ | |
| --apple-id "$APPLEID_USERNAME" \ | |
| --password "$APPLEID_PASSWORD" \ | |
| --keychain "$KEYCHAIN_PATH" | |
| echo ">>>> Signing binary" | |
| codesign --timestamp \ | |
| --keychain $KEYCHAIN_PATH \ | |
| --sign "$APPLICATION_KEY_IDENT" \ | |
| --options runtime \ | |
| --force \ | |
| --verbose \ | |
| "$BINARY_PATH" | |
| # Verify signing | |
| echo ">>>> Verifying signature" | |
| codesign --verify --verbose "$BINARY_PATH" | |
| # Make ZIP file for notarization (must be a zip for notarization) | |
| echo ">>>> Creating ZIP for notarization" | |
| cd "target/${{ matrix.target }}/release" | |
| zip -r cook-notarize.zip cook | |
| echo ">>>> Submitting for notarization" | |
| xcrun notarytool submit cook-notarize.zip \ | |
| --keychain-profile "$KEYCHAIN_ENTRY" \ | |
| --keychain "$KEYCHAIN_PATH" \ | |
| --wait \ | |
| --timeout 30m \ | |
| --verbose | |
| echo ">>>> Checking notarization status" | |
| xcrun notarytool log \ | |
| $(xcrun notarytool history --keychain-profile "$KEYCHAIN_ENTRY" --keychain "$KEYCHAIN_PATH" 2>&1 | grep -m1 "id:" | awk '{print $2}') \ | |
| --keychain-profile "$KEYCHAIN_ENTRY" \ | |
| --keychain "$KEYCHAIN_PATH" | |
| # Note: We can't staple to a standalone binary, only to app bundles, DMGs, or PKGs | |
| # But the notarization is still recorded with Apple and will be checked online | |
| echo ">>>> Verifying notarization" | |
| spctl -a -t open --context context:primary-signature -v cook || true | |
| # Clean up | |
| rm cook-notarize.zip | |
| cd - | |
| # Clean up keychain | |
| security delete-keychain $KEYCHAIN_PATH | |
| - name: Post Build | Prepare artifacts [Windows] | |
| if: matrix.os == 'windows-latest' | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| 7z a ../../../${{ matrix.name }} cook.exe | |
| cd - | |
| - name: Post Build | Prepare artifacts [-nix] | |
| if: matrix.os != 'windows-latest' | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| tar czvf ../../../${{ matrix.name }} cook | |
| cd - | |
| - name: Release | Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.name }} | |
| path: ${{ matrix.name }} | |
| - name: Release | Upload installer artifacts [Windows] | |
| continue-on-error: true | |
| if: matrix.os == 'windows-latest' && matrix.target != 'aarch64-pc-windows-msvc' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: cook-${{ matrix.target }}.msi | |
| path: target/wix/cook-${{ matrix.target }}.msi | |
| # Create GitHub release with Rust build targets and release notes | |
| upload_artifacts: | |
| name: Add Build Artifacts to Release | |
| needs: [release_please, github_build] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Setup | Artifacts | |
| uses: actions/download-artifact@v4 | |
| - name: Setup | Checksums | |
| run: for file in cook-*/cook-*; do openssl dgst -sha256 -r "$file" | awk '{print $1}' > "${file}.sha256"; done | |
| - name: Setup | Publish Release | |
| run: gh release edit ${{ needs.release_please.outputs.tag_name }} --draft=false --repo=cooklang/cookcli | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build | Add Artifacts to Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| files: cook-*/cook-* | |
| tag_name: ${{ needs.release_please.outputs.tag_name }} | |
| # Publish to crates.io | |
| publish_crates: | |
| name: Publish to crates.io | |
| needs: release_please | |
| if: ${{ needs.release_please.outputs.release_created == 'true' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Setup | Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '18' | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Build CSS | |
| run: npm run build-css | |
| - name: Build JS | |
| run: npm run build-js | |
| - name: Setup | Rust | |
| uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: stable | |
| - name: Authenticate to crates.io | |
| uses: rust-lang/crates-io-auth-action@v1 | |
| id: auth | |
| - name: Publish | crates.io | |
| run: cargo publish --allow-dirty | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} | |
| # Build and push Docker image to GHCR | |
| docker_publish: | |
| name: Build Docker image (${{ matrix.platform }}) | |
| needs: release_please | |
| if: ${{ needs.release_please.outputs.release_created == 'true' }} | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-latest | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| steps: | |
| - name: Setup | Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup | Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract version from tag | |
| id: version | |
| run: echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" | |
| env: | |
| TAG: ${{ needs.release_please.outputs.tag_name }} | |
| - name: Build and push | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| platforms: ${{ matrix.platform }} | |
| push: true | |
| tags: ghcr.io/cooklang/cookcli:build-${{ strategy.job-index }} | |
| cache-from: type=gha,scope=${{ matrix.platform }} | |
| cache-to: type=gha,scope=${{ matrix.platform }},mode=max | |
| docker_merge: | |
| name: Create multi-arch manifest | |
| needs: [release_please, docker_publish] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract version from tag | |
| id: version | |
| run: echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" | |
| env: | |
| TAG: ${{ needs.release_please.outputs.tag_name }} | |
| - name: Create and push manifest | |
| run: | | |
| docker buildx imagetools create \ | |
| -t ghcr.io/cooklang/cookcli:${{ steps.version.outputs.version }} \ | |
| -t ghcr.io/cooklang/cookcli:latest \ | |
| ghcr.io/cooklang/cookcli:build-0 \ | |
| ghcr.io/cooklang/cookcli:build-1 | |