From 5ce7f02d4eb1f5a0dea49ef8cbe467fc68de5bfb Mon Sep 17 00:00:00 2001 From: Ozgur Ersoy Date: Wed, 16 Apr 2025 22:58:05 +0200 Subject: [PATCH] fix(actions): enhance macOS notarization workflow by making install scripts executable, creating custom DMG with installer script, and improving logging for package creation --- .gitea/workflows/test-macos-build.yml | 44 ++++- scripts/create_dmg.sh | 251 ++++++++++++++++++++++++++ scripts/install_luckyworld.sh | 118 ++++++++++++ 3 files changed, 411 insertions(+), 2 deletions(-) create mode 100644 scripts/create_dmg.sh create mode 100644 scripts/install_luckyworld.sh diff --git a/.gitea/workflows/test-macos-build.yml b/.gitea/workflows/test-macos-build.yml index bbf2e560..33f0b4dc 100644 --- a/.gitea/workflows/test-macos-build.yml +++ b/.gitea/workflows/test-macos-build.yml @@ -143,6 +143,10 @@ jobs: else echo "Found entitlements file: ${{ env.ENTITLEMENTS_FILE }}" fi + + # Make install scripts executable + chmod +x ./scripts/install_luckyworld.sh + chmod +x ./scripts/create_dmg.sh shell: bash # Use the macos-notarize action to sign and notarize the app @@ -162,6 +166,29 @@ jobs: bundle-id: ${{ env.BUNDLE_ID }} fallback-to-adhoc: 'false' + # Create custom DMG with installer script + - name: Create Custom DMG with Installer + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' + run: | + echo "🔧 Creating custom DMG with installer script..." + + # Ensure app is in the expected location after notarization + APP_PATH="${{ env.APP_PATH }}" + + # Execute the DMG creation script + ./scripts/create_dmg.sh "$APP_PATH" "./PackagedReleases" + + # Set the custom DMG path + CUSTOM_DMG_PATH="./PackagedReleases/$(basename "$APP_PATH" .app).dmg" + echo "CUSTOM_DMG_PATH=$CUSTOM_DMG_PATH" >> $GITHUB_ENV + + if [ -f "$CUSTOM_DMG_PATH" ]; then + echo "✅ Custom DMG created successfully: $CUSTOM_DMG_PATH" + else + echo "❌ Failed to create custom DMG" + fi + shell: bash + # Upload stapled app directly (this is the most reliable approach) - name: Upload Stapled App Bundle uses: actions/upload-artifact@v3 @@ -171,8 +198,17 @@ jobs: path: ${{ env.APP_PATH }} retention-days: 30 + # Upload the custom DMG with installer script + - name: Upload Custom DMG with Installer + uses: actions/upload-artifact@v3 + if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' && env.CUSTOM_DMG_PATH != '' + with: + name: LuckyWorld-macOS-Installer-DMG + path: ${{ env.CUSTOM_DMG_PATH }} + retention-days: 30 + # Upload only the DMG file from the macos-notarize action - - name: Upload Stapled App DMG + - name: Upload Standard DMG uses: actions/upload-artifact@v3 if: steps.sign-and-notarize.outputs.notarized == 'true' && steps.sign-and-notarize.outputs.signed != 'none' with: @@ -188,7 +224,11 @@ jobs: if [ "${{ steps.sign-and-notarize.outputs.signed }}" != "none" ]; then echo "✅ Packaging completed successfully!" - echo "Final package: ${{ steps.sign-and-notarize.outputs.package-path }}" + echo "Final standard package: ${{ steps.sign-and-notarize.outputs.package-path }}" + + if [ -n "$CUSTOM_DMG_PATH" ] && [ -f "$CUSTOM_DMG_PATH" ]; then + echo "Final installer package: $CUSTOM_DMG_PATH" + fi else echo "⚠️ App was not signed - check the logs for details" fi diff --git a/scripts/create_dmg.sh b/scripts/create_dmg.sh new file mode 100644 index 00000000..b9ec59a6 --- /dev/null +++ b/scripts/create_dmg.sh @@ -0,0 +1,251 @@ +#!/bin/bash + +# LuckyWorld DMG Creation Script +# This script creates a DMG file for macOS containing the application and installation script + +# Terminal colors +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Check for create-dmg command +if ! command -v create-dmg &> /dev/null; then + echo -e "${RED}Error: 'create-dmg' command not found.${NC}" + echo -e "${YELLOW}Please install it with: 'brew install create-dmg'${NC}" + exit 1 +fi + +# Function to handle cleanup on exit +cleanup() { + echo -e "${BLUE}Cleaning up temporary files...${NC}" + if [ -d "$TEMP_DIR" ]; then + rm -rf "$TEMP_DIR" + fi +} + +# Set up trap for cleanup +trap cleanup EXIT + +# Usage information +if [ "$#" -lt 2 ]; then + echo -e "${YELLOW}Usage: $0 [version]${NC}" + echo -e "${BLUE}Example: $0 ./build/LuckyWorld.app ./dist 1.0.0${NC}" + exit 1 +fi + +# Parse parameters +APPLICATION_DIR="$1" +OUTPUT_DIR="$2" +VERSION="${3:-1.0.0}" + +# Validate parameters +if [ ! -d "$APPLICATION_DIR" ]; then + echo -e "${RED}Error: Application directory does not exist: $APPLICATION_DIR${NC}" + exit 1 +fi + +# Application name +APP_NAME=$(basename "$APPLICATION_DIR") +DMG_NAME="LuckyWorld-${VERSION}" + +# Create output directory if it doesn't exist +if [ ! -d "$OUTPUT_DIR" ]; then + echo -e "${BLUE}Creating output directory: $OUTPUT_DIR${NC}" + mkdir -p "$OUTPUT_DIR" +fi + +# Create temporary directory for DMG contents +TEMP_DIR=$(mktemp -d) +echo -e "${BLUE}Creating temporary directory: $TEMP_DIR${NC}" + +# Copy application to temp directory +echo -e "${BLUE}Copying application to temporary directory...${NC}" +cp -R "$APPLICATION_DIR" "$TEMP_DIR/" + +# Create installation script in temp directory +INSTALL_SCRIPT="$TEMP_DIR/install_luckyworld.sh" +echo -e "${BLUE}Creating installation script...${NC}" + +cat > "$INSTALL_SCRIPT" << 'EOF' +#!/bin/bash + +# LuckyWorld macOS Installation Script +# This script installs the LuckyWorld app and removes macOS Gatekeeper quarantine flags + +# Terminal colors +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# App paths +APP_NAME="LuckyWorld.app" +APP_SOURCE="$(cd "$(dirname "$0")" && pwd)/$APP_NAME" +APP_DEST="/Applications/$APP_NAME" + +# Checking script permissions +if [[ $EUID -ne 0 ]]; then + echo -e "${YELLOW}This script requires administrator permissions to run.${NC}" + echo -e "${BLUE}Requesting administrator access...${NC}" + + # Get the script path and re-run with sudo + SCRIPT_PATH=$(readlink -f "$0") + exec sudo "$SCRIPT_PATH" + exit 0 +fi + +# Header +echo -e "${BLUE}============================================${NC}" +echo -e "${GREEN}LuckyWorld macOS Installation Tool${NC}" +echo -e "${BLUE}============================================${NC}" +echo "" + +# Check if source app exists +if [ ! -d "$APP_SOURCE" ]; then + # Check if source app exists in the same directory as the script + APP_SOURCE="$(cd "$(dirname "$0")" && pwd)/../$APP_NAME" + + if [ ! -d "$APP_SOURCE" ]; then + echo -e "${RED}ERROR: Could not find $APP_NAME${NC}" + echo -e "${YELLOW}Please make sure the application is located in the same directory as this script.${NC}" + exit 1 + fi +fi + +echo -e "${BLUE}Source application: ${NC}${YELLOW}$APP_SOURCE${NC}" +echo -e "${BLUE}Destination: ${NC}${YELLOW}$APP_DEST${NC}" +echo "" + +# Check if application already exists and is running +if [ -d "$APP_DEST" ]; then + echo -e "${YELLOW}Application $APP_NAME already exists in Applications folder.${NC}" + + # Check if app is running + if pgrep -x "LuckyWorld" > /dev/null; then + echo -e "${RED}LuckyWorld is currently running. Please close the application before continuing.${NC}" + read -p "Press Enter after closing the application to continue..." + + # Check again + if pgrep -x "LuckyWorld" > /dev/null; then + echo -e "${RED}LuckyWorld is still running. Installation aborted.${NC}" + exit 1 + fi + fi + + echo -e "${BLUE}Removing existing version...${NC}" + rm -rf "$APP_DEST" + + if [ $? -ne 0 ]; then + echo -e "${RED}ERROR: Could not remove existing application. Possible permission issue.${NC}" + exit 1 + fi + + echo -e "${GREEN}Existing application removed successfully.${NC}" +fi + +# Install the application +echo -e "${BLUE}Installing $APP_NAME to Applications folder...${NC}" +cp -R "$APP_SOURCE" /Applications/ + +if [ $? -ne 0 ]; then + echo -e "${RED}ERROR: Installation failed. Could not copy the application to /Applications.${NC}" + exit 1 +fi + +# Clear macOS Gatekeeper quarantine flag +echo -e "${BLUE}Removing Gatekeeper quarantine flag...${NC}" +xattr -rd com.apple.quarantine "$APP_DEST" + +if [ $? -ne 0 ]; then + echo -e "${YELLOW}WARNING: Could not remove Gatekeeper quarantine flag.${NC}" + echo -e "${YELLOW}You may need to manually allow the application in System Preferences > Security & Privacy.${NC}" +else + echo -e "${GREEN}Gatekeeper restrictions removed successfully.${NC}" +fi + +# Set proper permissions +echo -e "${BLUE}Setting permissions...${NC}" +chmod -R 755 "$APP_DEST" + +# Successful installation message +echo -e "${GREEN}✅ LuckyWorld has been successfully installed!${NC}" +echo -e "${BLUE}============================================${NC}" +echo -e "${YELLOW}To start the application, open /Applications/$APP_NAME${NC}" +echo -e "${BLUE}============================================${NC}" + +# Ask if user wants to launch the app +echo "" +read -p "Would you like to launch LuckyWorld now? (y/n): " LAUNCH_APP + +if [[ "$LAUNCH_APP" =~ ^[Yy]$ ]]; then + echo -e "${BLUE}Launching LuckyWorld...${NC}" + open "$APP_DEST" + echo -e "${GREEN}Done!${NC}" +fi + +exit 0 +EOF + +# Make the installation script executable +chmod +x "$INSTALL_SCRIPT" + +# Create a README file +README_FILE="$TEMP_DIR/README.txt" +echo -e "${BLUE}Creating README file...${NC}" + +cat > "$README_FILE" << EOF +LuckyWorld ${VERSION} +=================== + +Installation Instructions: +1. Double-click the 'install_luckyworld.sh' script to install LuckyWorld +2. If prompted, enter your administrator password +3. The application will be installed to your Applications folder + +If you encounter any issues with installation: +- Make sure you have administrator privileges +- Check System Preferences > Security & Privacy if macOS blocks the application + +For support, please visit: https://luckyrobots.com +EOF + +# Create DMG file +echo -e "${BLUE}Creating DMG file...${NC}" +OUTPUT_DMG="$OUTPUT_DIR/${DMG_NAME}.dmg" + +# Remove existing DMG if it exists +if [ -f "$OUTPUT_DMG" ]; then + echo -e "${YELLOW}Removing existing DMG file: $OUTPUT_DMG${NC}" + rm -f "$OUTPUT_DMG" +fi + +# Create DMG using create-dmg +create-dmg \ + --volname "LuckyWorld ${VERSION}" \ + --volicon "$(dirname "$0")/assets/LuckyWorld.icns" \ + --window-pos 200 120 \ + --window-size 800 500 \ + --icon-size 128 \ + --icon "LuckyWorld.app" 200 250 \ + --icon "install_luckyworld.sh" 400 250 \ + --icon "README.txt" 600 250 \ + --hide-extension "LuckyWorld.app" \ + --hide-extension "install_luckyworld.sh" \ + --app-drop-link 400 120 \ + --no-internet-enable \ + "$OUTPUT_DMG" \ + "$TEMP_DIR" + +# Check if DMG creation was successful +if [ $? -ne 0 ]; then + echo -e "${RED}Error: Failed to create DMG file.${NC}" + exit 1 +fi + +echo -e "${GREEN}✅ DMG file created successfully: $OUTPUT_DMG${NC}" +echo -e "${BLUE}DMG size: $(du -h "$OUTPUT_DMG" | cut -f1)${NC}" + +exit 0 \ No newline at end of file diff --git a/scripts/install_luckyworld.sh b/scripts/install_luckyworld.sh new file mode 100644 index 00000000..e1875144 --- /dev/null +++ b/scripts/install_luckyworld.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +# LuckyWorld macOS Installation Script +# This script installs the LuckyWorld app and removes macOS Gatekeeper quarantine flags + +# Terminal colors +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# App paths +APP_NAME="LuckyWorld.app" +APP_SOURCE="$(cd "$(dirname "$0")" && pwd)/$APP_NAME" +APP_DEST="/Applications/$APP_NAME" + +# Checking script permissions +if [[ $EUID -ne 0 ]]; then + echo -e "${YELLOW}This script requires administrator permissions to run.${NC}" + echo -e "${BLUE}Requesting administrator access...${NC}" + + # Get the script path and re-run with sudo + SCRIPT_PATH=$(readlink -f "$0") + exec sudo "$SCRIPT_PATH" + exit 0 +fi + +# Header +echo -e "${BLUE}============================================${NC}" +echo -e "${GREEN}LuckyWorld macOS Installation Tool${NC}" +echo -e "${BLUE}============================================${NC}" +echo "" + +# Check if source app exists +if [ ! -d "$APP_SOURCE" ]; then + # Check if source app exists in the same directory as the script + APP_SOURCE="$(cd "$(dirname "$0")" && pwd)/../$APP_NAME" + + if [ ! -d "$APP_SOURCE" ]; then + echo -e "${RED}ERROR: Could not find $APP_NAME${NC}" + echo -e "${YELLOW}Please make sure the application is located in the same directory as this script.${NC}" + exit 1 + fi +fi + +echo -e "${BLUE}Source application: ${NC}${YELLOW}$APP_SOURCE${NC}" +echo -e "${BLUE}Destination: ${NC}${YELLOW}$APP_DEST${NC}" +echo "" + +# Check if application already exists and is running +if [ -d "$APP_DEST" ]; then + echo -e "${YELLOW}Application $APP_NAME already exists in Applications folder.${NC}" + + # Check if app is running + if pgrep -x "LuckyWorld" > /dev/null; then + echo -e "${RED}LuckyWorld is currently running. Please close the application before continuing.${NC}" + read -p "Press Enter after closing the application to continue..." + + # Check again + if pgrep -x "LuckyWorld" > /dev/null; then + echo -e "${RED}LuckyWorld is still running. Installation aborted.${NC}" + exit 1 + fi + fi + + echo -e "${BLUE}Removing existing version...${NC}" + rm -rf "$APP_DEST" + + if [ $? -ne 0 ]; then + echo -e "${RED}ERROR: Could not remove existing application. Possible permission issue.${NC}" + exit 1 + fi + + echo -e "${GREEN}Existing application removed successfully.${NC}" +fi + +# Install the application +echo -e "${BLUE}Installing $APP_NAME to Applications folder...${NC}" +cp -R "$APP_SOURCE" /Applications/ + +if [ $? -ne 0 ]; then + echo -e "${RED}ERROR: Installation failed. Could not copy the application to /Applications.${NC}" + exit 1 +fi + +# Clear macOS Gatekeeper quarantine flag +echo -e "${BLUE}Removing Gatekeeper quarantine flag...${NC}" +xattr -rd com.apple.quarantine "$APP_DEST" + +if [ $? -ne 0 ]; then + echo -e "${YELLOW}WARNING: Could not remove Gatekeeper quarantine flag.${NC}" + echo -e "${YELLOW}You may need to manually allow the application in System Preferences > Security & Privacy.${NC}" +else + echo -e "${GREEN}Gatekeeper restrictions removed successfully.${NC}" +fi + +# Set proper permissions +echo -e "${BLUE}Setting permissions...${NC}" +chmod -R 755 "$APP_DEST" + +# Successful installation message +echo -e "${GREEN}✅ LuckyWorld has been successfully installed!${NC}" +echo -e "${BLUE}============================================${NC}" +echo -e "${YELLOW}To start the application, open /Applications/$APP_NAME${NC}" +echo -e "${BLUE}============================================${NC}" + +# Ask if user wants to launch the app +echo "" +read -p "Would you like to launch LuckyWorld now? (y/n): " LAUNCH_APP + +if [[ "$LAUNCH_APP" =~ ^[Yy]$ ]]; then + echo -e "${BLUE}Launching LuckyWorld...${NC}" + open "$APP_DEST" + echo -e "${GREEN}Done!${NC}" +fi + +exit 0 \ No newline at end of file