Files
plezy/.github/workflows/ci.yml
T
edde746 200d896bea build: switch every platform's libmpv supply chain to the unified mpv-build repo
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.
2026-09-02 11:31:47 +02:00

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