Skip to content

ci: use GitHub-hosted macOS release runner (#3) #3

ci: use GitHub-hosted macOS release runner (#3)

ci: use GitHub-hosted macOS release runner (#3) #3

Workflow file for this run

name: release
on:
push:
tags:
- "v*"
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
verify:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: useblacksmith/checkout@v1
- uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
components: rustfmt, clippy
- name: Verify release tag matches Cargo version
shell: bash
run: |
version=$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -1)
escaped_version=${version//./\.}
if [[ $GITHUB_REF_NAME != "v$version" \
&& ! $GITHUB_REF_NAME =~ ^v${escaped_version}-pre(\.[0-9]+)?$ ]]; then
echo "expected v${version}, v${version}-pre, or v${version}-pre.N" >&2
exit 1
fi
- run: cargo fmt --check
- run: cargo clippy --locked --all-targets --all-features -- -D warnings
- run: cargo test --locked
linux-x64:
needs: verify
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- uses: useblacksmith/checkout@v1
- uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
targets: x86_64-unknown-linux-gnu
- name: Build and package
shell: bash
run: |
version=${GITHUB_REF_NAME#v}
cargo build --locked --release --target x86_64-unknown-linux-gnu
mkdir -p stage dist
cp target/x86_64-unknown-linux-gnu/release/kit stage/kit
stage/kit --version
tar -C stage -czf "dist/kit-v${version}-x86_64-unknown-linux-gnu.tar.gz" kit
- uses: actions/upload-artifact@v4
with:
name: kit-linux-x64
path: dist/*
if-no-files-found: error
macos-arm64:
needs: verify
runs-on: macos-15
outputs:
signed: ${{ steps.signing.outputs.enabled }}
env:
MACOS_CERTIFICATE_P12_BASE64: ${{ secrets.MACOS_CERTIFICATE_P12_BASE64 }}
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
APPLE_API_KEY_P8_BASE64: ${{ secrets.APPLE_API_KEY_P8_BASE64 }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }}
steps:
- uses: useblacksmith/checkout@v1
- uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.94.0
targets: aarch64-apple-darwin
- name: Check optional signing credentials
id: signing
shell: bash
run: |
credentials=(
MACOS_CERTIFICATE_P12_BASE64
MACOS_CERTIFICATE_PASSWORD
MACOS_SIGNING_IDENTITY
APPLE_API_KEY_P8_BASE64
APPLE_API_KEY_ID
APPLE_API_ISSUER_ID
)
configured=0
for name in "${credentials[@]}"; do
if [[ -n ${!name:-} ]]; then
configured=$((configured + 1))
fi
done
if [[ $configured -eq 0 ]]; then
echo "Apple credentials are not configured; building an unsigned macOS release."
echo "enabled=false" >> "$GITHUB_OUTPUT"
elif [[ $configured -eq ${#credentials[@]} ]]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "Apple signing credentials are only partially configured." >&2
exit 1
fi
- name: Import Developer ID certificate
if: steps.signing.outputs.enabled == 'true'
shell: bash
run: |
keychain=$RUNNER_TEMP/kit-signing.keychain-db
certificate=$RUNNER_TEMP/kit-signing.p12
printf '%s' "$MACOS_CERTIFICATE_P12_BASE64" | base64 --decode > "$certificate"
security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" "$keychain"
security set-keychain-settings -lut 21600 "$keychain"
security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" "$keychain"
security import "$certificate" -P "$MACOS_CERTIFICATE_PASSWORD" \
-f pkcs12 -k "$keychain" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: -s \
-k "$MACOS_CERTIFICATE_PASSWORD" "$keychain"
security list-keychains -d user -s "$keychain" login.keychain-db
- name: Build and package
shell: bash
env:
SIGN_RELEASE: ${{ steps.signing.outputs.enabled }}
run: |
version=${GITHUB_REF_NAME#v}
cargo build --locked --release --target aarch64-apple-darwin
mkdir -p stage dist
cp target/aarch64-apple-darwin/release/kit stage/kit
if [[ $SIGN_RELEASE == true ]]; then
codesign --force --options runtime --timestamp \
--identifier com.danielkov.kit \
--sign "$MACOS_SIGNING_IDENTITY" stage/kit
codesign --verify --strict --verbose=2 stage/kit
ditto -c -k --keepParent stage/kit "$RUNNER_TEMP/kit-notarization.zip"
api_key=$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8
trap 'rm -f "$api_key"' EXIT
printf '%s' "$APPLE_API_KEY_P8_BASE64" | base64 --decode > "$api_key"
chmod 600 "$api_key"
notary_log=$RUNNER_TEMP/kit-notarization.log
xcrun notarytool submit "$RUNNER_TEMP/kit-notarization.zip" \
--key "$api_key" \
--key-id "$APPLE_API_KEY_ID" \
--issuer "$APPLE_API_ISSUER_ID" \
--wait 2>&1 | tee "$notary_log"
if ! grep -Eq '(^|[[:space:]])status: Accepted([[:space:]]|$)' "$notary_log"; then
echo "Apple did not accept the notarization submission." >&2
exit 1
fi
fi
stage/kit --version
tar -C stage -czf "dist/kit-v${version}-aarch64-apple-darwin.tar.gz" kit
- uses: actions/upload-artifact@v4
with:
name: kit-macos-arm64
path: dist/*
if-no-files-found: error
publish:
needs: [linux-x64, macos-arm64]
runs-on: blacksmith-2vcpu-ubuntu-2404
permissions:
contents: write
env:
GH_TOKEN: ${{ github.token }}
MACOS_SIGNED: ${{ needs.macos-arm64.outputs.signed }}
steps:
- uses: actions/download-artifact@v4
with:
pattern: kit-*
path: dist
merge-multiple: true
- name: Publish release
shell: bash
run: |
cd dist
sha256sum kit-*.tar.gz > SHA256SUMS
prerelease=false
if [[ $GITHUB_REF_NAME == *-pre* ]]; then
prerelease=true
fi
if [[ $MACOS_SIGNED == true ]]; then
signing_note="The macOS binary is Developer ID signed and notarized."
else
signing_note="The macOS binary is unsigned and not notarized."
fi
title="Kit ${GITHUB_REF_NAME#v}"
notes="Prebuilt Kit binaries. $signing_note"
if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release upload "$GITHUB_REF_NAME" kit-*.tar.gz SHA256SUMS \
--clobber --repo "$GITHUB_REPOSITORY"
else
create_args=(
"$GITHUB_REF_NAME" kit-*.tar.gz SHA256SUMS
--repo "$GITHUB_REPOSITORY"
--title "$title"
--notes "$notes"
)
if [[ $prerelease == true ]]; then
create_args+=(--prerelease)
fi
gh release create "${create_args[@]}"
fi
edit_args=(
"$GITHUB_REF_NAME"
--repo "$GITHUB_REPOSITORY"
--title "$title"
--notes "$notes"
--draft=false
--prerelease="$prerelease"
)
if [[ $prerelease == false ]]; then
edit_args+=(--latest)
fi
gh release edit "${edit_args[@]}"