464 lines
20 KiB
YAML
464 lines
20 KiB
YAML
name: 'Flutter Build macOS'
|
|
description: 'Builds, signs (Developer ID & Sparkle), packages (.dmg / .zip), notarizes, and generates release metadata for macOS Flutter desktop apps.'
|
|
inputs:
|
|
working_directory:
|
|
description: 'Path to the Flutter app package directory (e.g., packages/sfw_desktop)'
|
|
required: false
|
|
default: '.'
|
|
app_name:
|
|
description: 'Display name of the .app bundle (e.g., "Slides for Worship" or auto-detected if empty)'
|
|
required: false
|
|
default: ''
|
|
build_args:
|
|
description: 'Extra arguments passed to flutter build macos (e.g., --dart-define=...)'
|
|
required: false
|
|
default: ''
|
|
disable_spm:
|
|
description: 'Disable Flutter Swift Package Manager before building'
|
|
required: false
|
|
default: 'true'
|
|
run_pod_install:
|
|
description: 'Run pod install inside working_directory/macos before building'
|
|
required: false
|
|
default: 'false'
|
|
package_type:
|
|
description: 'Packaging format to produce: dmg, zip, or both'
|
|
required: false
|
|
default: 'dmg'
|
|
dmg_filename:
|
|
description: 'Output DMG filename (e.g., slides-for-worship-macos-universal.dmg)'
|
|
required: false
|
|
default: ''
|
|
zip_filename:
|
|
description: 'Output ZIP path/filename when package_type is zip or both'
|
|
required: false
|
|
default: ''
|
|
entitlements_path:
|
|
description: 'Path to entitlements plist relative to working_directory'
|
|
required: false
|
|
default: 'macos/Runner/Release.entitlements'
|
|
signing_identity:
|
|
description: 'Fallback Developer ID Application signing identity if not auto-detected'
|
|
required: false
|
|
default: ''
|
|
certificate_base64:
|
|
description: 'Base64-encoded Apple .p12 certificate'
|
|
required: false
|
|
default: ''
|
|
certificate_password:
|
|
description: 'Password for the Apple .p12 certificate'
|
|
required: false
|
|
default: ''
|
|
certificate_file:
|
|
description: 'Fallback path to local .p12 certificate file in repository'
|
|
required: false
|
|
default: 'signing/macos/certificate.p12'
|
|
metadata_txt_file:
|
|
description: 'Fallback path to metadata.txt containing p12/notarization credentials'
|
|
required: false
|
|
default: 'signing/macos/metadata.txt'
|
|
provisioning_profile_base64:
|
|
description: 'Optional Base64-encoded .provisionprofile for Mac App Store / provisioning'
|
|
required: false
|
|
default: ''
|
|
notarize_apple_id:
|
|
description: 'Apple ID email for DMG notarization'
|
|
required: false
|
|
default: ''
|
|
notarize_password:
|
|
description: 'Apple ID App-Specific Password for DMG notarization'
|
|
required: false
|
|
default: ''
|
|
notarize_team_id:
|
|
description: 'Apple Developer 10-character Team ID for DMG notarization'
|
|
required: false
|
|
default: ''
|
|
sparkle_private_key:
|
|
description: 'Sparkle EdDSA private key content for signing DMG updates'
|
|
required: false
|
|
default: ''
|
|
sparkle_key_file:
|
|
description: 'Fallback path to Sparkle EdDSA private key file'
|
|
required: false
|
|
default: 'signing/sparkle/sparkle_key.pem'
|
|
generate_metadata_json:
|
|
description: 'Whether to generate macos_metadata.json and macos_signature.txt'
|
|
required: false
|
|
default: 'false'
|
|
asc_key_id:
|
|
description: 'Optional App Store Connect API Key ID for .pkg upload'
|
|
required: false
|
|
default: ''
|
|
asc_issuer_id:
|
|
description: 'Optional App Store Connect API Issuer ID for .pkg upload'
|
|
required: false
|
|
default: ''
|
|
asc_private_key:
|
|
description: 'Optional App Store Connect API Private Key (.p8) for .pkg upload'
|
|
required: false
|
|
default: ''
|
|
|
|
outputs:
|
|
version:
|
|
description: 'Resolved package version from pubspec.yaml'
|
|
value: ${{ steps.build.outputs.version }}
|
|
dmg_path:
|
|
description: 'Path to generated DMG installer'
|
|
value: ${{ steps.package.outputs.dmg_path }}
|
|
zip_path:
|
|
description: 'Path to generated ZIP archive'
|
|
value: ${{ steps.package.outputs.zip_path }}
|
|
signature:
|
|
description: 'Sparkle EdDSA signature if generated'
|
|
value: ${{ steps.sparkle.outputs.signature }}
|
|
metadata_path:
|
|
description: 'Path to generated macos_metadata.json'
|
|
value: ${{ steps.metadata.outputs.metadata_path }}
|
|
|
|
runs:
|
|
using: 'composite'
|
|
steps:
|
|
- name: Clean up previous temporary keychains
|
|
shell: bash
|
|
run: |
|
|
security list-keychains -d user -s "$HOME/Library/Keychains/login.keychain-db" || true
|
|
security default-keychain -s "$HOME/Library/Keychains/login.keychain-db" || true
|
|
security delete-keychain "$HOME/Library/Keychains/signing_macos_temp.keychain-db" 2>/dev/null || true
|
|
rm -f "$HOME/Library/Keychains/signing_macos_temp.keychain-db" || true
|
|
|
|
- name: Import Code-Signing Certificates
|
|
shell: bash
|
|
env:
|
|
CERT_B64: ${{ inputs.certificate_base64 }}
|
|
CERT_PWD: ${{ inputs.certificate_password }}
|
|
CERT_FILE: ${{ inputs.certificate_file }}
|
|
METADATA_FILE: ${{ inputs.metadata_txt_file }}
|
|
PROFILE_B64: ${{ inputs.provisioning_profile_base64 }}
|
|
run: |
|
|
CERT_P12="$CERT_FILE"
|
|
if [ -z "$CERT_PWD" ] && [ -n "$METADATA_FILE" ] && [ -f "$METADATA_FILE" ]; then
|
|
CERT_PWD=$(grep -A 1 "p12 password:" "$METADATA_FILE" | tail -n 1 | tr -d '\r\n' || true)
|
|
fi
|
|
|
|
if [ -n "$CERT_B64" ]; then
|
|
echo "$CERT_B64" | base64 --decode > /tmp/macos_certificate.p12
|
|
CERT_P12="/tmp/macos_certificate.p12"
|
|
fi
|
|
|
|
if [ -f "$CERT_P12" ] && [ -n "$CERT_PWD" ]; then
|
|
echo "Importing code-signing certificate from $CERT_P12..."
|
|
KEYCHAIN="$HOME/Library/Keychains/signing_macos_temp.keychain-db"
|
|
KEYCHAIN_PWD="temp_password_123"
|
|
security create-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN" || true
|
|
security unlock-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN" || true
|
|
security set-keychain-settings -lut 21600 "$KEYCHAIN" || true
|
|
security list-keychains -d user -s "$HOME/Library/Keychains/login.keychain-db" "$KEYCHAIN" || true
|
|
security default-keychain -s "$HOME/Library/Keychains/login.keychain-db" || true
|
|
security import "$CERT_P12" -k "$KEYCHAIN" -P "$CERT_PWD" -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild -A || true
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PWD" "$KEYCHAIN" || true
|
|
echo "Certificate imported successfully. Available identities:"
|
|
security find-identity -v -p codesigning || true
|
|
else
|
|
echo "Notice: No certificate or password found; building unsigned or ad-hoc signed macOS bundle."
|
|
fi
|
|
|
|
if [ -n "$PROFILE_B64" ]; then
|
|
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
|
|
echo "$PROFILE_B64" | base64 --decode > /tmp/macos_profile.provisionprofile
|
|
PROFILE_UUID=$(security cms -D -i /tmp/macos_profile.provisionprofile 2>/dev/null | plutil -extract UUID raw - 2>/dev/null || echo "macos_profile")
|
|
cp /tmp/macos_profile.provisionprofile "$HOME/Library/MobileDevice/Provisioning Profiles/${PROFILE_UUID}.provisionprofile"
|
|
cp /tmp/macos_profile.provisionprofile "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles/${PROFILE_UUID}.provisionprofile"
|
|
fi
|
|
|
|
- name: Install CocoaPods & Build macOS Release
|
|
id: build
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
RUN_PODS: ${{ inputs.run_pod_install }}
|
|
DISABLE_SPM: ${{ inputs.disable_spm }}
|
|
BUILD_ARGS: ${{ inputs.build_args }}
|
|
run: |
|
|
export PATH="/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:$PATH"
|
|
ROOT_DIR="$(pwd)"
|
|
VERSION=$(grep '^version: ' "$WORK_DIR/pubspec.yaml" | head -n 1 | cut -d ' ' -f 2 | tr -d '\r')
|
|
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
|
|
if [ "$RUN_PODS" = "true" ] && [ -d "$WORK_DIR/macos" ]; then
|
|
cd "$WORK_DIR/macos"
|
|
pod install || true
|
|
cd "$ROOT_DIR"
|
|
fi
|
|
|
|
cd "$WORK_DIR"
|
|
flutter config --enable-macos-desktop
|
|
if [ "$DISABLE_SPM" = "true" ]; then
|
|
flutter config --no-enable-swift-package-manager
|
|
fi
|
|
# shellcheck disable=SC2086
|
|
flutter build macos --release $BUILD_ARGS
|
|
cd "$ROOT_DIR"
|
|
|
|
- name: Sign App Bundle (Developer ID & Sparkle)
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
APP_NAME: ${{ inputs.app_name }}
|
|
ENTITLEMENTS_REL: ${{ inputs.entitlements_path }}
|
|
FALLBACK_IDENTITY: ${{ inputs.signing_identity }}
|
|
run: |
|
|
if [ -n "$APP_NAME" ]; then
|
|
APP_PATH="$WORK_DIR/build/macos/Build/Products/Release/${APP_NAME}.app"
|
|
else
|
|
APP_PATH=$(find "$WORK_DIR/build/macos/Build/Products/Release" -maxdepth 1 -name "*.app" | head -n 1)
|
|
fi
|
|
ENTITLEMENTS="$WORK_DIR/$ENTITLEMENTS_REL"
|
|
|
|
IDENTITY=$(security find-identity -v -p codesigning 2>/dev/null | grep "Developer ID Application" | head -1 | grep -oE '"[^"]+"' | sed 's/"//g' || true)
|
|
if [ -z "$IDENTITY" ] && [ -n "$FALLBACK_IDENTITY" ]; then
|
|
IDENTITY="$FALLBACK_IDENTITY"
|
|
fi
|
|
|
|
if [ -n "$APP_PATH" ] && [ -d "$APP_PATH" ] && [ -n "$IDENTITY" ]; then
|
|
echo "Signing Sparkle components, frameworks, and App Bundle at $APP_PATH with identity: $IDENTITY"
|
|
|
|
SPARKLE_FW="$APP_PATH/Contents/Frameworks/Sparkle.framework/Versions/B"
|
|
if [ -d "$SPARKLE_FW" ]; then
|
|
echo "Signing Sparkle internal components..."
|
|
[ -d "$SPARKLE_FW/XPCServices/Downloader.xpc" ] && codesign --force --options runtime --timestamp --sign "$IDENTITY" "$SPARKLE_FW/XPCServices/Downloader.xpc" || true
|
|
[ -d "$SPARKLE_FW/XPCServices/Installer.xpc" ] && codesign --force --options runtime --timestamp --sign "$IDENTITY" "$SPARKLE_FW/XPCServices/Installer.xpc" || true
|
|
[ -f "$SPARKLE_FW/Autoupdate" ] && codesign --force --options runtime --timestamp --sign "$IDENTITY" "$SPARKLE_FW/Autoupdate" || true
|
|
[ -d "$SPARKLE_FW/Updater.app" ] && codesign --force --options runtime --timestamp --sign "$IDENTITY" "$SPARKLE_FW/Updater.app" || true
|
|
codesign --force --options runtime --timestamp --sign "$IDENTITY" "$APP_PATH/Contents/Frameworks/Sparkle.framework" || true
|
|
fi
|
|
|
|
if [ -d "$APP_PATH/Contents/Frameworks" ]; then
|
|
find "$APP_PATH/Contents/Frameworks" -mindepth 1 -maxdepth 1 2>/dev/null | while read -r FW; do
|
|
if [ "$FW" != "$APP_PATH/Contents/Frameworks/Sparkle.framework" ]; then
|
|
codesign --force --options runtime --timestamp --sign "$IDENTITY" "$FW" || true
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [ -f "$ENTITLEMENTS" ]; then
|
|
codesign --force --options runtime --timestamp --entitlements "$ENTITLEMENTS" --sign "$IDENTITY" "$APP_PATH" || true
|
|
else
|
|
codesign --force --options runtime --timestamp --sign "$IDENTITY" "$APP_PATH" || true
|
|
fi
|
|
codesign -dv --verbose=4 "$APP_PATH" || true
|
|
fi
|
|
|
|
- name: Package macOS Installer (DMG / ZIP)
|
|
id: package
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
APP_NAME: ${{ inputs.app_name }}
|
|
PACKAGE_TYPE: ${{ inputs.package_type }}
|
|
DMG_FILENAME: ${{ inputs.dmg_filename }}
|
|
ZIP_FILENAME: ${{ inputs.zip_filename }}
|
|
run: |
|
|
if [ -n "$APP_NAME" ]; then
|
|
APP_PATH="$WORK_DIR/build/macos/Build/Products/Release/${APP_NAME}.app"
|
|
else
|
|
APP_PATH=$(find "$WORK_DIR/build/macos/Build/Products/Release" -maxdepth 1 -name "*.app" | head -n 1)
|
|
fi
|
|
|
|
if [ -z "$APP_PATH" ] || [ ! -d "$APP_PATH" ]; then
|
|
echo "::error::macOS .app bundle not found in $WORK_DIR/build/macos/Build/Products/Release"
|
|
exit 1
|
|
fi
|
|
|
|
BUNDLE_BASENAME=$(basename "$APP_PATH")
|
|
VOL_NAME="${APP_NAME:-${BUNDLE_BASENAME%.app}}"
|
|
|
|
if [ "$PACKAGE_TYPE" = "zip" ] || [ "$PACKAGE_TYPE" = "both" ]; then
|
|
ZIP_OUT="${ZIP_FILENAME:-$WORK_DIR/build/macos/release-archive/${VOL_NAME// /-}-macOS.zip}"
|
|
mkdir -p "$(dirname "$ZIP_OUT")"
|
|
ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "$ZIP_OUT"
|
|
echo "Packaged macOS ZIP archive: $ZIP_OUT"
|
|
echo "zip_path=$ZIP_OUT" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
if [ "$PACKAGE_TYPE" = "dmg" ] || [ "$PACKAGE_TYPE" = "both" ]; then
|
|
DMG_OUT="${DMG_FILENAME:-${VOL_NAME// /-}-macos-universal.dmg}"
|
|
if ! command -v create-dmg >/dev/null 2>&1; then
|
|
brew install create-dmg || true
|
|
fi
|
|
|
|
echo "Detaching any leftover disk image mounts..."
|
|
for dev in $(hdiutil info 2>/dev/null | awk -v vol="$VOL_NAME" '$0 ~ "/Volumes/.*" vol "|/Volumes/.*Presentation-Creator" {print $1}'); do
|
|
[ -n "$dev" ] && hdiutil detach "$dev" -force || true
|
|
done
|
|
|
|
rm -f "$DMG_OUT"
|
|
DMG_STAGING="dmg_staging"
|
|
rm -rf "$DMG_STAGING"
|
|
mkdir -p "$DMG_STAGING"
|
|
cp -R "$APP_PATH" "$DMG_STAGING/"
|
|
|
|
create-dmg \
|
|
--volname "$VOL_NAME" \
|
|
--window-pos 200 120 \
|
|
--window-size 800 400 \
|
|
--icon-size 100 \
|
|
--icon "$BUNDLE_BASENAME" 200 190 \
|
|
--hide-extension "$BUNDLE_BASENAME" \
|
|
--app-drop-link 600 185 \
|
|
--no-internet-enable \
|
|
--sandbox-safe \
|
|
--skip-jenkins \
|
|
--overwrite \
|
|
"$DMG_OUT" \
|
|
"$DMG_STAGING" || true
|
|
|
|
if [ ! -f "$DMG_OUT" ]; then
|
|
echo "create-dmg did not generate DMG, running hdiutil fallback with Applications link..."
|
|
ln -s /Applications "$DMG_STAGING/Applications" 2>/dev/null || true
|
|
hdiutil create -volname "$VOL_NAME" -srcfolder "$DMG_STAGING" -ov -format UDZO "$DMG_OUT"
|
|
fi
|
|
rm -rf "$DMG_STAGING"
|
|
|
|
for dev in $(hdiutil info 2>/dev/null | awk -v vol="$VOL_NAME" '$0 ~ "/Volumes/.*" vol "|/Volumes/.*Presentation-Creator" {print $1}'); do
|
|
[ -n "$dev" ] && hdiutil detach "$dev" -force || true
|
|
done
|
|
|
|
test -f "$DMG_OUT"
|
|
echo "dmg_path=$DMG_OUT" >> "$GITHUB_OUTPUT"
|
|
|
|
IDENTITY=$(security find-identity -v -p codesigning 2>/dev/null | grep "Developer ID Application" | head -1 | grep -oE '"[^"]+"' | sed 's/"//g' || true)
|
|
if [ -n "$IDENTITY" ] && [ -f "$DMG_OUT" ]; then
|
|
echo "Signing DMG with identity: $IDENTITY"
|
|
codesign --force --timestamp --sign "$IDENTITY" "$DMG_OUT" || true
|
|
fi
|
|
fi
|
|
|
|
- name: Notarize & Staple DMG
|
|
if: inputs.package_type == 'dmg' || inputs.package_type == 'both'
|
|
shell: bash
|
|
env:
|
|
DMG_FILE: ${{ steps.package.outputs.dmg_path }}
|
|
AC_USER: ${{ inputs.notarize_apple_id }}
|
|
AC_PASS: ${{ inputs.notarize_password }}
|
|
AC_TEAM: ${{ inputs.notarize_team_id }}
|
|
METADATA_FILE: ${{ inputs.metadata_txt_file }}
|
|
run: |
|
|
if [ -z "$AC_USER" ] && [ -n "$METADATA_FILE" ] && [ -f "$METADATA_FILE" ]; then
|
|
AC_USER=$(grep -A 1 "AC username:" "$METADATA_FILE" | tail -n 1 | tr -d '\r\n' || true)
|
|
AC_PASS=$(grep -A 1 "AC password:" "$METADATA_FILE" | tail -n 1 | tr -d '\r\n' || true)
|
|
AC_TEAM=$(grep -A 1 "Team ID:" "$METADATA_FILE" | tail -n 1 | tr -d '\r\n' || true)
|
|
fi
|
|
|
|
if [ -n "$AC_USER" ] && [ -n "$AC_PASS" ] && [ -n "$AC_TEAM" ] && [ -n "$DMG_FILE" ] && [ -f "$DMG_FILE" ]; then
|
|
echo "Submitting $DMG_FILE to Apple Notary Service..."
|
|
xcrun notarytool submit "$DMG_FILE" \
|
|
--apple-id "$AC_USER" \
|
|
--password "$AC_PASS" \
|
|
--team-id "$AC_TEAM" \
|
|
--wait || true
|
|
|
|
echo "Stapling notarization ticket..."
|
|
for i in {1..5}; do
|
|
xcrun stapler staple "$DMG_FILE" && break || sleep 10
|
|
done || true
|
|
else
|
|
echo "Notarization credentials not configured; skipping notarization."
|
|
fi
|
|
|
|
- name: Sign DMG for Sparkle
|
|
id: sparkle
|
|
if: inputs.package_type == 'dmg' || inputs.package_type == 'both'
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
DMG_FILE: ${{ steps.package.outputs.dmg_path }}
|
|
SPARKLE_KEY: ${{ inputs.sparkle_private_key }}
|
|
SPARKLE_KEY_FILE: ${{ inputs.sparkle_key_file }}
|
|
run: |
|
|
ROOT_DIR="$(pwd)"
|
|
touch macos_signature.txt
|
|
|
|
if [ -z "$SPARKLE_KEY" ] && [ -n "$SPARKLE_KEY_FILE" ] && [ -f "$SPARKLE_KEY_FILE" ]; then
|
|
SPARKLE_KEY=$(cat "$SPARKLE_KEY_FILE")
|
|
fi
|
|
|
|
if [ -n "$SPARKLE_KEY" ] && [ -n "$DMG_FILE" ] && [ -f "$DMG_FILE" ]; then
|
|
echo "$SPARKLE_KEY" > "$ROOT_DIR/sparkle_key.pem"
|
|
echo "Signing $DMG_FILE for Sparkle..."
|
|
cd "$WORK_DIR"
|
|
OUTPUT=$(dart run auto_updater:sign_update "$ROOT_DIR/$DMG_FILE" --ed-key-file "$ROOT_DIR/sparkle_key.pem" 2>&1 || true)
|
|
echo "$OUTPUT"
|
|
cd "$ROOT_DIR"
|
|
|
|
SIG=$(echo "$OUTPUT" | grep -o 'Signature="[^"]*"' | head -n 1 | cut -d'"' -f2 || true)
|
|
if [ -n "$SIG" ]; then
|
|
echo "$SIG" > macos_signature.txt
|
|
echo "signature=$SIG" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
rm -f "$ROOT_DIR/sparkle_key.pem"
|
|
fi
|
|
|
|
- name: Generate macOS Release Metadata
|
|
id: metadata
|
|
if: inputs.generate_metadata_json == 'true'
|
|
shell: bash
|
|
env:
|
|
VERSION: ${{ steps.build.outputs.version }}
|
|
DMG_FILE: ${{ steps.package.outputs.dmg_path }}
|
|
run: |
|
|
SIG=$(cat macos_signature.txt 2>/dev/null || true)
|
|
SIZE=$(stat -c%s "$DMG_FILE" 2>/dev/null || stat -f%z "$DMG_FILE" 2>/dev/null || echo "0")
|
|
FILENAME=$(basename "$DMG_FILE")
|
|
|
|
cat <<EOF > macos_metadata.json
|
|
{
|
|
"version": "$VERSION",
|
|
"platform": "macos",
|
|
"arch": "universal",
|
|
"filename": "$FILENAME",
|
|
"size": $SIZE,
|
|
"signature": "$SIG",
|
|
"signatureType": "edSignature"
|
|
}
|
|
EOF
|
|
cat macos_metadata.json
|
|
echo "metadata_path=macos_metadata.json" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload macOS Package to App Store Connect (Optional)
|
|
if: inputs.asc_key_id != '' && inputs.asc_issuer_id != '' && inputs.asc_private_key != ''
|
|
shell: bash
|
|
env:
|
|
WORK_DIR: ${{ inputs.working_directory }}
|
|
ASC_KEY_ID: ${{ inputs.asc_key_id }}
|
|
ASC_ISSUER_ID: ${{ inputs.asc_issuer_id }}
|
|
ASC_KEY_CONTENT: ${{ inputs.asc_private_key }}
|
|
run: |
|
|
PKG_FILE=$(ls "$WORK_DIR"/build/macos/*.pkg 2>/dev/null | head -n 1 || true)
|
|
if [ -z "$PKG_FILE" ]; then
|
|
echo "Skipping Mac App Store pkg upload (no signed .pkg generated)."
|
|
exit 0
|
|
fi
|
|
mkdir -p "$HOME/.appstoreconnect/private_keys"
|
|
echo "$ASC_KEY_CONTENT" > "$HOME/.appstoreconnect/private_keys/AuthKey_${ASC_KEY_ID}.p8"
|
|
xcrun altool --upload-app \
|
|
-f "$PKG_FILE" \
|
|
--type osx \
|
|
--apiKey "$ASC_KEY_ID" \
|
|
--apiIssuer "$ASC_ISSUER_ID"
|
|
|
|
- name: Eject DMG Mounts & Clean Up Keychain
|
|
if: always()
|
|
shell: bash
|
|
env:
|
|
APP_NAME: ${{ inputs.app_name }}
|
|
run: |
|
|
VOL_NAME="${APP_NAME:-Slides for Worship}"
|
|
for dev in $(hdiutil info 2>/dev/null | awk -v vol="$VOL_NAME" '$0 ~ "/Volumes/.*" vol "|/Volumes/.*Presentation-Creator" {print $1}'); do
|
|
[ -n "$dev" ] && hdiutil detach "$dev" -force || true
|
|
done
|
|
|
|
security list-keychains -d user -s "$HOME/Library/Keychains/login.keychain-db" || true
|
|
security default-keychain -s "$HOME/Library/Keychains/login.keychain-db" || true
|
|
security delete-keychain "$HOME/Library/Keychains/signing_macos_temp.keychain-db" 2>/dev/null || true
|
|
rm -f "$HOME/Library/Keychains/signing_macos_temp.keychain-db" /tmp/macos_certificate.p12 /tmp/macos_profile.provisionprofile || true
|