mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
219 lines
7.7 KiB
YAML
219 lines
7.7 KiB
YAML
name: Apple release (macOS DMG)
|
||
|
||
# Builds, signs, notarizes, and publishes the direct-download macOS build:
|
||
# - a Developer ID–signed, notarized VniDrop-<version>.dmg,
|
||
# - a Sparkle appcast.xml (both attached to the GitHub Release), and
|
||
# - an updated Homebrew cask pushed to the sudosylabs/homebrew-vnidrop tap.
|
||
#
|
||
# The App Store / TestFlight build is NOT produced here — that goes through Xcode
|
||
# Organizer / App Store Connect. This workflow only covers direct distribution.
|
||
#
|
||
# Trigger: push the canonical vMAJOR.MINOR.PATCH tag (must point at a commit on
|
||
# master), or run manually using the version committed in version.properties.
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- "v*.*.*"
|
||
workflow_dispatch:
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
concurrency:
|
||
group: apple-release-${{ github.ref }}
|
||
cancel-in-progress: false
|
||
|
||
defaults:
|
||
run:
|
||
shell: bash
|
||
|
||
jobs:
|
||
build:
|
||
name: Build & notarize DMG
|
||
runs-on: macos-latest
|
||
timeout-minutes: 90
|
||
permissions:
|
||
contents: write
|
||
outputs:
|
||
version: ${{ steps.version.outputs.app }}
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||
with:
|
||
fetch-depth: 0
|
||
persist-credentials: false
|
||
|
||
- name: Verify tag is on master
|
||
if: github.event_name == 'push'
|
||
run: |
|
||
if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/master; then
|
||
echo "Release tags must point to a commit on master" >&2
|
||
exit 1
|
||
fi
|
||
|
||
- name: Resolve canonical version
|
||
id: version
|
||
run: |
|
||
packaging/version/resolve-version.sh verify >/dev/null
|
||
version="$(packaging/version/resolve-version.sh product)"
|
||
echo "app=$version" >> "$GITHUB_OUTPUT"
|
||
|
||
- name: Select Xcode
|
||
run: sudo xcode-select -s /Applications/Xcode.app
|
||
|
||
- name: Install Rust toolchain
|
||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # v1
|
||
with:
|
||
toolchain: stable
|
||
targets: aarch64-apple-darwin
|
||
|
||
- name: Cache Cargo
|
||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||
with:
|
||
path: |
|
||
~/.cargo/registry
|
||
~/.cargo/git
|
||
target
|
||
key: apple-release-cargo-${{ hashFiles('Cargo.lock') }}
|
||
restore-keys: apple-release-cargo-
|
||
|
||
- name: Install tooling
|
||
run: brew install xcodegen swiftlint create-dmg
|
||
|
||
- name: Install Bun
|
||
uses: oven-sh/setup-bun@v2
|
||
|
||
- name: Download Sparkle tools
|
||
# generate_appcast + sign_update ship in the Sparkle release tarball.
|
||
run: |
|
||
set -euo pipefail
|
||
ver="2.9.4"
|
||
curl -fsSL -o /tmp/sparkle.tar.xz \
|
||
"https://github.com/sparkle-project/Sparkle/releases/download/${ver}/Sparkle-${ver}.tar.xz"
|
||
mkdir -p /tmp/sparkle && tar -xJf /tmp/sparkle.tar.xz -C /tmp/sparkle
|
||
echo "SPARKLE_BIN=/tmp/sparkle/bin" >> "$GITHUB_ENV"
|
||
|
||
- name: Import Developer ID certificate
|
||
env:
|
||
CERT_P12_BASE64: ${{ secrets.DEVELOPER_ID_CERT_P12 }}
|
||
CERT_PASSWORD: ${{ secrets.DEVELOPER_ID_CERT_PASSWORD }}
|
||
run: |
|
||
set -euo pipefail
|
||
keychain="$RUNNER_TEMP/signing.keychain-db"
|
||
kpw="$(openssl rand -hex 20)"
|
||
security create-keychain -p "$kpw" "$keychain"
|
||
security set-keychain-settings -lut 21600 "$keychain"
|
||
security unlock-keychain -p "$kpw" "$keychain"
|
||
echo "$CERT_P12_BASE64" | base64 --decode > "$RUNNER_TEMP/cert.p12"
|
||
security import "$RUNNER_TEMP/cert.p12" -k "$keychain" -P "$CERT_PASSWORD" \
|
||
-T /usr/bin/codesign -T /usr/bin/security
|
||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$kpw" "$keychain"
|
||
# Prepend our keychain so codesign/xcodebuild can find the identity.
|
||
security list-keychains -d user -s "$keychain" $(security list-keychains -d user | tr -d '"')
|
||
rm -f "$RUNNER_TEMP/cert.p12"
|
||
|
||
- name: Store notarytool credentials
|
||
env:
|
||
NOTARY_KEY_P8: ${{ secrets.NOTARY_API_KEY }}
|
||
NOTARY_KEY_ID: ${{ secrets.NOTARY_KEY_ID }}
|
||
NOTARY_ISSUER: ${{ secrets.NOTARY_ISSUER }}
|
||
run: |
|
||
set -euo pipefail
|
||
echo "$NOTARY_KEY_P8" | base64 --decode > "$RUNNER_TEMP/notary.p8"
|
||
xcrun notarytool store-credentials vnidrop-notary \
|
||
--key "$RUNNER_TEMP/notary.p8" \
|
||
--key-id "$NOTARY_KEY_ID" \
|
||
--issuer "$NOTARY_ISSUER"
|
||
echo "NOTARY_PROFILE=vnidrop-notary" >> "$GITHUB_ENV"
|
||
|
||
- name: Write Sparkle signing key
|
||
env:
|
||
SPARKLE_ED_PRIVATE_KEY: ${{ secrets.SPARKLE_ED_PRIVATE_KEY }}
|
||
run: |
|
||
printf '%s' "$SPARKLE_ED_PRIVATE_KEY" > "$RUNNER_TEMP/sparkle_ed_private_key"
|
||
echo "SPARKLE_ED_KEY_FILE=$RUNNER_TEMP/sparkle_ed_private_key" >> "$GITHUB_ENV"
|
||
|
||
- name: Build, sign & notarize DMG
|
||
run: apple/scripts/build-dmg.sh
|
||
|
||
- name: Generate appcast
|
||
env:
|
||
RELEASE_REPO: ${{ github.repository }}
|
||
run: apple/scripts/generate-appcast.sh
|
||
|
||
- name: Upload artifacts
|
||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||
with:
|
||
name: vnidrop-${{ steps.version.outputs.app }}-macos-dmg
|
||
path: |
|
||
apple/dist/VniDrop-*.dmg
|
||
apple/dist/appcast.xml
|
||
if-no-files-found: error
|
||
retention-days: 14
|
||
|
||
- name: Publish GitHub Release
|
||
if: github.event_name == 'push' && github.ref_type == 'tag'
|
||
env:
|
||
GH_TOKEN: ${{ github.token }}
|
||
GH_REPO: ${{ github.repository }}
|
||
run: |
|
||
set -euo pipefail
|
||
tag="$GITHUB_REF_NAME"
|
||
version="${tag#v}"
|
||
if gh release view "$tag" >/dev/null 2>&1; then
|
||
echo "Release $tag already exists; refusing to replace assets" >&2
|
||
exit 1
|
||
fi
|
||
gh release create "$tag" \
|
||
"apple/dist/VniDrop-${version}.dmg" \
|
||
"apple/dist/appcast.xml" \
|
||
--verify-tag \
|
||
--title "VniDrop $version" \
|
||
--generate-notes
|
||
|
||
update-cask:
|
||
name: Update Homebrew cask
|
||
needs: build
|
||
if: github.event_name == 'push' && github.ref_type == 'tag'
|
||
runs-on: ubuntu-22.04
|
||
timeout-minutes: 15
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||
with:
|
||
persist-credentials: false
|
||
|
||
- name: Download DMG artifact
|
||
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||
with:
|
||
name: vnidrop-${{ needs.build.outputs.version }}-macos-dmg
|
||
path: dist
|
||
|
||
- name: Render cask
|
||
env:
|
||
VERSION: ${{ needs.build.outputs.version }}
|
||
run: |
|
||
set -euo pipefail
|
||
sha="$(sha256sum "dist/VniDrop-${VERSION}.dmg" | cut -d' ' -f1)"
|
||
sed -e "s/^ version \".*\"/ version \"${VERSION}\"/" \
|
||
-e "s/^ sha256 \".*\"/ sha256 \"${sha}\"/" \
|
||
packaging/homebrew/vnidrop.rb > /tmp/vnidrop.rb
|
||
echo "Rendered cask:"; cat /tmp/vnidrop.rb
|
||
|
||
- name: Push to tap
|
||
env:
|
||
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
||
VERSION: ${{ needs.build.outputs.version }}
|
||
run: |
|
||
set -euo pipefail
|
||
git clone "https://x-access-token:${TAP_TOKEN}@github.com/sudosylabs/homebrew-vnidrop.git" tap
|
||
mkdir -p tap/Casks
|
||
cp /tmp/vnidrop.rb tap/Casks/vnidrop.rb
|
||
cd tap
|
||
git config user.name "vnidrop-release-bot"
|
||
git config user.email "release-bot@users.noreply.github.com"
|
||
git add Casks/vnidrop.rb
|
||
git commit -m "vnidrop ${VERSION}" || { echo "no cask changes"; exit 0; }
|
||
git push
|