Add professional DMG installer with drag-and-drop interface #19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build TablePro | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ['v*'] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - '.vscode/**' | |
| pull_request: | |
| branches: [main] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| env: | |
| XCODE_PROJECT: TablePro.xcodeproj | |
| XCODE_SCHEME: TablePro | |
| BUILD_CONFIGURATION: Release | |
| XCODE_VERSION: '16.1' | |
| jobs: | |
| lint: | |
| name: SwiftLint | |
| runs-on: macos-14 | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Cache SwiftLint | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/Library/Caches/Homebrew/swiftlint* | |
| key: swiftlint-${{ runner.os }}-${{ hashFiles('.swiftlint.yml') }} | |
| restore-keys: | | |
| swiftlint-${{ runner.os }}- | |
| - name: Install SwiftLint | |
| run: brew install swiftlint | |
| - name: Run SwiftLint | |
| run: swiftlint lint --strict | |
| prepare-libs: | |
| name: Prepare Universal Libraries | |
| runs-on: macos-14 | |
| needs: lint | |
| timeout-minutes: 25 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Cache Homebrew packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/Library/Caches/Homebrew | |
| /opt/homebrew/Cellar/mariadb-connector-c | |
| /opt/homebrew/Cellar/libpq | |
| /usr/local/Cellar/mariadb-connector-c | |
| /usr/local/Cellar/libpq | |
| key: brew-deps-${{ runner.os }}-${{ hashFiles('**/build-release.sh') }} | |
| restore-keys: | | |
| brew-deps-${{ runner.os }}- | |
| - name: Install ARM64 Homebrew dependencies | |
| run: | | |
| echo "Installing ARM64 dependencies..." | |
| brew install mariadb-connector-c libpq | |
| # Link packages with --force (needed for keg-only formulas) | |
| brew link --force mariadb-connector-c | |
| brew link --force libpq | |
| # Verify installations | |
| if ! brew list mariadb-connector-c >/dev/null 2>&1; then | |
| echo "❌ ERROR: mariadb-connector-c installation failed or incomplete" | |
| exit 1 | |
| fi | |
| if ! brew list libpq >/dev/null 2>&1; then | |
| echo "❌ ERROR: libpq installation failed or incomplete" | |
| exit 1 | |
| fi | |
| # Get the actual prefix for mariadb-connector-c (handles keg-only formulas) | |
| MARIADB_PREFIX=$(brew --prefix mariadb-connector-c) | |
| echo "MariaDB Connector/C prefix: $MARIADB_PREFIX" | |
| # Find the library file (may be in lib/ or lib/mariadb/) | |
| MARIADB_LIB="" | |
| for path in "$MARIADB_PREFIX/lib/mariadb/libmariadb.a" "$MARIADB_PREFIX/lib/libmariadb.a"; do | |
| if [ -f "$path" ]; then | |
| MARIADB_LIB="$path" | |
| break | |
| fi | |
| done | |
| if [ -z "$MARIADB_LIB" ]; then | |
| echo "❌ ERROR: mariadb-connector-c installed but library file not found" | |
| echo "Searched in:" | |
| echo " - $MARIADB_PREFIX/lib/mariadb/libmariadb.a" | |
| echo " - $MARIADB_PREFIX/lib/libmariadb.a" | |
| echo "" | |
| echo "Contents of $MARIADB_PREFIX/lib/:" | |
| ls -la "$MARIADB_PREFIX/lib/" || echo "Directory not found" | |
| exit 1 | |
| fi | |
| echo "✅ Found ARM64 MariaDB library at: $MARIADB_LIB" | |
| echo "ARM64_MARIADB_LIB=$MARIADB_LIB" >> $GITHUB_ENV | |
| echo "✅ All ARM64 dependencies installed successfully" | |
| - name: Install x86_64 Homebrew | |
| run: | | |
| # Install Rosetta 2 if needed | |
| if ! arch -x86_64 /usr/bin/true 2>/dev/null; then | |
| echo "Installing Rosetta 2..." | |
| if ! softwareupdate --install-rosetta --agree-to-license; then | |
| echo "❌ ERROR: Failed to install Rosetta 2" | |
| echo "This is required to run x86_64 binaries on Apple Silicon" | |
| exit 1 | |
| fi | |
| # Verify Rosetta 2 is now working | |
| if ! arch -x86_64 /usr/bin/true 2>/dev/null; then | |
| echo "❌ ERROR: Rosetta 2 installed but not functional" | |
| exit 1 | |
| fi | |
| echo "✅ Rosetta 2 installed successfully" | |
| else | |
| echo "✅ Rosetta 2 already installed" | |
| fi | |
| # Check if x86_64 Homebrew is already installed | |
| if [ ! -f /usr/local/bin/brew ]; then | |
| echo "Installing x86_64 Homebrew..." | |
| # Using official Homebrew installer (trusted source) | |
| if ! arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; then | |
| echo "❌ ERROR: Homebrew installation script failed" | |
| exit 1 | |
| fi | |
| # Verify installation | |
| if [ ! -f /usr/local/bin/brew ]; then | |
| echo "❌ ERROR: Homebrew installed but /usr/local/bin/brew not found" | |
| exit 1 | |
| fi | |
| # Verify it's executable | |
| if ! /usr/local/bin/brew --version; then | |
| echo "❌ ERROR: Homebrew binary is not functional" | |
| exit 1 | |
| fi | |
| echo "✅ x86_64 Homebrew installed successfully" | |
| else | |
| echo "x86_64 Homebrew already installed" | |
| # Still verify it works | |
| if ! /usr/local/bin/brew --version; then | |
| echo "❌ ERROR: x86_64 Homebrew exists but is not functional" | |
| exit 1 | |
| fi | |
| fi | |
| - name: Install x86_64 Homebrew dependencies | |
| run: | | |
| echo "Installing x86_64 dependencies..." | |
| arch -x86_64 /usr/local/bin/brew install mariadb-connector-c libpq | |
| # Link packages with --force (needed for keg-only formulas) | |
| arch -x86_64 /usr/local/bin/brew link --force mariadb-connector-c | |
| arch -x86_64 /usr/local/bin/brew link --force libpq | |
| # Verify installations | |
| if ! arch -x86_64 /usr/local/bin/brew list mariadb-connector-c >/dev/null 2>&1; then | |
| echo "❌ ERROR: mariadb-connector-c installation failed or incomplete" | |
| exit 1 | |
| fi | |
| if ! arch -x86_64 /usr/local/bin/brew list libpq >/dev/null 2>&1; then | |
| echo "❌ ERROR: libpq installation failed or incomplete" | |
| exit 1 | |
| fi | |
| # Get the actual prefix for mariadb-connector-c (handles keg-only formulas) | |
| X86_MARIADB_PREFIX=$(arch -x86_64 /usr/local/bin/brew --prefix mariadb-connector-c) | |
| echo "x86_64 MariaDB Connector/C prefix: $X86_MARIADB_PREFIX" | |
| # Find the library file (may be in lib/ or lib/mariadb/) | |
| X86_MARIADB_LIB="" | |
| for path in "$X86_MARIADB_PREFIX/lib/mariadb/libmariadb.a" "$X86_MARIADB_PREFIX/lib/libmariadb.a"; do | |
| if [ -f "$path" ]; then | |
| X86_MARIADB_LIB="$path" | |
| break | |
| fi | |
| done | |
| if [ -z "$X86_MARIADB_LIB" ]; then | |
| echo "❌ ERROR: mariadb-connector-c installed but library file not found" | |
| echo "Searched in:" | |
| echo " - $X86_MARIADB_PREFIX/lib/mariadb/libmariadb.a" | |
| echo " - $X86_MARIADB_PREFIX/lib/libmariadb.a" | |
| echo "" | |
| echo "Contents of $X86_MARIADB_PREFIX/lib/:" | |
| ls -la "$X86_MARIADB_PREFIX/lib/" || echo "Directory not found" | |
| exit 1 | |
| fi | |
| echo "✅ Found x86_64 MariaDB library at: $X86_MARIADB_LIB" | |
| echo "X86_MARIADB_LIB=$X86_MARIADB_LIB" >> $GITHUB_ENV | |
| echo "✅ All x86_64 dependencies installed successfully" | |
| - name: Create universal libmariadb library | |
| run: | | |
| echo "Creating universal libmariadb.a..." | |
| # Use library paths from environment (set by previous steps) | |
| ARM64_LIB="${ARM64_MARIADB_LIB}" | |
| X86_LIB="${X86_MARIADB_LIB}" | |
| echo "ARM64 library path: $ARM64_LIB" | |
| echo "x86_64 library path: $X86_LIB" | |
| # Verify input files exist | |
| if [ -z "$ARM64_LIB" ] || [ ! -f "$ARM64_LIB" ]; then | |
| echo "❌ ERROR: ARM64 library not found at: $ARM64_LIB" | |
| echo "ARM64 Homebrew installation may have failed" | |
| exit 1 | |
| fi | |
| if [ -z "$X86_LIB" ] || [ ! -f "$X86_LIB" ]; then | |
| echo "❌ ERROR: x86_64 library not found at: $X86_LIB" | |
| echo "x86_64 Homebrew installation may have failed" | |
| exit 1 | |
| fi | |
| # Verify inputs are correct architectures | |
| echo "Verifying input architectures:" | |
| lipo -info "$ARM64_LIB" | |
| lipo -info "$X86_LIB" | |
| # Ensure output directory exists | |
| mkdir -p Libs | |
| # Create universal binary | |
| if ! lipo -create "$ARM64_LIB" "$X86_LIB" -output Libs/libmariadb_universal.a; then | |
| echo "❌ ERROR: Failed to create universal library" | |
| echo "This could mean:" | |
| echo " - Libraries are incompatible" | |
| echo " - Libraries are already universal" | |
| echo " - Output directory is not writable" | |
| exit 1 | |
| fi | |
| # Verify output | |
| if [ ! -f "Libs/libmariadb_universal.a" ]; then | |
| echo "❌ ERROR: Universal library was not created" | |
| exit 1 | |
| fi | |
| echo "✅ Universal library created successfully:" | |
| lipo -info Libs/libmariadb_universal.a | |
| ls -lh Libs/libmariadb_universal.a | |
| # Verify it's actually universal (contains both architectures) | |
| if ! lipo -info Libs/libmariadb_universal.a | grep -q "arm64"; then | |
| echo "❌ ERROR: Universal library missing arm64 architecture" | |
| exit 1 | |
| fi | |
| if ! lipo -info Libs/libmariadb_universal.a | grep -q "x86_64"; then | |
| echo "❌ ERROR: Universal library missing x86_64 architecture" | |
| exit 1 | |
| fi | |
| echo "✅ Verified: Library contains both arm64 and x86_64" | |
| - name: Upload library artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: libs-universal | |
| path: Libs/ | |
| retention-days: 1 | |
| build-arm64: | |
| name: Build ARM64 | |
| runs-on: macos-14 | |
| needs: prepare-libs | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download library artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: libs-universal | |
| path: Libs/ | |
| - name: Verify downloaded artifacts | |
| run: | | |
| echo "Verifying downloaded library artifacts..." | |
| if [ ! -f "Libs/libmariadb_universal.a" ]; then | |
| echo "❌ ERROR: Required library artifact not found: Libs/libmariadb_universal.a" | |
| echo "This means:" | |
| echo " - The prepare-libs job failed to create the library" | |
| echo " - The artifact upload failed" | |
| echo " - The artifact download was corrupted" | |
| echo "" | |
| echo "Contents of Libs directory:" | |
| ls -la Libs/ || echo "Libs directory is empty or doesn't exist" | |
| exit 1 | |
| fi | |
| echo "✅ Universal library found" | |
| lipo -info Libs/libmariadb_universal.a | |
| ls -lh Libs/libmariadb_universal.a | |
| - name: Cache Homebrew packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/Library/Caches/Homebrew | |
| /opt/homebrew/Cellar/mariadb-connector-c | |
| /opt/homebrew/Cellar/libpq | |
| key: brew-arm64-${{ runner.os }}-${{ hashFiles('**/build-release.sh') }} | |
| restore-keys: | | |
| brew-arm64-${{ runner.os }}- | |
| - name: Install ARM64 dependencies | |
| run: | | |
| echo "Installing ARM64 dependencies..." | |
| brew install mariadb-connector-c libpq | |
| # Link packages with --force (needed for keg-only formulas) | |
| brew link --force mariadb-connector-c | |
| brew link --force libpq | |
| # Verify installations | |
| if ! brew list mariadb-connector-c >/dev/null 2>&1; then | |
| echo "❌ ERROR: mariadb-connector-c installation failed" | |
| exit 1 | |
| fi | |
| if ! brew list libpq >/dev/null 2>&1; then | |
| echo "❌ ERROR: libpq installation failed" | |
| exit 1 | |
| fi | |
| echo "✅ ARM64 dependencies installed" | |
| - name: Select Xcode version | |
| run: | | |
| sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer | |
| echo "Selected Xcode version:" | |
| xcodebuild -version | |
| - name: Build ARM64 | |
| run: | | |
| chmod +x build-release.sh | |
| ./build-release.sh arm64 | |
| - name: Verify build | |
| run: | | |
| echo "Verifying build output..." | |
| BINARY_PATH="build/Release/TablePro-arm64.app/Contents/MacOS/TablePro" | |
| # Check binary exists | |
| if [ ! -f "$BINARY_PATH" ]; then | |
| echo "❌ ERROR: Built binary not found at: $BINARY_PATH" | |
| echo "Build may have failed silently" | |
| exit 1 | |
| fi | |
| # Check it's not empty | |
| if [ ! -s "$BINARY_PATH" ]; then | |
| echo "❌ ERROR: Binary file is empty" | |
| exit 1 | |
| fi | |
| # Check architecture | |
| ARCH_INFO=$(lipo -info "$BINARY_PATH") | |
| echo "Architecture: $ARCH_INFO" | |
| if ! echo "$ARCH_INFO" | grep -q "arm64"; then | |
| echo "❌ ERROR: Binary does not contain arm64 architecture" | |
| echo "Expected: arm64 only" | |
| echo "Got: $ARCH_INFO" | |
| exit 1 | |
| fi | |
| if echo "$ARCH_INFO" | grep -q "x86_64"; then | |
| echo "❌ ERROR: Binary contains x86_64 but should be arm64 only" | |
| exit 1 | |
| fi | |
| # Check it's executable | |
| if [ ! -x "$BINARY_PATH" ]; then | |
| echo "❌ ERROR: Binary is not executable" | |
| exit 1 | |
| fi | |
| # Display info | |
| echo "✅ Build verified successfully" | |
| echo "Binary size: $(ls -lh "$BINARY_PATH" | awk '{print $5}')" | |
| echo "App bundle size: $(du -sh build/Release/TablePro-arm64.app | awk '{print $1}')" | |
| - name: Create DMG installer | |
| run: | | |
| echo "Creating DMG installer..." | |
| # Rename app to remove architecture suffix for better UX | |
| if [ -d "build/Release/TablePro-arm64.app" ]; then | |
| cp -R "build/Release/TablePro-arm64.app" "build/Release/TablePro.app" | |
| else | |
| echo "❌ ERROR: App bundle not found" | |
| exit 1 | |
| fi | |
| # Make DMG creation script executable | |
| chmod +x create-dmg.sh | |
| # Create DMG with version from git tag or use default | |
| VERSION=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo "0.1.13") | |
| ./create-dmg.sh "$VERSION" "arm64" "build/Release/TablePro.app" | |
| # Verify DMG was created | |
| if [ ! -f "build/Release/TablePro-${VERSION}-arm64.dmg" ]; then | |
| echo "❌ ERROR: DMG file was not created" | |
| exit 1 | |
| fi | |
| echo "✅ DMG installer created successfully" | |
| ls -lh build/Release/*.dmg | |
| - name: Create ZIP archive (fallback) | |
| run: | | |
| echo "Creating ZIP archive..." | |
| cd build/Release | |
| if ! zip -r TablePro-arm64.zip TablePro-arm64.app; then | |
| echo "❌ ERROR: Failed to create ZIP archive" | |
| exit 1 | |
| fi | |
| echo "✅ ZIP archive created" | |
| ls -lh TablePro-arm64.zip | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: TablePro-arm64-${{ github.sha }} | |
| path: | | |
| build/Release/*.dmg | |
| build/Release/TablePro-arm64.zip | |
| retention-days: ${{ startsWith(github.ref, 'refs/tags/v') && 90 || 7 }} | |
| build-x86_64: | |
| name: Build x86_64 | |
| runs-on: macos-14 | |
| needs: prepare-libs | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download library artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: libs-universal | |
| path: Libs/ | |
| - name: Verify downloaded artifacts | |
| run: | | |
| echo "Verifying downloaded library artifacts..." | |
| if [ ! -f "Libs/libmariadb_universal.a" ]; then | |
| echo "❌ ERROR: Required library artifact not found: Libs/libmariadb_universal.a" | |
| echo "" | |
| echo "Contents of Libs directory:" | |
| ls -la Libs/ || echo "Libs directory is empty or doesn't exist" | |
| exit 1 | |
| fi | |
| echo "✅ Universal library found" | |
| lipo -info Libs/libmariadb_universal.a | |
| - name: Cache Homebrew packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/Library/Caches/Homebrew | |
| /usr/local/Cellar/mariadb-connector-c | |
| /usr/local/Cellar/libpq | |
| key: brew-x86_64-${{ runner.os }}-${{ hashFiles('**/build-release.sh') }} | |
| restore-keys: | | |
| brew-x86_64-${{ runner.os }}- | |
| - name: Install Rosetta 2 | |
| run: | | |
| if ! arch -x86_64 /usr/bin/true 2>/dev/null; then | |
| echo "Installing Rosetta 2..." | |
| if ! softwareupdate --install-rosetta --agree-to-license; then | |
| echo "❌ ERROR: Failed to install Rosetta 2" | |
| exit 1 | |
| fi | |
| # Verify Rosetta 2 works | |
| if ! arch -x86_64 /usr/bin/true 2>/dev/null; then | |
| echo "❌ ERROR: Rosetta 2 installed but not functional" | |
| exit 1 | |
| fi | |
| echo "✅ Rosetta 2 installed" | |
| else | |
| echo "✅ Rosetta 2 already installed" | |
| fi | |
| - name: Install x86_64 Homebrew | |
| run: | | |
| if [ ! -f /usr/local/bin/brew ]; then | |
| echo "Installing x86_64 Homebrew..." | |
| if ! arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; then | |
| echo "❌ ERROR: Homebrew installation failed" | |
| exit 1 | |
| fi | |
| if [ ! -f /usr/local/bin/brew ]; then | |
| echo "❌ ERROR: Homebrew not found after installation" | |
| exit 1 | |
| fi | |
| if ! /usr/local/bin/brew --version; then | |
| echo "❌ ERROR: Homebrew not functional" | |
| exit 1 | |
| fi | |
| echo "✅ x86_64 Homebrew installed" | |
| else | |
| echo "x86_64 Homebrew already installed" | |
| if ! /usr/local/bin/brew --version; then | |
| echo "❌ ERROR: Homebrew not functional" | |
| exit 1 | |
| fi | |
| fi | |
| - name: Install x86_64 dependencies | |
| run: | | |
| echo "Installing x86_64 dependencies..." | |
| arch -x86_64 /usr/local/bin/brew install mariadb-connector-c libpq | |
| # Link packages with --force (needed for keg-only formulas) | |
| arch -x86_64 /usr/local/bin/brew link --force mariadb-connector-c | |
| arch -x86_64 /usr/local/bin/brew link --force libpq | |
| # Verify installations | |
| if ! arch -x86_64 /usr/local/bin/brew list mariadb-connector-c >/dev/null 2>&1; then | |
| echo "❌ ERROR: mariadb-connector-c installation failed" | |
| exit 1 | |
| fi | |
| if ! arch -x86_64 /usr/local/bin/brew list libpq >/dev/null 2>&1; then | |
| echo "❌ ERROR: libpq installation failed" | |
| exit 1 | |
| fi | |
| echo "✅ x86_64 dependencies installed" | |
| - name: Select Xcode version | |
| run: | | |
| sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app/Contents/Developer | |
| echo "Selected Xcode version:" | |
| xcodebuild -version | |
| - name: Build x86_64 | |
| run: | | |
| chmod +x build-release.sh | |
| ./build-release.sh x86_64 | |
| - name: Verify build | |
| run: | | |
| echo "Verifying build output..." | |
| BINARY_PATH="build/Release/TablePro-x86_64.app/Contents/MacOS/TablePro" | |
| # Check binary exists | |
| if [ ! -f "$BINARY_PATH" ]; then | |
| echo "❌ ERROR: Built binary not found at: $BINARY_PATH" | |
| exit 1 | |
| fi | |
| # Check it's not empty | |
| if [ ! -s "$BINARY_PATH" ]; then | |
| echo "❌ ERROR: Binary file is empty" | |
| exit 1 | |
| fi | |
| # Check architecture | |
| ARCH_INFO=$(lipo -info "$BINARY_PATH") | |
| echo "Architecture: $ARCH_INFO" | |
| if ! echo "$ARCH_INFO" | grep -q "x86_64"; then | |
| echo "❌ ERROR: Binary does not contain x86_64 architecture" | |
| echo "Expected: x86_64 only" | |
| echo "Got: $ARCH_INFO" | |
| exit 1 | |
| fi | |
| if echo "$ARCH_INFO" | grep -q "arm64"; then | |
| echo "❌ ERROR: Binary contains arm64 but should be x86_64 only" | |
| exit 1 | |
| fi | |
| # Check it's executable | |
| if [ ! -x "$BINARY_PATH" ]; then | |
| echo "❌ ERROR: Binary is not executable" | |
| exit 1 | |
| fi | |
| # Display info | |
| echo "✅ Build verified successfully" | |
| echo "Binary size: $(ls -lh "$BINARY_PATH" | awk '{print $5}')" | |
| echo "App bundle size: $(du -sh build/Release/TablePro-x86_64.app | awk '{print $1}')" | |
| - name: Create DMG installer | |
| run: | | |
| echo "Creating DMG installer..." | |
| # Rename app to remove architecture suffix for better UX | |
| if [ -d "build/Release/TablePro-x86_64.app" ]; then | |
| cp -R "build/Release/TablePro-x86_64.app" "build/Release/TablePro.app" | |
| else | |
| echo "❌ ERROR: App bundle not found" | |
| exit 1 | |
| fi | |
| # Make DMG creation script executable | |
| chmod +x create-dmg.sh | |
| # Create DMG with version from git tag or use default | |
| VERSION=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo "0.1.13") | |
| ./create-dmg.sh "$VERSION" "x86_64" "build/Release/TablePro.app" | |
| # Verify DMG was created | |
| if [ ! -f "build/Release/TablePro-${VERSION}-x86_64.dmg" ]; then | |
| echo "❌ ERROR: DMG file was not created" | |
| exit 1 | |
| fi | |
| echo "✅ DMG installer created successfully" | |
| ls -lh build/Release/*.dmg | |
| - name: Create ZIP archive (fallback) | |
| run: | | |
| echo "Creating ZIP archive..." | |
| cd build/Release | |
| if ! zip -r TablePro-x86_64.zip TablePro-x86_64.app; then | |
| echo "❌ ERROR: Failed to create ZIP archive" | |
| exit 1 | |
| fi | |
| echo "✅ ZIP archive created" | |
| ls -lh TablePro-x86_64.zip | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: TablePro-x86_64-${{ github.sha }} | |
| path: | | |
| build/Release/*.dmg | |
| build/Release/TablePro-x86_64.zip | |
| retention-days: ${{ startsWith(github.ref, 'refs/tags/v') && 90 || 7 }} | |
| release: | |
| name: Create GitHub Release | |
| runs-on: macos-14 | |
| needs: [build-arm64, build-x86_64] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Download ARM64 artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: TablePro-arm64-${{ github.sha }} | |
| path: artifacts/ | |
| - name: Download x86_64 artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: TablePro-x86_64-${{ github.sha }} | |
| path: artifacts/ | |
| - name: Verify and organize artifacts for release | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/v} | |
| if [ -z "$VERSION" ]; then | |
| echo "❌ ERROR: Failed to extract version from ref: $GITHUB_REF" | |
| exit 1 | |
| fi | |
| echo "Preparing artifacts for version: $VERSION" | |
| echo "Contents of artifacts directory:" | |
| ls -la artifacts/ | |
| # Note: DMG files should already have correct names from build | |
| # ZIP files need to be renamed | |
| # Rename ZIP files if they exist | |
| if [ -f "artifacts/TablePro-arm64.zip" ]; then | |
| mv artifacts/TablePro-arm64.zip "artifacts/TablePro-${VERSION}-arm64.zip" | |
| fi | |
| if [ -f "artifacts/TablePro-x86_64.zip" ]; then | |
| mv artifacts/TablePro-x86_64.zip "artifacts/TablePro-${VERSION}-x86_64.zip" | |
| fi | |
| echo "✅ Artifacts organized successfully" | |
| echo "Final artifacts:" | |
| ls -lh artifacts/ | |
| - name: Generate release notes | |
| id: release_notes | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/} | |
| # Try to get previous tag | |
| PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| if [ -z "$PREVIOUS_TAG" ]; then | |
| echo "No previous tag found, showing recent commits" | |
| CHANGES=$(git log --pretty=format:"- %s" HEAD~10..HEAD 2>/dev/null || echo "- Initial release") | |
| else | |
| echo "Generating changes since $PREVIOUS_TAG" | |
| CHANGES=$(git log --pretty=format:"- %s" "$PREVIOUS_TAG"..HEAD 2>/dev/null || echo "- Initial release") | |
| fi | |
| if [ -z "$CHANGES" ]; then | |
| CHANGES="- Initial release" | |
| fi | |
| cat > release_notes.md <<EOF | |
| ## TablePro ${VERSION} | |
| ### Downloads | |
| Choose the appropriate version for your Mac: | |
| **Recommended (DMG Installer):** | |
| - 🍎 **Apple Silicon (M1/M2/M3/M4)**: \`TablePro-${VERSION}-arm64.dmg\` | |
| - 💻 **Intel**: \`TablePro-${VERSION}-x86_64.dmg\` | |
| **Alternative (ZIP Archive):** | |
| - \`TablePro-${VERSION}-arm64.zip\` (Apple Silicon) | |
| - \`TablePro-${VERSION}-x86_64.zip\` (Intel) | |
| ### Installation | |
| **DMG Installer (Recommended):** | |
| 1. Download and open the DMG file | |
| 2. Drag TablePro to the Applications folder | |
| 3. Eject the DMG | |
| 4. Right-click TablePro in Applications and select "Open" on first launch | |
| **ZIP Archive:** | |
| 1. Download and unzip the file | |
| 2. Move TablePro.app to your Applications folder | |
| 3. Right-click and select "Open" on first launch | |
| > **Note:** This app is not signed with an Apple Developer certificate. You may need to allow it in System Settings > Privacy & Security on first launch. | |
| ### Changes | |
| $CHANGES | |
| EOF | |
| echo "✅ Release notes generated" | |
| cat release_notes.md | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| files: | | |
| artifacts/*.dmg | |
| artifacts/*.zip | |
| body_path: release_notes.md | |
| draft: false | |
| prerelease: ${{ contains(github.ref, '-beta') || contains(github.ref, '-alpha') || contains(github.ref, '-rc') }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |