Skip to content

Merge pull request #283 from cooklang/release-please--branches--main-… #217

Merge pull request #283 from cooklang/release-please--branches--main-…

Merge pull request #283 from cooklang/release-please--branches--main-… #217

Workflow file for this run

# 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