test: achieve 100% test coverage for core audio engine #539
Workflow file for this run
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: CI - Build and Test | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [develop, main] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| test-linux: | |
| name: Test on Linux | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Cache apt packages | |
| uses: actions/cache@v5 | |
| id: apt-cache | |
| with: | |
| path: ~/apt-cache | |
| key: apt-${{ runner.os }}-${{ hashFiles('.github/workflows/ci.yml') }} | |
| - name: Install Dependencies | |
| run: | | |
| if [ "${{ steps.apt-cache.outputs.cache-hit }}" = "true" ] && [ -d ~/apt-cache ]; then | |
| echo "Restoring cached .deb packages..." | |
| sudo cp ~/apt-cache/*.deb /var/cache/apt/archives/ 2>/dev/null || true | |
| fi | |
| sudo apt-get update -qq | |
| sudo apt-get install -y --no-install-recommends \ | |
| build-essential cmake \ | |
| libportaudio2 portaudio19-dev \ | |
| libsdl2-dev libgl1-mesa-dev libglu1-mesa-dev \ | |
| librtmidi-dev | |
| mkdir -p ~/apt-cache | |
| cp /var/cache/apt/archives/*.deb ~/apt-cache/ 2>/dev/null || true | |
| - name: Setup External Dependencies | |
| run: | | |
| bash ./scripts/setup_dependencies.sh | |
| - name: Generate Version | |
| id: version | |
| run: | | |
| COUNT=$(git rev-list --count HEAD) | |
| echo "version=0.1.${COUNT}" >> $GITHUB_OUTPUT | |
| - name: Build | |
| run: | | |
| mkdir -p build && cd build | |
| cmake -DCMAKE_BUILD_TYPE=Debug \ | |
| -DAMPLITRON_VERSION="${{ steps.version.outputs.version }}" \ | |
| -DCMAKE_C_FLAGS="--coverage -O0 -g" \ | |
| -DCMAKE_CXX_FLAGS="--coverage -O0 -g" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="--coverage" \ | |
| .. | |
| make -j$(nproc) | |
| - name: Run Tests | |
| run: cd build && ./amplitron-tests | |
| - name: Package Build Data for Coverage | |
| run: tar -czf build-coverage.tar.gz build/ | |
| - name: Upload Build Artifact for Coverage | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-coverage | |
| path: build-coverage.tar.gz | |
| retention-days: 1 | |
| - name: Upload Build | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: linux-build | |
| path: build/Amplitron | |
| retention-days: 1 | |
| coverage-linux: | |
| name: Coverage Report on Linux | |
| needs: test-linux | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install lcov | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -y --no-install-recommends lcov | |
| - name: Download Build Artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: build-coverage | |
| path: . | |
| - name: Extract Build Data | |
| run: tar -xzf build-coverage.tar.gz | |
| - name: Generate Coverage Report | |
| run: | | |
| lcov --capture --directory build --output-file coverage.info --ignore-errors mismatch,gcov,source | |
| lcov --remove coverage.info \ | |
| '/usr/*' \ | |
| '*/external/*' \ | |
| '*/tests/*' \ | |
| '*/build/*' \ | |
| --output-file coverage.filtered.info \ | |
| --ignore-errors unused | |
| genhtml coverage.filtered.info --output-directory coverage-report | |
| lcov --summary coverage.filtered.info | tee coverage-summary.txt | |
| - name: Enforce Coverage Threshold and Generate Markdown | |
| run: | | |
| COVERAGE=$(lcov --summary coverage.filtered.info 2>&1 | awk '/lines......:/ {print $2}' | sed 's/%//') | |
| echo "Line coverage: $COVERAGE%" | |
| THRESHOLD=60 | |
| echo "### Code Coverage Report 📊" > coverage_comment.md | |
| echo "**Line Coverage:** ${COVERAGE}%" >> coverage_comment.md | |
| echo "" >> coverage_comment.md | |
| if awk "BEGIN {exit !($COVERAGE >= $THRESHOLD)}"; then | |
| echo "✅ Coverage meets threshold: $COVERAGE% >= $THRESHOLD%" | |
| echo "✅ Coverage meets threshold: $COVERAGE% >= $THRESHOLD%" >> coverage_comment.md | |
| else | |
| echo "⚠️ Coverage is below threshold: $COVERAGE% < $THRESHOLD%" | |
| echo "⚠️ Coverage is below threshold: $COVERAGE% < $THRESHOLD%" >> coverage_comment.md | |
| echo "This PR adds coverage reporting, so low coverage is reported as a warning." | |
| echo "CI will continue and upload the coverage report." | |
| fi | |
| echo "" >> coverage_comment.md | |
| echo "<details>" >> coverage_comment.md | |
| echo "<summary>Full Coverage Summary</summary>" >> coverage_comment.md | |
| echo "" >> coverage_comment.md | |
| echo '```text' >> coverage_comment.md | |
| cat coverage-summary.txt >> coverage_comment.md | |
| echo '```' >> coverage_comment.md | |
| echo "</details>" >> coverage_comment.md | |
| cat coverage_comment.md >> $GITHUB_STEP_SUMMARY | |
| - name: Save PR Number and Coverage Comment | |
| if: github.event_name == 'pull_request' | |
| run: | | |
| mkdir -p pr_coverage | |
| echo "${{ github.event.pull_request.number }}" > pr_coverage/pr_number.txt | |
| cp coverage_comment.md pr_coverage/coverage_comment.md | |
| - name: Upload PR Coverage Artifact | |
| if: github.event_name == 'pull_request' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: pr-coverage-comment | |
| path: pr_coverage/ | |
| retention-days: 1 | |
| - name: Upload Coverage HTML Report | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-report | |
| path: coverage-report/ | |
| retention-days: 7 | |
| - name: Upload Coverage Summary | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-summary | |
| path: | | |
| coverage.filtered.info | |
| coverage-summary.txt | |
| retention-days: 7 | |
| test-macos: | |
| name: Test on macOS | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install Dependencies | |
| run: brew install portaudio sdl2 rtmidi | |
| - name: Setup External Dependencies | |
| run: | | |
| bash ./scripts/setup_dependencies.sh | |
| - name: Generate Version | |
| id: version | |
| run: | | |
| COUNT=$(git rev-list --count HEAD) | |
| echo "version=0.1.${COUNT}" >> $GITHUB_OUTPUT | |
| - name: Build | |
| run: | | |
| HOMEBREW_PREFIX=$(brew --prefix) | |
| mkdir -p build && cd build | |
| cmake -DCMAKE_BUILD_TYPE=Release \ | |
| -DAMPLITRON_VERSION="${{ steps.version.outputs.version }}" \ | |
| -DPORTAUDIO_INCLUDE_DIRS="$HOMEBREW_PREFIX/include" \ | |
| -DPORTAUDIO_LIBRARIES="$HOMEBREW_PREFIX/lib/libportaudio.dylib" \ | |
| -DSDL2_INCLUDE_DIRS="$HOMEBREW_PREFIX/include/SDL2" \ | |
| -DSDL2_LIBRARIES="$HOMEBREW_PREFIX/lib/libSDL2.dylib" \ | |
| -DRTMIDI_INCLUDE_DIRS="$HOMEBREW_PREFIX/include" \ | |
| -DRTMIDI_LIBRARIES="$HOMEBREW_PREFIX/lib/librtmidi.dylib" \ | |
| .. | |
| make -j$(sysctl -n hw.ncpu) | |
| - name: Run Tests | |
| run: cd build && ./amplitron-tests | |
| - name: Bundle Dylibs | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| run: | | |
| set -e | |
| mkdir -p staging | |
| cp build/Amplitron staging/ | |
| echo "=== Original linked libraries ===" | |
| otool -L staging/Amplitron | |
| otool -L staging/Amplitron | tail -n +2 | awk '{print $1}' > /tmp/deps.txt | |
| cat /tmp/deps.txt | |
| while IFS= read -r lib; do | |
| case "$lib" in | |
| /usr/lib/*|/System/*|@executable_path/*|@rpath/*|@loader_path/*) continue ;; | |
| esac | |
| libname=$(basename "$lib") | |
| echo ">>> Bundling: $lib -> staging/$libname" | |
| cp -L "$lib" "staging/$libname" | |
| chmod 644 "staging/$libname" | |
| echo ">>> Fixing reference: $lib -> @executable_path/$libname" | |
| install_name_tool -change "$lib" "@executable_path/$libname" staging/Amplitron | |
| done < /tmp/deps.txt | |
| for dylib in staging/*.dylib; do | |
| [ -f "$dylib" ] || continue | |
| libname=$(basename "$dylib") | |
| echo ">>> Fixing dylib id: $libname" | |
| install_name_tool -id "@executable_path/$libname" "$dylib" | |
| otool -L "$dylib" | tail -n +2 | awk '{print $1}' > /tmp/subdeps.txt | |
| while IFS= read -r lib; do | |
| case "$lib" in | |
| /usr/lib/*|/System/*|@executable_path/*|@rpath/*|@loader_path/*) continue ;; | |
| esac | |
| depname=$(basename "$lib") | |
| echo ">>> Fixing sub-dep in $libname: $lib -> @executable_path/$depname" | |
| if [ ! -f "staging/$depname" ]; then | |
| cp -L "$lib" "staging/$depname" | |
| chmod 644 "staging/$depname" | |
| install_name_tool -id "@executable_path/$depname" "staging/$depname" | |
| fi | |
| install_name_tool -change "$lib" "@executable_path/$depname" "$dylib" | |
| done < /tmp/subdeps.txt | |
| done | |
| echo "" | |
| echo "=== After bundling ===" | |
| otool -L staging/Amplitron | |
| echo "=== Dylib links ===" | |
| for f in staging/*.dylib; do | |
| [ -f "$f" ] || continue | |
| echo "--- $(basename $f) ---" | |
| otool -L "$f" | |
| done | |
| echo "=== Staged files ===" | |
| ls -la staging/ | |
| - name: Upload Build | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: macos-build | |
| path: staging/ | |
| retention-days: 1 | |
| build-web: | |
| name: Build Web Demo (Emscripten) | |
| runs-on: ubuntu-latest | |
| env: | |
| EMSDK_VERSION: 3.1.51 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Cache Emscripten SDK & ports | |
| uses: actions/cache@v5 | |
| id: emsdk-cache | |
| with: | |
| path: | | |
| emsdk | |
| ~/.emscripten_cache | |
| key: emsdk-${{ env.EMSDK_VERSION }}-${{ runner.os }}-${{ hashFiles('CMakeLists.txt') }} | |
| restore-keys: | | |
| emsdk-${{ env.EMSDK_VERSION }}-${{ runner.os }}- | |
| - name: Setup Emscripten | |
| if: steps.emsdk-cache.outputs.cache-hit != 'true' | |
| run: | | |
| if [ -d emsdk ]; then | |
| cd emsdk && git pull | |
| else | |
| git clone https://github.com/emscripten-core/emsdk.git | |
| cd emsdk | |
| fi | |
| ./emsdk install $EMSDK_VERSION | |
| ./emsdk activate $EMSDK_VERSION | |
| - name: Activate Emscripten | |
| run: | | |
| cd emsdk | |
| ./emsdk activate $EMSDK_VERSION | |
| echo "${{ github.workspace }}/emsdk" >> $GITHUB_PATH | |
| echo "${{ github.workspace }}/emsdk/upstream/emscripten" >> $GITHUB_PATH | |
| - name: Setup External Dependencies | |
| run: | | |
| bash ./scripts/setup_dependencies.sh | |
| - name: Generate Version | |
| id: version | |
| run: | | |
| COUNT=$(git rev-list --count HEAD) | |
| echo "version=0.1.${COUNT}" >> $GITHUB_OUTPUT | |
| - name: Build WASM | |
| run: | | |
| source emsdk/emsdk_env.sh | |
| mkdir -p build-web && cd build-web | |
| emcmake cmake -DCMAKE_BUILD_TYPE=Release -DAMPLITRON_VERSION="${{ steps.version.outputs.version }}" .. | |
| emmake make -j$(nproc) | |
| - name: Upload Web Build | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: web-build | |
| path: build-web/ | |
| retention-days: 1 | |
| test-web: | |
| name: Test Web Demo (Playwright) | |
| needs: build-web | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download web build artifact | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: web-build | |
| path: web-build/ | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| cache-dependency-path: tests/web/package.json | |
| - name: Install Playwright & dependencies | |
| working-directory: tests/web | |
| run: | | |
| npm ci | |
| npx playwright install --with-deps chromium | |
| - name: Run Playwright tests | |
| working-directory: tests/web | |
| env: | |
| WEB_BUILD_DIR: ${{ github.workspace }}/web-build | |
| CI: true | |
| run: npx playwright test | |
| - name: Upload Playwright HTML report | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: playwright-report | |
| path: tests/web/playwright-report/ | |
| retention-days: 7 | |
| test-windows: | |
| name: Test on Windows | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup MSYS2 | |
| uses: msys2/setup-msys2@v2 | |
| with: | |
| msystem: MINGW64 | |
| update: false | |
| pacboy: >- | |
| gcc:p | |
| cmake:p | |
| ninja:p | |
| ccache:p | |
| portaudio:p | |
| SDL2:p | |
| rtmidi:p | |
| install: git | |
| cache: true | |
| - name: Restore ccache | |
| uses: actions/cache@v5 | |
| continue-on-error: true | |
| with: | |
| path: .ccache | |
| key: ccache-windows-${{ runner.os }}-${{ hashFiles('src/**/*.cpp', 'src/**/*.h', 'CMakeLists.txt') }} | |
| restore-keys: | | |
| ccache-windows-${{ runner.os }}- | |
| ccache-windows- | |
| - name: Setup External Dependencies | |
| shell: msys2 {0} | |
| run: | | |
| bash ./scripts/setup_dependencies.sh | |
| - name: Generate Version | |
| shell: msys2 {0} | |
| id: version | |
| run: | | |
| COUNT=$(git rev-list --count HEAD) | |
| echo "version=0.1.${COUNT}" >> $GITHUB_OUTPUT | |
| - name: Build | |
| shell: msys2 {0} | |
| run: | | |
| export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache" | |
| export CCACHE_MAXSIZE=200M | |
| mkdir -p "$CCACHE_DIR" | |
| mkdir -p build && cd build | |
| cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \ | |
| -DAMPLITRON_VERSION="${{ steps.version.outputs.version }}" \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=ccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ | |
| .. | |
| ninja -j$NUMBER_OF_PROCESSORS | |
| ccache -s | |
| - name: Run Tests | |
| shell: msys2 {0} | |
| run: cd build && ./amplitron-tests.exe | |
| - name: Collect Binaries | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| shell: msys2 {0} | |
| run: | | |
| mkdir -p staging | |
| cp build/amplitron.exe staging/Amplitron.exe | |
| for dll in libgcc_s_seh-1.dll libstdc++-6.dll libwinpthread-1.dll SDL2.dll; do | |
| cp /mingw64/bin/$dll staging/ 2>/dev/null || true | |
| done | |
| cp /mingw64/bin/libportaudio*.dll staging/ 2>/dev/null || true | |
| cp /mingw64/bin/librtmidi*.dll staging/ 2>/dev/null || true | |
| ls -la staging/ | |
| - name: Upload Build | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: windows-build | |
| path: staging/ | |
| retention-days: 1 | |
| build-android: | |
| name: Build Android APK | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: "17" | |
| distribution: "temurin" | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v6 | |
| - name: Install Android NDK r27 | |
| run: | | |
| echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \ | |
| "ndk;27.1.12297006" \ | |
| "cmake;3.22.1" | |
| - name: Setup External Dependencies | |
| run: | | |
| bash ./scripts/setup_dependencies.sh | |
| - name: Fetch SDL2 Java bridge | |
| run: | | |
| git clone --depth 1 --branch release-2.30.12 \ | |
| https://github.com/libsdl-org/SDL.git sdl2-src | |
| mkdir -p android/app/src/main/java/org/libsdl/app | |
| cp sdl2-src/android-project/app/src/main/java/org/libsdl/app/*.java \ | |
| android/app/src/main/java/org/libsdl/app/ | |
| - name: Generate Version | |
| id: version | |
| run: | | |
| COUNT=$(git rev-list --count HEAD) | |
| echo "version=0.1.${COUNT}" >> $GITHUB_OUTPUT | |
| - name: Build APK | |
| working-directory: android | |
| run: | | |
| ./gradlew assembleRelease \ | |
| -PamplitronVersion=${{ steps.version.outputs.version }} \ | |
| --no-daemon | |
| - name: Validate APK | |
| run: | | |
| APK=$(find android/app/build/outputs/apk/release -name "*.apk" | head -1) | |
| echo "APK: $APK ($(du -sh "$APK" | cut -f1))" | |
| $ANDROID_HOME/build-tools/34.0.0/aapt2 dump badging "$APK" \ | |
| | grep -E "^(package|sdkVersion|targetSdkVersion|uses-permission|native-code)" | |
| unzip -p "$APK" lib/arm64-v8a/libmain.so | file - \ | |
| | grep -i "ELF.*aarch64" \ | |
| || { echo "ARM64 libmain.so not found or invalid"; exit 1; } | |
| echo "APK validation passed." | |
| - name: Upload APK | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: android-build | |
| path: android/app/build/outputs/apk/release/ | |
| retention-days: 1 | |
| build-ios: | |
| name: Build iOS App (Device) | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup External Dependencies | |
| run: | | |
| bash ./scripts/setup_dependencies.sh | |
| - name: Generate Version | |
| id: version | |
| run: | | |
| COUNT=$(git rev-list --count HEAD) | |
| echo "version=0.1.${COUNT}" >> $GITHUB_OUTPUT | |
| - name: Cache SDL2 iOS static library | |
| id: sdl2-ios-cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/sdl2-ios | |
| key: sdl2-ios-arm64-2.30.12 | |
| - name: Build SDL2 for iOS | |
| if: steps.sdl2-ios-cache.outputs.cache-hit != 'true' | |
| run: | | |
| curl -fsSL https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.30.12.tar.gz | tar xz | |
| cmake -S SDL-release-2.30.12 -B sdl2-build \ | |
| -G "Unix Makefiles" \ | |
| -DCMAKE_SYSTEM_NAME=iOS \ | |
| -DCMAKE_OSX_DEPLOYMENT_TARGET=15.0 \ | |
| -DCMAKE_OSX_ARCHITECTURES=arm64 \ | |
| -DCMAKE_INSTALL_PREFIX=$HOME/sdl2-ios \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DSDL_STATIC=ON -DSDL_SHARED=OFF -DSDL_TEST=OFF | |
| cmake --build sdl2-build -j$(sysctl -n hw.ncpu) | |
| cmake --install sdl2-build | |
| - name: Cache CMake configure output | |
| id: cmake-cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: build-ios | |
| key: ios-cmake-${{ runner.os }}-${{ hashFiles('CMakeLists.txt', 'ios/Info.plist', '.github/workflows/ci.yml') }} | |
| restore-keys: | | |
| ios-cmake-${{ runner.os }}- | |
| - name: Configure | |
| if: steps.cmake-cache.outputs.cache-hit != 'true' | |
| run: | | |
| cmake \ | |
| -DCMAKE_SYSTEM_NAME=iOS \ | |
| -DCMAKE_OSX_DEPLOYMENT_TARGET=15.0 \ | |
| -DCMAKE_OSX_ARCHITECTURES="arm64" \ | |
| -DAMPLITRON_VERSION="${{ steps.version.outputs.version }}" \ | |
| -DSDL2_DIR=$HOME/sdl2-ios/lib/cmake/SDL2 \ | |
| -G Xcode \ | |
| -S . -B build-ios | |
| - name: Query build products path | |
| id: ios-paths | |
| run: | | |
| PRODUCTS_DIR=$(xcodebuild -project build-ios/Amplitron.xcodeproj \ | |
| -scheme Amplitron -configuration Release -sdk iphoneos \ | |
| -showBuildSettings 2>/dev/null \ | |
| | grep ' BUILT_PRODUCTS_DIR' | awk '{print $3}') | |
| echo "products_dir=$PRODUCTS_DIR" >> $GITHUB_OUTPUT | |
| echo "Build products dir: $PRODUCTS_DIR" | |
| - name: Build iOS Device | |
| run: | | |
| set -o pipefail | |
| xcodebuild \ | |
| -project build-ios/Amplitron.xcodeproj \ | |
| -scheme Amplitron \ | |
| -configuration Release \ | |
| -sdk iphoneos \ | |
| ONLY_ACTIVE_ARCH=YES \ | |
| CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO \ | |
| build 2>&1 | tee /tmp/xcode.log | xcpretty --color; \ | |
| STATUS=${PIPESTATUS[0]}; \ | |
| [ $STATUS -eq 0 ] || { echo "=== FULL XCODE LOG ==="; cat /tmp/xcode.log; exit $STATUS; } | |
| - name: Validate .app bundle | |
| run: | | |
| PRODUCTS_DIR="${{ steps.ios-paths.outputs.products_dir }}" | |
| APP="$PRODUCTS_DIR/Amplitron.app" | |
| if [ ! -d "$APP" ]; then | |
| echo "Amplitron.app not found at $APP" | |
| echo "Searching workspace..." | |
| find . -name "Amplitron.app" -type d 2>/dev/null || true | |
| exit 1 | |
| fi | |
| echo "App bundle: $APP" | |
| BINARY="$APP/Amplitron" | |
| file "$BINARY" | |
| lipo -info "$BINARY" | grep -E "arm64" \ | |
| || { echo "Expected arm64 slice not found"; exit 1; } | |
| plutil -lint "$APP/Info.plist" | |
| BUNDLE_ID=$(/usr/libexec/PlistBuddy -c "Print CFBundleIdentifier" "$APP/Info.plist") | |
| [ "$BUNDLE_ID" = "com.amplitron.app" ] \ | |
| || { echo "Wrong bundle ID: $BUNDLE_ID"; exit 1; } | |
| echo ".app validation passed." | |
| - name: Package .ipa | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| run: | | |
| APP="${{ steps.ios-paths.outputs.products_dir }}/Amplitron.app" | |
| mkdir -p ios-staging/Payload | |
| cp -R "$APP" ios-staging/Payload/ | |
| cd ios-staging && zip -r Amplitron.ipa Payload/ | |
| ls -la | |
| - name: Upload iOS App | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: ios-build | |
| path: ios-staging/Amplitron.ipa | |
| retention-days: 1 |