feat: add reusable Flutter build actions for android, ios, macos, windows, and linux
Update README Actions Table / update-readme (push) Successful in 7s
Update README Actions Table / update-readme (push) Successful in 7s
This commit is contained in:
@@ -0,0 +1,463 @@
|
||||
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
|
||||
Reference in New Issue
Block a user