name: Build
on:
release:
types: [created]
permissions:
contents: write
jobs:
build:
name: ${{ matrix.target }}
if: startsWith(github.event.release.tag_name, 'v')
runs-on: ${{ matrix.os }}
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT_DAEMON }}
BYOKEY_SENTRY_DSN: ${{ secrets.BYOKEY_DAEMON_SENTRY_DSN }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-22.04
- target: aarch64-unknown-linux-gnu
os: ubuntu-22.04-arm
- target: x86_64-apple-darwin
os: macos-latest
- target: aarch64-apple-darwin
os: macos-latest
- target: x86_64-pc-windows-msvc
os: windows-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Install protoc
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Build
shell: bash
run: cargo build --release --target ${{ matrix.target }}
- name: Install sentry-cli (Unix)
if: env.SENTRY_AUTH_TOKEN != '' && runner.os != 'Windows'
shell: bash
run: curl -sL https://sentry.io/get-cli/ | INSTALL_DIR=/usr/local/bin bash
- name: Upload Rust debug symbols to Sentry
if: env.SENTRY_AUTH_TOKEN != '' && runner.os != 'Windows'
shell: bash
run: |
sentry-cli debug-files upload \
--include-sources \
"target/${{ matrix.target }}/release/"
- name: Package (Unix)
if: github.event_name == 'release' && runner.os != 'Windows'
shell: bash
run: |
BIN="target/${{ matrix.target }}/release/byokey"
ARCHIVE="byokey-${{ github.event.release.tag_name }}-${{ matrix.target }}.tar.gz"
tar czf "$ARCHIVE" -C "$(dirname "$BIN")" "$(basename "$BIN")"
echo "ASSET=$ARCHIVE" >> "$GITHUB_ENV"
- name: Package (Windows)
if: github.event_name == 'release' && runner.os == 'Windows'
shell: pwsh
run: |
$archive = "byokey-${{ github.event.release.tag_name }}-${{ matrix.target }}.zip"
Compress-Archive -Path "target\${{ matrix.target }}\release\byokey.exe" -DestinationPath $archive
"ASSET=$archive" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: Upload to Release
if: github.event_name == 'release'
uses: softprops/action-gh-release@v2
with:
files: ${{ env.ASSET }}
desktop:
name: Desktop ${{ matrix.arch }}
if: startsWith(github.event.release.tag_name, 'v')
runs-on: macos-latest
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT_DESKTOP }}
BYOKEY_SENTRY_DSN: ${{ secrets.BYOKEY_DESKTOP_SENTRY_DSN }}
strategy:
fail-fast: false
matrix:
include:
- arch: arm64
rust_target: aarch64-apple-darwin
build_suffix: "1"
- arch: x86_64
rust_target: x86_64-apple-darwin
build_suffix: "2"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.rust_target }}
- uses: Swatinem/rust-cache@v2
with:
key: desktop-${{ matrix.arch }}
- name: Install protoc
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Import certificate
uses: apple-actions/import-codesign-certs@v3
with:
p12-file-base64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
- name: Verify certificate
run: security find-identity -v -p codesigning
- name: Install App Store Connect API key
env:
APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
run: |
mkdir -p ~/private_keys
echo "$APPLE_API_KEY_BASE64" | base64 --decode \
> ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8
- name: Parse version from tag
run: |
TAG="${{ github.event.release.tag_name }}"
echo "VERSION=${TAG#v}" >> "$GITHUB_ENV"
- name: Archive
run: |
xcodebuild archive \
-project desktop/Byokey.xcodeproj \
-scheme Byokey \
-configuration Release \
-archivePath "$RUNNER_TEMP/Byokey.xcarchive" \
ARCHS="${{ matrix.arch }}" \
ONLY_ACTIVE_ARCH=NO \
MARKETING_VERSION="$VERSION" \
CURRENT_PROJECT_VERSION="${{ github.run_number }}.${{ matrix.build_suffix }}" \
CODE_SIGN_STYLE=Manual \
"CODE_SIGN_IDENTITY=Developer ID Application" \
DEVELOPMENT_TEAM=8U3ZJ258K9 \
PRODUCT_BUNDLE_IDENTIFIER=io.byokey.desktop \
"OTHER_CODE_SIGN_FLAGS=--timestamp --options=runtime" \
"BYOKEY_SENTRY_DSN=$BYOKEY_SENTRY_DSN"
- name: Install sentry-cli
if: env.SENTRY_AUTH_TOKEN != ''
run: curl -sL https://sentry.io/get-cli/ | INSTALL_DIR=/usr/local/bin bash
- name: Upload dSYM to Sentry
if: env.SENTRY_AUTH_TOKEN != ''
run: |
sentry-cli debug-files upload \
--include-sources \
"$RUNNER_TEMP/Byokey.xcarchive/dSYMs/"
- name: Export archive
run: |
xcodebuild -exportArchive \
-archivePath "$RUNNER_TEMP/Byokey.xcarchive" \
-exportOptionsPlist desktop/ExportOptions.plist \
-exportPath "$RUNNER_TEMP/export"
- name: Create DMG
run: |
brew install create-dmg
DMG_NAME="Byokey-${{ github.event.release.tag_name }}-${{ matrix.arch }}.dmg"
DMG_PATH="$RUNNER_TEMP/$DMG_NAME"
create-dmg \
--volname "Byokey" \
--window-pos 200 120 \
--window-size 600 400 \
--icon-size 100 \
--icon "Byokey.app" 175 190 \
--app-drop-link 425 190 \
"$DMG_PATH" \
"$RUNNER_TEMP/export/Byokey.app"
echo "DMG_NAME=$DMG_NAME" >> "$GITHUB_ENV"
echo "DMG_PATH=$DMG_PATH" >> "$GITHUB_ENV"
- name: Notarize
env:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }}
run: |
xcrun notarytool submit "$DMG_PATH" \
--key ~/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8 \
--key-id "$APPLE_API_KEY_ID" \
--issuer "$APPLE_API_ISSUER_ID" \
--wait
- name: Staple
run: xcrun stapler staple "$DMG_PATH"
- name: Upload DMG to Release
uses: softprops/action-gh-release@v2
with:
files: ${{ env.DMG_PATH }}
update-appcast:
name: Update Appcast
if: startsWith(github.event.release.tag_name, 'v')
needs: desktop
runs-on: macos-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download Sparkle
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p /tmp/sparkle
gh release download --repo sparkle-project/Sparkle \
--pattern 'Sparkle-*.tar.xz' -D /tmp/sparkle
tar xf /tmp/sparkle/Sparkle-*.tar.xz -C /tmp/sparkle
- name: Prepare release directory
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p /tmp/release
# Preserve existing appcast entries (remove if empty to avoid XML parse error)
git show origin/gh-pages:appcast.xml > /tmp/release/appcast.xml 2>/dev/null || rm -f /tmp/release/appcast.xml
# Download both arm64 and x86_64 DMGs; generate_appcast creates
# separate <item> entries with matching hardwareRequirements
gh release download "${{ github.event.release.tag_name }}" \
--pattern 'Byokey-*.dmg' -D /tmp/release
- name: Generate appcast
env:
SPARKLE_ED_PRIVATE_KEY: ${{ secrets.SPARKLE_ED_PRIVATE_KEY }}
run: |
TAG="${{ github.event.release.tag_name }}"
KEY_FILE=$(mktemp)
printf '%s' "$SPARKLE_ED_PRIVATE_KEY" > "$KEY_FILE"
trap "rm -f $KEY_FILE" EXIT
/tmp/sparkle/bin/generate_appcast /tmp/release \
--ed-key-file "$KEY_FILE" \
--download-url-prefix \
"https://github.com/AprilNEA/BYOKEY/releases/download/${TAG}/"
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: /tmp/release
publish_branch: gh-pages
keep_files: true
exclude_assets: '**.dmg'
update-homebrew:
name: Update Homebrew
needs: build
if: always() && github.event_name == 'release' && !cancelled() && startsWith(github.event.release.tag_name, 'v')
runs-on: ubuntu-latest
steps:
- name: Generate token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.RELEASE_APP_ID }}
private-key: ${{ secrets.RELEASE_APP_KEY }}
repositories: homebrew-tap
- name: Trigger homebrew-tap update
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ steps.app-token.outputs.token }}
repository: AprilNEA/homebrew-tap
event-type: update-formula
client-payload: '{"version": "${{ github.event.release.tag_name }}"}'