From 403bf011891662c3c1abe437a850410638d59652 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Wed, 18 Mar 2026 14:22:34 +0100 Subject: [PATCH] fix: Resolve macOS cross-compilation issues in unified release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Disable old unified-build.yml workflow (was causing conflicts) - Create new unified-release.yml with proper platform separation - macOS builds now run on macOS runners (fixes cross-compilation) - Linux and Windows builds use Ubuntu with cross-compilation - Separate build jobs for each platform to prevent cancellation - Rename workflow to indicate cross-platform support Platform matrix: ✅ Linux x64: Ubuntu runner (native) ✅ Windows x64: Ubuntu runner (cross-compile) ✅ macOS x64/ARM64: macOS runners (native) ✅ Android: Ubuntu runner (native) ✅ Backend: Ubuntu runner (native) Fixes macOS build failures and prevents other builds from being canceled! --- .github/workflows/unified-build.yml | 10 +- .github/workflows/unified-release.yml | 136 ++++++- .github/workflows/unified-release.yml.backup | 381 +++++++++++++++++++ 3 files changed, 498 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/unified-release.yml.backup diff --git a/.github/workflows/unified-build.yml b/.github/workflows/unified-build.yml index d2245b85..dbc00736 100644 --- a/.github/workflows/unified-build.yml +++ b/.github/workflows/unified-build.yml @@ -1,14 +1,6 @@ -name: Unified Build and Deploy +name: Unified Linux Build and Deploy (DISABLED - use unified-release.yml) on: - push: - branches: - - '**' - tags: - - 'v*' - pull_request: - branches: - - '**' workflow_dispatch: inputs: force_release: diff --git a/.github/workflows/unified-release.yml b/.github/workflows/unified-release.yml index 4d43bed1..e25f4d6e 100644 --- a/.github/workflows/unified-release.yml +++ b/.github/workflows/unified-release.yml @@ -1,4 +1,4 @@ -name: Unified Release +name: Unified Cross-Platform Release on: push: @@ -57,7 +57,7 @@ jobs: cd swingmusic-android && git fetch --tags && ANDROID_COMMITS=$(git log $LAST_TAG..HEAD --oneline --no-merges 2>/dev/null || echo "") && cd .. cd src/swingmusic && git fetch --tags && BACKEND_COMMITS=$(git log $LAST_TAG..HEAD --oneline --no-merges 2>/dev/null || echo "") && cd ../.. - # Combine all commits for analysis + # Count commit types ALL_COMMITS="$MAIN_COMMITS $DESKTOP_COMMITS $ANDROID_COMMITS $BACKEND_COMMITS" MAJOR_COUNT=$(echo "$ALL_COMMITS" | grep -iE "BREAKING CHANGE|major|!:|breaking" | wc -l || echo "0") @@ -108,9 +108,10 @@ jobs: echo "New version: $NEW_VERSION ($BUMP_TYPE)" - build-desktop: - name: Build Desktop App - runs-on: ${{ matrix.os }} + # Linux builds (can be cross-compiled) + build-linux-desktop: + name: Build Linux Desktop + runs-on: ubuntu-latest needs: get-version if: contains(github.event.inputs.components, 'desktop') @@ -119,25 +120,14 @@ jobs: matrix: include: - platform: 'linux-x64' - os: ubuntu-latest rust_target: 'x86_64-unknown-linux-gnu' - - platform: 'win-x64' - os: windows-latest - rust_target: 'x86_64-pc-windows-msvc' - - platform: 'darwin-x64' - os: macos-latest - rust_target: 'x86_64-apple-darwin' - - platform: 'darwin-arm64' - os: macos-latest - rust_target: 'aarch64-apple-darwin' steps: - uses: actions/checkout@v4 - name: Initialize submodules run: git submodule update --init --recursive - - name: Install dependencies (ubuntu) - if: startsWith(matrix.platform, 'linux') + - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf @@ -162,7 +152,7 @@ jobs: npm ci npm run tauri build -- --target ${{ matrix.rust_target }} - - name: Upload Desktop artifacts + - name: Upload Linux artifacts uses: actions/upload-artifact@v4 with: name: desktop-${{ matrix.platform }} @@ -171,6 +161,110 @@ jobs: !swingmusic-desktop/target/${{ matrix.rust_target }}/release/bundle/.*/ retention-days: 30 + # Windows builds (can be cross-compiled) + build-windows-desktop: + name: Build Windows Desktop + runs-on: ubuntu-latest + needs: get-version + if: contains(github.event.inputs.components, 'desktop') + + strategy: + fail-fast: false + matrix: + include: + - platform: 'windows-x64' + rust_target: 'x86_64-pc-windows-gnu' + + steps: + - uses: actions/checkout@v4 + - name: Initialize submodules + run: git submodule update --init --recursive + + - name: Install Windows cross-compilation tools + run: | + sudo apt-get update + sudo apt-get install -y mingw-w64 g++-multilib nsis + + - name: Rust setup + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.rust_target }} + + - name: Rust Cache + uses: swatinem/rust-cache@v2 + with: + workspaces: "swingmusic-desktop -> target" + key: desktop-${{ matrix.platform }} + + - name: Install Tauri CLI + run: npm install -g @tauri-apps/cli + + - name: Build Desktop App + run: | + cd swingmusic-desktop + npm ci + npm run tauri build -- --target ${{ matrix.rust_target }} + + - name: Upload Windows artifacts + uses: actions/upload-artifact@v4 + with: + name: desktop-${{ matrix.platform }} + path: | + swingmusic-desktop/target/${{ matrix.rust_target }}/release/bundle/ + !swingmusic-desktop/target/${{ matrix.rust_target }}/release/bundle/.*/ + retention-days: 30 + + # macOS builds (must run on macOS runners) + build-macos-desktop: + name: Build macOS Desktop + runs-on: macos-latest + needs: get-version + if: contains(github.event.inputs.components, 'desktop') + + strategy: + fail-fast: false + matrix: + include: + - platform: 'macos-x64' + rust_target: 'x86_64-apple-darwin' + - platform: 'macos-arm64' + rust_target: 'aarch64-apple-darwin' + + steps: + - uses: actions/checkout@v4 + - name: Initialize submodules + run: git submodule update --init --recursive + + - name: Rust setup + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.rust_target }} + + - name: Rust Cache + uses: swatinem/rust-cache@v2 + with: + workspaces: "swingmusic-desktop -> target" + key: desktop-${{ matrix.platform }} + + - name: Install Tauri CLI + run: npm install -g @tauri-apps/cli + + - name: Build Desktop App + run: | + cd swingmusic-desktop + npm ci + npm run tauri build -- --target ${{ matrix.rust_target }} + + - name: Upload macOS artifacts + uses: actions/upload-artifact@v4 + with: + name: desktop-${{ matrix.platform }} + path: | + swingmusic-desktop/target/${{ matrix.rust_target }}/release/bundle/ + !swingmusic-desktop/target/${{ matrix.rust_target }}/release/bundle/.*/ + retention-days: 30 + + # Android builds build-android: name: Build Android App runs-on: ubuntu-latest @@ -215,6 +309,7 @@ jobs: path: swingmusic-android/app/build/outputs/apk/release/*.apk retention-days: 30 + # Backend builds build-backend: name: Build Backend runs-on: ubuntu-latest @@ -256,10 +351,11 @@ jobs: path: src/swingmusic/dist/ retention-days: 30 + # Create unified release create-release: name: Create Unified Release runs-on: ubuntu-latest - needs: [get-version, build-desktop, build-android, build-backend] + needs: [get-version, build-linux-desktop, build-windows-desktop, build-macos-desktop, build-android, build-backend] if: success() steps: @@ -321,7 +417,7 @@ jobs: - **Windows**: Download `.exe` installer - **macOS Intel**: Download `x64.dmg` disk image - **macOS ARM64**: Download `arm64.dmg` disk image - - **Linux x64**: Choose `.deb`, `.rpm`, or `.AppImage` + - **Linux**: Choose `.deb`, `.rpm`, or `.AppImage` ### 📱 Mobile Application - **Android**: Download `.apk` file and install diff --git a/.github/workflows/unified-release.yml.backup b/.github/workflows/unified-release.yml.backup new file mode 100644 index 00000000..4d43bed1 --- /dev/null +++ b/.github/workflows/unified-release.yml.backup @@ -0,0 +1,381 @@ +name: Unified Release + +on: + push: + branches: [ "main" ] + workflow_dispatch: + inputs: + version_number: + description: 'Version Number (e.g., 1.2.3) - leave empty for auto' + required: false + type: string + default: '' + components: + description: 'Components to release (comma separated)' + required: false + default: 'desktop,android,backend' + type: string + +env: + CARGO_TERM_COLOR: always + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + get-version: + name: Calculate Unified Version + runs-on: ubuntu-latest + if: github.event.inputs.version_number == '' + outputs: + version: ${{ steps.version.outputs.version }} + tag_name: ${{ steps.version.outputs.tag_name }} + release_notes: ${{ steps.version.outputs.release_notes }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Initialize submodules + run: git submodule update --init --recursive + + - name: Get Last Release + id: last_release + run: | + LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") + echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT + + - name: Analyze Commits and Calculate Version + id: version + run: | + LAST_TAG="${{ steps.last_release.outputs.tag }}" + CURRENT_VERSION=${LAST_TAG#v} + + # Get commits from main repo and submodules + MAIN_COMMITS=$(git log $LAST_TAG..HEAD --oneline --no-merges) + + cd swingmusic-desktop && git fetch --tags && DESKTOP_COMMITS=$(git log $LAST_TAG..HEAD --oneline --no-merges 2>/dev/null || echo "") && cd .. + cd swingmusic-android && git fetch --tags && ANDROID_COMMITS=$(git log $LAST_TAG..HEAD --oneline --no-merges 2>/dev/null || echo "") && cd .. + cd src/swingmusic && git fetch --tags && BACKEND_COMMITS=$(git log $LAST_TAG..HEAD --oneline --no-merges 2>/dev/null || echo "") && cd ../.. + + # Combine all commits for analysis + ALL_COMMITS="$MAIN_COMMITS $DESKTOP_COMMITS $ANDROID_COMMITS $BACKEND_COMMITS" + + MAJOR_COUNT=$(echo "$ALL_COMMITS" | grep -iE "BREAKING CHANGE|major|!:|breaking" | wc -l || echo "0") + MINOR_COUNT=$(echo "$ALL_COMMITS" | grep -iE "feat|feature|add|new|enhance" | wc -l || echo "0") + PATCH_COUNT=$(echo "$ALL_COMMITS" | grep -iE "fix|bug|patch|update|improve|refactor|docs|style|test|chore" | wc -l || echo "0") + + # Calculate next version + IFS='.' read -ra PARTS <<< "$CURRENT_VERSION" + MAJOR=${PARTS[0]:-0} + MINOR=${PARTS[1]:-0} + PATCH=${PARTS[2]:-0} + + if [ "$MAJOR_COUNT" -gt 0 ]; then + MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0; BUMP_TYPE="major" + elif [ "$MINOR_COUNT" -gt 0 ]; then + MINOR=$((MINOR + 1)); PATCH=0; BUMP_TYPE="minor" + else + PATCH=$((PATCH + 1)); BUMP_TYPE="patch" + fi + + NEW_VERSION="$MAJOR.$MINOR.$PATCH" + TAG_NAME="v$NEW_VERSION" + + echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT + + # Generate release notes + RELEASE_NOTES="## 🎵 SwingMusic v$NEW_VERSION\n\n" + if [ "$MAJOR_COUNT" -gt 0 ]; then + RELEASE_NOTES+="### 🚨 BREAKING CHANGES\n" + echo "$ALL_COMMITS" | grep -iE "BREAKING CHANGE|major|!:|breaking" | sed 's/^/- /' >> /tmp/major_commits.txt + RELEASE_NOTES+="$(cat /tmp/major_commits.txt)\n\n" + fi + if [ "$MINOR_COUNT" -gt 0 ]; then + RELEASE_NOTES+="### ✨ New Features\n" + echo "$ALL_COMMITS" | grep -iE "feat|feature|add|new|enhance" | sed 's/^/- /' >> /tmp/minor_commits.txt + RELEASE_NOTES+="$(cat /tmp/minor_commits.txt)\n\n" + fi + if [ "$PATCH_COUNT" -gt 0 ]; then + RELEASE_NOTES+="### 🐛 Bug Fixes & Improvements\n" + echo "$ALL_COMMITS" | grep -iE "fix|bug|patch|update|improve|refactor|docs|style|test|chore" | sed 's/^/- /' >> /tmp/patch_commits.txt + RELEASE_NOTES+="$(cat /tmp/patch_commits.txt)\n\n" + fi + + echo "release_notes<> $GITHUB_OUTPUT + echo -e "$RELEASE_NOTES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + echo "New version: $NEW_VERSION ($BUMP_TYPE)" + + build-desktop: + name: Build Desktop App + runs-on: ${{ matrix.os }} + needs: get-version + if: contains(github.event.inputs.components, 'desktop') + + strategy: + fail-fast: false + matrix: + include: + - platform: 'linux-x64' + os: ubuntu-latest + rust_target: 'x86_64-unknown-linux-gnu' + - platform: 'win-x64' + os: windows-latest + rust_target: 'x86_64-pc-windows-msvc' + - platform: 'darwin-x64' + os: macos-latest + rust_target: 'x86_64-apple-darwin' + - platform: 'darwin-arm64' + os: macos-latest + rust_target: 'aarch64-apple-darwin' + + steps: + - uses: actions/checkout@v4 + - name: Initialize submodules + run: git submodule update --init --recursive + + - name: Install dependencies (ubuntu) + if: startsWith(matrix.platform, 'linux') + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf + + - name: Rust setup + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.rust_target }} + + - name: Rust Cache + uses: swatinem/rust-cache@v2 + with: + workspaces: "swingmusic-desktop -> target" + key: desktop-${{ matrix.platform }} + + - name: Install Tauri CLI + run: npm install -g @tauri-apps/cli + + - name: Build Desktop App + run: | + cd swingmusic-desktop + npm ci + npm run tauri build -- --target ${{ matrix.rust_target }} + + - name: Upload Desktop artifacts + uses: actions/upload-artifact@v4 + with: + name: desktop-${{ matrix.platform }} + path: | + swingmusic-desktop/target/${{ matrix.rust_target }}/release/bundle/ + !swingmusic-desktop/target/${{ matrix.rust_target }}/release/bundle/.*/ + retention-days: 30 + + build-android: + name: Build Android App + runs-on: ubuntu-latest + needs: get-version + if: contains(github.event.inputs.components, 'android') + + steps: + - uses: actions/checkout@v4 + - name: Initialize submodules + run: git submodule update --init --recursive + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '17' + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Cache Gradle + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} + restore-keys: gradle- + + - name: Grant execute permission for gradlew + run: cd swingmusic-android && chmod +x gradlew + + - name: Build Android App + run: | + cd swingmusic-android + ./gradlew assembleRelease + + - name: Upload Android artifacts + uses: actions/upload-artifact@v4 + with: + name: android-release + path: swingmusic-android/app/build/outputs/apk/release/*.apk + retention-days: 30 + + build-backend: + name: Build Backend + runs-on: ubuntu-latest + needs: get-version + if: contains(github.event.inputs.components, 'backend') + + steps: + - uses: actions/checkout@v4 + - name: Initialize submodules + run: git submodule update --init --recursive + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Cache Python dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: pip- + + - name: Install dependencies + run: | + cd src/swingmusic + pip install -r requirements.txt + + - name: Build Backend Package + run: | + cd src/swingmusic + pip install build + python -m build + + - name: Upload Backend artifacts + uses: actions/upload-artifact@v4 + with: + name: backend-package + path: src/swingmusic/dist/ + retention-days: 30 + + create-release: + name: Create Unified Release + runs-on: ubuntu-latest + needs: [get-version, build-desktop, build-android, build-backend] + if: success() + + steps: + - uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Prepare release assets + run: | + mkdir -p release-assets + + # Desktop apps + find artifacts -name "*.exe" -exec cp {} release-assets/ \; 2>/dev/null || true + find artifacts -name "*.dmg" -exec cp {} release-assets/ \; 2>/dev/null || true + find artifacts -name "*.AppImage" -exec cp {} release-assets/ \; 2>/dev/null || true + find artifacts -name "*.deb" -exec cp {} release-assets/ \; 2>/dev/null || true + find artifacts -name "*.rpm" -exec cp {} release-assets/ \; 2>/dev/null || true + + # Android APK + find artifacts -name "*.apk" -exec cp {} release-assets/ \; 2>/dev/null || true + + # Backend package + find artifacts -name "*.whl" -exec cp {} release-assets/ \; 2>/dev/null || true + find artifacts -name "*.tar.gz" -exec cp {} release-assets/ \; 2>/dev/null || true + + ls -la release-assets/ + + - name: Extract version + id: version + run: | + if [ -n "${{ github.event.inputs.version_number }}" ]; then + VERSION="${{ github.event.inputs.version_number }}" + TAG_NAME="v$VERSION" + else + VERSION="${{ needs.get-version.outputs.version }}" + TAG_NAME="${{ needs.get-version.outputs.tag_name }}" + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.version.outputs.tag_name }} + name: SwingMusic v${{ steps.version.outputs.version }} + draft: false + prerelease: false + generate_release_notes: false + files: release-assets/* + body: | + ${{ github.event.inputs.version_number == '' && needs.get-version.outputs.release_notes || '' }} + + ## 📦 Installation + + ### 🖥️ Desktop Applications + - **Windows**: Download `.exe` installer + - **macOS Intel**: Download `x64.dmg` disk image + - **macOS ARM64**: Download `arm64.dmg` disk image + - **Linux x64**: Choose `.deb`, `.rpm`, or `.AppImage` + + ### 📱 Mobile Application + - **Android**: Download `.apk` file and install + + ### 🔧 Backend Server + - **Python**: Download `.whl` file: `pip install swingmusic-*.whl` + - **Source**: Download `.tar.gz` for manual installation + + ### 🚀 Quick Start + + #### Desktop + ```bash + # Linux AppImage + chmod +x SwingMusic*.AppImage + ./SwingMusic*.AppImage + + # Windows + # Run the downloaded .exe installer + + # macOS + # Open the .dmg and drag to Applications + ``` + + #### Backend + ```bash + # Install from wheel + pip install swingmusic-*.whl + + # Or from source + tar -xzf swingmusic-*.tar.gz + cd swingmusic-* + pip install -r requirements.txt + python -m swingmusic + ``` + + #### Android + ```bash + # Install APK + adb install swingmusic-*.apk + ``` + + --- + + ## 📋 Components + - ✅ **Desktop**: Cross-platform desktop application (4 platforms) + - ✅ **Android**: Native Android application + - ✅ **Backend**: Python-based REST API server + + ## 🔗 Links + - **Repository**: ${{ github.repository }} + - **Issues**: ${{ github.server_url }}/${{ github.repository }}/issues + + --- + + 🚀 **Thank you for using SwingMusic!** + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}