Plezy consumed mpv through four unrelated supply chains: an MPVKit fork via SwiftPM for the Apple platforms, a libmpv-android fork's AAR for Android, an in-CI from-source build for Linux, and an unpinned sourceforge mpv-dev 7z for Windows. All four now consume the same per-commit, content-addressed binaries from https://github.com/edde746/mpv-build, pinned to one commit and built from one set of pinned sources (mpv v0.41.0 on Apple/Android/Windows, ffmpeg n8.0.1, our libass fork). - Apple: the SwiftPM package moves from edde746/MPVKit to edde746/mpv-build across the ios/macos/tvos projects; scripts/set_mpvkit_revision.sh becomes set_native_revision.sh, writes every pin site plus the new repo-root mpv-build.lock.json, and tvos/scripts/wire_mpv.rb derives the package repo from the locks. - Android: the mpv Kotlin API and JNI glue move in-app under android/libmpv (repackaged com.edde746.plezy.libmpv, exports renamed, shrinker rules covered), and the module downloads per-ABI native tarballs (lib/*.so incl. libc++_shared.so + include/) driven entirely by mpv-build.lock.json, with a PLEZY_LOCAL_MPV_DIR escape hatch for locally built artifacts. The fork AAR and its Maven coordinates are gone. - Linux: CI downloads the prebuilt self-relocating libmpv prefix (lock-driven, sha256-verified) instead of compiling mpv/ffmpeg/dav1d/ libplacebo/shaderc from source; linux/packaging/build-libmpv.sh and its test are deleted and native-inputs.json shrinks to the simdutf entry the CMake builds still fetch. - Windows: both arches FetchContent the mpv-build dev zips with URL_HASH enforcement, replacing the checksum-less sourceforge download and its ARM64 7-Zip special case; guard scripts updated. The lock plus the Apple pin sites all point at mpv-build commit d7c3d559, whose manifest was verified asset-by-asset against the published release digests (17/17 match). Verified locally: wire and pin-script suites green, runtime-input checks green, all four Android ABI tarballs downloaded/verified/extracted through the real Gradle tasks, the Windows FetchContent block exercised end to end through cmake, the Linux asset hash and layout checked against the workflow contract, and xcodebuild resolved the flipped SwiftPM graph with SwiftPM validating every binary checksum.
788 lines
29 KiB
YAML
788 lines
29 KiB
YAML
name: CI - Sanity Checks
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
# Keep untrusted code on the read-only pull_request event. Never use pull_request_target here.
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
workflow_dispatch:
|
|
inputs:
|
|
build_linux_packages:
|
|
description: >
|
|
Smoke-build the Linux deb/rpm/pacman packages. Off by default: it needs
|
|
a release build plus fpm, and build.yml only packages from main, so this
|
|
is the only way to exercise linux/packaging from a branch.
|
|
default: false
|
|
type: boolean
|
|
|
|
env:
|
|
# Only place this workflow names the SDK; .github/actions/setup-flutter-git pins the same release.
|
|
FLUTTER_VERSION: "3.47.1"
|
|
|
|
jobs:
|
|
analyze:
|
|
name: Code Analysis
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
pub-cache: false
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.pub-cache
|
|
key: ${{ runner.os }}-pub-v3-${{ hashFiles('**/pubspec.yaml', '**/pubspec.lock') }}
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
|
|
flutter pub get
|
|
|
|
- name: Install wakelock_plus development dependencies
|
|
working-directory: packages/wakelock_plus
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
- name: Verify generated files committed
|
|
run: scripts/codegen.sh --check
|
|
|
|
- name: Verify translation hygiene
|
|
run: python3 scripts/checks/clean_translations.py --check --strict
|
|
|
|
- name: Verify workflow and script guards
|
|
run: bash scripts/ci_guard_checks.sh
|
|
|
|
- name: Verify formatting
|
|
run: |
|
|
paths=(lib)
|
|
[ ! -d test ] || paths+=(test)
|
|
find "${paths[@]}" -name "*.dart" ! -name "*.g.dart" ! -name "*.freezed.dart" -type f -print0 |
|
|
xargs -0 -r dart format --output=none --set-exit-if-changed
|
|
|
|
- name: Verify icon consistency
|
|
run: dart run scripts/checks/check_icon_consistency.dart
|
|
|
|
- name: Analyze code
|
|
run: dart run scripts/checks/check_analyzer.dart
|
|
|
|
- name: Check for unused code
|
|
run: |
|
|
echo "🔍 Checking for unused code..."
|
|
dart run dart_code_linter:metrics check-unused-code lib 2>&1 | tee unused_code.txt
|
|
if grep -qi "no unused code found" unused_code.txt; then
|
|
echo "✅ No unused code found"
|
|
else
|
|
echo "❌ Found unused code:"
|
|
cat unused_code.txt
|
|
exit 1
|
|
fi
|
|
|
|
- name: Check for unused files
|
|
run: |
|
|
echo "🔍 Checking for unused files..."
|
|
dart run dart_code_linter:metrics check-unused-files lib 2>&1 | tee unused_files.txt
|
|
if grep -qi "no unused files found" unused_files.txt; then
|
|
echo "✅ No unused files found"
|
|
else
|
|
echo "❌ Found unused files:"
|
|
cat unused_files.txt
|
|
exit 1
|
|
fi
|
|
|
|
test:
|
|
name: Unit Tests
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
pub-cache: false
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.pub-cache
|
|
key: ${{ runner.os }}-pub-v3-${{ hashFiles('**/pubspec.yaml', '**/pubspec.lock') }}
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
flutter clean
|
|
flutter pub get
|
|
|
|
- name: Run tests
|
|
run: |
|
|
if [ -d "test" ] && [ "$(find test -name '*_test.dart' | wc -l)" -gt 0 ]; then
|
|
scripts/run_tests.sh
|
|
else
|
|
echo "No tests found, skipping test execution"
|
|
fi
|
|
|
|
- name: Install wakelock_plus test dependencies
|
|
working-directory: packages/wakelock_plus
|
|
run: flutter pub get --enforce-lockfile
|
|
|
|
- name: Run wakelock_plus VM tests
|
|
working-directory: packages/wakelock_plus
|
|
run: flutter test test/wakelock_plus_linux_plugin_test.dart
|
|
|
|
- name: Run wakelock_plus Chrome tests
|
|
working-directory: packages/wakelock_plus
|
|
run: flutter test --platform chrome --dart-define=WEB_PLUGIN_TESTS=true test/wakelock_plus_web_plugin_test.dart
|
|
|
|
# The vendored atomic-write patch has to keep the upstream contract, not
|
|
# just the new behaviour. Upstream's own suites are the check for that.
|
|
- name: Run the vendored desktop preference store tests
|
|
run: |
|
|
for pkg in shared_preferences_linux shared_preferences_windows; do
|
|
(cd "packages/$pkg" && flutter pub get --enforce-lockfile && flutter test)
|
|
done
|
|
|
|
android-test:
|
|
name: Android JVM and Native Tests
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Java
|
|
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
|
|
with:
|
|
distribution: "temurin"
|
|
java-version: "21"
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
pub-cache: false
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.pub-cache
|
|
key: ${{ runner.os }}-pub-v3-${{ hashFiles('**/pubspec.yaml', '**/pubspec.lock') }}
|
|
|
|
- name: Cache Gradle
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.gradle/caches
|
|
~/.gradle/wrapper
|
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-gradle-
|
|
|
|
- name: Install dependencies
|
|
run: flutter pub get
|
|
|
|
- name: Configure Android local properties
|
|
run: printf 'flutter.sdk=%s\nsdk.dir=%s\n' "$FLUTTER_ROOT" "$ANDROID_HOME" > android/local.properties
|
|
|
|
- name: Configure Android host native tests
|
|
run: |
|
|
cmake -S android/app/src/test/cpp -B build/android-host-tests \
|
|
-DCMAKE_BUILD_TYPE=Debug
|
|
|
|
- name: Build Android host native tests
|
|
run: cmake --build build/android-host-tests --parallel 2
|
|
|
|
- name: Run Android host native tests
|
|
run: |
|
|
ctest --test-dir build/android-host-tests \
|
|
--output-on-failure --no-tests=error
|
|
|
|
- name: Run Android JVM unit tests
|
|
working-directory: android
|
|
run: ./gradlew :app:testDebugUnitTest :saf_util:testDebugUnitTest :libass:testDebugUnitTest -x :app:compileFlutterBuildDebug --continue
|
|
|
|
- name: Check Android API compatibility
|
|
working-directory: android
|
|
run: ./gradlew :app:lintDebug
|
|
|
|
native-format:
|
|
name: Native Formatting
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Java
|
|
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
|
|
with:
|
|
distribution: "temurin"
|
|
java-version: "17"
|
|
|
|
- name: Verify native formatting
|
|
run: scripts/format_native.sh --check
|
|
|
|
linux-native-test:
|
|
name: Linux native reliability (${{ matrix.sanitizer }})
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- sanitizer: address
|
|
lifecycle_sanitizers: ON
|
|
- sanitizer: thread
|
|
lifecycle_sanitizers: OFF
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
pub-cache: false
|
|
|
|
- name: Install Linux native test dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends \
|
|
clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev \
|
|
libstdc++-12-dev libmpv-dev libepoxy-dev libcurl4-openssl-dev libevdev-dev \
|
|
libwayland-dev libegl-dev
|
|
|
|
- name: Prepare Flutter Linux configuration
|
|
run: |
|
|
flutter pub get --enforce-lockfile --no-example
|
|
flutter build linux --debug --config-only --no-pub
|
|
|
|
- name: Configure Linux native reliability tests
|
|
run: |
|
|
cmake -S linux -B build/linux-native-${{ matrix.sanitizer }} -G Ninja \
|
|
-DCMAKE_BUILD_TYPE=Debug \
|
|
-DPLEZY_BUILD_MPV_PLAYER_LIFECYCLE_TESTS=ON \
|
|
-DPLEZY_MPV_LIFECYCLE_SANITIZERS=${{ matrix.lifecycle_sanitizers }} \
|
|
-DPLEZY_BUILD_MPV_RELIABILITY_TESTS=ON \
|
|
-DPLEZY_MPV_RELIABILITY_SANITIZER=${{ matrix.sanitizer }}
|
|
|
|
# `plezy` is the runner itself. Without it nothing in CI ever compiles
|
|
# my_application.cc, mpv_plugin.cc or the Wayland video plane — the
|
|
# reliability test targets each pull in only a couple of translation units,
|
|
# so a break in the rest of linux/runner reached a release build unseen.
|
|
- name: Build Linux native reliability tests
|
|
run: |
|
|
cmake --build build/linux-native-${{ matrix.sanitizer }} --parallel 2 --target \
|
|
plezy \
|
|
mpv_player_lifecycle_test \
|
|
mpv_player_hdr_output_test \
|
|
mpv_property_result_contract_test \
|
|
hdr_metadata_test \
|
|
plane_geometry_test \
|
|
video_params_test \
|
|
plane_render_executor_test
|
|
|
|
- name: Run Linux native reliability tests
|
|
run: |
|
|
ctest --test-dir build/linux-native-${{ matrix.sanitizer }} \
|
|
--output-on-failure --no-tests=error
|
|
|
|
apple-native-test:
|
|
name: Apple native reliability (${{ matrix.platform }})
|
|
runs-on: macos-26
|
|
permissions:
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- platform: iOS
|
|
project_directory: ios
|
|
workspace: ios/Runner.xcworkspace
|
|
simulator_runtime: iOS
|
|
simulator_platform: iOS
|
|
static_destination: ""
|
|
- platform: macOS
|
|
project_directory: macos
|
|
workspace: macos/Runner.xcworkspace
|
|
simulator_runtime: ""
|
|
simulator_platform: ""
|
|
static_destination: platform=macOS
|
|
- platform: tvOS
|
|
project_directory: tvos
|
|
workspace: tvos/Runner.xcworkspace
|
|
simulator_runtime: tvOS
|
|
simulator_platform: tvOS
|
|
static_destination: ""
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
pub-cache: false
|
|
|
|
- name: Install locked Dart dependencies
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
- name: Record committed CocoaPods lockfile
|
|
if: matrix.platform != 'tvOS'
|
|
env:
|
|
PODFILE_LOCK: ${{ matrix.project_directory }}/Podfile.lock
|
|
run: |
|
|
test -f "$PODFILE_LOCK"
|
|
shasum -a 256 "$PODFILE_LOCK" > "$RUNNER_TEMP/plezy-podfile-lock.sha256"
|
|
|
|
- name: Prepare iOS Flutter build settings
|
|
if: matrix.platform == 'iOS'
|
|
run: flutter build ios --config-only --simulator --debug --no-pub
|
|
|
|
- name: Prepare macOS Flutter build settings
|
|
if: matrix.platform == 'macOS'
|
|
run: flutter build macos --config-only --debug --no-pub
|
|
|
|
- name: Prepare tvOS Flutter engine
|
|
if: matrix.platform == 'tvOS'
|
|
run: tvos/scripts/fetch_engine.sh
|
|
|
|
- name: Verify Flutter configuration preserved CocoaPods lockfile
|
|
if: matrix.platform != 'tvOS'
|
|
run: shasum -a 256 --check "$RUNNER_TEMP/plezy-podfile-lock.sha256"
|
|
|
|
- name: Install locked CocoaPods dependencies
|
|
if: matrix.platform != 'tvOS'
|
|
working-directory: ${{ matrix.project_directory }}
|
|
run: pod install --deployment
|
|
|
|
- name: Install tvOS CocoaPods dependencies
|
|
if: matrix.platform == 'tvOS'
|
|
run: tvos/scripts/pod_install.sh
|
|
|
|
- name: Verify tvOS project wiring
|
|
if: matrix.platform == 'tvOS'
|
|
run: ruby tvos/scripts/test_wire_mpv.rb
|
|
|
|
- name: Select Apple test destination
|
|
env:
|
|
SIMULATOR_RUNTIME: ${{ matrix.simulator_runtime }}
|
|
SIMULATOR_PLATFORM: ${{ matrix.simulator_platform }}
|
|
STATIC_DESTINATION: ${{ matrix.static_destination }}
|
|
run: |
|
|
python3 - <<'PY'
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
destination = os.environ["STATIC_DESTINATION"]
|
|
if not destination:
|
|
runtime_name = os.environ["SIMULATOR_RUNTIME"]
|
|
payload = json.loads(
|
|
subprocess.check_output(
|
|
["xcrun", "simctl", "list", "devices", "available", "-j"],
|
|
text=True,
|
|
)
|
|
)
|
|
devices = [
|
|
device
|
|
for runtime, candidates in payload["devices"].items()
|
|
if f".{runtime_name}-" in runtime
|
|
for device in candidates
|
|
if device.get("isAvailable", False)
|
|
]
|
|
if not devices:
|
|
raise SystemExit(f"no available {runtime_name} simulator")
|
|
destination = (
|
|
f"platform={os.environ['SIMULATOR_PLATFORM']} Simulator,"
|
|
f"id={devices[0]['udid']}"
|
|
)
|
|
with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as output:
|
|
output.write(f"APPLE_TEST_DESTINATION={destination}\n")
|
|
PY
|
|
|
|
- name: Run Apple native reliability tests
|
|
run: |
|
|
xcodebuild test \
|
|
-workspace "${{ matrix.workspace }}" \
|
|
-scheme Runner \
|
|
-configuration Debug \
|
|
-destination "$APPLE_TEST_DESTINATION" \
|
|
-disableAutomaticPackageResolution \
|
|
CODE_SIGNING_ALLOWED=NO \
|
|
COMPILER_INDEX_STORE_ENABLE=NO
|
|
|
|
windows-native-test:
|
|
name: Windows native reliability (${{ matrix.arch }})
|
|
runs-on: ${{ matrix.runner }}
|
|
permissions:
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- arch: x64
|
|
runner: windows-latest
|
|
flutter_setup: action
|
|
- arch: arm64
|
|
runner: windows-11-arm
|
|
flutter_setup: git
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Install 7-Zip
|
|
if: matrix.arch == 'arm64'
|
|
shell: pwsh
|
|
run: choco install 7zip -y
|
|
|
|
- name: Setup Flutter
|
|
if: matrix.flutter_setup == 'action'
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
pub-cache: false
|
|
|
|
- name: Set up Flutter from its pinned commit
|
|
if: matrix.flutter_setup == 'git'
|
|
uses: ./.github/actions/setup-flutter-git
|
|
|
|
- name: Install locked Dart dependencies
|
|
shell: pwsh
|
|
run: flutter pub get --enforce-lockfile --no-example
|
|
|
|
# Windows replacement semantics (`MoveFileExW` with
|
|
# MOVEFILE_REPLACE_EXISTING) cannot be proven on the POSIX runners, and a
|
|
# memory file system proves nothing about either. The vendored
|
|
# shared_preferences_windows store write is the fix for #1732, so exercise
|
|
# it here, on a real NTFS volume, against the real backend.
|
|
- name: Run the vendored Windows preference store tests
|
|
shell: pwsh
|
|
run: flutter test test/services/prefs_store_atomic_write_windows_test.dart
|
|
|
|
- name: Install patched Flutter engine
|
|
shell: pwsh
|
|
run: |
|
|
flutter precache --windows
|
|
.\windows\tool\install-patched-engine.ps1
|
|
|
|
- name: Prepare Flutter Windows configuration
|
|
shell: pwsh
|
|
run: flutter build windows --debug --config-only --no-pub
|
|
|
|
- name: Configure Windows native reliability tests
|
|
shell: pwsh
|
|
run: |
|
|
$buildDir = "build/windows/${{ matrix.arch }}"
|
|
cmake -S windows -B $buildDir `
|
|
-DPLEZY_BUILD_MPV_PROPERTY_CONTRACT_TESTS=ON `
|
|
-DPLEZY_BUILD_DISPLAY_RECOVERY_TESTS=ON
|
|
|
|
- name: Build Windows native reliability tests
|
|
shell: pwsh
|
|
run: |
|
|
$buildDir = "build/windows/${{ matrix.arch }}"
|
|
cmake --build $buildDir --config Debug --parallel 2 --target `
|
|
mpv_property_result_contract_test `
|
|
mpv_player_property_contract_test `
|
|
display_mode_manager_test
|
|
|
|
- name: Run Windows native reliability tests
|
|
shell: pwsh
|
|
run: |
|
|
$buildDir = "build/windows/${{ matrix.arch }}"
|
|
ctest --test-dir "$buildDir/runner" -C Debug --output-on-failure --no-tests=error
|
|
|
|
dependency-check:
|
|
name: Dependency Validation
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
pub-cache: false
|
|
|
|
- name: Cache Pub dependencies
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: |
|
|
~/.pub-cache
|
|
key: ${{ runner.os }}-pub-v3-${{ hashFiles('**/pubspec.yaml', '**/pubspec.lock') }}
|
|
|
|
- name: Verify dependencies
|
|
run: |
|
|
flutter clean
|
|
flutter pub get
|
|
flutter pub outdated
|
|
|
|
server:
|
|
name: Server checks
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Go
|
|
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
|
with:
|
|
go-version-file: server/go.mod
|
|
cache-dependency-path: server/go.sum
|
|
|
|
- name: Run server checks
|
|
run: scripts/ci_server_checks.sh
|
|
|
|
|
|
website:
|
|
name: Website checks
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Bun
|
|
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
|
with:
|
|
bun-version: "1.3.14"
|
|
|
|
- name: Run website checks
|
|
run: scripts/ci_website_checks.sh
|
|
|
|
|
|
# The only job that checks packaging against a real artifact. build.yml also
|
|
# packages Linux, but refuses any ref but refs/heads/main, and
|
|
# check_linux_package_deps.py can only compare a hand-written list against
|
|
# CMake - it cannot prove the list reaches the artifact, nor see the
|
|
# transitive libraries the bundled libmpv drags in. This can, by reading the
|
|
# built bundle back with ldd.
|
|
#
|
|
# Runs on every push to main and on request, but not on pull requests: it
|
|
# needs a release build plus fpm, which is minutes of runner time that most
|
|
# changes here have no reason to pay. That buys post-merge detection rather
|
|
# than pre-merge, which is the deliberate trade. Dispatch it from a branch
|
|
# with build_linux_packages when touching linux/packaging - which is the only
|
|
# way to exercise it before merging.
|
|
linux-packages:
|
|
name: Linux package smoke build
|
|
if: ${{ inputs.build_linux_packages || github.event_name == 'push' }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Setup Flutter
|
|
uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2
|
|
with:
|
|
channel: "stable"
|
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
|
cache: true
|
|
pub-cache: false
|
|
|
|
# The packaging deps, minus libmpv: that arrives prebuilt from mpv-build
|
|
# below. The dev packages still matter — they install the runtime
|
|
# libraries the pinned libmpv links (ass, pulse, pipewire, ...), which
|
|
# bundle-libs.sh resolves off the host into the bundle.
|
|
- name: Install packaging dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends \
|
|
clang cmake meson ninja-build pkg-config nasm libgtk-3-dev liblzma-dev \
|
|
libstdc++-12-dev libepoxy-dev libcurl4-openssl-dev libevdev-dev \
|
|
libasound2-dev libass-dev libfreetype-dev libfontconfig-dev libfribidi-dev \
|
|
libharfbuzz-dev libegl-dev libgl-dev libgnutls28-dev libpipewire-0.3-dev \
|
|
libva-dev libxkbcommon-dev libpulse-dev libdbus-1-dev libdrm-dev \
|
|
libdisplay-info-dev libgbm-dev libwayland-dev wayland-protocols liblcms2-dev libmujs-dev \
|
|
liblua5.2-dev rpm libarchive-tools imagemagick ruby-dev build-essential
|
|
sudo gem install fpm --version 1.17.0 --no-document
|
|
|
|
# Keyed the same way build.yml keys it: the lock names the asset and its
|
|
# checksum, so editing the lock is what invalidates the cache.
|
|
- name: Cache libmpv prefix
|
|
id: libmpv-cache
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
|
|
with:
|
|
path: libmpv-prefix
|
|
key: ci-libmpv-${{ runner.arch }}-${{ hashFiles('mpv-build.lock.json') }}
|
|
|
|
# Same contract as build.yml: read mpv-build.lock.json, download the
|
|
# linux asset for this arch, verify its SHA-256, extract the prefix tree.
|
|
- name: Fetch libmpv
|
|
if: steps.libmpv-cache.outputs.cache-hit != 'true'
|
|
run: |
|
|
command -v zstd >/dev/null 2>&1 || { sudo apt-get update && sudo apt-get install -y --no-install-recommends zstd; }
|
|
python3 - <<'PY'
|
|
import hashlib
|
|
import json
|
|
import platform
|
|
import subprocess
|
|
import tempfile
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
lock = json.loads(Path("mpv-build.lock.json").read_text(encoding="utf-8"))
|
|
group = lock["artifacts"]["linux"]
|
|
entry = group["assets"][platform.machine()]
|
|
url = f"{group['assetBase']}/{entry['asset']}"
|
|
print(f"fetching {url}", flush=True)
|
|
with urllib.request.urlopen(url) as response:
|
|
data = response.read()
|
|
digest = hashlib.sha256(data).hexdigest()
|
|
if digest != entry["checksum"]:
|
|
raise SystemExit(f"{entry['asset']}: SHA-256 {digest} does not match locked {entry['checksum']}")
|
|
Path("libmpv-prefix").mkdir(exist_ok=True)
|
|
with tempfile.NamedTemporaryFile(suffix=".tar.zst") as archive:
|
|
archive.write(data)
|
|
archive.flush()
|
|
subprocess.run(["tar", "--zstd", "-xf", archive.name, "-C", "libmpv-prefix"], check=True)
|
|
PY
|
|
|
|
# The windowing backends the runner depends on, read off the pinned
|
|
# library just extracted. The plane hands mpv MPV_RENDER_PARAM_WL_DISPLAY,
|
|
# so a libmpv without Wayland cannot find the VAAPI device and quietly
|
|
# decodes in software; X11 and VDPAU are gone with the texture path.
|
|
- name: Check the pinned libmpv's backends
|
|
run: |
|
|
LIB=$(find libmpv-prefix -name 'libmpv.so.2' | head -1)
|
|
echo "== $LIB =="
|
|
ldd "$LIB" | grep -iE 'wayland|libX11|vdpau' || echo '(none)'
|
|
ldd "$LIB" | grep -q libwayland-client || {
|
|
echo "::error::the built libmpv does not link libwayland-client, so the video plane cannot work"
|
|
exit 1
|
|
}
|
|
|
|
- name: Build the release bundle
|
|
run: |
|
|
flutter pub get --enforce-lockfile --no-example
|
|
flutter build linux --release
|
|
env:
|
|
PKG_CONFIG_PATH: ${{ github.workspace }}/libmpv-prefix/lib/pkgconfig:${{ github.workspace }}/libmpv-prefix/lib/x86_64-linux-gnu/pkgconfig
|
|
|
|
# Mirrors build.yml: resolve the bundle completely, then package from it.
|
|
# libmpv travels with us, so nothing depends on a host one - which also
|
|
# removes the transitive pull of everything libmpv links, hence bundle-libs
|
|
# before packaging rather than after.
|
|
- name: Copy libmpv into the bundle
|
|
run: |
|
|
BUNDLE_LIB=build/linux/x64/release/bundle/lib
|
|
LIBMPV_DIR=$(dirname "$(find libmpv-prefix -name 'libmpv.so' | head -1)")
|
|
cp -a "$LIBMPV_DIR"/libmpv.so* "$BUNDLE_LIB/"
|
|
cp -a libmpv-prefix/lib/libshaderc_shared.so* "$BUNDLE_LIB/"
|
|
|
|
- name: Bundle shared libraries
|
|
run: bash linux/packaging/bundle-libs.sh build/linux/x64/release/bundle
|
|
|
|
- name: Copy wrapper script into the bundle
|
|
run: cp linux/packaging/plezy.sh build/linux/x64/release/bundle/plezy.sh
|
|
|
|
# Derives what the resolved bundle still needs from the host and proves
|
|
# every one of those libraries is declared. This is the check that would
|
|
# have caught bundling libmpv without also declaring what libmpv links.
|
|
- name: Verify every unbundled library the bundle needs is declared
|
|
run: python3 linux/packaging/check-bundle-host-deps.py build/linux/x64/release/bundle
|
|
|
|
# OUTPUT_DIR defaults to the repo root; name it so the paths below are not
|
|
# a guess about where fpm dropped things. The host-dependency guard is
|
|
# skipped because the named step above just ran it against this same
|
|
# bundle; the internal run exists for by-hand packaging outside CI.
|
|
- name: Build the packages
|
|
run: |
|
|
mkdir -p "$OUTPUT_DIR"
|
|
python3 linux/packaging/build-packages.py
|
|
env:
|
|
OUTPUT_DIR: ${{ github.workspace }}/packages
|
|
PLEZY_SKIP_HOST_DEP_CHECK: "1"
|
|
|
|
# The guard above reconciles the depends lists with the staged bundle; only
|
|
# the packages themselves can show that list survived fpm. Every name comes
|
|
# from build-packages.py, so adding a library there is verified here without
|
|
# a second edit - and this job is off by default, so a hand-copied list
|
|
# would rot unseen. The release job in build.yml runs the same script
|
|
# against the artifacts users install, so the assertions cannot drift.
|
|
- name: Verify the declared dependencies reached the package metadata
|
|
run: python3 linux/packaging/check-package-deps.py "${{ github.workspace }}/packages"
|
|
|
|
# Same resolved bundle the packages were cut from, so the tarball is not a
|
|
# second, differently-assembled artifact. It is the one to put on a USB for
|
|
# a foreign machine, because it needs nothing installed.
|
|
- name: Create the tarball
|
|
run: |
|
|
BUNDLE_DIR=build/linux/x64/release/bundle
|
|
mkdir -p "$OUTPUT_DIR"
|
|
tar -czf "$OUTPUT_DIR/plezy-linux-x64.tar.gz" -C "$BUNDLE_DIR" .
|
|
echo "=== libmpv travelling in every artifact ==="
|
|
ldd "$BUNDLE_DIR/lib/libmpv.so" | grep -iE 'wayland|libX11|vdpau' || echo '(none)'
|
|
env:
|
|
OUTPUT_DIR: ${{ github.workspace }}/packages
|
|
|
|
- name: Upload the packages
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: linux-packages-smoke
|
|
path: ${{ github.workspace }}/packages/plezy-linux-x64.*
|
|
if-no-files-found: error
|
|
retention-days: 7
|