mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
feat(packaging): ship Linux embedded MPV frame-copy runtime (#1200)
* docs: design Linux frame-copy packaging * docs: plan Linux frame-copy packaging * feat(packaging): define Linux frame-copy profiles * fix(packaging): reject inherited profile names * feat(embedded-mpv): validate staged Linux runtime * fix(embedded-mpv): require Linux source packages * fix(embedded-mpv): harden Linux runtime staging * feat(embedded-mpv): build LGPL Linux runtime * fix(embedded-mpv): pin Linux runtime inputs * feat(embedded-mpv): build relocatable Linux helper * fix(embedded-mpv): require bundled Linux runtime * fix(embedded-mpv): make Linux runtime portable * feat(packaging): ship Linux frame-copy artifacts * fix(embedded-mpv): verify Linux helper linkage * fix(packaging): enforce Linux frame-copy isolation * fix(embedded-mpv): pin Linux display data * docs(embedded-mpv): document Linux frame-copy packaging * feat(embedded-mpv): probe Linux frame-copy runtime * test(embedded-mpv): smoke packaged Linux frame-copy * docs(embedded-mpv): clarify Linux system runtime baseline * fix(embedded-mpv): harden Linux runtime capability gate * ci: verify Linux frame-copy packages * test(embedded-mpv): harden packaged Linux smoke * test(embedded-mpv): preserve packaged GL mode * test(packaging): harden Linux package probes * fix(embedded-mpv): enable private Snap shared memory * fix(embedded-mpv): sanitize Linux helper environment * fix(packaging): enforce private Snap memory semantics * fix(packaging): reject ambiguous Snap memory metadata * fix(embedded-mpv): prioritize trusted Snap GL * fix(packaging): reject advanced Snap YAML semantics * fix(packaging): reject arbitrary Snap YAML aliases * feat(packaging): ship Linux runtime license notices * docs(embedded-mpv): document Linux runtime distribution * fix(packaging): parse Snap trailing comments safely * fix(release): gate Snap publish on public source release * fix(packaging): strip VCS metadata from source bundle * docs(packaging): clarify Linux source release gate * test(embedded-mpv): smoke missing bundled libmpv * style(embedded-mpv): format final validation inputs * fix(e2e): satisfy fixture index signature typing * fix(ci): declare fontconfig gperf generator * fix(embedded-mpv): hash runtime cache identities * fix(packaging): harden Linux frame-copy delivery * fix(packaging): tighten runtime delivery gates * fix(ci): decouple Linux runtime matrix * fix(packaging): harden Linux frame-copy delivery * fix(packaging): validate Linux frame-copy runtimes * fix(packaging): scope Snap Electron library checks * feat(packaging): ship Linux frame-copy runtimes * fix(packaging): improve Linux runtime smoke diagnostics * fix(packaging): expose bounded helper probe details * test(packaging): trace Snap EGL probe failures * fix(packaging): prefer core22 ABI in Snap helper * fix(packaging): bound helper probe capture * fix(packaging): harden Linux frame-copy releases * fix(packaging): canonicalize libplacebo submodule identity * fix(packaging): make source archive inspection portable * fix(packaging): harden Snap release verification
This commit is contained in:
1 parent
643dee1be3
commit
8fdac824fd
102 files changed
+36064
-801
No files matched your search
@@ -12,11 +12,300 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
linux-embedded-mpv-runtime:
|
||||
name: Build pinned Linux Embedded MPV runtime
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 120
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Resolve Linux runtime toolchain cache key
|
||||
id: linux-runtime-cache-key
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
sudo apt-get update
|
||||
{
|
||||
apt-cache policy \
|
||||
binutils build-essential cmake curl git gperf \
|
||||
libasound2-dev libdrm-dev libegl-dev libgbm-dev \
|
||||
libgl-dev libpulse-dev libva-dev make nasm \
|
||||
ninja-build patchelf perl pkg-config python3-pip \
|
||||
tar xz-utils
|
||||
echo 'meson=1.7.2'
|
||||
} > "${RUNNER_TEMP}/linux-runtime-toolchain.txt"
|
||||
TOOLCHAIN_SHA256="$(sha256sum "${RUNNER_TEMP}/linux-runtime-toolchain.txt" | cut -d ' ' -f 1)"
|
||||
SOURCE_SHA256="${{ hashFiles('tools/embedded-mpv/build-linux-runtime.cjs', 'tools/embedded-mpv/build-linux-runtime.mjs', 'tools/embedded-mpv/generate-linux-runtime-notices.cjs', 'tools/embedded-mpv/linux-runtime-manifest.cjs', 'tools/embedded-mpv/linux-source-archive-contract.cjs', 'tools/embedded-mpv/stage-runtime.mjs', 'tools/packaging/prepare-linux-runtime-source-snapshot.cjs') }}"
|
||||
echo "toolchain-sha256=${TOOLCHAIN_SHA256}" >> "${GITHUB_OUTPUT}"
|
||||
echo "key=linux-frame-copy-runtime-v5-ubuntu-22.04-${TOOLCHAIN_SHA256}-${SOURCE_SHA256}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Restore pinned Linux runtime and immutable source inputs
|
||||
id: linux-runtime-cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
vendor/embedded-mpv/linux-x64/include
|
||||
vendor/embedded-mpv/linux-x64/lib
|
||||
vendor/embedded-mpv/linux-x64/runtime-manifest.json
|
||||
dist/linux-frame-copy-runtime-source-inputs
|
||||
key: ${{ steps.linux-runtime-cache-key.outputs.key }}
|
||||
|
||||
- name: Install pinned Linux runtime build dependencies
|
||||
if: steps.linux-runtime-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
binutils \
|
||||
build-essential \
|
||||
cmake \
|
||||
curl \
|
||||
git \
|
||||
gperf \
|
||||
libasound2-dev \
|
||||
libdrm-dev \
|
||||
libegl-dev \
|
||||
libgbm-dev \
|
||||
libgl-dev \
|
||||
libpulse-dev \
|
||||
libva-dev \
|
||||
make \
|
||||
nasm \
|
||||
ninja-build \
|
||||
patchelf \
|
||||
perl \
|
||||
pkg-config \
|
||||
python3-pip \
|
||||
tar \
|
||||
xz-utils
|
||||
python3 -m pip install --user 'meson==1.7.2'
|
||||
|
||||
- name: Build and stage pinned LGPL Linux runtime
|
||||
if: steps.linux-runtime-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
export PATH="${HOME}/.local/bin:${PATH}"
|
||||
export IPTVNATOR_EMBEDDED_MPV_LINUX_BUILD_ROOT="${RUNNER_TEMP}/linux-frame-copy-runtime-build"
|
||||
export RUNTIME_PREFIX="${RUNNER_TEMP}/linux-frame-copy-runtime-prefix"
|
||||
|
||||
node tools/embedded-mpv/build-linux-runtime.mjs "${RUNTIME_PREFIX}"
|
||||
node tools/embedded-mpv/stage-runtime.mjs linux x64 "${RUNTIME_PREFIX}"
|
||||
|
||||
export SOURCE_INPUT_ROOT="${GITHUB_WORKSPACE}/dist/linux-frame-copy-runtime-source-inputs"
|
||||
rm -rf "${SOURCE_INPUT_ROOT}"
|
||||
mkdir -p \
|
||||
"${SOURCE_INPUT_ROOT}/archives" \
|
||||
"${SOURCE_INPUT_ROOT}/git"
|
||||
|
||||
git -C "${IPTVNATOR_EMBEDDED_MPV_LINUX_BUILD_ROOT}/sources/libplacebo" \
|
||||
submodule foreach --recursive git clean -ffdqx
|
||||
git -C "${IPTVNATOR_EMBEDDED_MPV_LINUX_BUILD_ROOT}/sources/libplacebo" \
|
||||
clean -ffdqx
|
||||
cp -a "${IPTVNATOR_EMBEDDED_MPV_LINUX_BUILD_ROOT}/archives/." "${SOURCE_INPUT_ROOT}/archives/"
|
||||
cp -a "${IPTVNATOR_EMBEDDED_MPV_LINUX_BUILD_ROOT}/sources/libplacebo" "${SOURCE_INPUT_ROOT}/git/libplacebo"
|
||||
node tools/embedded-mpv/generate-linux-runtime-notices.cjs collect \
|
||||
--runtime-manifest "${RUNTIME_PREFIX}/runtime-manifest.json" \
|
||||
--source-root "${IPTVNATOR_EMBEDDED_MPV_LINUX_BUILD_ROOT}/sources" \
|
||||
--output-root "${SOURCE_INPUT_ROOT}/license-inputs"
|
||||
|
||||
- name: Generate Linux runtime notices and assemble source compliance
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
export RUNTIME_ROOT="${GITHUB_WORKSPACE}/vendor/embedded-mpv/linux-x64"
|
||||
export SOURCE_INPUT_ROOT="${GITHUB_WORKSPACE}/dist/linux-frame-copy-runtime-source-inputs"
|
||||
export SOURCE_BUNDLE_ROOT="${RUNNER_TEMP}/linux-frame-copy-runtime-sources"
|
||||
export LIBPLACEBO_SOURCE_RECORD="${RUNNER_TEMP}/libplacebo-source-record.json"
|
||||
|
||||
test -f "${RUNTIME_ROOT}/runtime-manifest.json"
|
||||
test -d "${SOURCE_INPUT_ROOT}/archives"
|
||||
test -d "${SOURCE_INPUT_ROOT}/git/libplacebo"
|
||||
test -f "${SOURCE_INPUT_ROOT}/license-inputs/linux-runtime-license-inputs.json"
|
||||
|
||||
rm -rf "${RUNTIME_ROOT}/notices" "${SOURCE_BUNDLE_ROOT}"
|
||||
node tools/embedded-mpv/generate-linux-runtime-notices.cjs generate \
|
||||
--runtime-manifest "${RUNTIME_ROOT}/runtime-manifest.json" \
|
||||
--license-input-root "${SOURCE_INPUT_ROOT}/license-inputs" \
|
||||
--output-root "${RUNTIME_ROOT}/notices"
|
||||
|
||||
mkdir -p \
|
||||
"${SOURCE_BUNDLE_ROOT}/archives" \
|
||||
"${SOURCE_BUNDLE_ROOT}/git" \
|
||||
"${SOURCE_BUNDLE_ROOT}/license-inputs" \
|
||||
"${SOURCE_BUNDLE_ROOT}/metadata" \
|
||||
"${SOURCE_BUNDLE_ROOT}/notices" \
|
||||
"${SOURCE_BUNDLE_ROOT}/tooling"
|
||||
|
||||
cp -a "${SOURCE_INPUT_ROOT}/archives/." "${SOURCE_BUNDLE_ROOT}/archives/"
|
||||
cp -a "${SOURCE_INPUT_ROOT}/license-inputs/." "${SOURCE_BUNDLE_ROOT}/license-inputs/"
|
||||
cp -a "${RUNTIME_ROOT}/notices/." "${SOURCE_BUNDLE_ROOT}/notices/"
|
||||
cp "${RUNTIME_ROOT}/runtime-manifest.json" "${SOURCE_BUNDLE_ROOT}/metadata/runtime-manifest.json"
|
||||
node tools/packaging/prepare-linux-runtime-source-snapshot.cjs prepare \
|
||||
--runtime-manifest "${RUNTIME_ROOT}/runtime-manifest.json" \
|
||||
--checkout "${SOURCE_INPUT_ROOT}/git/libplacebo" \
|
||||
--output "${SOURCE_BUNDLE_ROOT}/git/libplacebo" \
|
||||
--record-output "${LIBPLACEBO_SOURCE_RECORD}"
|
||||
cp \
|
||||
tools/embedded-mpv/build-linux-runtime.cjs \
|
||||
tools/embedded-mpv/build-linux-runtime.mjs \
|
||||
tools/embedded-mpv/generate-linux-runtime-notices.cjs \
|
||||
tools/embedded-mpv/linux-runtime-manifest.cjs \
|
||||
tools/embedded-mpv/linux-source-archive-contract.cjs \
|
||||
tools/embedded-mpv/stage-runtime.mjs \
|
||||
tools/packaging/prepare-linux-runtime-source-snapshot.cjs \
|
||||
"${SOURCE_BUNDLE_ROOT}/tooling/"
|
||||
test -f "${SOURCE_BUNDLE_ROOT}/notices/THIRD_PARTY_NOTICES.txt"
|
||||
test -f "${SOURCE_BUNDLE_ROOT}/notices/embedded-mpv-notices.json"
|
||||
git rev-parse HEAD > "${SOURCE_BUNDLE_ROOT}/metadata/iptvnator-git-revision.txt"
|
||||
git diff --binary HEAD > "${SOURCE_BUNDLE_ROOT}/metadata/local-changes.patch"
|
||||
node <<'NODE'
|
||||
const crypto = require('node:crypto');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const {
|
||||
EXPECTED_LIBPLACEBO_V7_360_1_SOURCE_SNAPSHOT_SHA256,
|
||||
validateLinuxRuntimeSourceSnapshot,
|
||||
} = require('./tools/packaging/prepare-linux-runtime-source-snapshot.cjs');
|
||||
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(path.join(process.env.RUNTIME_ROOT, 'runtime-manifest.json'), 'utf8')
|
||||
);
|
||||
const archivesDirectory = path.join(process.env.SOURCE_BUNDLE_ROOT, 'archives');
|
||||
const archives = fs.readdirSync(archivesDirectory).sort().map((name) => {
|
||||
const contents = fs.readFileSync(path.join(archivesDirectory, name));
|
||||
return {
|
||||
name,
|
||||
sha256: crypto.createHash('sha256').update(contents).digest('hex'),
|
||||
};
|
||||
});
|
||||
const expectedArchiveHashes = Object.values(manifest.packages)
|
||||
.map(({ sourceSha256 }) => sourceSha256)
|
||||
.filter(Boolean)
|
||||
.sort();
|
||||
const actualArchiveHashes = archives.map(({ sha256 }) => sha256).sort();
|
||||
if (
|
||||
new Set(expectedArchiveHashes).size !== expectedArchiveHashes.length ||
|
||||
new Set(actualArchiveHashes).size !== actualArchiveHashes.length ||
|
||||
archives.length !== expectedArchiveHashes.length ||
|
||||
JSON.stringify(actualArchiveHashes) !== JSON.stringify(expectedArchiveHashes)
|
||||
) {
|
||||
throw new Error(
|
||||
'Source bundle archives must match the exact unique pinned archive hash set.'
|
||||
);
|
||||
}
|
||||
|
||||
const libplacebo = JSON.parse(
|
||||
fs.readFileSync(process.env.LIBPLACEBO_SOURCE_RECORD, 'utf8')
|
||||
);
|
||||
if (
|
||||
libplacebo.sourceGitCommit !== manifest.packages.libplacebo.sourceGitCommit ||
|
||||
JSON.stringify(libplacebo.sourceSubmodules) !==
|
||||
JSON.stringify(manifest.packages.libplacebo.sourceSubmodules)
|
||||
) {
|
||||
throw new Error('Prepared libplacebo source identity does not match the runtime manifest.');
|
||||
}
|
||||
validateLinuxRuntimeSourceSnapshot(libplacebo.sourceSnapshot, {
|
||||
expectedSha256:
|
||||
EXPECTED_LIBPLACEBO_V7_360_1_SOURCE_SNAPSHOT_SHA256,
|
||||
});
|
||||
|
||||
const notices = JSON.parse(
|
||||
fs.readFileSync(
|
||||
path.join(process.env.SOURCE_BUNDLE_ROOT, 'notices', 'embedded-mpv-notices.json'),
|
||||
'utf8'
|
||||
)
|
||||
);
|
||||
const repositoryRevision = fs
|
||||
.readFileSync(
|
||||
path.join(
|
||||
process.env.SOURCE_BUNDLE_ROOT,
|
||||
'metadata',
|
||||
'iptvnator-git-revision.txt'
|
||||
),
|
||||
'utf8'
|
||||
)
|
||||
.trim();
|
||||
fs.writeFileSync(
|
||||
path.join(process.env.SOURCE_BUNDLE_ROOT, 'metadata', 'source-index.json'),
|
||||
`${JSON.stringify(
|
||||
{
|
||||
schemaVersion: 3,
|
||||
repositoryRevision,
|
||||
sourcePackages: manifest.packages,
|
||||
archives,
|
||||
libplacebo,
|
||||
legal: {
|
||||
manifest: 'notices/embedded-mpv-notices.json',
|
||||
noticeFile: notices.noticeFile,
|
||||
packages: notices.packages,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}\n`
|
||||
);
|
||||
NODE
|
||||
(
|
||||
cd "${SOURCE_BUNDLE_ROOT}/archives"
|
||||
sha256sum * > "../metadata/archive-sha256.txt"
|
||||
)
|
||||
node tools/packaging/prepare-linux-runtime-source-snapshot.cjs assert-vcs-free \
|
||||
--directory "${SOURCE_BUNDLE_ROOT}"
|
||||
|
||||
mkdir -p dist/compliance
|
||||
rm -f dist/compliance/linux-frame-copy-runtime-sources.tar.xz
|
||||
tar \
|
||||
--create \
|
||||
--xz \
|
||||
--sort=name \
|
||||
--mtime='UTC 1970-01-01' \
|
||||
--owner=0 \
|
||||
--group=0 \
|
||||
--numeric-owner \
|
||||
--file dist/compliance/linux-frame-copy-runtime-sources.tar.xz \
|
||||
--directory "${SOURCE_BUNDLE_ROOT}" \
|
||||
.
|
||||
rm -f "${RUNTIME_ROOT}/source-archive-binding.json"
|
||||
node tools/embedded-mpv/linux-source-archive-contract.cjs create \
|
||||
--archive dist/compliance/linux-frame-copy-runtime-sources.tar.xz \
|
||||
--repository-revision "$(git rev-parse HEAD)" \
|
||||
--output "${RUNTIME_ROOT}/source-archive-binding.json"
|
||||
test -s "${RUNTIME_ROOT}/source-archive-binding.json"
|
||||
|
||||
- name: Upload staged Linux runtime
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-embedded-mpv-runtime
|
||||
path: vendor/embedded-mpv/linux-x64
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
- name: Upload Linux runtime source compliance
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-frame-copy-runtime-sources
|
||||
path: dist/compliance/linux-frame-copy-runtime-sources.tar.xz
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
build-cross-platform:
|
||||
name: Build on ${{ matrix.os }} ${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# macOS builds - separate runners to avoid native module conflicts
|
||||
@@ -32,26 +321,14 @@ jobs:
|
||||
embedded_mpv_platform: darwin
|
||||
embedded_mpv_arch: arm64
|
||||
embedded_mpv_build_runtime: true
|
||||
# Linux and Windows
|
||||
- os: linux
|
||||
runner: ubuntu-22.04
|
||||
linux_profile: standard
|
||||
embedded_mpv_platform: linux
|
||||
embedded_mpv_arch: x64
|
||||
embedded_mpv_build_runtime: false
|
||||
- os: linux
|
||||
runner: ubuntu-24.04
|
||||
linux_profile: flatpak
|
||||
embedded_mpv_platform: linux
|
||||
embedded_mpv_arch: x64
|
||||
embedded_mpv_build_runtime: false
|
||||
- os: windows
|
||||
runner: windows-2022
|
||||
arch: x64
|
||||
embedded_mpv_platform: win32
|
||||
embedded_mpv_arch: x64
|
||||
embedded_mpv_build_runtime: false
|
||||
|
||||
steps:
|
||||
steps: &electron-build-steps
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -68,38 +345,50 @@ jobs:
|
||||
if: matrix.os == 'linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y rpm libarchive-tools flatpak flatpak-builder appstream libx11-dev libxext-dev libmpv-dev mpv pkg-config libegl-dev libgl-dev libopengl-dev libgbm-dev
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
appstream \
|
||||
binutils \
|
||||
dbus-daemon \
|
||||
flatpak \
|
||||
flatpak-builder \
|
||||
libarchive-tools \
|
||||
libegl-dev \
|
||||
libgbm-dev \
|
||||
libgl-dev \
|
||||
libx11-dev \
|
||||
libxext-dev \
|
||||
mpv \
|
||||
pkg-config \
|
||||
rpm \
|
||||
snapd \
|
||||
squashfs-tools \
|
||||
xauth \
|
||||
xvfb
|
||||
|
||||
- name: Configure Flatpak build runtime
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'flatpak'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Configure Flatpak
|
||||
# 1. Add the Flathub repository (source of runtimes)
|
||||
flatpak remote-add --if-not-exists --user flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
|
||||
# 2. Install the standard Freedesktop Platform and SDK (required by electron-builder)
|
||||
# We install version 24.08 as a safe default, electron-builder might pick what it needs
|
||||
flatpak install --user -y flathub org.freedesktop.Platform//24.08 org.freedesktop.Sdk//24.08
|
||||
|
||||
- name: Select Linux packaging targets for CI profile
|
||||
if: matrix.os == 'linux'
|
||||
run: |
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const path = 'electron-builder.json';
|
||||
const config = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||
const targets = Array.isArray(config.linux?.target) ? config.linux.target : [];
|
||||
const profile = '${{ matrix.linux_profile }}';
|
||||
|
||||
if (profile === 'standard') {
|
||||
config.linux.target = targets.filter((entry) => String(entry.target).toLowerCase() !== 'flatpak');
|
||||
} else if (profile === 'flatpak') {
|
||||
config.linux.target = targets.filter((entry) => String(entry.target).toLowerCase() === 'flatpak');
|
||||
}
|
||||
|
||||
fs.writeFileSync(path, JSON.stringify(config, null, 4) + '\n');
|
||||
"
|
||||
cp electron-builder.json "${RUNNER_TEMP}/electron-builder.base.json"
|
||||
node tools/packaging/configure-linux-frame-copy-build.mjs --profile "${{ matrix.linux_profile }}"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Download pinned Linux Embedded MPV runtime
|
||||
if: matrix.os == 'linux'
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-embedded-mpv-runtime
|
||||
path: vendor/embedded-mpv/linux-x64
|
||||
|
||||
- name: Inject TMDB API key
|
||||
# No-op when the secret is unavailable (e.g. fork PRs) — the
|
||||
# app then requires a user-provided key for TMDB enrichment.
|
||||
@@ -113,12 +402,12 @@ jobs:
|
||||
- name: Resolve embedded MPV runtime cache key
|
||||
# TEMPORARY ARTIFACT TEST: remove `|| github.event_name == 'pull_request' || github.ref == 'refs/heads/master'`
|
||||
# after the macOS Embedded MPV artifacts are built and manually tested.
|
||||
if: matrix.embedded_mpv_platform && !startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master')
|
||||
if: matrix.embedded_mpv_platform && matrix.os != 'linux' && !startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master')
|
||||
id: embedded-mpv-runtime-cache-key
|
||||
shell: bash
|
||||
env:
|
||||
IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256: ${{ vars.IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256 || secrets.IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256 || '' }}
|
||||
IPTVNATOR_DEFAULT_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256: a26e28fa55c15ac5b6209d8a9f9c3c8cb39649631a53d3c4774beeae559a078c
|
||||
IPTVNATOR_DEFAULT_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256: 6014aa0e6d8e98cdba90f5288295a7105d7d14ab0ca906f51465eeb478d5fea0
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -186,7 +475,7 @@ jobs:
|
||||
- name: Restore embedded MPV runtime cache
|
||||
# TEMPORARY ARTIFACT TEST: remove `|| github.event_name == 'pull_request' || github.ref == 'refs/heads/master'`
|
||||
# after the macOS Embedded MPV artifacts are built and manually tested.
|
||||
if: matrix.embedded_mpv_platform && !startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master')
|
||||
if: matrix.embedded_mpv_platform && matrix.os != 'linux' && !startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master')
|
||||
id: embedded-mpv-runtime-cache
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
@@ -199,7 +488,7 @@ jobs:
|
||||
- name: Clear stale embedded MPV runtime files
|
||||
# TEMPORARY ARTIFACT TEST: remove `|| github.event_name == 'pull_request' || github.ref == 'refs/heads/master'`
|
||||
# after the macOS Embedded MPV artifacts are built and manually tested.
|
||||
if: matrix.embedded_mpv_platform && !startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master') && steps.embedded-mpv-runtime-cache.outputs.cache-hit != 'true'
|
||||
if: matrix.embedded_mpv_platform && matrix.os != 'linux' && !startsWith(github.ref, 'refs/tags/v') && (github.event_name == 'pull_request' || github.ref == 'refs/heads/master') && steps.embedded-mpv-runtime-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
@@ -229,8 +518,8 @@ jobs:
|
||||
env:
|
||||
IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_URL: ${{ vars.IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_URL || secrets.IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_URL || '' }}
|
||||
IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256: ${{ vars.IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256 || secrets.IPTVNATOR_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256 || '' }}
|
||||
IPTVNATOR_DEFAULT_WINDOWS_EMBEDDED_MPV_RUNTIME_URL: https://github.com/zhongfly/mpv-winbuild/releases/download/2026-06-14-7d245fd100/mpv-dev-lgpl-x86_64-20260614-git-7d245fd100.7z
|
||||
IPTVNATOR_DEFAULT_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256: a26e28fa55c15ac5b6209d8a9f9c3c8cb39649631a53d3c4774beeae559a078c
|
||||
IPTVNATOR_DEFAULT_WINDOWS_EMBEDDED_MPV_RUNTIME_URL: https://github.com/zhongfly/mpv-winbuild/releases/download/2026-07-17-94335ab87a/mpv-dev-lgpl-x86_64-20260717-git-94335ab87a.7z
|
||||
IPTVNATOR_DEFAULT_WINDOWS_EMBEDDED_MPV_RUNTIME_SHA256: 6014aa0e6d8e98cdba90f5288295a7105d7d14ab0ca906f51465eeb478d5fea0
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -254,47 +543,11 @@ jobs:
|
||||
|
||||
pnpm embedded-mpv:stage-runtime:windows-archive -- "${WINDOWS_RUNTIME_URL}" "${WINDOWS_RUNTIME_SHA256}"
|
||||
|
||||
- name: Stage Linux embedded MPV build inputs
|
||||
if: matrix.os == 'linux'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
RUNTIME_PREFIX="${RUNNER_TEMP}/embedded-mpv-runtime/linux-x64/prefix"
|
||||
rm -rf "${RUNTIME_PREFIX}"
|
||||
mkdir -p "${RUNTIME_PREFIX}/include"
|
||||
|
||||
cp -a /usr/include/mpv "${RUNTIME_PREFIX}/include/"
|
||||
|
||||
LIBMPV_DEV_VERSION="$(dpkg-query -W -f='${Version}' libmpv-dev)"
|
||||
MPV_VERSION="$(dpkg-query -W -f='${Version}' mpv)"
|
||||
export RUNTIME_PREFIX LIBMPV_DEV_VERSION MPV_VERSION
|
||||
node <<'NODE'
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const manifest = {
|
||||
linuxBackend: 'process-isolated mpv --wid',
|
||||
buildInputs: {
|
||||
libmpvDevPackage: process.env.LIBMPV_DEV_VERSION,
|
||||
mpvPackage: process.env.MPV_VERSION,
|
||||
},
|
||||
sourceDistribution:
|
||||
'Linux CI build inputs come from Ubuntu runner packages. Runtime playback uses the system mpv executable; IPTVnator does not bundle or load libmpv in the Electron process on Linux.',
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(process.env.RUNTIME_PREFIX, 'runtime-manifest.json'),
|
||||
`${JSON.stringify(manifest, null, 2)}\n`
|
||||
);
|
||||
NODE
|
||||
|
||||
pnpm embedded-mpv:stage-runtime -- linux x64 "${RUNTIME_PREFIX}"
|
||||
|
||||
- name: Build backend
|
||||
env:
|
||||
IPTVNATOR_EMBEDDED_MPV_PLATFORM: ${{ matrix.embedded_mpv_platform || '' }}
|
||||
IPTVNATOR_EMBEDDED_MPV_ARCH: ${{ matrix.embedded_mpv_arch || matrix.arch || '' }}
|
||||
IPTVNATOR_LINUX_FRAME_COPY_PROFILE: ${{ matrix.linux_profile || '' }}
|
||||
IPTVNATOR_REQUIRE_EMBEDDED_MPV: ${{ (matrix.os == 'linux' || matrix.os == 'windows' || (matrix.os == 'macos' && (startsWith(github.ref, 'refs/tags/v') || github.event_name == 'pull_request' || github.ref == 'refs/heads/master'))) && '1' || '0' }}
|
||||
run: pnpm run build:backend
|
||||
|
||||
@@ -331,27 +584,29 @@ jobs:
|
||||
find dist/apps/electron-backend/native -maxdepth 1 \( -name 'mpv-2.dll' -o -name 'libmpv-2.dll' -o -name 'mpv.dll' -o -name 'libmpv.dll' \) -print -quit | grep -q .
|
||||
;;
|
||||
linux)
|
||||
node -e "const manifest = require('./dist/apps/electron-backend/native/embedded-mpv-runtime.json'); if (manifest.origin !== 'external-mpv-process') { throw new Error('Linux embedded MPV manifest must use external-mpv-process origin.'); }"
|
||||
if find dist/apps/electron-backend/native/lib -name 'libmpv.so*' -print -quit 2>/dev/null | grep -q .; then
|
||||
echo "::error::Linux embedded MPV packages must not bundle libmpv"
|
||||
find dist/apps/electron-backend/native/lib -name 'libmpv.so*' -print
|
||||
exit 1
|
||||
fi
|
||||
if ldd dist/apps/electron-backend/native/embedded_mpv.node | grep -q 'libmpv'; then
|
||||
echo "::error::Linux embedded MPV addon must not link directly to libmpv"
|
||||
ldd dist/apps/electron-backend/native/embedded_mpv.node
|
||||
exit 1
|
||||
fi
|
||||
# The frame-copy helper is the inverse: a separate process
|
||||
# that MUST link libmpv (dev-mode engine; stripped from
|
||||
# packages until the bundled-runtime staging lands).
|
||||
# test -f, not -x: the webpack dist asset copy drops file
|
||||
# modes; consumers restore the bit (after-pack) or require
|
||||
# it via the X_OK support probe.
|
||||
node -e "const { execFileSync } = require('node:child_process'); const manifest = require('./dist/apps/electron-backend/native/embedded-mpv-runtime.json'); const revision = execFileSync('git', ['rev-parse', 'HEAD'], { encoding: 'utf8' }).trim(); if (manifest.origin !== 'linux-frame-copy-build' || manifest.sourceRuntimeValidated !== true || manifest.sourceArchive?.schemaVersion !== 1 || manifest.sourceArchive?.name !== 'linux-frame-copy-runtime-sources.tar.xz' || !/^[a-f0-9]{64}$/.test(manifest.sourceArchive?.sha256 ?? '') || manifest.sourceArchive?.repositoryRevision !== revision) { throw new Error('Linux embedded MPV build manifest must describe the validated source runtime and exact source archive.'); }"
|
||||
test -f dist/apps/electron-backend/native/lib/libmpv.so.2
|
||||
test -f dist/apps/electron-backend/native/iptvnator_mpv_helper
|
||||
if ! ldd dist/apps/electron-backend/native/iptvnator_mpv_helper | grep -q 'libmpv'; then
|
||||
echo "::error::Linux frame-copy helper must link libmpv"
|
||||
ldd dist/apps/electron-backend/native/iptvnator_mpv_helper
|
||||
test -f dist/apps/electron-backend/native/embedded_mpv_frame_reader.node
|
||||
if readelf -d dist/apps/electron-backend/native/embedded_mpv.node | grep -Eq 'Shared library:.*libmpv\.so'; then
|
||||
echo "::error::Linux embedded MPV addon must not link directly to libmpv"
|
||||
readelf -d dist/apps/electron-backend/native/embedded_mpv.node
|
||||
exit 1
|
||||
fi
|
||||
if readelf -d dist/apps/electron-backend/native/embedded_mpv_frame_reader.node | grep -Eq 'Shared library:.*libmpv\.so'; then
|
||||
echo "::error::Linux frame reader must not link directly to libmpv"
|
||||
readelf -d dist/apps/electron-backend/native/embedded_mpv_frame_reader.node
|
||||
exit 1
|
||||
fi
|
||||
HELPER_DYNAMIC="$(readelf -d dist/apps/electron-backend/native/iptvnator_mpv_helper)"
|
||||
if ! printf '%s\n' "${HELPER_DYNAMIC}" | grep -Eq 'Shared library: \[libmpv\.so\.2\]'; then
|
||||
echo "::error::Linux frame-copy helper must need libmpv.so.2"
|
||||
printf '%s\n' "${HELPER_DYNAMIC}"
|
||||
exit 1
|
||||
fi
|
||||
if ! printf '%s\n' "${HELPER_DYNAMIC}" | grep -Fq 'Library runpath: [$ORIGIN/lib]'; then
|
||||
echo "::error::Linux frame-copy helper must keep only the relative runtime path"
|
||||
printf '%s\n' "${HELPER_DYNAMIC}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
@@ -557,6 +812,7 @@ jobs:
|
||||
env:
|
||||
IPTVNATOR_EMBEDDED_MPV_PLATFORM: ${{ matrix.embedded_mpv_platform || '' }}
|
||||
IPTVNATOR_EMBEDDED_MPV_ARCH: ${{ matrix.embedded_mpv_arch || matrix.arch || '' }}
|
||||
IPTVNATOR_LINUX_FRAME_COPY_PROFILE: ${{ matrix.linux_profile || '' }}
|
||||
# TEMPORARY PR TEST: change this back to '0' after manually
|
||||
# testing the macOS PR artifact with Embedded MPV included.
|
||||
IPTVNATOR_REQUIRE_EMBEDDED_MPV: ${{ (matrix.os == 'linux' || matrix.os == 'windows' || (matrix.os == 'macos' && github.event_name == 'pull_request')) && '1' || '0' }}
|
||||
@@ -567,11 +823,250 @@ jobs:
|
||||
env:
|
||||
PACKAGE_OS: ${{ matrix.os }}
|
||||
PACKAGE_ARCH: ${{ matrix.arch || matrix.embedded_mpv_arch || '' }}
|
||||
IPTVNATOR_LINUX_FRAME_COPY_PROFILE: ${{ matrix.linux_profile || '' }}
|
||||
# TEMPORARY ARTIFACT TEST: remove `|| github.event_name == 'pull_request' || github.ref == 'refs/heads/master'`
|
||||
# after the macOS Embedded MPV artifacts are built and manually tested.
|
||||
IPTVNATOR_REQUIRE_EMBEDDED_MPV: ${{ (matrix.os == 'linux' || matrix.os == 'windows' || (matrix.os == 'macos' && (startsWith(github.ref, 'refs/tags/v') || github.event_name == 'pull_request' || github.ref == 'refs/heads/master'))) && '1' || '0' }}
|
||||
run: pnpm run verify:package-layout -- "$PACKAGE_OS" "$PACKAGE_ARCH"
|
||||
|
||||
- name: Make marker-only foreign-architecture DEB packages
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'system'
|
||||
shell: bash
|
||||
env:
|
||||
IPTVNATOR_EMBEDDED_MPV_PLATFORM: linux
|
||||
IPTVNATOR_EMBEDDED_MPV_ARCH: x64
|
||||
IPTVNATOR_LINUX_FRAME_COPY_PROFILE: ''
|
||||
IPTVNATOR_REQUIRE_EMBEDDED_MPV: '1'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
for foreign_arch in armv7l arm64; do
|
||||
rm -rf dist/executables-linux-foreign
|
||||
cp "${RUNNER_TEMP}/electron-builder.base.json" electron-builder.json
|
||||
node tools/packaging/configure-linux-frame-copy-build.mjs \
|
||||
--foreign-deb \
|
||||
--foreign-arch "${foreign_arch}"
|
||||
pnpm nx run electron-backend:make \
|
||||
--arch="${foreign_arch}" \
|
||||
--outputPath=dist/executables-linux-foreign \
|
||||
--publishPolicy=never
|
||||
mapfile -t foreign_debs < <(
|
||||
find dist/executables-linux-foreign -maxdepth 1 -type f -name '*.deb' -print
|
||||
)
|
||||
test "${#foreign_debs[@]}" -eq 1
|
||||
case "${foreign_arch}" in
|
||||
armv7l) expected_deb_arch=armhf ;;
|
||||
arm64) expected_deb_arch=arm64 ;;
|
||||
*)
|
||||
echo "::error::Unexpected foreign DEB build architecture ${foreign_arch}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
actual_deb_arch="$(dpkg-deb --field "${foreign_debs[0]}" Architecture)"
|
||||
test "${actual_deb_arch}" = "${expected_deb_arch}"
|
||||
mv "${foreign_debs[0]}" dist/executables/
|
||||
done
|
||||
|
||||
- name: Verify DEB payloads and x64 system runtime
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'system'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
found=false
|
||||
for artifact in dist/executables/*.deb; do
|
||||
test -f "${artifact}" || continue
|
||||
found=true
|
||||
case "$(dpkg-deb --field "${artifact}" Architecture)" in
|
||||
amd64)
|
||||
docker run --rm \
|
||||
--volume "${GITHUB_WORKSPACE}:/workspace:ro" \
|
||||
--volume "$(realpath "${artifact}"):/artifact.deb:ro" \
|
||||
--workdir /workspace \
|
||||
ubuntu:24.04 \
|
||||
bash -euo pipefail -c '
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||
binutils libegl1 libgbm1 libgl1 libgl1-mesa-dri libmpv2 \
|
||||
nodejs squashfs-tools xauth xvfb
|
||||
xvfb-run -a env LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
node tools/packaging/verify-linux-frame-copy-runtime.mjs \
|
||||
--artifact /artifact.deb --profile system
|
||||
'
|
||||
;;
|
||||
arm64|armhf)
|
||||
node tools/packaging/verify-linux-frame-copy-runtime.mjs \
|
||||
--artifact "${artifact}" --profile system
|
||||
;;
|
||||
*)
|
||||
echo "::error::Unexpected DEB architecture in ${artifact}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
test "${found}" = true
|
||||
|
||||
- name: Verify RPM payload and x64 system runtime
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'system'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
artifact="$(find dist/executables -maxdepth 1 -type f -name '*.rpm' -print -quit)"
|
||||
test -n "${artifact}"
|
||||
docker run --rm \
|
||||
--volume "${GITHUB_WORKSPACE}:/workspace:ro" \
|
||||
--volume "$(realpath "${artifact}"):/artifact.rpm:ro" \
|
||||
--workdir /workspace \
|
||||
fedora:latest \
|
||||
bash -euo pipefail -c '
|
||||
dnf install -y \
|
||||
binutils bsdtar libglvnd-egl libglvnd-glx mesa-dri-drivers \
|
||||
mesa-libgbm mpv-libs nodejs rpm xorg-x11-server-Xvfb \
|
||||
xorg-x11-xauth
|
||||
xvfb-run -a env LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
node tools/packaging/verify-linux-frame-copy-runtime.mjs \
|
||||
--artifact /artifact.rpm --profile system
|
||||
'
|
||||
|
||||
- name: Verify Pacman payload and x64 system runtime
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'system'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
artifact="$(find dist/executables -maxdepth 1 -type f \( -name '*.pacman' -o -name '*.pkg.tar.*' \) -print -quit)"
|
||||
test -n "${artifact}"
|
||||
docker run --rm \
|
||||
--volume "${GITHUB_WORKSPACE}:/workspace:ro" \
|
||||
--volume "$(realpath "${artifact}"):/artifact.pacman:ro" \
|
||||
--workdir /workspace \
|
||||
archlinux:latest \
|
||||
bash -euo pipefail -c '
|
||||
pacman -Syu --noconfirm \
|
||||
binutils libarchive libglvnd mesa mpv nodejs xorg-server-xvfb \
|
||||
xorg-xauth
|
||||
xvfb-run -a env LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
node tools/packaging/verify-linux-frame-copy-runtime.mjs \
|
||||
--artifact /artifact.pacman --profile system
|
||||
'
|
||||
|
||||
- name: Verify AppImage payloads and bundled runtime
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'portable'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
found=false
|
||||
for artifact in dist/executables/*.AppImage; do
|
||||
test -f "${artifact}" || continue
|
||||
found=true
|
||||
xvfb-run -a env LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
node tools/packaging/verify-linux-frame-copy-runtime.mjs \
|
||||
--artifact "${artifact}" --profile portable
|
||||
done
|
||||
test "${found}" = true
|
||||
|
||||
- name: Verify Snap payloads and strict-confinement runtime
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'portable'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
found=false
|
||||
installed_x64=false
|
||||
for artifact in dist/executables/*.snap; do
|
||||
test -f "${artifact}" || continue
|
||||
found=true
|
||||
verification="$(
|
||||
xvfb-run -a env LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
node tools/packaging/verify-linux-frame-copy-runtime.mjs \
|
||||
--artifact "${artifact}" --profile portable \
|
||||
2>&1 | tee /dev/stderr
|
||||
)"
|
||||
if printf '%s\n' "${verification}" | grep -Fq 'Verified snap x64 Linux'; then
|
||||
snap list mesa-core22 >/dev/null 2>&1 || sudo snap install mesa-core22
|
||||
snap list gnome-3-28-1804 >/dev/null 2>&1 || sudo snap install gnome-3-28-1804
|
||||
sudo snap install --dangerous "${artifact}"
|
||||
installed_x64=true
|
||||
fi
|
||||
done
|
||||
test "${found}" = true
|
||||
test "${installed_x64}" = true
|
||||
sudo snap connect iptvnator:graphics-core22 mesa-core22:graphics-core22
|
||||
sudo snap connect iptvnator:gnome-3-28-1804 gnome-3-28-1804:gnome-3-28-1804
|
||||
sudo snap disconnect iptvnator:graphics-core22 mesa-core22:graphics-core22
|
||||
snap connections iptvnator | awk \
|
||||
'$2 == "iptvnator:graphics-core22" && $3 == "-" { found=1 } END { exit !found }'
|
||||
set +e
|
||||
disconnected_probe="$(
|
||||
xvfb-run -a env LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
snap run iptvnator --embedded-mpv-runtime-probe 2>&1
|
||||
)"
|
||||
disconnected_status=$?
|
||||
set -e
|
||||
printf '%s\n' "${disconnected_probe}"
|
||||
test "${disconnected_status}" -eq 1
|
||||
printf '%s\n' "${disconnected_probe}" | \
|
||||
grep -Fx '{"usable":false,"reason":"snap-graphics-provider-unavailable"}'
|
||||
sudo snap connect iptvnator:graphics-core22 mesa-core22:graphics-core22
|
||||
snap connections iptvnator | awk \
|
||||
'$2 == "iptvnator:graphics-core22" && $3 == "mesa-core22:graphics-core22" { found=1 } END { exit !found }'
|
||||
snap connections iptvnator | awk \
|
||||
'$2 == "iptvnator:gnome-3-28-1804" && $3 == "gnome-3-28-1804:gnome-3-28-1804" { found=1 } END { exit !found }'
|
||||
snap connections iptvnator | awk \
|
||||
'$1 == "shared-memory" && $2 == "iptvnator:shared-memory" && $3 == ":shared-memory" { found=1 } END { exit !found }'
|
||||
xvfb-run -a env \
|
||||
LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
IPTVNATOR_TRACE_PLAYER=1 \
|
||||
EGL_LOG_LEVEL=debug \
|
||||
LIBGL_DEBUG=verbose \
|
||||
__EGL_VENDOR_LIBRARY_FILENAMES=/tmp/hostile-egl-vendor.json \
|
||||
GBM_BACKEND=/tmp/hostile-gbm \
|
||||
MESA_LOADER_DRIVER_OVERRIDE=/tmp/hostile-dri \
|
||||
LIBVA_DRIVER_NAME=/tmp/hostile-va \
|
||||
VDPAU_DRIVER_PATH=/tmp/hostile-vdpau \
|
||||
VK_DRIVER_FILES=/tmp/hostile-vulkan-driver.json \
|
||||
VK_ICD_FILENAMES=/tmp/hostile-vulkan-icd.json \
|
||||
VK_ADD_DRIVER_FILES=/tmp/hostile-vulkan-add-driver.json \
|
||||
VK_ADD_LAYER_PATH=/tmp/hostile-vulkan-layers \
|
||||
VK_IMPLICIT_LAYER_PATH=/tmp/hostile-vulkan-implicit-layers \
|
||||
VK_ADD_IMPLICIT_LAYER_PATH=/tmp/hostile-vulkan-add-implicit-layers \
|
||||
XDG_CONFIG_HOME=/tmp/hostile-xdg-config-home \
|
||||
XDG_CONFIG_DIRS=/tmp/hostile-xdg-config-dirs \
|
||||
XDG_DATA_HOME=/tmp/hostile-xdg-data-home \
|
||||
XDG_DATA_DIRS=/tmp/hostile-xdg-data-dirs \
|
||||
snap run iptvnator --embedded-mpv-runtime-probe
|
||||
|
||||
- name: Run packaged x64 frame-copy and fallback smoke
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'portable'
|
||||
env:
|
||||
IPTVNATOR_E2E_REQUIRE_PACKAGED_FRAME_COPY: '1'
|
||||
IPTVNATOR_E2E_PACKAGED_EXECUTABLE: ${{ github.workspace }}/dist/executables/linux-unpacked/iptvnator
|
||||
LIBGL_ALWAYS_SOFTWARE: '1'
|
||||
run: |
|
||||
xvfb-run -a pnpm nx run \
|
||||
electron-backend-e2e:packaged-frame-copy-smoke \
|
||||
--skip-nx-cache
|
||||
|
||||
- name: Diagnose packaged x64 frame-copy hardware path
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'portable'
|
||||
continue-on-error: true
|
||||
env:
|
||||
IPTVNATOR_E2E_REQUIRE_PACKAGED_FRAME_COPY: '1'
|
||||
IPTVNATOR_E2E_PACKAGED_EXECUTABLE: ${{ github.workspace }}/dist/executables/linux-unpacked/iptvnator
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ ! -e /dev/dri/renderD128 ]; then
|
||||
echo "::notice::No /dev/dri/renderD128 is available; skipping the non-blocking hardware-path diagnostic."
|
||||
exit 0
|
||||
fi
|
||||
ls -la /dev/dri
|
||||
xvfb-run -a pnpm nx run \
|
||||
electron-backend-e2e:packaged-frame-copy-smoke \
|
||||
--skip-nx-cache
|
||||
|
||||
- name: Save embedded MPV runtime cache
|
||||
# TEMPORARY ARTIFACT TEST: remove `|| github.ref == 'refs/heads/master'`
|
||||
# after the macOS Embedded MPV artifacts are built and manually tested.
|
||||
@@ -584,7 +1079,7 @@ jobs:
|
||||
vendor/embedded-mpv/${{ matrix.embedded_mpv_platform }}-${{ matrix.embedded_mpv_arch }}/runtime-manifest.json
|
||||
key: ${{ steps.embedded-mpv-runtime-cache-key.outputs.key }}
|
||||
|
||||
- name: Smoke test packaged Flatpak launcher
|
||||
- name: Verify Flatpak payload, launcher, and sandboxed runtime
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'flatpak'
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -596,8 +1091,12 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
xvfb-run -a env LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
node tools/packaging/verify-linux-frame-copy-runtime.mjs \
|
||||
--artifact "${FLATPAK_BUNDLE}" --profile flatpak
|
||||
flatpak install --user --noninteractive -y "${FLATPAK_BUNDLE}"
|
||||
flatpak run --command=sh com.fourgray.iptvnator -c '
|
||||
xvfb-run -a env LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
flatpak run --command=sh com.fourgray.iptvnator -c '
|
||||
set -euo pipefail
|
||||
|
||||
test -f /app/share/metainfo/com.fourgray.iptvnator.metainfo.xml
|
||||
@@ -609,6 +1108,10 @@ jobs:
|
||||
grep -q '\''readlink -f "$SCRIPT_PATH"'\'' "${LAUNCHER_PATH}"
|
||||
grep -q '\''exec "$SCRIPT_DIR/iptvnator.bin"'\'' "${LAUNCHER_PATH}"
|
||||
'
|
||||
xvfb-run -a dbus-run-session -- flatpak run \
|
||||
--env=LIBGL_ALWAYS_SOFTWARE=1 \
|
||||
com.fourgray.iptvnator \
|
||||
--embedded-mpv-runtime-probe
|
||||
|
||||
- name: Upload artifacts (macOS)
|
||||
if: matrix.os == 'macos'
|
||||
@@ -622,23 +1125,31 @@ jobs:
|
||||
dist/executables/**/*.blockmap
|
||||
retention-days: 7
|
||||
|
||||
- name: Upload artifacts (Linux)
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'standard'
|
||||
- name: Upload system-runtime Linux artifacts
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'system'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-artifacts
|
||||
name: linux-system-artifacts
|
||||
path: |
|
||||
dist/executables/**/*.deb
|
||||
dist/executables/**/*.rpm
|
||||
dist/executables/**/*.snap
|
||||
dist/executables/**/*.AppImage
|
||||
dist/executables/**/*.tar.gz
|
||||
dist/executables/**/*.pacman
|
||||
dist/executables/*.deb
|
||||
dist/executables/*.rpm
|
||||
dist/executables/*.pacman
|
||||
dist/executables/*.pkg.tar.*
|
||||
retention-days: 7
|
||||
|
||||
- name: Upload portable-runtime Linux artifacts
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'portable'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-portable-artifacts
|
||||
path: |
|
||||
dist/executables/*.AppImage
|
||||
dist/executables/*.snap
|
||||
dist/executables/**/latest-linux*.yml
|
||||
dist/executables/**/*.blockmap
|
||||
retention-days: 7
|
||||
|
||||
- name: Upload artifacts (Flatpak)
|
||||
- name: Upload Flatpak-runtime Linux artifacts
|
||||
if: matrix.os == 'linux' && matrix.linux_profile == 'flatpak'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -660,9 +1171,44 @@ jobs:
|
||||
dist/executables/**/*.blockmap
|
||||
retention-days: 7
|
||||
|
||||
build-linux:
|
||||
name: Build on ${{ matrix.os }} ${{ matrix.arch }} (${{ matrix.linux_profile }})
|
||||
needs: linux-embedded-mpv-runtime
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 120
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
runner: ubuntu-22.04
|
||||
arch: x64
|
||||
linux_profile: system
|
||||
embedded_mpv_platform: linux
|
||||
embedded_mpv_arch: x64
|
||||
embedded_mpv_build_runtime: false
|
||||
- os: linux
|
||||
runner: ubuntu-22.04
|
||||
arch: x64
|
||||
linux_profile: portable
|
||||
embedded_mpv_platform: linux
|
||||
embedded_mpv_arch: x64
|
||||
embedded_mpv_build_runtime: false
|
||||
- os: linux
|
||||
runner: ubuntu-24.04
|
||||
arch: x64
|
||||
linux_profile: flatpak
|
||||
embedded_mpv_platform: linux
|
||||
embedded_mpv_arch: x64
|
||||
embedded_mpv_build_runtime: false
|
||||
|
||||
steps: *electron-build-steps
|
||||
|
||||
create-release:
|
||||
name: Create Draft Release
|
||||
needs: build
|
||||
needs:
|
||||
- build-cross-platform
|
||||
- build-linux
|
||||
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
@@ -813,15 +1359,16 @@ jobs:
|
||||
artifacts/macos-arm64-artifacts/*-arm64.zip
|
||||
artifacts/macos-arm64-artifacts/*.blockmap
|
||||
artifacts/latest-mac.yml
|
||||
artifacts/linux-artifacts/*.AppImage
|
||||
artifacts/linux-artifacts/*.deb
|
||||
artifacts/linux-artifacts/*.rpm
|
||||
artifacts/linux-artifacts/*.snap
|
||||
artifacts/linux-artifacts/*.tar.gz
|
||||
artifacts/linux-artifacts/*.pacman
|
||||
artifacts/linux-artifacts/latest-linux*.yml
|
||||
artifacts/linux-artifacts/*.blockmap
|
||||
artifacts/linux-system-artifacts/*.deb
|
||||
artifacts/linux-system-artifacts/*.rpm
|
||||
artifacts/linux-system-artifacts/*.pacman
|
||||
artifacts/linux-system-artifacts/*.pkg.tar.*
|
||||
artifacts/linux-portable-artifacts/*.AppImage
|
||||
artifacts/linux-portable-artifacts/*.snap
|
||||
artifacts/linux-portable-artifacts/latest-linux*.yml
|
||||
artifacts/linux-portable-artifacts/*.blockmap
|
||||
artifacts/linux-flatpak-artifacts/*.flatpak
|
||||
artifacts/linux-frame-copy-runtime-sources/linux-frame-copy-runtime-sources.tar.xz
|
||||
artifacts/windows-artifacts/*-setup.exe
|
||||
artifacts/windows-artifacts/*.msi
|
||||
artifacts/windows-artifacts/*.zip
|
||||
@@ -829,31 +1376,3 @@ jobs:
|
||||
artifacts/windows-artifacts/*.blockmap
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
publish-snap:
|
||||
name: Publish to Snapcraft Store
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.snapcraft_token }}
|
||||
|
||||
steps:
|
||||
- name: Download snap artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-artifacts
|
||||
path: artifacts
|
||||
|
||||
- name: Setup Snapcraft
|
||||
uses: samuelmeuli/action-snapcraft@v3
|
||||
|
||||
- name: Publish all snaps to edge channel
|
||||
run: |
|
||||
# Find and publish all snap files
|
||||
for SNAP_FILE in artifacts/*.snap; do
|
||||
if [ -f "$SNAP_FILE" ]; then
|
||||
echo "Publishing: $SNAP_FILE"
|
||||
snapcraft upload --release=edge "$SNAP_FILE"
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,269 @@
|
||||
name: Publish Snap after public release
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
verify-snap:
|
||||
name: Verify public-release Snap assets
|
||||
if: ${{ startsWith(github.event.release.tag_name, 'v') && github.event.release.draft == false }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
SOURCE_ARCHIVE_NAME: linux-frame-copy-runtime-sources.tar.xz
|
||||
outputs:
|
||||
receipt-sha256: ${{ steps.bind-transfer.outputs.receipt-sha256 }}
|
||||
|
||||
steps:
|
||||
- name: Checkout released tooling
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install release source verifier
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
binutils \
|
||||
squashfs-tools \
|
||||
xz-utils
|
||||
|
||||
- name: Select exact public release assets
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
gh api \
|
||||
--paginate \
|
||||
--slurp \
|
||||
"repos/${GITHUB_REPOSITORY}/releases/${{ github.event.release.id }}/assets?per_page=100" \
|
||||
> "${RUNNER_TEMP}/snap-release-assets.json"
|
||||
node tools/packaging/release-snap-assets.cjs select \
|
||||
--assets-json "${RUNNER_TEMP}/snap-release-assets.json" \
|
||||
--output-json "${RUNNER_TEMP}/selected-snap-release-assets.json"
|
||||
|
||||
- name: Download exact public release assets
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
ASSET_DIRECTORY="${RUNNER_TEMP}/snap-release-downloads"
|
||||
rm -rf "${ASSET_DIRECTORY}"
|
||||
mkdir -p "${ASSET_DIRECTORY}"
|
||||
node -e \
|
||||
"const fs=require('node:fs'); const selected=JSON.parse(fs.readFileSync(process.argv[1],'utf8')); for (const asset of [...selected.snapAssets, selected.sourceAsset]) console.log([asset.id, asset.name].join('\\t'));" \
|
||||
"${RUNNER_TEMP}/selected-snap-release-assets.json" |
|
||||
while IFS=$'\t' read -r ASSET_ID ASSET_NAME; do
|
||||
gh api \
|
||||
--header "Accept: application/octet-stream" \
|
||||
"repos/${GITHUB_REPOSITORY}/releases/assets/${ASSET_ID}" \
|
||||
> "${ASSET_DIRECTORY}/${ASSET_NAME}"
|
||||
done
|
||||
|
||||
- name: Verify downloaded public release assets
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
VERIFIED_ASSET_STAGING="${RUNNER_TEMP}/verified-snap-release-assets"
|
||||
SEALED_ASSET_PARENT="/var/lib/iptvnator-snap-release"
|
||||
SEALED_ASSET_DIRECTORY="${SEALED_ASSET_PARENT}/assets"
|
||||
test -s "${RUNNER_TEMP}/snap-release-downloads/${SOURCE_ARCHIVE_NAME}"
|
||||
test ! -e "${VERIFIED_ASSET_STAGING}"
|
||||
sudo test ! -e "${SEALED_ASSET_PARENT}"
|
||||
node tools/packaging/release-snap-assets.cjs verify \
|
||||
--manifest "${RUNNER_TEMP}/selected-snap-release-assets.json" \
|
||||
--directory "${RUNNER_TEMP}/snap-release-downloads" \
|
||||
--repository-revision "$(git rev-parse HEAD)" \
|
||||
--verified-directory "${VERIFIED_ASSET_STAGING}"
|
||||
sudo install -d -m 0700 -o root -g root "${SEALED_ASSET_PARENT}"
|
||||
sudo mv "${VERIFIED_ASSET_STAGING}" "${SEALED_ASSET_DIRECTORY}"
|
||||
sudo chown -R root:root "${SEALED_ASSET_DIRECTORY}"
|
||||
sudo find "${SEALED_ASSET_DIRECTORY}" -type d -exec chmod 0555 {} +
|
||||
sudo find "${SEALED_ASSET_DIRECTORY}" -type f -exec chmod 0444 {} +
|
||||
sudo chmod 0555 "${SEALED_ASSET_PARENT}"
|
||||
|
||||
- name: Reverify sealed public release assets
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
VERIFIED_ASSET_DIRECTORY="/var/lib/iptvnator-snap-release/assets"
|
||||
node tools/packaging/release-snap-assets.cjs verify-sealed \
|
||||
--manifest "${RUNNER_TEMP}/selected-snap-release-assets.json" \
|
||||
--directory "${VERIFIED_ASSET_DIRECTORY}" \
|
||||
--receipt "${VERIFIED_ASSET_DIRECTORY}/verified-release-assets.json" \
|
||||
--repository-revision "$(git rev-parse HEAD)"
|
||||
|
||||
- name: Bind verified release transfer
|
||||
id: bind-transfer
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
RECEIPT_PATH="/var/lib/iptvnator-snap-release/assets/verified-release-assets.json"
|
||||
RECEIPT_RECORD="$(/usr/bin/sha256sum --binary "${RECEIPT_PATH}")"
|
||||
RECEIPT_SHA256="${RECEIPT_RECORD%% *}"
|
||||
[[ "${RECEIPT_SHA256}" =~ ^[a-f0-9]{64}$ ]]
|
||||
printf 'receipt-sha256=%s\n' "${RECEIPT_SHA256}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Transfer verified release assets
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: verified-snap-release-assets
|
||||
path: /var/lib/iptvnator-snap-release/assets
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
compression-level: 0
|
||||
include-hidden-files: true
|
||||
|
||||
publish-snap:
|
||||
name: Publish verified public-release Snap to edge
|
||||
needs: verify-snap
|
||||
if: ${{ needs.verify-snap.result == 'success' && startsWith(github.event.release.tag_name, 'v') && github.event.release.draft == false }}
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Download verified release assets
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
|
||||
with:
|
||||
name: verified-snap-release-assets
|
||||
path: ${{ runner.temp }}/verified-snap-release-assets
|
||||
|
||||
- name: Seal transferred public release assets
|
||||
shell: bash
|
||||
env:
|
||||
EXPECTED_RECEIPT_SHA256: ${{ needs.verify-snap.outputs.receipt-sha256 }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
TRANSFERRED_ASSET_DIRECTORY="${RUNNER_TEMP}/verified-snap-release-assets"
|
||||
SEALED_ASSET_PARENT="/var/lib/iptvnator-snap-release"
|
||||
SEALED_ASSET_DIRECTORY="${SEALED_ASSET_PARENT}/assets"
|
||||
test -d "${TRANSFERRED_ASSET_DIRECTORY}"
|
||||
test ! -L "${TRANSFERRED_ASSET_DIRECTORY}"
|
||||
shopt -s nullglob dotglob
|
||||
TRANSFERRED_FILES=("${TRANSFERRED_ASSET_DIRECTORY}"/*)
|
||||
TRANSFERRED_SNAPS=("${TRANSFERRED_ASSET_DIRECTORY}"/*.snap)
|
||||
test "${#TRANSFERRED_SNAPS[@]}" -gt 0
|
||||
test "${#TRANSFERRED_FILES[@]}" -eq "$(( ${#TRANSFERRED_SNAPS[@]} + 2 ))"
|
||||
test -f "${TRANSFERRED_ASSET_DIRECTORY}/linux-frame-copy-runtime-sources.tar.xz"
|
||||
test ! -L "${TRANSFERRED_ASSET_DIRECTORY}/linux-frame-copy-runtime-sources.tar.xz"
|
||||
test -f "${TRANSFERRED_ASSET_DIRECTORY}/verified-release-assets.json"
|
||||
test ! -L "${TRANSFERRED_ASSET_DIRECTORY}/verified-release-assets.json"
|
||||
for ASSET_FILE in "${TRANSFERRED_FILES[@]}"; do
|
||||
test -f "${ASSET_FILE}"
|
||||
test ! -L "${ASSET_FILE}"
|
||||
done
|
||||
RECEIPT_PATH="${TRANSFERRED_ASSET_DIRECTORY}/verified-release-assets.json"
|
||||
RECEIPT_RECORD="$(/usr/bin/sha256sum --binary "${RECEIPT_PATH}")"
|
||||
ACTUAL_RECEIPT_SHA256="${RECEIPT_RECORD%% *}"
|
||||
[[ "${EXPECTED_RECEIPT_SHA256}" =~ ^[a-f0-9]{64}$ ]]
|
||||
test "${ACTUAL_RECEIPT_SHA256}" = "${EXPECTED_RECEIPT_SHA256}"
|
||||
/usr/bin/jq --exit-status '
|
||||
type == "object" and
|
||||
(keys == ["assets", "repositoryRevision", "schemaVersion"]) and
|
||||
(.schemaVersion == 1) and
|
||||
(.repositoryRevision |
|
||||
type == "string" and test("^[a-f0-9]{40,64}$")) and
|
||||
(.assets | type == "array" and length >= 2) and
|
||||
(.assets | all(.[];
|
||||
type == "object" and
|
||||
(keys == ["id", "name", "sha256", "size"]) and
|
||||
(.id |
|
||||
type == "number" and . > 0 and
|
||||
. <= 9007199254740991 and . == floor) and
|
||||
(.name |
|
||||
type == "string" and length > 0 and
|
||||
. != "." and . != ".." and
|
||||
(contains("/") | not) and
|
||||
(contains("\\") | not) and
|
||||
(explode | all(.[]; . > 31 and . != 127))) and
|
||||
(.sha256 |
|
||||
type == "string" and test("^[a-f0-9]{64}$")) and
|
||||
(.size |
|
||||
type == "number" and . > 0 and
|
||||
. <= 9007199254740991 and . == floor))) and
|
||||
([.assets[].name] | length == (unique | length)) and
|
||||
([.assets[] |
|
||||
select(.name == "linux-frame-copy-runtime-sources.tar.xz")] |
|
||||
length == 1) and
|
||||
([.assets[] | select(.name | endswith(".snap"))] |
|
||||
length >= 1) and
|
||||
(.assets | all(.[];
|
||||
.name == "linux-frame-copy-runtime-sources.tar.xz" or
|
||||
(.name | endswith(".snap"))))
|
||||
' "${RECEIPT_PATH}" > /dev/null
|
||||
RECEIPT_ASSET_COUNT="$(/usr/bin/jq --raw-output '.assets | length' "${RECEIPT_PATH}")"
|
||||
test "${RECEIPT_ASSET_COUNT}" -eq "$(( ${#TRANSFERRED_SNAPS[@]} + 1 ))"
|
||||
SIZE_MANIFEST="${RUNNER_TEMP}/verified-release-asset-sizes.tsv"
|
||||
CHECKSUM_MANIFEST="${RUNNER_TEMP}/verified-release-asset-checksums.txt"
|
||||
umask 077
|
||||
/usr/bin/jq --raw-output \
|
||||
'.assets[] | [.name, (.size | tostring)] | @tsv' \
|
||||
"${RECEIPT_PATH}" > "${SIZE_MANIFEST}"
|
||||
while IFS=$'\t' read -r ASSET_NAME EXPECTED_SIZE; do
|
||||
ASSET_PATH="${TRANSFERRED_ASSET_DIRECTORY}/${ASSET_NAME}"
|
||||
ACTUAL_SIZE="$(/usr/bin/stat --format=%s -- "${ASSET_PATH}")"
|
||||
test "${ACTUAL_SIZE}" = "${EXPECTED_SIZE}"
|
||||
done < "${SIZE_MANIFEST}"
|
||||
/usr/bin/jq --raw-output \
|
||||
'.assets[] | "\(.sha256) \(.name)"' \
|
||||
"${RECEIPT_PATH}" > "${CHECKSUM_MANIFEST}"
|
||||
(
|
||||
cd "${TRANSFERRED_ASSET_DIRECTORY}"
|
||||
/usr/bin/sha256sum --strict --check "${CHECKSUM_MANIFEST}"
|
||||
)
|
||||
rm -f "${SIZE_MANIFEST}" "${CHECKSUM_MANIFEST}"
|
||||
shopt -u nullglob dotglob
|
||||
sudo test ! -e "${SEALED_ASSET_PARENT}"
|
||||
sudo install -d -m 0700 -o root -g root "${SEALED_ASSET_PARENT}"
|
||||
sudo mv "${TRANSFERRED_ASSET_DIRECTORY}" "${SEALED_ASSET_DIRECTORY}"
|
||||
sudo chown -R root:root "${SEALED_ASSET_DIRECTORY}"
|
||||
sudo find "${SEALED_ASSET_DIRECTORY}" -type d -exec chmod 0555 {} +
|
||||
sudo find "${SEALED_ASSET_DIRECTORY}" -type f -exec chmod 0444 {} +
|
||||
sudo chmod 0555 "${SEALED_ASSET_PARENT}"
|
||||
|
||||
- name: Install Snapcraft
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
sudo snap install snapcraft --classic --channel=stable
|
||||
|
||||
- name: Publish all public-release snaps to edge
|
||||
shell: bash
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.snapcraft_token }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
VERIFIED_ASSET_DIRECTORY="/var/lib/iptvnator-snap-release/assets"
|
||||
STORE_CREDENTIALS="${SNAPCRAFT_STORE_CREDENTIALS}"
|
||||
unset SNAPCRAFT_STORE_CREDENTIALS
|
||||
shopt -s nullglob dotglob
|
||||
SNAP_FILES=("${VERIFIED_ASSET_DIRECTORY}"/*.snap)
|
||||
test "${#SNAP_FILES[@]}" -gt 0
|
||||
for SNAP_FILE in "${SNAP_FILES[@]}"; do
|
||||
SNAP_NAME="${SNAP_FILE##*/}"
|
||||
echo "Publishing public release asset: ${SNAP_NAME}"
|
||||
# Candidate/stable promotion is manual after installed-Snap frame-copy and missing-runtime fallback smoke.
|
||||
# GitHub Actions never promotes automatically.
|
||||
SNAPCRAFT_STORE_CREDENTIALS="${STORE_CREDENTIALS}" /snap/bin/snapcraft upload --release=edge "${SNAP_FILE}"
|
||||
done
|
||||
unset STORE_CREDENTIALS
|
||||
shopt -u nullglob dotglob
|
||||
Reference in new issue
Block a user