WIP: feat(workflows): add new build workflows for Windows, Linux, and macOS, and remove obsolete build scripts #17
46
.gitea/actions/linux-build/action.yml
Normal file
46
.gitea/actions/linux-build/action.yml
Normal file
@ -0,0 +1,46 @@
|
||||
name: 'Linux Build Steps'
|
||||
description: 'Build Linux application'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup environment
|
||||
run: |
|
||||
# Set environment variables for Unreal Engine
|
||||
echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV
|
||||
|
||||
# Set environment variables for Linux toolchain (needed for cross-compilation)
|
||||
$env:LINUX_MULTIARCH_ROOT="C:/UnrealToolchains/v23_clang-18.1.0-rockylinux8"
|
||||
echo "LINUX_MULTIARCH_ROOT=${LINUX_MULTIARCH_ROOT}" >> $GITHUB_ENV
|
||||
|
||||
# Create directories for builds
|
||||
if (!(Test-Path "Builds/Linux")) { New-Item -ItemType Directory -Path "Builds/Linux" -Force }
|
||||
if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force }
|
||||
shell: pwsh
|
||||
|
||||
- name: Build for Linux
|
||||
run: |
|
||||
# Chmod command doesn't exist in Windows, use PowerShell to run the bash script
|
||||
& 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/linux_build.sh"
|
||||
shell: pwsh
|
||||
|
||||
- name: Package Linux build
|
||||
run: |
|
||||
echo "Packaging Linux build..."
|
||||
if [ -d "Builds/Linux" ]; then
|
||||
cd Builds/Linux
|
||||
zip -r ../../PackagedReleases/LuckyRobots-Linux.zip .
|
||||
cd ../..
|
||||
fi
|
||||
|
||||
echo "=== Packaged Linux release ==="
|
||||
ls -la PackagedReleases/
|
||||
shell: bash
|
||||
|
||||
- name: Upload Linux Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
if: success() && hashFiles('PackagedReleases/LuckyRobots-Linux.zip') != ''
|
||||
with:
|
||||
name: LuckyRobots-Linux
|
||||
path: PackagedReleases/LuckyRobots-Linux.zip
|
||||
retention-days: 365
|
132
.gitea/actions/macos-build/action.yml
Normal file
132
.gitea/actions/macos-build/action.yml
Normal file
@ -0,0 +1,132 @@
|
||||
name: 'macOS Build Steps'
|
||||
description: 'Build, sign and notarize macOS application'
|
||||
|
||||
inputs:
|
||||
apple_team_id:
|
||||
description: 'Apple Team ID for signing'
|
||||
required: true
|
||||
apple_certificate_base64:
|
||||
description: 'Base64-encoded certificate file'
|
||||
required: true
|
||||
apple_certificate_password:
|
||||
description: 'Password for certificate file'
|
||||
required: true
|
||||
api_key_path:
|
||||
description: 'Base64-encoded API key file'
|
||||
required: true
|
||||
api_key_id:
|
||||
description: 'API Key ID'
|
||||
required: true
|
||||
api_key_issuer_id:
|
||||
description: 'API Key Issuer ID'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup environment
|
||||
run: |
|
||||
# Use the correct path where Unreal Engine is installed
|
||||
UE_PATH="/Users/Shared/Epic Games/UE_5.5"
|
||||
|
||||
if [ ! -d "$UE_PATH" ]; then
|
||||
echo "Error: Unreal Engine is not installed in the expected location"
|
||||
echo "Please ensure Unreal Engine is installed at $UE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create directories for builds
|
||||
mkdir -p Builds/Mac
|
||||
mkdir -p PackagedReleases
|
||||
|
||||
echo "Using Unreal Engine 5.5"
|
||||
shell: bash
|
||||
|
||||
- name: Build for macOS
|
||||
run: |
|
||||
chmod +x ./scripts/mac_build.sh
|
||||
./scripts/mac_build.sh
|
||||
shell: bash
|
||||
|
||||
- name: Setup for Signing
|
||||
id: setup-signing
|
||||
if: ${{ success() }}
|
||||
env:
|
||||
API_KEY_PATH: ${{ inputs.api_key_path }}
|
||||
run: |
|
||||
# Create output directory
|
||||
mkdir -p PackagedReleases
|
||||
|
||||
# Decode the API key from Base64 secret
|
||||
echo "$API_KEY_PATH" | base64 --decode > api_key.p8
|
||||
echo "api_key_file=$(pwd)/api_key.p8" >> $GITHUB_OUTPUT
|
||||
|
||||
# Find app bundle
|
||||
APP_PATH=$(find Builds -type d -name "*.app" | head -1)
|
||||
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
# Look for a directory that might be a bundle but not named .app
|
||||
APP_PATH=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1)
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo "No build directory found, cannot continue"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Found app path: $APP_PATH"
|
||||
echo "app_path=$APP_PATH" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Sign macOS App
|
||||
uses: lando/code-sign-action@v3
|
||||
id: sign-app
|
||||
with:
|
||||
file: ${{ steps.setup-signing.outputs.app_path }}
|
||||
certificate-data: ${{ inputs.apple_certificate_base64 }}
|
||||
certificate-password: ${{ inputs.apple_certificate_password }}
|
||||
certificate-id: ${{ inputs.apple_team_id }}
|
||||
options: --force --options runtime --deep --timestamp --entitlements ./LuckyRobots.entitlements
|
||||
|
||||
- name: Notarize macOS App
|
||||
run: |
|
||||
# Create a temporary file for notarization
|
||||
APP_PATH="${{ steps.setup-signing.outputs.app_path }}"
|
||||
NOTARIZE_APP_PATH="./LuckyRobots-notarize.zip"
|
||||
ditto -c -k --keepParent "$APP_PATH" "$NOTARIZE_APP_PATH"
|
||||
|
||||
API_KEY_FILE="${{ steps.setup-signing.outputs.api_key_file }}"
|
||||
|
||||
# Submit for notarization using API key
|
||||
echo "Submitting for notarization with API key..."
|
||||
xcrun notarytool submit "$NOTARIZE_APP_PATH" --key "$API_KEY_FILE" --key-id "${{ inputs.api_key_id }}" --issuer "${{ inputs.api_key_issuer_id }}" --wait
|
||||
|
||||
# Staple the ticket to the application
|
||||
xcrun stapler staple "$APP_PATH"
|
||||
|
||||
# Clean up the API key file
|
||||
rm -f "$API_KEY_FILE"
|
||||
rm -f "$NOTARIZE_APP_PATH"
|
||||
shell: bash
|
||||
|
||||
- name: Package macOS App
|
||||
run: |
|
||||
# Package the signed and notarized app
|
||||
APP_PATH="${{ steps.setup-signing.outputs.app_path }}"
|
||||
APP_NAME=$(basename "$APP_PATH")
|
||||
DIR_PATH=$(dirname "$APP_PATH")
|
||||
|
||||
echo "Creating final package..."
|
||||
(cd "$DIR_PATH" && zip -r "../../PackagedReleases/LuckyRobots-macOS.zip" "$APP_NAME")
|
||||
echo "Created packaged release: PackagedReleases/LuckyRobots-macOS.zip"
|
||||
|
||||
echo "Packaged releases:"
|
||||
ls -la PackagedReleases/
|
||||
shell: bash
|
||||
|
||||
- name: Upload macOS Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
if: success()
|
||||
with:
|
||||
name: LuckyRobots-macOS
|
||||
path: PackagedReleases/LuckyRobots-macOS.zip
|
||||
retention-days: 365
|
717
.gitea/actions/macos-notarize/action.yml
Normal file
717
.gitea/actions/macos-notarize/action.yml
Normal file
@ -0,0 +1,717 @@
|
||||
name: "macOS Sign and Notarize"
|
||||
description: "Signs and notarizes macOS applications with Developer ID certificate"
|
||||
author: moersoy"
|
||||
|
||||
inputs:
|
||||
app-path:
|
||||
description: "Path to the app bundle (.app)"
|
||||
required: true
|
||||
entitlements-file:
|
||||
description: "Path to the entitlements file (.entitlements)"
|
||||
required: true
|
||||
team-id:
|
||||
description: "Apple Developer Team ID"
|
||||
required: true
|
||||
certificate-base64:
|
||||
description: "Base64-encoded Developer ID Application certificate (.p12)"
|
||||
required: true
|
||||
certificate-password:
|
||||
description: "Password for the Developer ID Application certificate"
|
||||
required: true
|
||||
notarization-method:
|
||||
description: "Method to use for notarization: 'api-key' or 'app-password'"
|
||||
required: false
|
||||
default: "api-key"
|
||||
notary-user:
|
||||
description: "Apple ID for notarization (for app-password method)"
|
||||
required: false
|
||||
notary-password:
|
||||
description: "App-specific password for notarization (for app-password method)"
|
||||
required: false
|
||||
notary-api-key-id:
|
||||
description: "API Key ID for notarization (for api-key method)"
|
||||
required: false
|
||||
notary-api-key-issuer-id:
|
||||
description: "API Issuer ID for notarization (for api-key method)"
|
||||
required: false
|
||||
notary-api-key-path:
|
||||
description: "Path to or content of the API Key .p8 file (for api-key method)"
|
||||
required: false
|
||||
bundle-id:
|
||||
description: "App bundle identifier (com.example.app)"
|
||||
required: false
|
||||
fallback-to-adhoc:
|
||||
description: "Whether to fall back to ad-hoc signing if certificate is invalid"
|
||||
required: false
|
||||
default: "true"
|
||||
|
||||
outputs:
|
||||
signed:
|
||||
description: "Whether the app was signed (identity, adhoc, or none)"
|
||||
value: ${{ steps.sign.outputs.signed }}
|
||||
notarized:
|
||||
description: "Whether the app was notarized (true or false)"
|
||||
value: ${{ steps.notarize.outputs.notarized }}
|
||||
package-path:
|
||||
description: "Path to the final package"
|
||||
value: ${{ steps.package.outputs.package-path }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup Certificate
|
||||
id: setup-cert
|
||||
shell: bash
|
||||
env:
|
||||
CERTIFICATE_BASE64: ${{ inputs.certificate-base64 }}
|
||||
CERTIFICATE_PASSWORD: ${{ inputs.certificate-password }}
|
||||
APPLE_TEAM_ID: ${{ inputs.team-id }}
|
||||
run: |
|
||||
echo "🔐 Setting up certificate..."
|
||||
|
||||
# Create a temporary directory for certificates
|
||||
CERT_DIR="$HOME/certificates"
|
||||
mkdir -p "$CERT_DIR"
|
||||
|
||||
# Decode the certificate to a p12 file
|
||||
echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_DIR/certificate.p12"
|
||||
|
||||
# Create keychain
|
||||
KEYCHAIN_PATH="$CERT_DIR/app-signing.keychain-db"
|
||||
KEYCHAIN_PASSWORD="temppassword123"
|
||||
|
||||
# Delete existing keychain if it exists
|
||||
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true
|
||||
|
||||
# Create new keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH"
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
|
||||
# Add to search list and make default
|
||||
security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"')
|
||||
security default-keychain -s "$KEYCHAIN_PATH"
|
||||
|
||||
# Import certificate
|
||||
echo "🔑 Importing developer certificate..."
|
||||
security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
|
||||
|
||||
# Try with additional parameters if needed
|
||||
security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -f pkcs12 || true
|
||||
|
||||
# Set partition list for codesign to access keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
|
||||
# Verify certificate
|
||||
echo "🔍 Verifying code signing identities..."
|
||||
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
|
||||
|
||||
# Try to use the System keychain as a fallback
|
||||
echo "🔍 Checking system keychain for code signing identities..."
|
||||
SYSTEM_IDENTITIES=$(security find-identity -v -p codesigning)
|
||||
echo "$SYSTEM_IDENTITIES"
|
||||
|
||||
if echo "$SYSTEM_IDENTITIES" | grep -q "Developer ID Application"; then
|
||||
echo "✅ Found Developer ID Application certificate in system keychain"
|
||||
echo "::set-output name=use_system_cert::true"
|
||||
else
|
||||
echo "::set-output name=use_system_cert::false"
|
||||
fi
|
||||
|
||||
# Store keychain variables for later steps
|
||||
echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> $GITHUB_ENV
|
||||
echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV
|
||||
echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> $GITHUB_ENV
|
||||
|
||||
# Clean up
|
||||
rm -f "$CERT_DIR/certificate.p12"
|
||||
|
||||
- name: Sign App
|
||||
id: sign
|
||||
shell: bash
|
||||
run: |
|
||||
echo "🔏 Signing app with Developer ID certificate..."
|
||||
|
||||
# Check if app path exists
|
||||
if [ ! -d "${{ inputs.app-path }}" ]; then
|
||||
echo "❌ App bundle not found at ${{ inputs.app-path }}"
|
||||
echo "::set-output name=signed::none"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if entitlements file exists
|
||||
if [ ! -f "${{ inputs.entitlements-file }}" ]; then
|
||||
echo "❌ Entitlements file not found at ${{ inputs.entitlements-file }}"
|
||||
echo "::set-output name=signed::none"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Decide which keychain to use
|
||||
if [ "${{ steps.setup-cert.outputs.use_system_cert }}" = "true" ]; then
|
||||
echo "Using system keychain identity"
|
||||
# Get certificate hash instead of name to avoid ambiguity
|
||||
IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}')
|
||||
echo "Using certificate hash: $IDENTITY_HASH"
|
||||
else
|
||||
# Make sure keychain is unlocked
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
echo "Using custom keychain identity"
|
||||
# Get certificate hash instead of name to avoid ambiguity
|
||||
IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}')
|
||||
echo "Using certificate hash: $IDENTITY_HASH"
|
||||
fi
|
||||
|
||||
if [ -z "$IDENTITY_HASH" ]; then
|
||||
echo "❌ No valid Developer ID Application certificate found"
|
||||
|
||||
if [ "${{ inputs.fallback-to-adhoc }}" = "true" ]; then
|
||||
echo "Falling back to ad-hoc signing for testing..."
|
||||
# Use ad-hoc identity as fallback
|
||||
codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign - --timestamp "${{ inputs.app-path }}"
|
||||
echo "::set-output name=signed::adhoc"
|
||||
else
|
||||
echo "Skipping signing. Set fallback-to-adhoc=true to use ad-hoc signing instead."
|
||||
echo "::set-output name=signed::none"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Signing app bundle with Developer ID hash: $IDENTITY_HASH"
|
||||
|
||||
# Enhanced deep recursive signing for all binaries
|
||||
echo "🔍 Performing deep recursive signing of all components..."
|
||||
|
||||
# First, find all .dylib files and sign them individually
|
||||
echo "Signing all dynamic libraries (.dylib files)..."
|
||||
find "${{ inputs.app-path }}" -name "*.dylib" | while read -r dylib; do
|
||||
echo "Signing: $dylib"
|
||||
codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$dylib" || echo "⚠️ Failed to sign: $dylib"
|
||||
done
|
||||
|
||||
# Sign all .so files
|
||||
echo "Signing all shared objects (.so files)..."
|
||||
find "${{ inputs.app-path }}" -name "*.so" | while read -r so; do
|
||||
echo "Signing: $so"
|
||||
codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$so" || echo "⚠️ Failed to sign: $so"
|
||||
done
|
||||
|
||||
# Sign all executable files (files with execute permission)
|
||||
echo "Signing all executable files..."
|
||||
find "${{ inputs.app-path }}" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | while read -r exe; do
|
||||
echo "Signing executable: $exe"
|
||||
codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$exe" || echo "⚠️ Failed to sign: $exe"
|
||||
done
|
||||
|
||||
# Sign all frameworks
|
||||
echo "Signing frameworks..."
|
||||
find "${{ inputs.app-path }}" -path "*.framework" -type d | while read -r framework; do
|
||||
echo "Signing framework: $framework"
|
||||
codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$framework" || echo "⚠️ Failed to sign: $framework"
|
||||
done
|
||||
|
||||
# Special handling for CrashReportClient.app
|
||||
CRASH_REPORTER=$(find "${{ inputs.app-path }}" -path "*CrashReportClient.app" -type d | head -1)
|
||||
if [ -n "$CRASH_REPORTER" ]; then
|
||||
echo "🔍 Special handling for CrashReportClient.app: $CRASH_REPORTER"
|
||||
# Sign CrashReportClient.app specifically with focus on hardened runtime
|
||||
find "$CRASH_REPORTER" -type f -perm +111 | while read -r crash_bin; do
|
||||
echo "Signing CrashReportClient binary: $crash_bin"
|
||||
codesign --force --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$crash_bin" || echo "⚠️ Failed to sign: $crash_bin"
|
||||
done
|
||||
|
||||
echo "Signing the CrashReportClient.app bundle itself..."
|
||||
codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$CRASH_REPORTER" || echo "⚠️ Failed to sign CrashReportClient.app"
|
||||
fi
|
||||
|
||||
# Sign any other nested app bundles
|
||||
find "${{ inputs.app-path }}" -path "*.app" -type d | grep -v CrashReportClient | while read -r nested_app; do
|
||||
if [ "$nested_app" != "${{ inputs.app-path }}" ]; then
|
||||
echo "Signing nested app: $nested_app"
|
||||
codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "$nested_app" || echo "⚠️ Failed to sign: $nested_app"
|
||||
fi
|
||||
done
|
||||
|
||||
# Final signing of the main bundle
|
||||
echo "🔐 Performing final signing of the main app bundle..."
|
||||
codesign --force --deep --verbose --options runtime --entitlements "${{ inputs.entitlements-file }}" --sign "$IDENTITY_HASH" --timestamp "${{ inputs.app-path }}"
|
||||
echo "::set-output name=signed::identity"
|
||||
fi
|
||||
|
||||
# Verify signing
|
||||
echo "🔍 Verifying signature..."
|
||||
codesign -vvv --deep --strict "${{ inputs.app-path }}"
|
||||
|
||||
# Check entitlements
|
||||
echo "🔍 Checking entitlements..."
|
||||
codesign -d --entitlements - "${{ inputs.app-path }}"
|
||||
|
||||
# Verify CrashReportClient
|
||||
CRASH_REPORTER=$(find "${{ inputs.app-path }}" -path "*CrashReportClient.app" -type d | head -1)
|
||||
if [ -n "$CRASH_REPORTER" ]; then
|
||||
echo "🔍 Verifying CrashReportClient signature..."
|
||||
codesign -vvv --deep --strict "$CRASH_REPORTER" || echo "⚠️ CrashReportClient may have verification issues"
|
||||
|
||||
echo "CrashReportClient entitlements:"
|
||||
codesign -d --entitlements - "$CRASH_REPORTER" || echo "⚠️ Could not display CrashReportClient entitlements"
|
||||
fi
|
||||
|
||||
- name: Notarize App
|
||||
id: notarize
|
||||
if: steps.sign.outputs.signed != 'none'
|
||||
shell: bash
|
||||
env:
|
||||
APPLE_ID: ${{ inputs.notary-user }}
|
||||
APP_PASSWORD: ${{ inputs.notary-password }}
|
||||
API_KEY_ID: ${{ inputs.notary-api-key-id }}
|
||||
API_ISSUER_ID: ${{ inputs.notary-api-key-issuer-id }}
|
||||
API_KEY_PATH: ${{ inputs.notary-api-key-path }}
|
||||
run: |
|
||||
echo "📤 Notarizing app..."
|
||||
|
||||
# Set default output
|
||||
echo "::set-output name=notarized::false"
|
||||
|
||||
# Get app name for zip file naming
|
||||
APP_NAME=$(basename "${{ inputs.app-path }}" .app)
|
||||
BUNDLE_ID="${{ inputs.bundle-id }}"
|
||||
|
||||
# If bundle ID is not provided, try to extract from Info.plist
|
||||
if [ -z "$BUNDLE_ID" ]; then
|
||||
if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then
|
||||
BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist")
|
||||
echo "Extracted bundle ID: $BUNDLE_ID"
|
||||
else
|
||||
BUNDLE_ID="com.luckyrobots.app"
|
||||
echo "Using default bundle ID: $BUNDLE_ID"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if we're using API key notarization method
|
||||
if [ "${{ inputs.notarization-method }}" = "api-key" ] && [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then
|
||||
echo "Using App Store Connect API key for notarization..."
|
||||
|
||||
# Create directory for API key if API_KEY_PATH contains content
|
||||
mkdir -p ~/private_keys
|
||||
|
||||
# Check if API_KEY_PATH is a path or content
|
||||
if [[ "$API_KEY_PATH" == /* ]] && [ -f "$API_KEY_PATH" ]; then
|
||||
# It's a path to a file
|
||||
echo "Using API key from path: $API_KEY_PATH"
|
||||
cp "$API_KEY_PATH" ~/private_keys/AuthKey_${API_KEY_ID}.p8
|
||||
else
|
||||
# It contains the key content
|
||||
echo "Using API key from content"
|
||||
echo "$API_KEY_PATH" > ~/private_keys/AuthKey_${API_KEY_ID}.p8
|
||||
fi
|
||||
|
||||
# Create zip for notarization
|
||||
ZIP_PATH="${APP_NAME}-notarize.zip"
|
||||
ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH"
|
||||
|
||||
echo "Submitting for notarization with API key..."
|
||||
|
||||
# First, submit without waiting for completion
|
||||
SUBMIT_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \
|
||||
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
|
||||
--key-id "$API_KEY_ID" \
|
||||
--issuer "$API_ISSUER_ID" 2>&1)
|
||||
SUBMIT_STATUS=$?
|
||||
|
||||
# Display output for debugging
|
||||
echo "Notarization submission output:"
|
||||
echo "$SUBMIT_OUTPUT"
|
||||
echo "Submission exit status: $SUBMIT_STATUS"
|
||||
|
||||
# Check if submission was successful
|
||||
if [ $SUBMIT_STATUS -ne 0 ]; then
|
||||
echo "❌ Failed to submit for notarization. Exit code: $SUBMIT_STATUS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract submission ID for log retrieval
|
||||
SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2)
|
||||
|
||||
if [ -z "$SUBMISSION_ID" ]; then
|
||||
echo "❌ Could not extract submission ID from output. Notarization failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Submission ID: $SUBMISSION_ID"
|
||||
echo "Waiting for notarization to complete..."
|
||||
|
||||
# Now wait for the processing to complete
|
||||
COMPLETE=false
|
||||
MAX_ATTEMPTS=60 # Maximum number of attempts (60 * 30 seconds = 30 minutes max)
|
||||
ATTEMPT=1
|
||||
|
||||
while [ "$COMPLETE" = "false" ] && [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
|
||||
echo "Checking notarization status (attempt $ATTEMPT of $MAX_ATTEMPTS)..."
|
||||
|
||||
INFO_OUTPUT=$(xcrun notarytool info "$SUBMISSION_ID" \
|
||||
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
|
||||
--key-id "$API_KEY_ID" \
|
||||
--issuer "$API_ISSUER_ID" 2>&1)
|
||||
INFO_STATUS=$?
|
||||
|
||||
echo "Status check output:"
|
||||
echo "$INFO_OUTPUT"
|
||||
|
||||
# Check if the notarization is complete
|
||||
if echo "$INFO_OUTPUT" | grep -q "status: Accepted"; then
|
||||
echo "✅ Notarization completed successfully!"
|
||||
COMPLETE=true
|
||||
FINAL_STATUS="Accepted"
|
||||
elif echo "$INFO_OUTPUT" | grep -q "status: Invalid"; then
|
||||
echo "❌ Notarization failed with status: Invalid"
|
||||
COMPLETE=true
|
||||
FINAL_STATUS="Invalid"
|
||||
elif echo "$INFO_OUTPUT" | grep -q "status: Rejected"; then
|
||||
echo "❌ Notarization failed with status: Rejected"
|
||||
COMPLETE=true
|
||||
FINAL_STATUS="Rejected"
|
||||
else
|
||||
echo "Notarization still in progress. Waiting 30 seconds before checking again..."
|
||||
sleep 30
|
||||
ATTEMPT=$((ATTEMPT + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# Handle timeout
|
||||
if [ "$COMPLETE" = "false" ]; then
|
||||
echo "❌ Notarization timed out after $MAX_ATTEMPTS attempts."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle completed notarization
|
||||
if [ "$FINAL_STATUS" = "Accepted" ]; then
|
||||
# Get logs for information (even though successful)
|
||||
echo "📋 Getting notarization logs for information..."
|
||||
LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \
|
||||
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
|
||||
--key-id "$API_KEY_ID" \
|
||||
--issuer "$API_ISSUER_ID" 2>&1)
|
||||
|
||||
echo "==== NOTARIZATION LOG SUMMARY ===="
|
||||
echo "$LOGS_OUTPUT" | head -20
|
||||
echo "=================================="
|
||||
|
||||
# Staple the notarization ticket
|
||||
echo "Stapling notarization ticket..."
|
||||
xcrun stapler staple -v "${{ inputs.app-path }}"
|
||||
STAPLE_STATUS=$?
|
||||
|
||||
if [ $STAPLE_STATUS -eq 0 ]; then
|
||||
echo "✅ Stapling completed successfully!"
|
||||
|
||||
# Verify the stapling worked properly
|
||||
echo "Verifying stapled ticket is properly attached..."
|
||||
xcrun stapler validate -v "${{ inputs.app-path }}"
|
||||
|
||||
# Check if stapling metadata is correctly stored in xattr
|
||||
echo "Checking app extended attributes..."
|
||||
if command -v xattr &> /dev/null; then
|
||||
xattr "${{ inputs.app-path }}" | grep -q "com.apple.provenance" || echo "⚠️ Warning: com.apple.provenance attribute not found"
|
||||
fi
|
||||
|
||||
# Add special instructions for distribution
|
||||
echo "📋 IMPORTANT DISTRIBUTION NOTE: When users download this app, they may still see Gatekeeper warnings."
|
||||
echo "This happens because of the 'quarantine' extended attribute that browsers add to downloaded files."
|
||||
echo "For proper distribution, consider the following options:"
|
||||
echo "1. Use a DMG installer with a signed, notarized app inside"
|
||||
echo "2. Add instructions for users on how to open a quarantined app (right-click > Open)"
|
||||
echo "3. If distributing directly, use a distribution platform that preserves notarization tickets"
|
||||
else
|
||||
echo "⚠️ Stapling completed with status $STAPLE_STATUS (may still be valid)"
|
||||
fi
|
||||
|
||||
# Verify notarization
|
||||
echo "🔍 Verifying notarization..."
|
||||
spctl --assess --verbose --type exec "${{ inputs.app-path }}"
|
||||
|
||||
echo "::set-output name=notarized::true"
|
||||
else
|
||||
# Get detailed logs for failed notarization
|
||||
echo "📋 Fetching detailed logs for submission ID: $SUBMISSION_ID"
|
||||
LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \
|
||||
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
|
||||
--key-id "$API_KEY_ID" \
|
||||
--issuer "$API_ISSUER_ID" 2>&1)
|
||||
|
||||
echo "==== DETAILED NOTARIZATION LOGS ===="
|
||||
echo "$LOGS_OUTPUT"
|
||||
echo "=================================="
|
||||
|
||||
# Extract specific issues for easier debugging
|
||||
echo "🔍 Extracting specific issues from logs..."
|
||||
echo "$LOGS_OUTPUT" | grep -A 3 "issues"
|
||||
|
||||
# Show current bundle ID in Info.plist
|
||||
echo "📋 Current bundle ID information:"
|
||||
if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then
|
||||
echo "Info.plist content for bundle ID:"
|
||||
/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" || echo "Could not read bundle ID from Info.plist"
|
||||
echo "Full Info.plist excerpt:"
|
||||
plutil -p "${{ inputs.app-path }}/Contents/Info.plist" | grep -i bundle
|
||||
else
|
||||
echo "Info.plist not found at expected location: ${{ inputs.app-path }}/Contents/Info.plist"
|
||||
fi
|
||||
|
||||
# Check for mismatched bundle ID
|
||||
if [ "$BUNDLE_ID" != "$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" 2>/dev/null)" ]; then
|
||||
echo "⚠️ WARNING: Bundle ID mismatch detected between workflow and app!"
|
||||
echo " - Workflow/input bundle ID: $BUNDLE_ID"
|
||||
echo " - Actual app bundle ID: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" 2>/dev/null || echo "Could not read")"
|
||||
echo "This mismatch could cause notarization problems."
|
||||
fi
|
||||
|
||||
# Check for code signature issues in internal components
|
||||
echo "🔍 Checking for code signature issues in app components..."
|
||||
find "${{ inputs.app-path }}" -type f -name "*.dylib" -o -name "*.so" | head -5 | while read -r lib; do
|
||||
echo "Checking signature on: $lib"
|
||||
codesign -vvv "$lib" || echo "⚠️ Signature issue with: $lib"
|
||||
done
|
||||
|
||||
echo "❌ Notarization failed with status: $FINAL_STATUS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up
|
||||
rm -rf ~/private_keys
|
||||
|
||||
# Fall back to App-specific password if requested
|
||||
elif [ "${{ inputs.notarization-method }}" = "app-password" ] && [ -n "$APPLE_ID" ] && [ -n "$APP_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then
|
||||
echo "Using App-specific password for notarization..."
|
||||
|
||||
# Create zip for notarization
|
||||
ZIP_PATH="${APP_NAME}-notarize.zip"
|
||||
ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_PATH"
|
||||
|
||||
echo "Submitting for notarization..."
|
||||
|
||||
# First, submit without waiting for completion
|
||||
SUBMIT_OUTPUT=$(xcrun notarytool submit "$ZIP_PATH" \
|
||||
--apple-id "$APPLE_ID" \
|
||||
--password "$APP_PASSWORD" \
|
||||
--team-id "$APPLE_TEAM_ID" 2>&1)
|
||||
SUBMIT_STATUS=$?
|
||||
|
||||
# Display output for debugging
|
||||
echo "Notarization submission output:"
|
||||
echo "$SUBMIT_OUTPUT"
|
||||
echo "Submission exit status: $SUBMIT_STATUS"
|
||||
|
||||
# Check if submission was successful
|
||||
if [ $SUBMIT_STATUS -ne 0 ]; then
|
||||
echo "❌ Failed to submit for notarization. Exit code: $SUBMIT_STATUS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract submission ID for log retrieval
|
||||
SUBMISSION_ID=$(echo "$SUBMIT_OUTPUT" | grep -o "id: [a-f0-9\-]*" | head -1 | cut -d ' ' -f 2)
|
||||
|
||||
if [ -z "$SUBMISSION_ID" ]; then
|
||||
echo "❌ Could not extract submission ID from output. Notarization failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Submission ID: $SUBMISSION_ID"
|
||||
echo "Waiting for notarization to complete..."
|
||||
|
||||
# Now wait for the processing to complete
|
||||
COMPLETE=false
|
||||
MAX_ATTEMPTS=60 # Maximum number of attempts (60 * 30 seconds = 30 minutes max)
|
||||
ATTEMPT=1
|
||||
|
||||
while [ "$COMPLETE" = "false" ] && [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
|
||||
echo "Checking notarization status (attempt $ATTEMPT of $MAX_ATTEMPTS)..."
|
||||
|
||||
INFO_OUTPUT=$(xcrun notarytool info "$SUBMISSION_ID" \
|
||||
--apple-id "$APPLE_ID" \
|
||||
--password "$APP_PASSWORD" \
|
||||
--team-id "$APPLE_TEAM_ID" 2>&1)
|
||||
INFO_STATUS=$?
|
||||
|
||||
echo "Status check output:"
|
||||
echo "$INFO_OUTPUT"
|
||||
|
||||
# Check if the notarization is complete
|
||||
if echo "$INFO_OUTPUT" | grep -q "status: Accepted"; then
|
||||
echo "✅ Notarization completed successfully!"
|
||||
COMPLETE=true
|
||||
FINAL_STATUS="Accepted"
|
||||
elif echo "$INFO_OUTPUT" | grep -q "status: Invalid"; then
|
||||
echo "❌ Notarization failed with status: Invalid"
|
||||
COMPLETE=true
|
||||
FINAL_STATUS="Invalid"
|
||||
elif echo "$INFO_OUTPUT" | grep -q "status: Rejected"; then
|
||||
echo "❌ Notarization failed with status: Rejected"
|
||||
COMPLETE=true
|
||||
FINAL_STATUS="Rejected"
|
||||
else
|
||||
echo "Notarization still in progress. Waiting 30 seconds before checking again..."
|
||||
sleep 30
|
||||
ATTEMPT=$((ATTEMPT + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# Handle timeout
|
||||
if [ "$COMPLETE" = "false" ]; then
|
||||
echo "❌ Notarization timed out after $MAX_ATTEMPTS attempts."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle completed notarization
|
||||
if [ "$FINAL_STATUS" = "Accepted" ]; then
|
||||
# Get logs for information (even though successful)
|
||||
echo "📋 Getting notarization logs for information..."
|
||||
LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \
|
||||
--apple-id "$APPLE_ID" \
|
||||
--password "$APP_PASSWORD" \
|
||||
--team-id "$APPLE_TEAM_ID" 2>&1)
|
||||
|
||||
echo "==== NOTARIZATION LOG SUMMARY ===="
|
||||
echo "$LOGS_OUTPUT" | head -20
|
||||
echo "=================================="
|
||||
|
||||
# Staple the notarization ticket
|
||||
echo "Stapling notarization ticket..."
|
||||
xcrun stapler staple -v "${{ inputs.app-path }}"
|
||||
STAPLE_STATUS=$?
|
||||
|
||||
if [ $STAPLE_STATUS -eq 0 ]; then
|
||||
echo "✅ Stapling completed successfully!"
|
||||
|
||||
# Verify the stapling worked properly
|
||||
echo "Verifying stapled ticket is properly attached..."
|
||||
xcrun stapler validate -v "${{ inputs.app-path }}"
|
||||
|
||||
# Check if stapling metadata is correctly stored in xattr
|
||||
echo "Checking app extended attributes..."
|
||||
if command -v xattr &> /dev/null; then
|
||||
xattr "${{ inputs.app-path }}" | grep -q "com.apple.provenance" || echo "⚠️ Warning: com.apple.provenance attribute not found"
|
||||
fi
|
||||
|
||||
# Add special instructions for distribution
|
||||
echo "📋 IMPORTANT DISTRIBUTION NOTE: When users download this app, they may still see Gatekeeper warnings."
|
||||
echo "This happens because of the 'quarantine' extended attribute that browsers add to downloaded files."
|
||||
echo "For proper distribution, consider the following options:"
|
||||
echo "1. Use a DMG installer with a signed, notarized app inside"
|
||||
echo "2. Add instructions for users on how to open a quarantined app (right-click > Open)"
|
||||
echo "3. If distributing directly, use a distribution platform that preserves notarization tickets"
|
||||
else
|
||||
echo "⚠️ Stapling completed with status $STAPLE_STATUS (may still be valid)"
|
||||
fi
|
||||
|
||||
# Verify notarization
|
||||
echo "🔍 Verifying notarization..."
|
||||
spctl --assess --verbose --type exec "${{ inputs.app-path }}"
|
||||
|
||||
echo "::set-output name=notarized::true"
|
||||
else
|
||||
# Get detailed logs for failed notarization
|
||||
echo "📋 Fetching detailed logs for submission ID: $SUBMISSION_ID"
|
||||
LOGS_OUTPUT=$(xcrun notarytool log "$SUBMISSION_ID" \
|
||||
--apple-id "$APPLE_ID" \
|
||||
--password "$APP_PASSWORD" \
|
||||
--team-id "$APPLE_TEAM_ID" 2>&1)
|
||||
|
||||
echo "==== DETAILED NOTARIZATION LOGS ===="
|
||||
echo "$LOGS_OUTPUT"
|
||||
echo "=================================="
|
||||
|
||||
# Extract specific issues for easier debugging
|
||||
echo "🔍 Extracting specific issues from logs..."
|
||||
echo "$LOGS_OUTPUT" | grep -A 3 "issues"
|
||||
|
||||
# Show current bundle ID in Info.plist
|
||||
echo "📋 Current bundle ID information:"
|
||||
if [ -f "${{ inputs.app-path }}/Contents/Info.plist" ]; then
|
||||
echo "Info.plist content for bundle ID:"
|
||||
/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${{ inputs.app-path }}/Contents/Info.plist" || echo "Could not read bundle ID from Info.plist"
|
||||
echo "Full Info.plist excerpt:"
|
||||
plutil -p "${{ inputs.app-path }}/Contents/Info.plist" | grep -i bundle
|
||||
else
|
||||
echo "Info.plist not found at expected location: ${{ inputs.app-path }}/Contents/Info.plist"
|
||||
fi
|
||||
|
||||
echo "❌ Notarization failed with status: $FINAL_STATUS"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Missing notarization credentials. Skipping notarization."
|
||||
echo "For App Store Connect API key method, set these inputs:"
|
||||
echo " - notarization-method: api-key"
|
||||
echo " - notary-api-key-id: Your API key ID"
|
||||
echo " - notary-api-key-issuer-id: Your API issuer ID"
|
||||
echo " - notary-api-key-path: Path to or content of your p8 file"
|
||||
echo ""
|
||||
echo "For App-specific password method, set these inputs:"
|
||||
echo " - notarization-method: app-password"
|
||||
echo " - notary-user: Your Apple ID (email)"
|
||||
echo " - notary-password: Your app-specific password"
|
||||
echo " - team-id: Your Apple Developer team ID"
|
||||
fi
|
||||
|
||||
- name: Package App
|
||||
id: package
|
||||
if: steps.sign.outputs.signed != 'none'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "📦 Packaging signed app..."
|
||||
|
||||
# Get app name for zip file naming
|
||||
APP_NAME=$(basename "${{ inputs.app-path }}" .app)
|
||||
|
||||
if [ "${{ steps.notarize.outputs.notarized }}" = "true" ]; then
|
||||
PACKAGE_SUFFIX="Signed-Notarized"
|
||||
echo "Creating distribution package with notarized app..."
|
||||
else
|
||||
PACKAGE_SUFFIX="Signed"
|
||||
echo "Creating distribution package with signed app..."
|
||||
fi
|
||||
|
||||
# Create zip package
|
||||
ZIP_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.zip"
|
||||
ditto -c -k --keepParent "${{ inputs.app-path }}" "$ZIP_FILE"
|
||||
echo "✅ Created ZIP package: $ZIP_FILE"
|
||||
|
||||
# Check if we can create DMG (hdiutil is available)
|
||||
if command -v hdiutil &> /dev/null; then
|
||||
# Create DMG package (much better for distribution)
|
||||
DMG_FILE="${APP_NAME}-${PACKAGE_SUFFIX}.dmg"
|
||||
echo "Creating DMG distribution package..."
|
||||
|
||||
# Create temporary folder for DMG contents
|
||||
DMG_TMP_DIR=$(mktemp -d)
|
||||
cp -R "${{ inputs.app-path }}" "$DMG_TMP_DIR/"
|
||||
|
||||
# Optional: Add README or instructions
|
||||
echo "# Installation Instructions\n\nDrag the application to your Applications folder to install." > "$DMG_TMP_DIR/README.txt"
|
||||
|
||||
# Create DMG file with the app
|
||||
hdiutil create -volname "${APP_NAME}" -srcfolder "$DMG_TMP_DIR" -ov -format UDZO "$DMG_FILE"
|
||||
|
||||
if [ -f "$DMG_FILE" ]; then
|
||||
echo "✅ Created DMG package: $DMG_FILE"
|
||||
# Use DMG as the primary package if available
|
||||
echo "::set-output name=package-path::$DMG_FILE"
|
||||
echo "::set-output name=zip-package-path::$ZIP_FILE"
|
||||
else
|
||||
echo "⚠️ Failed to create DMG, falling back to ZIP package"
|
||||
echo "::set-output name=package-path::$ZIP_FILE"
|
||||
fi
|
||||
|
||||
# Clean up temp directory
|
||||
rm -rf "$DMG_TMP_DIR"
|
||||
else
|
||||
echo "hdiutil not available, skipping DMG creation"
|
||||
echo "::set-output name=package-path::$ZIP_FILE"
|
||||
fi
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
echo "🧹 Cleaning up..."
|
||||
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true
|
||||
rm -f *-notarize.zip || true
|
||||
echo "✅ Cleanup complete"
|
42
.gitea/actions/windows-build/action.yml
Normal file
42
.gitea/actions/windows-build/action.yml
Normal file
@ -0,0 +1,42 @@
|
||||
name: 'Windows Build Steps'
|
||||
description: 'Build Windows application'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Setup environment
|
||||
run: |
|
||||
# Set environment variables for Unreal Engine
|
||||
echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV
|
||||
|
||||
# Create directories for builds
|
||||
if (!(Test-Path "Builds/Windows")) { New-Item -ItemType Directory -Path "Builds/Windows" -Force }
|
||||
if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force }
|
||||
shell: pwsh
|
||||
|
||||
- name: Build for Windows
|
||||
run: |
|
||||
# Chmod command doesn't exist in Windows, use PowerShell to run the bash script
|
||||
& 'C:\Program Files\Git\bin\bash.exe' -c "./scripts/win_build.sh"
|
||||
shell: pwsh
|
||||
|
||||
- name: Package Windows build
|
||||
run: |
|
||||
echo "Packaging Windows build..."
|
||||
if [ -d "Builds/Windows" ]; then
|
||||
cd Builds/Windows
|
||||
zip -r ../../PackagedReleases/LuckyRobots-Windows.zip .
|
||||
cd ../..
|
||||
fi
|
||||
|
||||
echo "=== Packaged Windows release ==="
|
||||
ls -la PackagedReleases/
|
||||
shell: bash
|
||||
|
||||
- name: Upload Windows Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
if: success() && hashFiles('PackagedReleases/LuckyRobots-Windows.zip') != ''
|
||||
with:
|
||||
name: LuckyRobots-Windows
|
||||
path: PackagedReleases/LuckyRobots-Windows.zip
|
||||
retention-days: 365
|
209
.gitea/workflows/build.yml
Normal file
209
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,209 @@
|
||||
name: Unreal Engine Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# push:
|
||||
# branches: [ozgur/build]
|
||||
|
||||
jobs:
|
||||
windows-build:
|
||||
runs-on: windows
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build Windows
|
||||
uses: ./.gitea/actions/windows-build
|
||||
|
||||
linux-build:
|
||||
runs-on: windows
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build Linux
|
||||
uses: ./.gitea/actions/linux-build
|
||||
|
||||
macos-build:
|
||||
runs-on: macos
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build macOS
|
||||
uses: ./.gitea/actions/macos-build
|
||||
with:
|
||||
apple_team_id: ${{ secrets.APPLE_TEAM_ID }}
|
||||
apple_certificate_base64: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
apple_certificate_password: ${{ secrets.MACOS_CERTIFICATE_PWD }}
|
||||
api_key_path: ${{ secrets.NOTARY_API_KEY_PATH }}
|
||||
api_key_id: ${{ secrets.NOTARY_API_KEY_ID }}
|
||||
api_key_issuer_id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }}
|
||||
|
||||
create-release:
|
||||
needs: [windows-build, linux-build, macos-build]
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create Tag
|
||||
run: |
|
||||
# Fetch all tags
|
||||
git fetch --tags
|
||||
|
||||
# Get the latest version tag, if any
|
||||
LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n1)
|
||||
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
# No previous version tag, start with 1.0.0
|
||||
NEW_VERSION="1.0.0"
|
||||
echo "No previous version tags found, starting with 1.0.0"
|
||||
else
|
||||
# Strip 'v' prefix if it exists
|
||||
VERSION=${LATEST_TAG#v}
|
||||
|
||||
# Split version into parts
|
||||
MAJOR=$(echo $VERSION | cut -d. -f1)
|
||||
MINOR=$(echo $VERSION | cut -d. -f2)
|
||||
PATCH=$(echo $VERSION | cut -d. -f3)
|
||||
|
||||
# Auto-increment patch version
|
||||
PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
|
||||
echo "Auto-incremented patch version from ${VERSION} to ${NEW_VERSION}"
|
||||
fi
|
||||
|
||||
# Final tag with v prefix
|
||||
TAG="v${NEW_VERSION}"
|
||||
echo "Creating git tag: $TAG"
|
||||
|
||||
# Configure git with token authentication
|
||||
git config --global user.email "actions@gitea.com"
|
||||
git config --global user.name "Gitea Actions"
|
||||
|
||||
# Direct token approach
|
||||
git remote set-url origin "https://runner:${{ secrets.GITEATOKEN }}@luckyrobots.com/luckyrobots/luckyworld.git"
|
||||
|
||||
# Check if tag exists
|
||||
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
# Create tag
|
||||
git tag -a "$TAG" -m "Release $TAG"
|
||||
|
||||
# Push tag
|
||||
git push origin "$TAG"
|
||||
echo "Successfully created and pushed tag: $TAG"
|
||||
else
|
||||
echo "Tag $TAG already exists, skipping tag creation"
|
||||
fi
|
||||
echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: releases
|
||||
|
||||
- name: Create Build Info
|
||||
run: |
|
||||
# Create a build info JSON file
|
||||
echo '{
|
||||
"version": "${{ env.RELEASE_TAG }}",
|
||||
"buildNumber": "${{ github.run_number }}",
|
||||
"commit": "${{ github.sha }}",
|
||||
"branch": "${{ github.ref_name }}",
|
||||
"buildDate": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",
|
||||
"artifacts": {
|
||||
"windows": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows",
|
||||
"linux": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux",
|
||||
"macos": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS"
|
||||
}
|
||||
}' > build-info.json
|
||||
|
||||
# Create a simple HTML download page
|
||||
echo '<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LuckyRobots ${{ env.RELEASE_TAG }} Downloads</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
margin: 10px 5px;
|
||||
}
|
||||
.download-btn:hover { background-color: #45a049; }
|
||||
.platform { margin-bottom: 30px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LuckyRobots Game - ${{ env.RELEASE_TAG }}</h1>
|
||||
<p>Build #${{ github.run_number }} - Built from commit: ${{ github.sha }}</p>
|
||||
|
||||
<div class="platform">
|
||||
<h2>Windows</h2>
|
||||
<p><a href="https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows" class="download-btn">Download Windows Build</a></p>
|
||||
</div>
|
||||
|
||||
<div class="platform">
|
||||
<h2>Linux</h2>
|
||||
<p><a href="https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux" class="download-btn">Download Linux Build</a></p>
|
||||
</div>
|
||||
|
||||
<div class="platform">
|
||||
<h2>macOS</h2>
|
||||
<p><a href="https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS" class="download-btn">Download macOS Build</a></p>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>Generated on '$(date -u +"%Y-%m-%d %H:%M:%S UTC")'</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>' > downloads.html
|
||||
|
||||
- name: Create Release
|
||||
uses: https://gitea.com/actions/gitea-release-action@main
|
||||
with:
|
||||
files: |-
|
||||
build-info.json
|
||||
downloads.html
|
||||
token: '${{ secrets.GITEATOKEN }}'
|
||||
title: 'Release ${{ env.RELEASE_TAG }}'
|
||||
body: |
|
||||
## LuckyRobots Game Release ${{ env.RELEASE_TAG }}
|
||||
|
||||
### Download Links
|
||||
|
||||
Download builds from our CI artifacts:
|
||||
|
||||
- [Windows Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows)
|
||||
- [Linux Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux)
|
||||
- [macOS Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS)
|
||||
|
||||
### Build Information
|
||||
|
||||
- Build Number: #${{ github.run_number }}
|
||||
- Commit: ${{ github.sha }}
|
||||
- Branch: ${{ github.ref_name }}
|
||||
- Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
prerelease: ${{ github.ref != 'refs/heads/main' }}
|
||||
tag_name: '${{ env.RELEASE_TAG }}'
|
||||
|
@ -1,103 +0,0 @@
|
||||
name: Unreal Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
windows_build_path:
|
||||
description: 'Absolute path to the Windows build zip file'
|
||||
required: true
|
||||
default: 'E:\LuckyWorld\LuckyRobots\UNREAL_PROJECTS\Luckyrobots\Builds\Windows\LuckyRobots-Windows.zip'
|
||||
linux_build_path:
|
||||
description: 'Absolute path to the Linux build zip file'
|
||||
required: true
|
||||
default: 'E:\LuckyWorld\LuckyRobots\UNREAL_PROJECTS\Luckyrobots\Builds\Linux\LuckyRobots-Linux.zip'
|
||||
mac_build_path:
|
||||
description: 'Absolute path to the Mac build zip file'
|
||||
required: true
|
||||
default: 'E:\LuckyWorld\LuckyRobots\UNREAL_PROJECTS\Luckyrobots\Builds\Mac\LuckyRobots-Mac.zip'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows
|
||||
steps:
|
||||
- name: Upload Linux Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: LuckyRobots-Linux
|
||||
path: ${{ github.event.inputs.linux_build_path }}
|
||||
retention-days: 365
|
||||
|
||||
- name: Upload Windows Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: LuckyRobots-Windows
|
||||
path: ${{ github.event.inputs.windows_build_path }}
|
||||
retention-days: 365
|
||||
|
||||
- name: Upload Mac Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: LuckyRobots-Mac
|
||||
path: ${{ github.event.inputs.mac_build_path }}
|
||||
retention-days: 365
|
||||
|
||||
- name: Get Release Tag
|
||||
shell: pwsh
|
||||
run: |
|
||||
# Fetch all tags
|
||||
git fetch --tags
|
||||
|
||||
# Get the latest version tag, if any
|
||||
# Uses Sort-Object with a version comparison scriptblock
|
||||
$latestTag = git tag -l "v[0-9]*.[0-9]*.[0-9]*" | Sort-Object -Property @{Expression={[version]($_ -replace 'v')}} | Select-Object -Last 1
|
||||
|
||||
$newVersion = "1.0.0" # Default start version
|
||||
|
||||
if ($null -ne $latestTag -and $latestTag -ne '') {
|
||||
Write-Host "Latest tag found: $latestTag"
|
||||
# Strip 'v' prefix
|
||||
$versionString = $latestTag -replace '^v'
|
||||
|
||||
# Split version into parts
|
||||
$versionParts = $versionString.Split('.')
|
||||
if ($versionParts.Length -eq 3) {
|
||||
$major = [int]$versionParts[0]
|
||||
$minor = [int]$versionParts[1]
|
||||
$patch = [int]$versionParts[2]
|
||||
|
||||
# Auto-increment patch version
|
||||
$patch++
|
||||
$newVersion = "$major.$minor.$patch"
|
||||
Write-Host "Auto-incremented patch version from $versionString to $newVersion"
|
||||
} else {
|
||||
Write-Host "Could not parse version from tag: $latestTag. Defaulting to 1.0.0"
|
||||
}
|
||||
} else {
|
||||
Write-Host "No previous version tags found, starting with 1.0.0"
|
||||
}
|
||||
|
||||
# Final tag with v prefix
|
||||
$tag = "v$newVersion"
|
||||
|
||||
# Set environment variable for subsequent steps
|
||||
echo "RELEASE_TAG=$tag" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
Write-Host "Using release tag: $tag"
|
||||
|
||||
- name: Create Release
|
||||
uses: https://gitea.com/actions/gitea-release-action@main
|
||||
with:
|
||||
token: '${{ secrets.GITEA_TOKEN }}'
|
||||
title: 'Release ${{ env.RELEASE_TAG }}'
|
||||
body: |
|
||||
## LuckyRobots Game Release ${{ env.RELEASE_TAG }}
|
||||
|
||||
Windows, Linux and Mac builds are attached below.
|
||||
|
||||
### Build Information
|
||||
|
||||
- Build Number: #${{ github.run_number }}
|
||||
- Commit: ${{ github.sha }}
|
||||
- Branch: ${{ github.ref_name }}
|
||||
- Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
prerelease: ${{ github.ref != 'refs/heads/main' }}
|
||||
tag_name: '${{ env.RELEASE_TAG }}'
|
163
.gitea/workflows/release.yml
Normal file
163
.gitea/workflows/release.yml
Normal file
@ -0,0 +1,163 @@
|
||||
name: Create Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
create-release:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Create Tag
|
||||
run: |
|
||||
# Fetch all tags
|
||||
git fetch --tags
|
||||
|
||||
# Get the latest version tag, if any
|
||||
LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n1)
|
||||
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
# No previous version tag, start with 1.0.0
|
||||
NEW_VERSION="1.0.0"
|
||||
echo "No previous version tags found, starting with 1.0.0"
|
||||
else
|
||||
# Strip 'v' prefix if it exists
|
||||
VERSION=${LATEST_TAG#v}
|
||||
|
||||
# Split version into parts
|
||||
MAJOR=$(echo $VERSION | cut -d. -f1)
|
||||
MINOR=$(echo $VERSION | cut -d. -f2)
|
||||
PATCH=$(echo $VERSION | cut -d. -f3)
|
||||
|
||||
# Auto-increment patch version
|
||||
PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
|
||||
echo "Auto-incremented patch version from ${VERSION} to ${NEW_VERSION}"
|
||||
fi
|
||||
|
||||
# Final tag with v prefix
|
||||
TAG="v${NEW_VERSION}"
|
||||
echo "Creating git tag: $TAG"
|
||||
|
||||
# Configure git with token authentication
|
||||
git config --global user.email "actions@gitea.com"
|
||||
git config --global user.name "Gitea Actions"
|
||||
|
||||
# Direct token approach
|
||||
git remote set-url origin "https://runner:${{ secrets.GITEATOKEN }}@luckyrobots.com/luckyrobots/luckyworld.git"
|
||||
|
||||
# Check if tag exists
|
||||
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
# Create tag
|
||||
git tag -a "$TAG" -m "Release $TAG"
|
||||
|
||||
# Push tag
|
||||
git push origin "$TAG"
|
||||
echo "Successfully created and pushed tag: $TAG"
|
||||
else
|
||||
echo "Tag $TAG already exists, skipping tag creation"
|
||||
fi
|
||||
echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: releases
|
||||
|
||||
- name: Create Build Info
|
||||
run: |
|
||||
# Create a build info JSON file
|
||||
echo '{
|
||||
"version": "${{ env.RELEASE_TAG }}",
|
||||
"buildNumber": "${{ github.run_number }}",
|
||||
"commit": "${{ github.sha }}",
|
||||
"branch": "${{ github.ref_name }}",
|
||||
"buildDate": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",
|
||||
"artifacts": {
|
||||
"windows": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows",
|
||||
"linux": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux",
|
||||
"macos": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS"
|
||||
}
|
||||
}' > build-info.json
|
||||
|
||||
# Create a simple HTML download page
|
||||
echo '<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LuckyRobots ${{ env.RELEASE_TAG }} Downloads</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
margin: 10px 5px;
|
||||
}
|
||||
.download-btn:hover { background-color: #45a049; }
|
||||
.platform { margin-bottom: 30px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LuckyRobots Game - ${{ env.RELEASE_TAG }}</h1>
|
||||
<p>Build #${{ github.run_number }} - Built from commit: ${{ github.sha }}</p>
|
||||
|
||||
<div class="platform">
|
||||
<h2>Windows</h2>
|
||||
<p><a href="https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows" class="download-btn">Download Windows Build</a></p>
|
||||
</div>
|
||||
|
||||
<div class="platform">
|
||||
<h2>Linux</h2>
|
||||
<p><a href="https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux" class="download-btn">Download Linux Build</a></p>
|
||||
</div>
|
||||
|
||||
<div class="platform">
|
||||
<h2>macOS</h2>
|
||||
<p><a href="https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS" class="download-btn">Download macOS Build</a></p>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>Generated on '$(date -u +"%Y-%m-%d %H:%M:%S UTC")'</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>' > downloads.html
|
||||
|
||||
- name: Create Release
|
||||
uses: https://gitea.com/actions/gitea-release-action@main
|
||||
with:
|
||||
files: |-
|
||||
build-info.json
|
||||
downloads.html
|
||||
token: '${{ secrets.GITEATOKEN }}'
|
||||
title: 'Release ${{ env.RELEASE_TAG }}'
|
||||
body: |
|
||||
## LuckyRobots Game Release ${{ env.RELEASE_TAG }}
|
||||
|
||||
### Download Links
|
||||
|
||||
Download builds from our CI artifacts:
|
||||
|
||||
- [Windows Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows)
|
||||
- [Linux Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux)
|
||||
- [macOS Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS)
|
||||
|
||||
### Build Information
|
||||
|
||||
- Build Number: #${{ github.run_number }}
|
||||
- Commit: ${{ github.sha }}
|
||||
- Branch: ${{ github.ref_name }}
|
||||
- Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
prerelease: ${{ github.ref != 'refs/heads/main' }}
|
||||
tag_name: '${{ env.RELEASE_TAG }}'
|
388
.gitea/workflows/test-local-signing.yml
Normal file
388
.gitea/workflows/test-local-signing.yml
Normal file
@ -0,0 +1,388 @@
|
||||
name: Test Local Signing
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Manual trigger
|
||||
# push:
|
||||
# branches: [ozgur/build]
|
||||
|
||||
jobs:
|
||||
test-local-signing:
|
||||
runs-on: macos
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Create Test Entitlements
|
||||
run: |
|
||||
echo "📝 Creating entitlements file..."
|
||||
cat > LuckyWorld.entitlements << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
echo "✅ Created entitlements file"
|
||||
cat LuckyWorld.entitlements
|
||||
shell: bash
|
||||
|
||||
- name: Create Test App Bundle
|
||||
run: |
|
||||
echo "📦 Creating test app bundle..."
|
||||
|
||||
# Create test app bundle structure
|
||||
TEST_APP_DIR="TestApp.app"
|
||||
mkdir -p "$TEST_APP_DIR/Contents/MacOS"
|
||||
|
||||
# Create a simple test executable
|
||||
echo '#!/bin/bash
|
||||
echo "Hello from TestApp!"' > "$TEST_APP_DIR/Contents/MacOS/TestApp"
|
||||
chmod +x "$TEST_APP_DIR/Contents/MacOS/TestApp"
|
||||
|
||||
# Create Info.plist
|
||||
cat > "$TEST_APP_DIR/Contents/Info.plist" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>TestApp</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.luckyrobots.luckyworld.testapp</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>TestApp</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.10</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
echo "✅ Created test app bundle"
|
||||
|
||||
# Verify app bundle exists
|
||||
if [ ! -d "$TEST_APP_DIR" ]; then
|
||||
echo "❌ Error: App bundle not found at $TEST_APP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔍 App bundle contents:"
|
||||
ls -la "$TEST_APP_DIR"
|
||||
|
||||
# Store app path as environment variable
|
||||
echo "APP_PATH=$(pwd)/TestApp.app" >> "$GITHUB_ENV"
|
||||
shell: bash
|
||||
|
||||
- name: Setup Certificate
|
||||
env:
|
||||
CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
run: |
|
||||
echo "🔐 Setting up certificate..."
|
||||
|
||||
# Create a temporary directory for certificates
|
||||
CERT_DIR="$HOME/certificates"
|
||||
mkdir -p "$CERT_DIR"
|
||||
|
||||
# Decode the certificate to a p12 file
|
||||
echo "$CERTIFICATE_BASE64" | base64 --decode > "$CERT_DIR/certificate.p12"
|
||||
|
||||
# Check certificate format and details
|
||||
echo "📑 Certificate format check:"
|
||||
file "$CERT_DIR/certificate.p12"
|
||||
|
||||
# Try to get certificate info with openssl
|
||||
echo "📑 Certificate info with OpenSSL:"
|
||||
openssl pkcs12 -info -in "$CERT_DIR/certificate.p12" -nokeys -passin pass:"$CERTIFICATE_PASSWORD" || echo "Failed to read certificate with OpenSSL"
|
||||
|
||||
# Create keychain
|
||||
KEYCHAIN_PATH="$CERT_DIR/app-signing.keychain-db"
|
||||
KEYCHAIN_PASSWORD="temppassword123"
|
||||
|
||||
# Delete existing keychain if it exists
|
||||
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true
|
||||
|
||||
# Create new keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
security set-keychain-settings -t 3600 -u -l "$KEYCHAIN_PATH"
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
|
||||
# Add to search list and make default
|
||||
security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"')
|
||||
security default-keychain -s "$KEYCHAIN_PATH"
|
||||
|
||||
# Try multiple import approaches
|
||||
echo "🔑 Importing developer certificate - attempt 1 (standard)..."
|
||||
security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
|
||||
|
||||
echo "🔑 Importing developer certificate - attempt 2 (with flags)..."
|
||||
security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -x -A
|
||||
|
||||
echo "🔑 Importing developer certificate - attempt 3 (with format)..."
|
||||
security import "$CERT_DIR/certificate.p12" -k "$KEYCHAIN_PATH" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign -f pkcs12
|
||||
|
||||
# Set partition list for codesign to access keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
|
||||
# Check all certificates in keychain
|
||||
echo "🔍 Listing all certificates in keychain..."
|
||||
security find-certificate -a "$KEYCHAIN_PATH"
|
||||
|
||||
# Verify certificate
|
||||
echo "🔍 Verifying code signing identities..."
|
||||
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
|
||||
|
||||
# Alternative check for identities
|
||||
echo "🔍 Listing identities with code signing usage..."
|
||||
security find-certificate -a -c "Developer ID Application" -p "$KEYCHAIN_PATH" | grep -q "Code Signing" && echo "✅ Certificate has code signing usage" || echo "❌ Certificate does NOT have code signing usage"
|
||||
|
||||
# Try to use the System keychain as a fallback
|
||||
echo "🔍 Checking system keychain for code signing identities..."
|
||||
SYSTEM_IDENTITIES=$(security find-identity -v -p codesigning)
|
||||
echo "$SYSTEM_IDENTITIES"
|
||||
|
||||
if echo "$SYSTEM_IDENTITIES" | grep -q "Developer ID Application"; then
|
||||
echo "✅ Found Developer ID Application certificate in system keychain"
|
||||
echo "USE_SYSTEM_CERT=true" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "❌ No Developer ID Application certificate found in system keychain"
|
||||
echo "USE_SYSTEM_CERT=false" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
# Store keychain variables for later steps
|
||||
echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV"
|
||||
echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> "$GITHUB_ENV"
|
||||
echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" >> "$GITHUB_ENV"
|
||||
|
||||
# Debug: keep p12 file for inspection
|
||||
echo "💾 Keeping certificate.p12 for debugging"
|
||||
shell: bash
|
||||
|
||||
- name: Debug Certificate Content
|
||||
if: always()
|
||||
env:
|
||||
CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
|
||||
run: |
|
||||
echo "🔎 Debugging certificate content..."
|
||||
CERT_DIR="$HOME/certificates"
|
||||
|
||||
# Check if p12 file exists
|
||||
if [ ! -f "$CERT_DIR/certificate.p12" ]; then
|
||||
echo "❌ Certificate file not found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Try with OpenSSL to extract certificate info
|
||||
echo "Attempting to extract certificate info..."
|
||||
openssl pkcs12 -in "$CERT_DIR/certificate.p12" -info -nokeys -passin pass:"$CERTIFICATE_PASSWORD" > cert_info.txt || echo "Failed to extract info"
|
||||
|
||||
# Check certificate contents
|
||||
echo "Certificate subject information:"
|
||||
grep "subject" cert_info.txt || echo "No subject information found"
|
||||
|
||||
echo "Certificate issuer information:"
|
||||
grep "issuer" cert_info.txt || echo "No issuer information found"
|
||||
|
||||
# Check if it's a Developer ID certificate
|
||||
if grep -q "Developer ID" cert_info.txt; then
|
||||
echo "✅ This appears to be a Developer ID certificate"
|
||||
else
|
||||
echo "❌ This does NOT appear to be a Developer ID certificate"
|
||||
fi
|
||||
|
||||
# Check if it has a private key
|
||||
echo "Checking for private key..."
|
||||
if openssl pkcs12 -in "$CERT_DIR/certificate.p12" -nocerts -passin pass:"$CERTIFICATE_PASSWORD" -passout pass:temp 2>/dev/null; then
|
||||
echo "✅ Certificate contains a private key"
|
||||
else
|
||||
echo "❌ Certificate does NOT contain a private key or wrong password"
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Sign with Developer ID
|
||||
run: |
|
||||
echo "🔏 Signing app with Developer ID certificate..."
|
||||
|
||||
# Decide which keychain to use
|
||||
if [ "${USE_SYSTEM_CERT:-false}" = "true" ]; then
|
||||
echo "Using system keychain identity"
|
||||
# Get certificate hash instead of name to avoid ambiguity
|
||||
IDENTITY_HASH=$(security find-identity -v -p codesigning | grep "Developer ID Application" | head -1 | awk '{print $2}')
|
||||
echo "Using certificate hash: $IDENTITY_HASH"
|
||||
else
|
||||
# Make sure keychain is unlocked
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
||||
echo "Using custom keychain identity"
|
||||
# Get certificate hash instead of name to avoid ambiguity
|
||||
IDENTITY_HASH=$(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" | head -1 | awk '{print $2}')
|
||||
echo "Using certificate hash: $IDENTITY_HASH"
|
||||
fi
|
||||
|
||||
if [ -z "$IDENTITY_HASH" ]; then
|
||||
echo "❌ No valid Developer ID Application certificate found"
|
||||
echo "Falling back to ad-hoc signing for testing..."
|
||||
# Use ad-hoc identity as fallback
|
||||
codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign - --timestamp "$APP_PATH"
|
||||
echo "SIGNED=adhoc" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "Signing app bundle with Developer ID hash: $IDENTITY_HASH"
|
||||
|
||||
# Sign the app bundle using the hash
|
||||
codesign --force --deep --verbose --options runtime --entitlements LuckyWorld.entitlements --sign "$IDENTITY_HASH" --timestamp "$APP_PATH"
|
||||
echo "SIGNED=identity" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
# Verify signing
|
||||
echo "🔍 Verifying signature..."
|
||||
codesign -vvv --deep --strict "$APP_PATH"
|
||||
|
||||
# Check entitlements
|
||||
echo "🔍 Checking entitlements..."
|
||||
codesign -d --entitlements - "$APP_PATH"
|
||||
shell: bash
|
||||
|
||||
- name: Notarize App
|
||||
if: success()
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.NOTARY_USER }}
|
||||
APP_PASSWORD: ${{ secrets.NOTARY_PASSWORD }}
|
||||
API_KEY_ID: ${{ secrets.NOTARY_API_KEY_ID }}
|
||||
API_ISSUER_ID: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }}
|
||||
API_KEY_PATH: ${{ secrets.NOTARY_API_KEY_PATH }}
|
||||
run: |
|
||||
echo "📤 Notarizing app..."
|
||||
|
||||
# Check if we have API key credentials
|
||||
if [ -n "$API_KEY_ID" ] && [ -n "$API_ISSUER_ID" ] && [ -n "$API_KEY_PATH" ]; then
|
||||
echo "Using App Store Connect API key for notarization..."
|
||||
|
||||
# Create directory for API key if API_KEY_PATH contains content
|
||||
mkdir -p ~/private_keys
|
||||
|
||||
# Check if API_KEY_PATH is a path or content
|
||||
if [[ "$API_KEY_PATH" == /* ]] && [ -f "$API_KEY_PATH" ]; then
|
||||
# It's a path to a file
|
||||
echo "Using API key from path: $API_KEY_PATH"
|
||||
cp "$API_KEY_PATH" ~/private_keys/AuthKey_${API_KEY_ID}.p8
|
||||
else
|
||||
# It contains the key content
|
||||
echo "Using API key from content"
|
||||
echo "$API_KEY_PATH" > ~/private_keys/AuthKey_${API_KEY_ID}.p8
|
||||
fi
|
||||
|
||||
# Create zip for notarization
|
||||
ZIP_PATH="TestApp-notarize.zip"
|
||||
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
|
||||
|
||||
echo "Submitting for notarization with API key..."
|
||||
xcrun notarytool submit "$ZIP_PATH" \
|
||||
--key ~/private_keys/AuthKey_${API_KEY_ID}.p8 \
|
||||
--key-id "$API_KEY_ID" \
|
||||
--issuer "$API_ISSUER_ID" \
|
||||
--wait
|
||||
|
||||
# Staple the notarization ticket
|
||||
echo "Stapling notarization ticket..."
|
||||
xcrun stapler staple "$APP_PATH"
|
||||
|
||||
# Verify notarization
|
||||
echo "🔍 Verifying notarization..."
|
||||
spctl --assess --verbose --type exec "$APP_PATH"
|
||||
|
||||
echo "NOTARIZED=true" >> "$GITHUB_ENV"
|
||||
|
||||
# Clean up
|
||||
rm -rf ~/private_keys
|
||||
|
||||
# Fall back to App-specific password if API key not available
|
||||
elif [ -n "$APPLE_ID" ] && [ -n "$APP_PASSWORD" ] && [ -n "$APPLE_TEAM_ID" ]; then
|
||||
echo "Using App-specific password for notarization..."
|
||||
|
||||
# Create zip for notarization
|
||||
ZIP_PATH="TestApp-notarize.zip"
|
||||
ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
|
||||
|
||||
echo "Submitting for notarization..."
|
||||
xcrun notarytool submit "$ZIP_PATH" \
|
||||
--apple-id "$APPLE_ID" \
|
||||
--password "$APP_PASSWORD" \
|
||||
--team-id "$APPLE_TEAM_ID" \
|
||||
--wait
|
||||
|
||||
# Staple the notarization ticket
|
||||
echo "Stapling notarization ticket..."
|
||||
xcrun stapler staple "$APP_PATH"
|
||||
|
||||
# Verify notarization
|
||||
echo "🔍 Verifying notarization..."
|
||||
spctl --assess --verbose --type exec "$APP_PATH"
|
||||
|
||||
echo "NOTARIZED=true" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "⚠️ Missing notarization credentials. Skipping notarization."
|
||||
echo "For App Store Connect API key method, set these secrets:"
|
||||
echo " - NOTARY_API_KEY_ID: Your API key ID"
|
||||
echo " - NOTARY_API_KEY_ISSUER_ID: Your API issuer ID"
|
||||
echo " - NOTARY_API_KEY_PATH: Path to or content of your p8 file"
|
||||
echo ""
|
||||
echo "For App-specific password method, set these secrets:"
|
||||
echo " - NOTARY_USER: Your Apple ID (email)"
|
||||
echo " - NOTARY_PASSWORD: Your app-specific password"
|
||||
echo " - APPLE_TEAM_ID: Your Apple Developer team ID"
|
||||
|
||||
echo "NOTARIZED=false" >> "$GITHUB_ENV"
|
||||
exit 0
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Package Signed App
|
||||
run: |
|
||||
echo "📦 Packaging signed app..."
|
||||
|
||||
if [ "${NOTARIZED:-false}" == "true" ]; then
|
||||
ZIP_FILE="TestApp-Signed-Notarized.zip"
|
||||
echo "Creating distribution package with notarized app..."
|
||||
else
|
||||
ZIP_FILE="TestApp-Signed.zip"
|
||||
echo "Creating distribution package with signed app..."
|
||||
fi
|
||||
|
||||
# Create zip package
|
||||
ditto -c -k --keepParent "$APP_PATH" "$ZIP_FILE"
|
||||
|
||||
echo "✅ Created package: $ZIP_FILE"
|
||||
shell: bash
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: LuckyWorld-Signed-App
|
||||
path: TestApp-*.zip
|
||||
retention-days: 7
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
echo "🧹 Cleaning up..."
|
||||
rm -rf TestApp.app TestApp-*.zip || true
|
||||
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null || true
|
||||
echo "✅ Cleanup complete"
|
||||
shell: bash
|
365
.gitea/workflows/test-macos-build.yml
Normal file
365
.gitea/workflows/test-macos-build.yml
Normal file
@ -0,0 +1,365 @@
|
||||
name: Test macOS Build Action
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Manual trigger only for testing
|
||||
push:
|
||||
branches: [ozgur/build]
|
||||
|
||||
jobs:
|
||||
test-macos-build:
|
||||
runs-on: macos
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
fetch-depth: 0
|
||||
|
||||
# Cache Unreal Engine build artifacts to speed up builds
|
||||
- name: Cache UE build artifacts
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
./Intermediate
|
||||
./DerivedDataCache
|
||||
./Saved/StagedBuilds
|
||||
key: ${{ runner.os }}-ue-build-${{ hashFiles('LuckyWorld.uproject') }}-${{ hashFiles('Config/**/*.ini') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ue-build-${{ hashFiles('LuckyWorld.uproject') }}-
|
||||
${{ runner.os }}-ue-build-
|
||||
|
||||
# Setup environment for build
|
||||
- name: Setup environment
|
||||
run: |
|
||||
# Get the working directory path for absolute paths
|
||||
WORKSPACE_DIR="$(pwd)"
|
||||
echo "WORKSPACE_DIR=$WORKSPACE_DIR" >> "$GITHUB_ENV"
|
||||
echo "ENTITLEMENTS_FILE=LuckyWorld.entitlements" >> "$GITHUB_ENV"
|
||||
|
||||
# Set CI environment variable to true for build script
|
||||
echo "CI=true" >> "$GITHUB_ENV"
|
||||
|
||||
# Create directories for builds
|
||||
mkdir -p Builds/Mac
|
||||
mkdir -p PackagedReleases
|
||||
|
||||
echo "Environment setup complete"
|
||||
shell: bash
|
||||
|
||||
# Verify bundle identifier is correctly set
|
||||
- name: Verify bundle identifier
|
||||
run: |
|
||||
# Set the constant bundle ID for the workflow
|
||||
echo "BUNDLE_ID=com.luckyrobots.luckyworld" >> "$GITHUB_ENV"
|
||||
|
||||
# Verify the bundle ID is correctly set in DefaultGame.ini
|
||||
CONFIG_FILE="Config/DefaultGame.ini"
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE" && grep -q "BundleIdentifier=com.luckyrobots.luckyworld" "$CONFIG_FILE"; then
|
||||
echo "✅ Bundle ID correctly set in DefaultGame.ini"
|
||||
else
|
||||
echo "⚠️ Warning: Bundle ID may not be correctly set in DefaultGame.ini"
|
||||
echo "Please make sure the following section exists:"
|
||||
echo "[/Script/MacTargetPlatform.MacTargetSettings]"
|
||||
echo "BundleIdentifier=com.luckyrobots.luckyworld"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ DefaultGame.ini not found!"
|
||||
fi
|
||||
|
||||
# Verify Build.cs and Target.cs files
|
||||
BUILD_CS="Source/LuckyWorld/LuckyWorld.Build.cs"
|
||||
TARGET_CS="Source/LuckyWorld.Target.cs"
|
||||
|
||||
if [ -f "$BUILD_CS" ]; then
|
||||
if grep -q "APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld" "$BUILD_CS"; then
|
||||
echo "✅ Bundle ID correctly set in LuckyWorld.Build.cs"
|
||||
else
|
||||
echo "⚠️ Warning: Bundle ID may not be correctly set in LuckyWorld.Build.cs"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ LuckyWorld.Build.cs not found!"
|
||||
fi
|
||||
|
||||
if [ -f "$TARGET_CS" ]; then
|
||||
if grep -q "APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld" "$TARGET_CS"; then
|
||||
echo "✅ Bundle ID correctly set in LuckyWorld.Target.cs"
|
||||
else
|
||||
echo "⚠️ Warning: Bundle ID may not be correctly set in LuckyWorld.Target.cs"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ LuckyWorld.Target.cs not found!"
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
# Check Unreal Engine Project settings
|
||||
- name: Inspect Unreal Settings
|
||||
run: |
|
||||
# Check for any potential issues in UE project settings
|
||||
if [ -f "Config/DefaultEngine.ini" ]; then
|
||||
echo "Checking DefaultEngine.ini for settings that might affect bundle ID..."
|
||||
grep -i "bundle\|identifier\|package" Config/DefaultEngine.ini || echo "No relevant settings found"
|
||||
fi
|
||||
|
||||
if [ -f "Config/DefaultGame.ini" ]; then
|
||||
echo "Checking DefaultGame.ini for settings that might affect bundle ID..."
|
||||
grep -i "bundle\|identifier\|package" Config/DefaultGame.ini || echo "No relevant settings found"
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
# Build for macOS - use your own build script or create a test app if needed
|
||||
- name: Build for macOS
|
||||
id: build-app
|
||||
run: |
|
||||
if [ -f "./scripts/mac_build.sh" ]; then
|
||||
echo "🔨 Running mac_build.sh and capturing output to build_log.txt..."
|
||||
chmod +x ./scripts/mac_build.sh
|
||||
# Set CI environment variable explicitly before running
|
||||
export CI=true
|
||||
# Run build script and capture all output to a log file
|
||||
./scripts/mac_build.sh 2>&1 | tee build_log.txt
|
||||
|
||||
# Check if build succeeded based on exit code
|
||||
if [ ${PIPESTATUS[0]} -ne 0 ]; then
|
||||
echo "❌ Build script failed with exit code ${PIPESTATUS[0]}"
|
||||
echo "See build_log.txt for details"
|
||||
# Set output to indicate failure
|
||||
echo "::set-output name=build_success::false"
|
||||
else
|
||||
echo "✅ Build script completed successfully"
|
||||
echo "::set-output name=build_success::true"
|
||||
fi
|
||||
else
|
||||
echo "❌ ERROR: Build script not found at ./scripts/mac_build.sh"
|
||||
echo "::set-output name=build_success::false"
|
||||
exit 1
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
# Upload build logs regardless of success
|
||||
- name: Upload Build Logs
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build-logs
|
||||
path: |
|
||||
build_log.txt
|
||||
./Saved/Logs/*.log
|
||||
retention-days: 7
|
||||
if-no-files-found: warn
|
||||
|
||||
# Find the app bundle - this may fail if build failed
|
||||
- name: Find app bundle
|
||||
id: find-app
|
||||
continue-on-error: true # Allow this step to fail but continue the workflow
|
||||
run: |
|
||||
# Debug: Show directory structure to help diagnose issues
|
||||
echo "📂 Current directory structure:"
|
||||
ls -la ./
|
||||
|
||||
# Debug: Show if the build directory exists
|
||||
echo "📂 Checking if Builds directory exists:"
|
||||
ls -la ./ | grep Builds || echo "Builds directory not found!"
|
||||
|
||||
# Debug: Show if Saved directory exists
|
||||
echo "📂 Checking if Saved directory exists:"
|
||||
ls -la ./ | grep Saved || echo "Saved directory not found!"
|
||||
|
||||
# First check Saved/StagedBuilds directory - where Unreal often places built apps
|
||||
echo "📂 Checking Saved/StagedBuilds directory..."
|
||||
if [ -d "./Saved/StagedBuilds" ]; then
|
||||
echo "Saved/StagedBuilds exists, checking content:"
|
||||
ls -la ./Saved/StagedBuilds
|
||||
APP_PATHS=$(find ./Saved/StagedBuilds -type d -name "*.app" 2>/dev/null)
|
||||
else
|
||||
echo "⚠️ Saved/StagedBuilds directory doesn't exist!"
|
||||
APP_PATHS=""
|
||||
fi
|
||||
|
||||
# If not found, check Saved directory
|
||||
if [ -z "$APP_PATHS" ]; then
|
||||
echo "📂 Checking Saved directory..."
|
||||
if [ -d "./Saved" ]; then
|
||||
echo "Saved exists, looking for app bundles:"
|
||||
ls -la ./Saved
|
||||
APP_PATHS=$(find ./Saved -type d -name "*.app" 2>/dev/null)
|
||||
else
|
||||
echo "⚠️ Saved directory doesn't exist!"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If not found, check Builds directory
|
||||
if [ -z "$APP_PATHS" ]; then
|
||||
echo "📂 Checking Builds directory..."
|
||||
if [ -d "./Builds" ]; then
|
||||
echo "Builds exists, looking for app bundles:"
|
||||
ls -la ./Builds
|
||||
ls -la ./Builds/Mac 2>/dev/null || echo "No Builds/Mac directory found"
|
||||
APP_PATHS=$(find ./Builds -type d -name "*.app" 2>/dev/null)
|
||||
else
|
||||
echo "⚠️ Builds directory doesn't exist!"
|
||||
fi
|
||||
fi
|
||||
|
||||
# If still not found, check the whole workspace
|
||||
if [ -z "$APP_PATHS" ]; then
|
||||
echo "📂 Checking entire workspace for .app bundles..."
|
||||
APP_PATHS=$(find . -type d -name "*.app" -not -path "*/\.*" 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ -z "$APP_PATHS" ]; then
|
||||
echo "❌ ERROR: Could not find any app bundles!"
|
||||
echo "Listing all directories to help debug:"
|
||||
find . -type d -maxdepth 3 | sort
|
||||
|
||||
echo "Build process likely failed. Checking mac_build.sh log:"
|
||||
cat build_log.txt 2>/dev/null || echo "No build log found"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📦 Found potential app bundles:"
|
||||
echo "$APP_PATHS"
|
||||
|
||||
# Use the first app path found (preferably the main app, not a child app)
|
||||
MAIN_APP_PATH=$(echo "$APP_PATHS" | grep -v "CrashReportClient" | head -1 || echo "$APP_PATHS" | head -1)
|
||||
|
||||
echo "🚀 Using app bundle: $MAIN_APP_PATH"
|
||||
echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV"
|
||||
|
||||
# Make sure app exists - using local variable
|
||||
if [ ! -d "$MAIN_APP_PATH" ]; then
|
||||
echo "❌ ERROR: App bundle not found at $MAIN_APP_PATH!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Export APP_PATH for next steps to use
|
||||
echo "APP_PATH=$MAIN_APP_PATH" >> "$GITHUB_ENV"
|
||||
|
||||
# Fix bundle ID in Info.plist before signing
|
||||
if [ -f "$MAIN_APP_PATH/Contents/Info.plist" ]; then
|
||||
echo "Checking current bundle identifier..."
|
||||
CURRENT_BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")
|
||||
echo "Current bundle ID: $CURRENT_BUNDLE_ID"
|
||||
|
||||
if [ "$CURRENT_BUNDLE_ID" != "$BUNDLE_ID" ]; then
|
||||
echo "Bundle ID mismatch - fixing it!"
|
||||
echo "Setting bundle identifier to $BUNDLE_ID"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BUNDLE_ID" "$MAIN_APP_PATH/Contents/Info.plist"
|
||||
echo "Updated bundle ID in Info.plist: $(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$MAIN_APP_PATH/Contents/Info.plist")"
|
||||
else
|
||||
echo "Bundle ID is already correct: $BUNDLE_ID"
|
||||
fi
|
||||
|
||||
# Set the application name to "LuckyWorld" instead of "LuckyWorld-Mac-Shipping"
|
||||
echo "Setting application display name to LuckyWorld..."
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleName LuckyWorld" "$MAIN_APP_PATH/Contents/Info.plist"
|
||||
echo "Updated app name: $(/usr/libexec/PlistBuddy -c "Print :CFBundleName" "$MAIN_APP_PATH/Contents/Info.plist")"
|
||||
else
|
||||
echo "WARNING: Could not find Info.plist in app bundle."
|
||||
fi
|
||||
|
||||
# Find and repair nested app bundles as well (like CrashReportClient.app)
|
||||
NESTED_APPS=$(find "$MAIN_APP_PATH" -name "*.app" -type d)
|
||||
if [ -n "$NESTED_APPS" ]; then
|
||||
echo "Found nested app bundles, fixing their bundle IDs:"
|
||||
echo "$NESTED_APPS" | while read -r NESTED_APP; do
|
||||
if [ -f "$NESTED_APP/Contents/Info.plist" ]; then
|
||||
NESTED_NAME=$(basename "$NESTED_APP" .app)
|
||||
NESTED_BUNDLE_ID="$BUNDLE_ID.$NESTED_NAME"
|
||||
echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist"
|
||||
|
||||
# Verify the change
|
||||
UPDATED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist")
|
||||
echo "Updated nested app bundle ID: $UPDATED_ID"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
# Fix common issues that may cause notarization failure
|
||||
- name: Fix common issues for notarization
|
||||
run: |
|
||||
echo "🛠️ Fixing common issues that may cause notarization failure..."
|
||||
|
||||
APP_PATH="${{ env.APP_PATH }}"
|
||||
|
||||
# Remove get-task-allow entitlement from Info.plist files
|
||||
echo "Checking for get-task-allow entitlement..."
|
||||
find "$APP_PATH" -name "*.plist" -exec plutil -convert xml1 {} \; -exec grep -l "get-task-allow" {} \; | while read -r plist_file; do
|
||||
echo "Removing get-task-allow from $plist_file"
|
||||
/usr/libexec/PlistBuddy -c "Delete :com.apple.security.get-task-allow" "$plist_file" 2>/dev/null || true
|
||||
done
|
||||
|
||||
# Check for problematic libraries that cause issues
|
||||
echo "Looking for problematic files..."
|
||||
PROBLEM_FILES=$(find "$APP_PATH" -type f -name "*.dylib" | grep -i "boost\|tbb\|ogg\|vorbis\|onnx")
|
||||
if [ -n "$PROBLEM_FILES" ]; then
|
||||
echo "Found potentially problematic libraries. These will be carefully handled during signing:"
|
||||
echo "$PROBLEM_FILES" | head -10
|
||||
if [ $(echo "$PROBLEM_FILES" | wc -l) -gt 10 ]; then
|
||||
echo "... and $(echo "$PROBLEM_FILES" | wc -l) more"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Verify CrashReportClient specifically
|
||||
CRASH_REPORTER=$(find "$APP_PATH" -path "*CrashReportClient.app*" -type d | head -1)
|
||||
if [ -n "$CRASH_REPORTER" ]; then
|
||||
echo "Found CrashReportClient at $CRASH_REPORTER"
|
||||
if [ -f "$CRASH_REPORTER/Contents/Info.plist" ]; then
|
||||
# Ensure it has the correct bundle ID format
|
||||
CRASH_BUNDLE_ID="$BUNDLE_ID.CrashReportClient"
|
||||
echo "Setting CrashReportClient bundle ID to $CRASH_BUNDLE_ID"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $CRASH_BUNDLE_ID" "$CRASH_REPORTER/Contents/Info.plist"
|
||||
fi
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
# Use the macos-notarize action to sign and notarize the app
|
||||
- name: Sign and Notarize macOS App
|
||||
uses: ./.gitea/actions/macos-notarize
|
||||
id: sign-and-notarize
|
||||
with:
|
||||
app-path: ${{ env.APP_PATH }}
|
||||
entitlements-file: ${{ env.ENTITLEMENTS_FILE }}
|
||||
team-id: ${{ secrets.APPLE_TEAM_ID }}
|
||||
certificate-base64: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
certificate-password: ${{ secrets.MACOS_CERTIFICATE_PWD }}
|
||||
notarization-method: 'api-key'
|
||||
notary-api-key-id: ${{ secrets.NOTARY_API_KEY_ID }}
|
||||
notary-api-key-issuer-id: ${{ secrets.NOTARY_API_KEY_ISSUER_ID }}
|
||||
notary-api-key-path: ${{ secrets.NOTARY_API_KEY_PATH }}
|
||||
bundle-id: ${{ env.BUNDLE_ID }}
|
||||
fallback-to-adhoc: 'false'
|
||||
|
||||
# Upload signed app if available
|
||||
- name: Upload Signed App
|
||||
uses: actions/upload-artifact@v3
|
||||
if: steps.sign-and-notarize.outputs.signed != 'none'
|
||||
with:
|
||||
name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized' || 'LuckyWorld-macOS-Signed' }}
|
||||
path: ${{ steps.sign-and-notarize.outputs.package-path }}
|
||||
retention-days: 30
|
||||
|
||||
# Upload ZIP package if DMG was created (as a backup)
|
||||
- name: Upload ZIP Package
|
||||
uses: actions/upload-artifact@v3
|
||||
if: steps.sign-and-notarize.outputs.signed != 'none' && steps.sign-and-notarize.outputs.zip-package-path != ''
|
||||
with:
|
||||
name: ${{ steps.sign-and-notarize.outputs.notarized == 'true' && 'LuckyWorld-macOS-Signed-Notarized-ZIP' || 'LuckyWorld-macOS-Signed-ZIP' }}
|
||||
path: ${{ steps.sign-and-notarize.outputs.zip-package-path }}
|
||||
retention-days: 30
|
||||
|
||||
# Report results
|
||||
- name: Report Results
|
||||
run: |
|
||||
echo "🔐 App signing: ${{ steps.sign-and-notarize.outputs.signed }}"
|
||||
echo "🔏 App notarization: ${{ steps.sign-and-notarize.outputs.notarized }}"
|
||||
|
||||
if [ "${{ steps.sign-and-notarize.outputs.signed }}" != "none" ]; then
|
||||
echo "✅ Packaging completed successfully!"
|
||||
echo "Final package: ${{ steps.sign-and-notarize.outputs.package-path }}"
|
||||
else
|
||||
echo "⚠️ App was not signed - check the logs for details"
|
||||
fi
|
||||
shell: bash
|
@ -1,347 +0,0 @@
|
||||
name: Unreal Engine Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-release:
|
||||
runs-on: windows
|
||||
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
# Set environment variables for Unreal Engine
|
||||
echo "UE_ROOT=E:/Games/UE_5.5" >> $GITHUB_ENV
|
||||
# Set environment variables for Linux toolchain
|
||||
$env:LINUX_MULTIARCH_ROOT="C:/UnrealToolchains/v23_clang-18.1.0-rockylinux8"
|
||||
echo "LINUX_MULTIARCH_ROOT=${LINUX_MULTIARCH_ROOT}" >> $GITHUB_ENV
|
||||
|
||||
# Create directories for builds (with error handling)
|
||||
if (!(Test-Path "Builds/Windows")) { New-Item -ItemType Directory -Path "Builds/Windows" -Force }
|
||||
if (!(Test-Path "Builds/Linux")) { New-Item -ItemType Directory -Path "Builds/Linux" -Force }
|
||||
if (!(Test-Path "PackagedReleases")) { New-Item -ItemType Directory -Path "PackagedReleases" -Force }
|
||||
|
||||
- name: Build for Windows
|
||||
run: |
|
||||
# Chmod command doesn't exist in Windows, use PowerShell to run the bash script
|
||||
& 'C:\Program Files\Git\bin\bash.exe' -c "./win_build.sh"
|
||||
|
||||
- name: Build for Linux
|
||||
run: |
|
||||
# Chmod command doesn't exist in Windows, use PowerShell to run the bash script
|
||||
& 'C:\Program Files\Git\bin\bash.exe' -c "./linux_build.sh"
|
||||
|
||||
- name: Package builds
|
||||
run: |
|
||||
echo "Packaging Windows build..."
|
||||
if [ -d "Builds/Windows" ]; then
|
||||
cd Builds/Windows
|
||||
zip -r ../../PackagedReleases/LuckyRobots-Windows.zip .
|
||||
cd ../..
|
||||
fi
|
||||
|
||||
echo "Packaging Linux build..."
|
||||
if [ -d "Builds/Linux" ]; then
|
||||
cd Builds/Linux
|
||||
zip -r ../../PackagedReleases/LuckyRobots-Linux.zip .
|
||||
cd ../..
|
||||
fi
|
||||
|
||||
echo "=== Packaged releases ==="
|
||||
ls -la PackagedReleases/
|
||||
|
||||
- name: Upload Windows Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
if: success() && hashFiles('PackagedReleases/LuckyRobots-Windows.zip') != ''
|
||||
with:
|
||||
name: LuckyRobots-Windows
|
||||
path: PackagedReleases/LuckyRobots-Windows.zip
|
||||
retention-days: 365
|
||||
|
||||
- name: Upload Linux Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
if: success() && hashFiles('PackagedReleases/LuckyRobots-Linux.zip') != ''
|
||||
with:
|
||||
name: LuckyRobots-Linux
|
||||
path: PackagedReleases/LuckyRobots-Linux.zip
|
||||
retention-days: 365
|
||||
|
||||
- name: Create Tag
|
||||
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
|
||||
run: |
|
||||
# Fetch all tags
|
||||
git fetch --tags
|
||||
|
||||
# Get the latest version tag, if any
|
||||
LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n1)
|
||||
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
# No previous version tag, start with 1.0.0
|
||||
NEW_VERSION="1.0.0"
|
||||
echo "No previous version tags found, starting with 1.0.0"
|
||||
else
|
||||
# Strip 'v' prefix if it exists
|
||||
VERSION=${LATEST_TAG#v}
|
||||
|
||||
# Split version into parts
|
||||
MAJOR=$(echo $VERSION | cut -d. -f1)
|
||||
MINOR=$(echo $VERSION | cut -d. -f2)
|
||||
PATCH=$(echo $VERSION | cut -d. -f3)
|
||||
|
||||
# Auto-increment patch version
|
||||
PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
|
||||
echo "Auto-incremented patch version from ${VERSION} to ${NEW_VERSION}"
|
||||
fi
|
||||
|
||||
# Final tag with v prefix
|
||||
TAG="v${NEW_VERSION}"
|
||||
echo "Creating git tag: $TAG"
|
||||
|
||||
# Configure git with token authentication
|
||||
git config --global user.email "actions@gitea.com"
|
||||
git config --global user.name "Gitea Actions"
|
||||
|
||||
# Direct token approach - simplest method
|
||||
git remote set-url origin "https://goran:${{ secrets.GITEATOKEN }}@luckyrobots.com/luckyrobots/luckyworld.git"
|
||||
|
||||
# Set git to not prompt for input
|
||||
$env:GIT_TERMINAL_PROMPT=0
|
||||
|
||||
# Check if tag exists
|
||||
if ! git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||
# Create tag without opening editor (-m flag)
|
||||
git tag -a "$TAG" -m "Release $TAG"
|
||||
|
||||
# Push with timeout and debug
|
||||
echo "Pushing tag $TAG to origin..."
|
||||
git push --verbose origin "$TAG" || {
|
||||
echo "Error: Failed to push tag. Check your token permissions."
|
||||
exit 1
|
||||
}
|
||||
echo "Successfully created and pushed tag: $TAG"
|
||||
else
|
||||
echo "Tag $TAG already exists, skipping tag creation"
|
||||
fi
|
||||
echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
|
||||
|
||||
- name: Create Build Info
|
||||
run: |
|
||||
# Create a build info JSON file
|
||||
echo '{
|
||||
"version": "${{ env.RELEASE_TAG }}",
|
||||
"buildNumber": "${{ github.run_number }}",
|
||||
"commit": "${{ github.sha }}",
|
||||
"branch": "${{ github.ref_name }}",
|
||||
"buildDate": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",
|
||||
"artifacts": {
|
||||
"windows": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows",
|
||||
"linux": "https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux"
|
||||
}
|
||||
}' > PackagedReleases/build-info.json
|
||||
|
||||
# Create a simple HTML download page
|
||||
echo '<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>LuckyRobots ${{ env.RELEASE_TAG }} Downloads</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
|
||||
h1 { color: #333; }
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
margin: 10px 5px;
|
||||
}
|
||||
.download-btn:hover { background-color: #45a049; }
|
||||
.platform { margin-bottom: 30px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>LuckyRobots Game - ${{ env.RELEASE_TAG }}</h1>
|
||||
<p>Build #${{ github.run_number }} - Built from commit: ${{ github.sha }}</p>
|
||||
|
||||
<div class="platform">
|
||||
<h2>Windows</h2>
|
||||
<p><a href="https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows" class="download-btn">Download Windows Build</a></p>
|
||||
</div>
|
||||
|
||||
<div class="platform">
|
||||
<h2>Linux</h2>
|
||||
<p><a href="https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux" class="download-btn">Download Linux Build</a></p>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>Generated on '$(date -u +"%Y-%m-%d %H:%M:%S UTC")'</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>' > PackagedReleases/downloads.html
|
||||
|
||||
- name: Create Release
|
||||
uses: https://gitea.com/actions/gitea-release-action@main
|
||||
with:
|
||||
files: |-
|
||||
PackagedReleases/build-info.json
|
||||
PackagedReleases/downloads.html
|
||||
token: '${{ secrets.GITEA_TOKEN }}'
|
||||
title: 'Release ${{ env.RELEASE_TAG }}'
|
||||
body: |
|
||||
## LuckyRobots Game Release ${{ env.RELEASE_TAG }}
|
||||
|
||||
### Download Links
|
||||
|
||||
Download builds from our CI artifacts:
|
||||
|
||||
- [Windows Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Windows)
|
||||
- [Linux Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-Linux)
|
||||
|
||||
### Build Information
|
||||
|
||||
- Build Number: #${{ github.run_number }}
|
||||
- Commit: ${{ github.sha }}
|
||||
- Branch: ${{ github.ref_name }}
|
||||
- Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
prerelease: ${{ github.ref != 'refs/heads/main' }}
|
||||
tag_name: '${{ env.RELEASE_TAG }}'
|
||||
|
||||
macos-build:
|
||||
runs-on: macos
|
||||
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
lfs: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get Release Tag
|
||||
run: |
|
||||
# Fetch all tags
|
||||
git fetch --tags
|
||||
|
||||
# Get the latest version tag
|
||||
LATEST_TAG=$(git tag -l "v[0-9]*.[0-9]*.[0-9]*" | sort -V | tail -n1)
|
||||
|
||||
if [ -z "$LATEST_TAG" ]; then
|
||||
NEW_VERSION="1.0.0"
|
||||
else
|
||||
VERSION=${LATEST_TAG#v}
|
||||
MAJOR=$(echo $VERSION | cut -d. -f1)
|
||||
MINOR=$(echo $VERSION | cut -d. -f2)
|
||||
PATCH=$(echo $VERSION | cut -d. -f3)
|
||||
PATCH=$((PATCH + 1))
|
||||
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
|
||||
fi
|
||||
|
||||
TAG="v${NEW_VERSION}"
|
||||
echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
|
||||
echo "Using release tag: $TAG"
|
||||
|
||||
- name: Setup Unreal Engine
|
||||
run: |
|
||||
# Use the correct path where Unreal Engine is installed
|
||||
UE_PATH="/Users/Shared/Epic Games/UE_5.5"
|
||||
|
||||
if [ ! -d "$UE_PATH" ]; then
|
||||
echo "Error: Unreal Engine is not installed in the expected location"
|
||||
echo "Please ensure Unreal Engine is installed at $UE_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set environment variable with the correct Engine path
|
||||
echo "UE_ROOT=$UE_PATH/Engine" >> $GITHUB_ENV
|
||||
echo "Using Unreal Engine 5.5"
|
||||
|
||||
- name: Build Unreal Project
|
||||
run: |
|
||||
chmod +x ./mac_build.sh
|
||||
./mac_build.sh
|
||||
|
||||
- name: Prepare Mac release
|
||||
run: |
|
||||
echo "Preparing packaged files for release..."
|
||||
|
||||
# Create a directory for release files
|
||||
mkdir -p PackagedReleases
|
||||
|
||||
# Debug: Show what we're packaging
|
||||
echo "=== Packaging for Release ==="
|
||||
echo "Build directory contents:"
|
||||
ls -la Builds/
|
||||
|
||||
# Find the app bundle in the Builds directory
|
||||
APP_PATH=$(find Builds -type d -name "*.app" | head -1)
|
||||
|
||||
if [ -n "$APP_PATH" ]; then
|
||||
echo "Found app bundle: $APP_PATH"
|
||||
# Get the app name
|
||||
APP_NAME=$(basename "$APP_PATH")
|
||||
# Create zip file of the app bundle
|
||||
(cd $(dirname "$APP_PATH") && zip -r "../../PackagedReleases/${APP_NAME%.app}-macOS.zip" "$APP_NAME")
|
||||
echo "Created packaged release: PackagedReleases/${APP_NAME%.app}-macOS.zip"
|
||||
else
|
||||
echo "No .app bundle found in Builds directory"
|
||||
|
||||
# Look for a directory that might be a bundle but not named .app
|
||||
MAIN_BUILD_DIR=$(find Builds -mindepth 1 -maxdepth 1 -type d | head -1)
|
||||
if [ -n "$MAIN_BUILD_DIR" ]; then
|
||||
echo "Found main build directory: $MAIN_BUILD_DIR"
|
||||
DIR_NAME=$(basename "$MAIN_BUILD_DIR")
|
||||
# Package this directory as if it were the app
|
||||
(cd $(dirname "$MAIN_BUILD_DIR") && zip -r "../../PackagedReleases/${DIR_NAME}-macOS.zip" "$DIR_NAME")
|
||||
echo "Created packaged release from main directory: PackagedReleases/${DIR_NAME}-macOS.zip"
|
||||
else
|
||||
# Package the entire Builds directory as a fallback
|
||||
echo "No main directory found, packaging everything"
|
||||
zip -r "PackagedReleases/LuckyRobots-macOS.zip" Builds
|
||||
echo "Created fallback package: PackagedReleases/LuckyRobots-macOS.zip"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Packaged releases:"
|
||||
ls -la PackagedReleases/
|
||||
|
||||
- name: Upload macOS Build Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
if: success()
|
||||
with:
|
||||
name: LuckyRobots-macOS
|
||||
path: PackagedReleases/*-macOS.zip
|
||||
retention-days: 365
|
||||
|
||||
- name: Create Release Note
|
||||
run: |
|
||||
echo "## macOS Build Completed" > release-note.md
|
||||
echo "" >> release-note.md
|
||||
echo "macOS build is available as an artifact." >> release-note.md
|
||||
echo "" >> release-note.md
|
||||
echo "Download from: [macOS Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS)" >> release-note.md
|
||||
|
||||
- name: Create Gitea Release
|
||||
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
|
||||
uses: https://gitea.com/actions/gitea-release-action@main
|
||||
with:
|
||||
token: ${{ secrets.GITEATOKEN }}
|
||||
tag_name: ${{ env.RELEASE_TAG }}
|
||||
title: "Release ${{ env.RELEASE_TAG }} - macOS"
|
||||
body: |
|
||||
## macOS Build Available as Artifact
|
||||
|
||||
The macOS build is available as an artifact due to its large file size.
|
||||
|
||||
[Download macOS Build](https://luckyrobots.com/luckyrobots/luckyworld/actions/runs/${{ github.run_id }}/artifacts/LuckyRobots-macOS)
|
||||
|
||||
Built from commit: ${{ github.sha }}
|
||||
files: release-note.md
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -41,3 +41,4 @@ DerivedDataCache/*
|
||||
#this only is the Binaries folder on the root, not the Binaries folder in the plugin folders
|
||||
Binaries/**
|
||||
*.app/
|
||||
.cursorrules
|
||||
|
@ -338,3 +338,27 @@ NearClipPlane=0.100000
|
||||
bFinalUsesRDO=True
|
||||
FinalRDOLambda=100
|
||||
|
||||
[/Script/MacTargetPlatform.MacTargetSettings]
|
||||
TargetedRHIs=SF_METAL_SM5
|
||||
MetalLanguageVersion=5
|
||||
MaxShaderLanguageVersion=4
|
||||
MinimumOSVersion=11
|
||||
BundleName=LuckyWorld
|
||||
BundleDisplayName=LuckyWorld
|
||||
bEnableMathOptimizations=True
|
||||
UseFastIntrinsics=True
|
||||
EnableMipGenOption=Default
|
||||
FrameRateLock=PUFRL_None
|
||||
AudioSampleRate=48000
|
||||
AudioMaxChannels=32
|
||||
bUseCustomIcon=False
|
||||
bUseMiniUPnP=False
|
||||
MetalDynamicLibraries=()
|
||||
MetalRuntimeLibrary=1
|
||||
OutputRealFPS=False
|
||||
bBuildEmbeddedFrameworksForGame=False
|
||||
EnableCodeCoverage=False
|
||||
EnableCodeCoveragePath=(Path="")
|
||||
ForwardShading=False
|
||||
UseFastCopyToResolve=True
|
||||
|
||||
|
@ -7,6 +7,9 @@ ProjectVersion=0.1
|
||||
;bAddPacks=True
|
||||
;InsertPack=(PackSource="StarterContent.upack",PackName="StarterContent")
|
||||
|
||||
[/Script/MacTargetPlatform.MacTargetSettings]
|
||||
BundleIdentifier=com.luckyrobots.luckyworld
|
||||
|
||||
[/Script/UnrealEd.ProjectPackagingSettings]
|
||||
Build=IfProjectHasCode
|
||||
BuildConfiguration=PPBC_Shipping
|
||||
|
26
LuckyWorld.entitlements
Normal file
26
LuckyWorld.entitlements
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
@ -196,4 +196,4 @@ git lfs pull
|
||||
|
||||
## License
|
||||
|
||||
Lucky World is licensed under the Polyform License - see the [LICENSE](LICENSE) file for details.
|
||||
Lucky World is licensed under the Polyform License - see the [LICENSE](LICENSE) file for details.
|
||||
|
@ -18,5 +18,14 @@ public class LuckyWorldTarget : TargetRules
|
||||
{
|
||||
this.bUseLoggingInShipping = true;
|
||||
}
|
||||
|
||||
// macOS specific settings
|
||||
if (Target.Platform == UnrealTargetPlatform.Mac)
|
||||
{
|
||||
// Force use the bundle ID from DefaultGame.ini
|
||||
GlobalDefinitions.Add("APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld");
|
||||
GlobalDefinitions.Add("APP_BUNDLE_NAME=LuckyWorld");
|
||||
GlobalDefinitions.Add("APP_BUNDLE_DISPLAY_NAME=LuckyWorld");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,5 +19,13 @@ public class LuckyWorld : ModuleRules
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
|
||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||
|
||||
// Set the bundle identifier for macOS builds
|
||||
if (Target.Platform == UnrealTargetPlatform.Mac)
|
||||
{
|
||||
PublicDefinitions.Add("APP_BUNDLE_IDENTIFIER=com.luckyrobots.luckyworld");
|
||||
PublicDefinitions.Add("APP_BUNDLE_NAME=LuckyWorld");
|
||||
PublicDefinitions.Add("APP_BUNDLE_DISPLAY_NAME=LuckyWorld");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
55
mac_build.sh
55
mac_build.sh
@ -1,55 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Get the user's home directory
|
||||
USER_HOME="$HOME"
|
||||
|
||||
# Set up Unreal Engine paths
|
||||
UE_ROOT="/Users/Shared/Epic Games/UE_5.5"
|
||||
UE_EDITOR="$UE_ROOT/Engine/Binaries/Mac/UnrealEditor.app/Contents/MacOS/UnrealEditor"
|
||||
UE_UAT="$UE_ROOT/Engine/Build/BatchFiles/RunUAT.command"
|
||||
|
||||
# Set up project paths
|
||||
PROJECT_ROOT="$(pwd)"
|
||||
PROJECT_FILE="$PROJECT_ROOT/LuckyWorld.uproject"
|
||||
ARCHIVE_DIR="$PROJECT_ROOT/Builds"
|
||||
|
||||
rm -rf DerivedDataCache Intermediate Binaries Saved
|
||||
|
||||
"$UE_ROOT/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh" -project="$PROJECT_FILE" -game -engine
|
||||
# Run the build command
|
||||
"$UE_UAT" -ScriptsForProject="$PROJECT_FILE" Turnkey \
|
||||
-command=VerifySdk \
|
||||
-platform=Mac \
|
||||
-UpdateIfNeeded \
|
||||
-EditorIO \
|
||||
-EditorIOPort=59484 \
|
||||
-project="$PROJECT_FILE" \
|
||||
BuildCookRun \
|
||||
-nop4 \
|
||||
-utf8output \
|
||||
-cook \
|
||||
-project="$PROJECT_FILE" \
|
||||
-target=LuckyWorld \
|
||||
-unrealexe="$UE_EDITOR" \
|
||||
-platform=Mac \
|
||||
-installed \
|
||||
-stage \
|
||||
-archive \
|
||||
-package \
|
||||
-build \
|
||||
-iterativecooking \
|
||||
-pak \
|
||||
-iostore \
|
||||
-compressed \
|
||||
-prereqs \
|
||||
-archivedirectory="$ARCHIVE_DIR" \
|
||||
-CrashReporter \
|
||||
-clientconfig=Shipping \
|
||||
# -nocompile \
|
||||
# -nocompileuat \
|
||||
# -nocompileeditor \
|
||||
# -skipbuildeditor \
|
||||
|
||||
# enable these if you want to test build without pak and iostore (you're just testing the build)
|
||||
# -skipiostore \
|
||||
# -skippak \ (disable -pak and -iostore)
|
236
scripts/mac_build.sh
Executable file
236
scripts/mac_build.sh
Executable file
@ -0,0 +1,236 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Get the user's home directory
|
||||
USER_HOME="$HOME"
|
||||
|
||||
# Set up Unreal Engine paths
|
||||
UE_ROOT="/Users/Shared/Epic Games/UE_5.5"
|
||||
UE_EDITOR="$UE_ROOT/Engine/Binaries/Mac/UnrealEditor.app/Contents/MacOS/UnrealEditor"
|
||||
UE_UAT="$UE_ROOT/Engine/Build/BatchFiles/RunUAT.command"
|
||||
|
||||
# Set up project paths
|
||||
PROJECT_ROOT="$(pwd)"
|
||||
PROJECT_FILE="$PROJECT_ROOT/LuckyWorld.uproject"
|
||||
ARCHIVE_DIR="$PROJECT_ROOT/Builds"
|
||||
|
||||
# Check for entitlements file
|
||||
if [ -f "$PROJECT_ROOT/LuckyWorld.entitlements" ]; then
|
||||
ENTITLEMENTS_FILE="$PROJECT_ROOT/LuckyWorld.entitlements"
|
||||
else
|
||||
echo "Warning: No entitlements file found. This might affect notarization."
|
||||
ENTITLEMENTS_FILE=""
|
||||
fi
|
||||
|
||||
# For debugging: print paths and config
|
||||
echo "Project root: $PROJECT_ROOT"
|
||||
echo "Project file: $PROJECT_FILE"
|
||||
echo "Archive directory: $ARCHIVE_DIR"
|
||||
echo "Entitlements file: $ENTITLEMENTS_FILE"
|
||||
|
||||
# Clean up previous build artifacts
|
||||
rm -rf DerivedDataCache Intermediate Binaries Saved
|
||||
|
||||
# Generate project files
|
||||
"$UE_ROOT/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh" -project="$PROJECT_FILE" -game -engine
|
||||
|
||||
# Run the build command
|
||||
"$UE_UAT" -ScriptsForProject="$PROJECT_FILE" Turnkey \
|
||||
-command=VerifySdk \
|
||||
-platform=Mac \
|
||||
-UpdateIfNeeded \
|
||||
-EditorIO \
|
||||
-EditorIOPort=59484 \
|
||||
-project="$PROJECT_FILE" \
|
||||
BuildCookRun \
|
||||
-nop4 \
|
||||
-utf8output \
|
||||
-cook \
|
||||
-project="$PROJECT_FILE" \
|
||||
-target=LuckyWorld \
|
||||
-unrealexe="$UE_EDITOR" \
|
||||
-platform=Mac \
|
||||
-installed \
|
||||
-stage \
|
||||
-archive \
|
||||
-package \
|
||||
-build \
|
||||
-iterativecooking \
|
||||
-pak \
|
||||
-iostore \
|
||||
-compressed \
|
||||
-prereqs \
|
||||
-archivedirectory="$ARCHIVE_DIR" \
|
||||
-CrashReporter \
|
||||
-clientconfig=Shipping \
|
||||
# -nocompile \
|
||||
# -nocompileuat \
|
||||
# -nocompileeditor \
|
||||
# -skipbuildeditor \
|
||||
|
||||
BUILD_EXIT_CODE=$?
|
||||
|
||||
echo ""
|
||||
echo "🦾 Build process completed with exit code: $BUILD_EXIT_CODE"
|
||||
|
||||
# Debug check for where the app might be
|
||||
echo "📂 Checking potential build output locations:"
|
||||
echo "Saved directory contents (if exists):"
|
||||
ls -la Saved 2>/dev/null || echo "Saved directory not found"
|
||||
|
||||
echo "Saved/StagedBuilds directory contents (if exists):"
|
||||
ls -la Saved/StagedBuilds 2>/dev/null || echo "Saved/StagedBuilds directory not found"
|
||||
|
||||
echo "Builds directory contents:"
|
||||
ls -la "$ARCHIVE_DIR" 2>/dev/null || echo "Builds directory not found"
|
||||
|
||||
echo "Builds/Mac directory contents (if exists):"
|
||||
ls -la "$ARCHIVE_DIR/Mac" 2>/dev/null || echo "Builds/Mac directory not found"
|
||||
|
||||
# Find the app, regardless of build success
|
||||
echo "🔍 Searching for .app bundles in Saved and Builds directories:"
|
||||
APP_PATH=""
|
||||
for search_dir in "$ARCHIVE_DIR" "$ARCHIVE_DIR/Mac" "Saved/StagedBuilds" "Saved/StagedBuilds/Mac" "Saved"; do
|
||||
if [ -d "$search_dir" ]; then
|
||||
echo "Searching in $search_dir"
|
||||
APP_FOUND=$(find "$search_dir" -name "*.app" -type d | head -n 1)
|
||||
if [ -n "$APP_FOUND" ]; then
|
||||
APP_PATH="$APP_FOUND"
|
||||
echo "Found app bundle at: $APP_PATH"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo "❌ No app bundle found. Build may have failed or output location is unexpected."
|
||||
|
||||
# Set a fake path for debug tests
|
||||
if [ -n "$CI" ]; then
|
||||
echo "This is a CI environment, continuing with error checks..."
|
||||
else
|
||||
echo "Exiting with error code from build"
|
||||
exit $BUILD_EXIT_CODE
|
||||
fi
|
||||
else
|
||||
echo "🦾 Build completed. Application path:"
|
||||
echo "$APP_PATH"
|
||||
|
||||
echo ""
|
||||
echo "🔍 Binary files that will need signing:"
|
||||
DYLIB_COUNT=$(find "$APP_PATH" -name "*.dylib" | wc -l)
|
||||
SO_COUNT=$(find "$APP_PATH" -name "*.so" | wc -l)
|
||||
FRAMEWORKS=$(find "$APP_PATH" -path "*.framework/*" -type f -perm +111 | wc -l)
|
||||
EXECUTABLES=$(find "$APP_PATH" -type f -perm +111 -not -path "*.framework/*" -not -name "*.dylib" -not -name "*.so" | wc -l)
|
||||
|
||||
echo "- $DYLIB_COUNT .dylib libraries"
|
||||
echo "- $SO_COUNT .so libraries"
|
||||
echo "- $FRAMEWORKS framework executables"
|
||||
echo "- $EXECUTABLES other executables"
|
||||
echo "Total binary files: $((DYLIB_COUNT + SO_COUNT + FRAMEWORKS + EXECUTABLES))"
|
||||
|
||||
echo ""
|
||||
echo "🔍 Checking for PhysX and other special libraries (often need special handling):"
|
||||
find "$APP_PATH" -name "*PhysX*" -o -name "*APEX*"
|
||||
fi
|
||||
|
||||
# Update bundle ID in project settings
|
||||
echo ""
|
||||
echo "🔧 Checking for bundle ID in UE config..."
|
||||
CONFIG_FILE="$PROJECT_ROOT/Config/DefaultGame.ini"
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
if grep -q "\[/Script/MacTargetPlatform\.MacTargetSettings\]" "$CONFIG_FILE" && grep -q "BundleIdentifier=com.luckyrobots.luckyworld" "$CONFIG_FILE"; then
|
||||
echo "Bundle ID already correctly set in project config ✅"
|
||||
else
|
||||
echo "⚠️ Warning: Bundle ID may not be correctly set in DefaultGame.ini"
|
||||
echo "Please ensure [/Script/MacTargetPlatform.MacTargetSettings] section exists with BundleIdentifier=com.luckyrobots.luckyworld"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Config file not found at $CONFIG_FILE"
|
||||
fi
|
||||
|
||||
# Post-build process - set bundle ID
|
||||
echo ""
|
||||
echo "🔧 Performing post-build fix for bundle ID..."
|
||||
|
||||
# First verify that APP_PATH is defined and exists
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo "⚠️ APP_PATH is not defined, trying to find the app bundle again..."
|
||||
# Try to find the app bundle in common locations
|
||||
for search_dir in "$ARCHIVE_DIR" "$ARCHIVE_DIR/Mac" "Saved/StagedBuilds" "Saved/StagedBuilds/Mac" "Saved"; do
|
||||
if [ -d "$search_dir" ]; then
|
||||
APP_FOUND=$(find "$search_dir" -name "*.app" -type d | head -n 1)
|
||||
if [ -n "$APP_FOUND" ]; then
|
||||
APP_PATH="$APP_FOUND"
|
||||
echo "✅ Found app bundle at: $APP_PATH"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo "❌ ERROR: Could not find any app bundle. Skipping bundle ID fix."
|
||||
# Don't exit, just skip this part
|
||||
APP_PATH=""
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$APP_PATH" ] && [ -d "$APP_PATH" ]; then
|
||||
INFO_PLIST="$APP_PATH/Contents/Info.plist"
|
||||
if [ -f "$INFO_PLIST" ]; then
|
||||
CURRENT_BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST" 2>/dev/null)
|
||||
echo "Current bundle ID: $CURRENT_BUNDLE_ID"
|
||||
|
||||
if [ $? -ne 0 ] || [ "$CURRENT_BUNDLE_ID" != "com.luckyrobots.luckyworld" ]; then
|
||||
echo "Bundle ID mismatch or not set - fixing it!"
|
||||
echo "Setting bundle identifier to com.luckyrobots.luckyworld"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.luckyrobots.luckyworld" "$INFO_PLIST"
|
||||
UPDATED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$INFO_PLIST" 2>/dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Updated bundle ID: $UPDATED_ID"
|
||||
else
|
||||
echo "⚠️ Failed to update bundle ID"
|
||||
fi
|
||||
else
|
||||
echo "Bundle ID is already correct: com.luckyrobots.luckyworld"
|
||||
fi
|
||||
|
||||
# Set the application name to "LuckyWorld" instead of "LuckyWorld-Mac-Shipping"
|
||||
echo "Setting application name to LuckyWorld..."
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleName LuckyWorld" "$INFO_PLIST"
|
||||
UPDATED_NAME=$(/usr/libexec/PlistBuddy -c "Print :CFBundleName" "$INFO_PLIST" 2>/dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Updated app name: $UPDATED_NAME"
|
||||
else
|
||||
echo "⚠️ Failed to update app name"
|
||||
fi
|
||||
|
||||
# Find and repair nested app bundles as well (like CrashReportClient.app)
|
||||
echo "Checking for nested app bundles..."
|
||||
NESTED_APPS=$(find "$APP_PATH" -name "*.app" -type d 2>/dev/null)
|
||||
if [ -n "$NESTED_APPS" ]; then
|
||||
echo "Found nested app bundles, fixing their bundle IDs:"
|
||||
echo "$NESTED_APPS" | while read -r NESTED_APP; do
|
||||
if [ -f "$NESTED_APP/Contents/Info.plist" ]; then
|
||||
NESTED_NAME=$(basename "$NESTED_APP" .app)
|
||||
NESTED_BUNDLE_ID="com.luckyrobots.luckyworld.$NESTED_NAME"
|
||||
echo "Setting nested bundle ID to $NESTED_BUNDLE_ID for $NESTED_APP"
|
||||
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $NESTED_BUNDLE_ID" "$NESTED_APP/Contents/Info.plist"
|
||||
|
||||
# Verify the change
|
||||
UPDATED_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$NESTED_APP/Contents/Info.plist" 2>/dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Updated nested app bundle ID: $UPDATED_ID"
|
||||
else
|
||||
echo "⚠️ Failed to update nested app bundle ID for $NESTED_APP"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "No nested app bundles found."
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Info.plist not found at $INFO_PLIST"
|
||||
fi
|
||||
else
|
||||
echo "⚠️ App bundle not found or APP_PATH is not valid. Skipping bundle ID fix."
|
||||
fi
|
Loading…
x
Reference in New Issue
Block a user