diff --git a/.github/workflows/component-tests.yml b/.github/workflows/component-tests.yml index 2e3a06de..6f9ab7c4 100644 --- a/.github/workflows/component-tests.yml +++ b/.github/workflows/component-tests.yml @@ -1,10 +1,6 @@ -name: Component Tests +name: Component Tests (DISABLED - use unified-release.yml) on: - push: - branches: [ develop ] - pull_request: - branches: [ main, master, develop ] workflow_dispatch: jobs: diff --git a/.github/workflows/desktop-ci.yml b/.github/workflows/desktop-ci.yml index e9e7dbab..ceed4fbd 100644 --- a/.github/workflows/desktop-ci.yml +++ b/.github/workflows/desktop-ci.yml @@ -1,10 +1,6 @@ -name: Desktop CI +name: Desktop CI (DISABLED - use unified-release.yml) on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] workflow_dispatch: env: diff --git a/.github/workflows/unified-build.yml b/.github/workflows/unified-build.yml deleted file mode 100644 index dbc00736..00000000 --- a/.github/workflows/unified-build.yml +++ /dev/null @@ -1,480 +0,0 @@ -name: Unified Linux Build and Deploy (DISABLED - use unified-release.yml) - -on: - workflow_dispatch: - inputs: - force_release: - description: "Force release creation" - required: false - default: "false" - type: choice - options: - - true - - false - components: - description: "Components to build (comma separated)" - required: false - default: "webclient,desktop,android,backend" - type: string - -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true - -jobs: - # Initialize and update submodules - init-submodules: - runs-on: ubuntu-latest - name: Initialize Submodules - outputs: - webclient-changed: ${{ steps.changes.outputs.webclient }} - desktop-changed: ${{ steps.changes.outputs.desktop }} - android-changed: ${{ steps.changes.outputs.android }} - backend-changed: ${{ steps.changes.outputs.backend }} - should-build-webclient: ${{ steps.decision.outputs.webclient }} - should-build-desktop: ${{ steps.decision.outputs.desktop }} - should-build-android: ${{ steps.decision.outputs.android }} - should-build-backend: ${{ steps.decision.outputs.backend }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - submodules: recursive - - - name: Detect changes - id: changes - run: | - # Get changed files - if [ ${{ github.event_name }} == 'push' ]; then - if [ ${{ github.ref }} == 'refs/heads/main' ] || [ ${{ github.ref }} == 'refs/heads/master' ]; then - BASE="HEAD~1" - else - BASE="origin/main" - fi - elif [ ${{ github.event_name }} == 'pull_request' ]; then - BASE="${{ github.event.pull_request.base.sha }}" - else - BASE="HEAD~1" - fi - - echo "Checking changes between $BASE and HEAD" - - # Check submodule changes - git diff --name-only $BASE HEAD | grep -E "^swingmusic-webclient/" > /dev/null && echo "webclient=true" >> $GITHUB_OUTPUT || echo "webclient=false" >> $GITHUB_OUTPUT - git diff --name-only $BASE HEAD | grep -E "^swingmusic-desktop/" > /dev/null && echo "desktop=true" >> $GITHUB_OUTPUT || echo "desktop=false" >> $GITHUB_OUTPUT - git diff --name-only $BASE HEAD | grep -E "^swingmusic-android/" > /dev/null && echo "android=true" >> $GITHUB_OUTPUT || echo "android=false" >> $GITHUB_OUTPUT - git diff --name-only $BASE HEAD | grep -E "^src/" > /dev/null && echo "backend=true" >> $GITHUB_OUTPUT || echo "backend=false" >> $GITHUB_OUTPUT - - # Also check if submodules themselves changed - git submodule status --recursive - - - name: Decide what to build - id: decision - run: | - # Parse user input or build all - INPUT_COMPONENTS="${{ github.event.inputs.components || 'webclient,desktop,android,backend' }}" - IFS=',' read -ra COMPONENTS <<< "$INPUT_COMPONENTS" - - # Default to building everything on tags/main branch - if [[ $GITHUB_REF == refs/tags/* ]] || [[ $GITHUB_REF == refs/heads/main ]] || [[ $GITHUB_REF == refs/heads/master ]]; then - echo "webclient=true" >> $GITHUB_OUTPUT - echo "desktop=true" >> $GITHUB_OUTPUT - echo "android=true" >> $GITHUB_OUTPUT - echo "backend=true" >> $GITHUB_OUTPUT - else - # Build only what changed or was specified - for component in "${COMPONENTS[@]}"; do - component=$(echo "$component" | xargs) # trim whitespace - if [[ "${{ steps.changes.outputs.webclient }}" == "true" ]] || [[ "$component" == "webclient" ]]; then - echo "webclient=true" >> $GITHUB_OUTPUT - else - echo "webclient=false" >> $GITHUB_OUTPUT - fi - - if [[ "${{ steps.changes.outputs.desktop }}" == "true" ]] || [[ "$component" == "desktop" ]]; then - echo "desktop=true" >> $GITHUB_OUTPUT - else - echo "desktop=false" >> $GITHUB_OUTPUT - fi - - if [[ "${{ steps.changes.outputs.android }}" == "true" ]] || [[ "$component" == "android" ]]; then - echo "android=true" >> $GITHUB_OUTPUT - else - echo "android=false" >> $GITHUB_OUTPUT - fi - - if [[ "${{ steps.changes.outputs.backend }}" == "true" ]] || [[ "$component" == "backend" ]]; then - echo "backend=true" >> $GITHUB_OUTPUT - else - echo "backend=false" >> $GITHUB_OUTPUT - fi - done - fi - - # Build Web Client - build-webclient: - runs-on: ubuntu-latest - name: Build Web Client - needs: init-submodules - if: needs.init-submodules.outputs.should-build-webclient == 'true' - outputs: - client-sha: ${{ steps.sha.outputs.sha }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Setup Node 24 - uses: actions/setup-node@v4 - with: - node-version: 24.x - - - name: Build client - run: | - cd swingmusic-webclient - npm install - npm run build - cd .. - - - name: Generate client SHA - id: sha - run: | - cd swingmusic-webclient/dist - sha256sum * | sort | sha256sum | cut -d' ' -f1 > client.sha - echo "sha=$(cat client.sha)" >> $GITHUB_OUTPUT - - - name: Upload client artifact - uses: actions/upload-artifact@v4 - with: - path: "swingmusic-webclient/dist/" - compression-level: 0 - name: "webclient" - - # Build Desktop App - build-desktop: - runs-on: ubuntu-latest - name: Build Desktop App - needs: init-submodules - if: needs.init-submodules.outputs.should-build-desktop == 'true' - strategy: - matrix: - os: [ubuntu-latest, windows-latest, macos-latest] - include: - - os: ubuntu-latest - platform: linux - target: x86_64-unknown-linux-gnu - - os: windows-latest - platform: windows - target: x86_64-pc-windows-msvc - - os: macos-latest - platform: macos - target: x86_64-apple-darwin - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install dependencies (Ubuntu) - if: matrix.os == 'ubuntu-latest' - 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.target }} - - - name: Rust Cache - uses: swatinem/rust-cache@v2 - with: - workspaces: "swingmusic-desktop -> target" - key: ${{ matrix.platform }}-x64 - - - name: Install Tauri CLI - run: npm install -g @tauri-apps/cli - - - name: Install desktop dependencies - run: | - cd swingmusic-desktop - npm install - - - name: Install webclient dependencies - run: | - cd swingmusic-webclient - npm install - - - name: Build the app - run: | - cd swingmusic-desktop - npm run tauri build -- --target ${{ matrix.target }} - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: swingmusic-desktop-${{ matrix.platform }}-x64 - path: | - swingmusic-desktop/target/${{ matrix.target }}/release/bundle/ - !swingmusic-desktop/target/${{ matrix.target }}/release/bundle/.*/ - retention-days: 30 - - # Build Android App - build-android: - runs-on: ubuntu-latest - name: Build Android App - needs: init-submodules - if: needs.init-submodules.outputs.should-build-android == 'true' - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - - - name: Setup Android SDK - uses: android-actions/setup-android@v3 - - - 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: swingmusic-android - path: swingmusic-android/app/build/outputs/apk/release/*.apk - retention-days: 30 - - # Build Backend (Python) - build-backend: - runs-on: ubuntu-latest - name: Build Backend - needs: [init-submodules, build-webclient] - if: needs.init-submodules.outputs.should-build-backend == 'true' - outputs: - version: ${{ steps.version.outputs.version }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - submodules: recursive - - - name: Download webclient artifact - if: needs.init-submodules.outputs.should-build-webclient == 'true' - uses: actions/download-artifact@v4 - with: - name: webclient - path: swingmusic-webclient/dist - - - name: Compress client and copy to src/swingmusic/client.zip - if: needs.init-submodules.outputs.should-build-webclient == 'true' - run: | - cd swingmusic-webclient/dist - zip -r client.zip . - cd ../.. - cp swingmusic-webclient/dist/client.zip src/swingmusic/client.zip - - - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Get version - id: version - run: | - if [[ $GITHUB_REF == refs/tags/* ]]; then - VERSION=${GITHUB_REF#refs/tags/v} - else - VERSION=$(python3 -c "import sys; sys.path.insert(0, 'src'); from swingmusic import __version__; print(__version__)") - VERSION="$VERSION-${{ github.run_number }}" - fi - echo "version=$VERSION" >> $GITHUB_OUTPUT - - - name: Build wheels - run: pip wheel . -w wheelhouse --no-deps - - - name: Upload wheels - uses: actions/upload-artifact@v4 - with: - path: ./wheelhouse/*.whl - compression-level: 0 - name: "backend-wheels" - - # Build Docker Image (includes backend + webclient) - build-docker: - runs-on: ubuntu-latest - name: Build Docker Image - needs: [init-submodules, build-webclient, build-backend] - if: needs.init-submodules.outputs.should-build-backend == 'true' - permissions: - contents: read - packages: write - outputs: - image: ${{ steps.meta.outputs.tags }} - digest: ${{ steps.build.outputs.digest }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Download webclient artifact - if: needs.init-submodules.outputs.should-build-webclient == 'true' - uses: actions/download-artifact@v4 - with: - name: webclient - path: swingmusic-webclient/dist - - - name: Download backend wheels - uses: actions/download-artifact@v4 - with: - name: backend-wheels - path: wheels - merge-multiple: true - - - name: Compress client and copy to src/swingmusic/client.zip - if: needs.init-submodules.outputs.should-build-webclient == 'true' - run: | - cd swingmusic-webclient/dist - zip -r client.zip . - cd ../.. - cp swingmusic-webclient/dist/client.zip src/swingmusic/client.zip - - - name: Create version.txt - run: echo "${{ needs.build-backend.outputs.version }}" > version.txt - - - name: Log in to Container Registry - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=ref,event=branch,suffix=-${{ github.run_number }} - type=ref,event=pr,suffix=-pr-${{ github.event.number }} - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=raw,value=latest,enable={{is_default_branch}} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Build and push Docker image - id: build - uses: docker/build-push-action@v5 - with: - context: . - platforms: linux/amd64,linux/arm64 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - app_version=${{ needs.build-backend.outputs.version }} - client_sha=${{ needs.build-webclient.outputs.client-sha }} - cache-from: type=gha - cache-to: type=gha,mode=max - - # Create Release - create-release: - runs-on: ubuntu-latest - name: Create Release - needs: [init-submodules, build-webclient, build-desktop, build-android, build-backend, build-docker] - if: | - startsWith(github.ref, 'refs/tags/') || - github.event.inputs.force_release == 'true' - permissions: - contents: write - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Download all artifacts - uses: actions/download-artifact@v4 - - - name: Create release - uses: softprops/action-gh-release@v1 - with: - name: Release ${{ needs.build-backend.outputs.version }} - tag_name: v${{ needs.build-backend.outputs.version }} - body: | - ## Release ${{ needs.build-backend.outputs.version }} - - ### Docker Image - - `${{ needs.build-docker.outputs.image }}` - - ### Components - - **Web Client**: Built and included in Docker image - - **Desktop Apps**: Available in artifacts - - **Android App**: Available in artifacts - - **Backend**: Python wheels available - - ### Changes - - View full changelog in [CHANGELOG.md](CHANGELOG.md) - - ### Installation - #### Docker (Recommended) - ```bash - docker pull ${{ needs.build-docker.outputs.image }} - docker run -p 1979:1979 ${{ needs.build-docker.outputs.image }} - ``` - - #### Desktop - Download the appropriate artifact for your platform: - - Linux: swingmusic-desktop-linux-x64 - - Windows: swingmusic-desktop-windows-x64 - - macOS: swingmusic-desktop-macos-x64 - - #### Android - Download the APK from the swingmusic-android artifact. - files: | - backend-wheels/* - webclient/* - swingmusic-desktop-*/ - swingmusic-android/* - draft: false - prerelease: ${{ contains(needs.build-backend.outputs.version, '-') }} - generate_release_notes: true - - # Summary - build-summary: - runs-on: ubuntu-latest - name: Build Summary - needs: [init-submodules, build-webclient, build-desktop, build-android, build-backend, build-docker] - if: always() - steps: - - name: Build Summary - run: | - echo "## Build Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "| Component | Status | Result |" >> $GITHUB_STEP_SUMMARY - echo "|-----------|--------|--------|" >> $GITHUB_STEP_SUMMARY - echo "| Web Client | ${{ needs.build-webclient.result || 'skipped' }} | ${{ contains(needs.build-webclient.result, 'failure') && '❌ Failed' || contains(needs.build-webclient.result, 'success') && '✅ Success' || '⏭️ Skipped' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Desktop | ${{ needs.build-desktop.result || 'skipped' }} | ${{ contains(needs.build-desktop.result, 'failure') && '❌ Failed' || contains(needs.build-desktop.result, 'success') && '✅ Success' || '⏭️ Skipped' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Android | ${{ needs.build-android.result || 'skipped' }} | ${{ contains(needs.build-android.result, 'failure') && '❌ Failed' || contains(needs.build-android.result, 'success') && '✅ Success' || '⏭️ Skipped' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Backend | ${{ needs.build-backend.result || 'skipped' }} | ${{ contains(needs.build-backend.result, 'failure') && '❌ Failed' || contains(needs.build-backend.result, 'success') && '✅ Success' || '⏭️ Skipped' }} |" >> $GITHUB_STEP_SUMMARY - echo "| Docker | ${{ needs.build-docker.result || 'skipped' }} | ${{ contains(needs.build-docker.result, 'failure') && '❌ Failed' || contains(needs.build-docker.result, 'success') && '✅ Success' || '⏭️ Skipped' }} |" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/unified-release.yml.backup b/.github/workflows/unified-release.yml.backup deleted file mode 100644 index 4d43bed1..00000000 --- a/.github/workflows/unified-release.yml.backup +++ /dev/null @@ -1,381 +0,0 @@ -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 }}