name: Desktop Smoke Test on: workflow_dispatch: pull_request: paths: - 'desktopApp/**' - '.github/workflows/smoke-test-desktop.yml' permissions: contents: read concurrency: group: smoke-desktop-${{ github.ref }} cancel-in-progress: true jobs: # ------------------------------------------------------------------------- # 1) Compose UI test — verifies the composable tree renders (login screen) # under the dev classpath. Catches missing string resources, broken # composables, and basic dependency-graph issues. # ------------------------------------------------------------------------- compose-ui-test: runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout code uses: actions/checkout@v6 - name: Set up JDK 21 uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 21 - name: Set up Gradle uses: gradle/actions/setup-gradle@v6 with: cache-read-only: true - name: Install xvfb run: sudo apt-get update && sudo apt-get install -y xvfb - name: Run desktop tests (including UI smoke test) run: xvfb-run --auto-servernum ./gradlew :desktopApp:test # ------------------------------------------------------------------------- # 2) Release .deb build + launch — builds the ProGuard'd, jlink'd .deb # package, installs it, and verifies the process stays alive for 10s. # Catches ProGuard stripping (JNI, reflection), missing jlink modules # (java.management, java.prefs), and native lib bundling issues. # ------------------------------------------------------------------------- release-deb-launch: runs-on: ubuntu-latest timeout-minutes: 45 steps: - name: Checkout code uses: actions/checkout@v6 - name: Set up JDK 21 uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 21 - name: Set up Gradle uses: gradle/actions/setup-gradle@v6 with: cache-read-only: true - name: Install xvfb + packaging deps run: sudo apt-get update && sudo apt-get install -y xvfb fakeroot - name: Build release .deb uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0 with: max_attempts: 2 timeout_minutes: 20 command: ./gradlew --no-daemon :desktopApp:packageReleaseDeb - name: Relax libicu dependency run: | set -euo pipefail chmod +x scripts/relax-deb-libicu.sh scripts/relax-deb-libicu.sh desktopApp/build/compose/binaries/main-release/deb/*.deb - name: Install .deb run: | # jpackage's post-install script runs xdg-desktop-menu which fails # on CI runners ("No writable system menu directory"). The files are # extracted successfully; only the menu registration fails. Allow the # dpkg error, then verify the binary was actually installed. sudo dpkg -i desktopApp/build/compose/binaries/main-release/deb/*.deb || true echo "Installed files:" dpkg -L amethyst | head -30 # Fail if the binary wasn't actually extracted test -d /opt/amethyst || test -d /opt/Amethyst || { echo "FAIL: /opt/amethyst not found after dpkg -i" exit 1 } - name: Smoke test — app launches and stays alive run: | set -euo pipefail # Find the launcher binary LAUNCHER=$(find /opt -name "Amethyst" -type f -executable 2>/dev/null | head -1) if [[ -z "$LAUNCHER" ]]; then # Fallback: search dpkg file list LAUNCHER=$(dpkg -L amethyst | grep -E '/bin/[Aa]methyst$' | head -1) fi if [[ -z "$LAUNCHER" ]]; then echo "FAIL: could not find Amethyst launcher binary" dpkg -L amethyst exit 1 fi echo "Launcher: $LAUNCHER" # Launch under xvfb with a timeout safety net xvfb-run --auto-servernum timeout 30 "$LAUNCHER" & APP_PID=$! echo "PID: $APP_PID" # Wait 10s — if the process is still alive, the app launched successfully sleep 10 if kill -0 "$APP_PID" 2>/dev/null; then echo "PASS: Application launched and stayed alive for 10s" kill "$APP_PID" || true wait "$APP_PID" 2>/dev/null || true else wait "$APP_PID" 2>/dev/null EXIT_CODE=$? echo "FAIL: Application exited with code $EXIT_CODE within 10s" exit 1 fi - name: Upload .deb artifact (for manual testing) if: always() uses: actions/upload-artifact@v7 with: name: Release DEB (smoke-tested) path: desktopApp/build/compose/binaries/main-release/deb/*.deb