feat: Add NAM Loader pedal for machine learning based amp simulation #1139
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 ninja-build lcov \ | |
| 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: | | |
| chmod +x scripts/setup_dependencies.sh | |
| ./scripts/setup_dependencies.sh --no-system-deps | |
| - 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 -G Ninja -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" \ | |
| .. | |
| ninja -j$(nproc) | |
| - name: Run Tests | |
| run: cd build && ./amplitron-tests | |
| - name: Install Smoke Test | |
| env: | |
| INSTALL_PREFIX: ${{ runner.temp }}/amplitron-install | |
| run: | | |
| cmake --install build --prefix "$INSTALL_PREFIX" | |
| test -x "$INSTALL_PREFIX/bin/Amplitron" | |
| "$INSTALL_PREFIX/bin/Amplitron" --version | grep -q "Amplitron v1.0" | |
| - name: Uninstall Smoke Test | |
| env: | |
| INSTALL_PREFIX: ${{ runner.temp }}/amplitron-install | |
| run: | | |
| make PREFIX="$INSTALL_PREFIX" uninstall | |
| test ! -e "$INSTALL_PREFIX/bin/Amplitron" | |
| test ! -e "$INSTALL_PREFIX/share/amplitron" | |
| test ! -e "$INSTALL_PREFIX/bin/assets" | |
| - name: Generate Linux Coverage | |
| if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| run: | | |
| LCOV_IGNORE="--ignore-errors mismatch,mismatch,gcov,gcov,source,source,inconsistent,inconsistent,format,format,unsupported,unsupported,corrupt,corrupt,unused,unused" | |
| lcov --capture --initial --directory build --output-file coverage_base.info $LCOV_IGNORE | |
| lcov --capture --directory build --output-file coverage_test.info $LCOV_IGNORE | |
| lcov --add-tracefile coverage_base.info --add-tracefile coverage_test.info \ | |
| --output-file coverage.info $LCOV_IGNORE | |
| sed -i 's|/build/../|/|g' coverage.info | |
| sed -i 's|SF:.*/Amplitron/|SF:/home/runner/work/Amplitron/Amplitron/|g' coverage.info | |
| lcov --remove coverage.info \ | |
| '/usr/*' '/Library/*' '/opt/homebrew/*' '*external/*' '*tests/*' '*build/*' '*mingw64/*' '*_temp/*' '*include/c++/*' \ | |
| --output-file coverage.filtered.info $LCOV_IGNORE | |
| lcov --summary coverage.filtered.info $LCOV_IGNORE | tee coverage-summary.txt | |
| - name: Quick Linux Coverage Summary | |
| if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| run: | | |
| LCOV_IGNORE="--ignore-errors unused,unused,inconsistent,inconsistent,format,format,corrupt,corrupt,unsupported,unsupported" | |
| COVERAGE=$(lcov --summary coverage.filtered.info $LCOV_IGNORE 2>&1 | awk '/lines......:/ {print $2}' | sed 's/%//') | |
| echo "Linux line coverage: $COVERAGE%" | |
| echo "### Linux Coverage: ${COVERAGE}%" >> $GITHUB_STEP_SUMMARY | |
| - name: Upload Linux Coverage | |
| if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: linux-coverage | |
| path: coverage.filtered.info | |
| 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 | |
| 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 lcov ninja | |
| - name: Setup External Dependencies | |
| run: | | |
| chmod +x scripts/setup_dependencies.sh | |
| ./scripts/setup_dependencies.sh --no-system-deps | |
| - 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) | |
| if [ "${{ github.event_name }}" = "pull_request" ] || [ "${{ github.ref }}" = "refs/heads/main" ]; then | |
| BUILD_TYPE=Debug | |
| COV_FLAGS="--coverage -O0 -g" | |
| LINK_FLAGS="--coverage" | |
| else | |
| BUILD_TYPE=Release | |
| COV_FLAGS="" | |
| LINK_FLAGS="" | |
| fi | |
| mkdir -p build && cd build | |
| cmake -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ | |
| -DAMPLITRON_VERSION="${{ steps.version.outputs.version }}" \ | |
| -DCMAKE_C_FLAGS="$COV_FLAGS" \ | |
| -DCMAKE_CXX_FLAGS="$COV_FLAGS" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="$LINK_FLAGS" \ | |
| -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" \ | |
| .. | |
| ninja -j$(sysctl -n hw.ncpu) | |
| - name: Run Tests | |
| run: cd build && ./amplitron-tests | |
| - name: Install Smoke Test | |
| env: | |
| INSTALL_PREFIX: ${{ runner.temp }}/amplitron-install | |
| run: | | |
| cmake --install build --prefix "$INSTALL_PREFIX" | |
| test -x "$INSTALL_PREFIX/bin/Amplitron" | |
| "$INSTALL_PREFIX/bin/Amplitron" --version | grep -q "Amplitron v1.0" | |
| - name: Uninstall Smoke Test | |
| env: | |
| INSTALL_PREFIX: ${{ runner.temp }}/amplitron-install | |
| run: | | |
| make PREFIX="$INSTALL_PREFIX" uninstall | |
| test ! -e "$INSTALL_PREFIX/bin/Amplitron" | |
| test ! -e "$INSTALL_PREFIX/share/amplitron" | |
| test ! -e "$INSTALL_PREFIX/bin/assets" | |
| - name: Generate macOS Coverage | |
| if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| run: | | |
| printf '#!/bin/bash\nexec xcrun llvm-cov gcov "$@"\n' > /tmp/llvm-gcov.sh | |
| chmod +x /tmp/llvm-gcov.sh | |
| LCOV_IGNORE="--ignore-errors mismatch,mismatch,gcov,gcov,source,source,inconsistent,inconsistent,format,format,unsupported,unsupported,corrupt,corrupt,unused,unused" | |
| lcov --capture --directory build --output-file coverage.info \ | |
| --gcov-tool /tmp/llvm-gcov.sh $LCOV_IGNORE | |
| sed -i '' 's|/build/../|/|g' coverage.info | |
| sed -i '' 's|SF:.*/Amplitron/|SF:/home/runner/work/Amplitron/Amplitron/|g' coverage.info | |
| lcov --remove coverage.info \ | |
| '/usr/*' '/Library/*' '/opt/homebrew/*' '*external/*' '*tests/*' '*build/*' '*mingw64/*' '*_temp/*' '*include/c++/*' \ | |
| --output-file coverage.filtered.info $LCOV_IGNORE | |
| lcov --summary coverage.filtered.info $LCOV_IGNORE | tee coverage-summary-macos.txt | |
| - name: Upload macOS Coverage | |
| if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: macos-coverage | |
| path: coverage.filtered.info | |
| retention-days: 1 | |
| - 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: | | |
| chmod +x scripts/setup_dependencies.sh | |
| ./scripts/setup_dependencies.sh --no-system-deps | |
| - 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: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: playwright-report | |
| path: tests/web/playwright-report/ | |
| retention-days: 7 | |
| - name: Upload Playwright test results | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: playwright-test-results | |
| path: tests/web/test-results/ | |
| retention-days: 7 | |
| test-windows: | |
| name: Test on Windows | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - 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 lcov | |
| 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: | | |
| chmod +x scripts/setup_dependencies.sh | |
| ./scripts/setup_dependencies.sh --no-system-deps | |
| - name: Generate Version | |
| id: version | |
| shell: bash | |
| run: echo "version=0.1.${{ github.run_number }}" >> $GITHUB_OUTPUT | |
| - name: Build | |
| shell: msys2 {0} | |
| run: | | |
| export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache" | |
| export CCACHE_MAXSIZE=200M | |
| mkdir -p "$CCACHE_DIR" | |
| if [ "${{ github.event_name }}" = "pull_request" ] || [ "${{ github.ref }}" = "refs/heads/main" ]; then | |
| BUILD_TYPE=RelWithDebInfo | |
| COV_FLAGS="--coverage -O2" | |
| LINK_FLAGS="--coverage" | |
| else | |
| BUILD_TYPE=Release | |
| COV_FLAGS="" | |
| LINK_FLAGS="" | |
| fi | |
| mkdir -p build && cd build | |
| cmake -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ | |
| -DAMPLITRON_VERSION="${{ steps.version.outputs.version }}" \ | |
| -DCMAKE_C_FLAGS="$COV_FLAGS" \ | |
| -DCMAKE_CXX_FLAGS="$COV_FLAGS" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="$LINK_FLAGS" \ | |
| -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: Install Smoke Test | |
| shell: msys2 {0} | |
| env: | |
| INSTALL_PREFIX: ${{ runner.temp }}\amplitron-install | |
| run: | | |
| cmake --install build --prefix "$INSTALL_PREFIX" | |
| test -x "$INSTALL_PREFIX/bin/Amplitron.exe" | |
| "$INSTALL_PREFIX/bin/Amplitron.exe" --version | grep -q "Amplitron v1.0" | |
| - name: Uninstall Smoke Test | |
| shell: msys2 {0} | |
| env: | |
| INSTALL_PREFIX: ${{ runner.temp }}\amplitron-install | |
| run: | | |
| rm -f "$INSTALL_PREFIX/bin/Amplitron.exe" | |
| rm -rf "$INSTALL_PREFIX/share/amplitron" | |
| rm -rf "$INSTALL_PREFIX/bin/assets" | |
| test ! -e "$INSTALL_PREFIX/bin/Amplitron.exe" | |
| test ! -e "$INSTALL_PREFIX/share/amplitron" | |
| test ! -e "$INSTALL_PREFIX/bin/assets" | |
| - name: Generate Windows Coverage | |
| if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| shell: msys2 {0} | |
| run: | | |
| LCOV_VER=$(lcov --version 2>&1 | grep -oP '\d+' | head -1) | |
| if [ "$LCOV_VER" -ge 2 ] 2>/dev/null; then | |
| LCOV_IGNORE="--ignore-errors gcov,gcov,source,source,inconsistent,inconsistent,format,format,unsupported,unsupported,corrupt,corrupt,unused,unused" | |
| else | |
| LCOV_IGNORE="" | |
| fi | |
| lcov --capture \ | |
| --directory build/CMakeFiles/amplitron_core.dir \ | |
| --directory build/CMakeFiles/Amplitron.dir \ | |
| --directory build/CMakeFiles/amplitron-tests.dir \ | |
| --output-file coverage.info $LCOV_IGNORE 2>&1 | tail -20 | |
| sed -i 's|\\|/|g' coverage.info | |
| sed -i 's|/build/../|/|g' coverage.info | |
| sed -i 's|SF:.*/Amplitron/|SF:/home/runner/work/Amplitron/Amplitron/|g' coverage.info | |
| lcov --remove coverage.info \ | |
| '/usr/*' '/Library/*' '/opt/homebrew/*' '*external/*' '*tests/*' '*build/*' '*mingw64/*' '*_temp/*' '*include/c++/*' \ | |
| --output-file coverage.filtered.info $LCOV_IGNORE 2>&1 | tail -5 | |
| lcov --summary coverage.filtered.info $LCOV_IGNORE | tee coverage-summary-windows.txt | |
| - name: Upload Windows Coverage | |
| if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: windows-coverage | |
| path: coverage.filtered.info | |
| retention-days: 1 | |
| - 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: | | |
| chmod +x scripts/setup_dependencies.sh | |
| ./scripts/setup_dependencies.sh --no-system-deps | |
| - 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: | | |
| chmod +x scripts/setup_dependencies.sh | |
| ./scripts/setup_dependencies.sh --no-system-deps | |
| - 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_INCLUDE_DIRS=$HOME/sdl2-ios/include/SDL2 \ | |
| -DSDL2_LIBRARIES="$HOME/sdl2-ios/lib/libSDL2main.a;$HOME/sdl2-ios/lib/libSDL2.a" \ | |
| -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 | |
| merge-coverage: | |
| name: Merge Cross-Platform Coverage | |
| needs: [test-linux, test-macos, test-windows] | |
| if: ${{ !cancelled() && (github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main')) }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install lcov | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -y --no-install-recommends lcov | |
| - name: Download Linux Coverage | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: linux-coverage | |
| path: coverage-linux/ | |
| - name: Download macOS Coverage | |
| uses: actions/download-artifact@v8 | |
| continue-on-error: true | |
| id: macos-dl | |
| with: | |
| name: macos-coverage | |
| path: coverage-macos/ | |
| - name: Download Windows Coverage | |
| uses: actions/download-artifact@v8 | |
| continue-on-error: true | |
| id: windows-dl | |
| with: | |
| name: windows-coverage | |
| path: coverage-windows/ | |
| - name: Merge Coverage Reports | |
| run: | | |
| MERGE_CMD="lcov" | |
| MERGE_CMD="$MERGE_CMD --add-tracefile coverage-linux/coverage.filtered.info" | |
| PLATFORMS="Linux" | |
| if [ -f coverage-macos/coverage.filtered.info ]; then | |
| MERGE_CMD="$MERGE_CMD --add-tracefile coverage-macos/coverage.filtered.info" | |
| PLATFORMS="$PLATFORMS + macOS" | |
| fi | |
| if [ -f coverage-windows/coverage.filtered.info ]; then | |
| MERGE_CMD="$MERGE_CMD --add-tracefile coverage-windows/coverage.filtered.info" | |
| PLATFORMS="$PLATFORMS + Windows" | |
| fi | |
| LCOV_IGNORE="--ignore-errors unused,unused,inconsistent,inconsistent,format,format,corrupt,corrupt,unsupported,unsupported,source,source,mismatch,mismatch,gcov,gcov" | |
| GENHTML_IGNORE="--ignore-errors unused,unused,inconsistent,inconsistent,format,format,corrupt,corrupt,unsupported,unsupported,source,source,category,category" | |
| $MERGE_CMD --output-file merged.info $LCOV_IGNORE | |
| echo "PLATFORMS=$PLATFORMS" >> $GITHUB_ENV | |
| genhtml merged.info --output-directory coverage-report $GENHTML_IGNORE --synthesize-missing --prefix $GITHUB_WORKSPACE | |
| lcov --summary merged.info $LCOV_IGNORE | tee merged-summary.txt | |
| - name: Generate Merged Coverage Comment | |
| run: | | |
| LCOV_IGNORE="--ignore-errors unused,unused,inconsistent,inconsistent,format,format,corrupt,corrupt,unsupported,unsupported,source,source,mismatch,mismatch,gcov,gcov" | |
| COVERAGE=$(lcov --summary merged.info $LCOV_IGNORE 2>&1 | awk '/lines......:/ {print $2}' | sed 's/%//') | |
| echo "Merged line coverage: $COVERAGE%" | |
| THRESHOLD=60 | |
| echo "### 🌍 Cross-Platform Coverage Report" > coverage_comment.md | |
| echo "**Platforms:** ${{ env.PLATFORMS }}" >> coverage_comment.md | |
| echo "**Merged Line Coverage:** ${COVERAGE}%" >> coverage_comment.md | |
| echo "" >> coverage_comment.md | |
| if awk "BEGIN {exit !($COVERAGE >= $THRESHOLD)}"; then | |
| echo "✅ Coverage meets threshold: $COVERAGE% >= $THRESHOLD%" >> coverage_comment.md | |
| else | |
| echo "⚠️ Coverage is below threshold: $COVERAGE% < $THRESHOLD%" >> coverage_comment.md | |
| fi | |
| echo "" >> coverage_comment.md | |
| echo "<details>" >> coverage_comment.md | |
| echo "<summary>Full Merged Coverage Summary</summary>" >> coverage_comment.md | |
| echo "" >> coverage_comment.md | |
| echo '```text' >> coverage_comment.md | |
| cat merged-summary.txt >> coverage_comment.md | |
| echo '```' >> coverage_comment.md | |
| echo "</details>" >> coverage_comment.md | |
| cat coverage_comment.md >> $GITHUB_STEP_SUMMARY | |
| - name: Upload Merged Coverage HTML Report | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-report | |
| path: coverage-report/ | |
| retention-days: 7 | |
| - name: Upload Merged Coverage Info | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: merged-coverage-summary | |
| path: | | |
| merged.info | |
| merged-summary.txt | |
| retention-days: 7 | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| files: merged.info | |
| flags: cross-platform | |
| name: cross-platform-coverage | |
| fail_ci_if_error: true | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} |