Files
openless/.github/workflows/release-linux-egui.yml
T
16c3f841b5 chore(release): prepare 2.0.0-Beta.2 build 20260924
Integrate the reviewed 2.0 PRs and local fixes from 03136853.
Preserve the verified subtitle behavior and model/runtime corrections.
Keep the numeric Beta tag compatible with released clients while exposing
the date as application build metadata.

Co-authored-by: DepengWang <2818245+DepengWang@users.noreply.github.com>
Co-authored-by: HKLHaoBin <we3q@qq.com>
Co-authored-by: Nahida <1139500183@qq.com>
Co-authored-by: TRIP <1933142963@qq.com>
Co-authored-by: chyuwei <weichangyuwcy@gmail.com>
Co-authored-by: leonoxo <leonoxo@gmail.com>
Co-authored-by: tayir <arnoldincredible@126.com>
2026-09-24 17:28:24 +08:00

269 lines
10 KiB
YAML

name: Release Linux egui
# This workflow deliberately has no automatic tag trigger until real Ubuntu
# audio, focus/input, install, upgrade, and rollback evidence is recorded. It is
# already reusable by a release orchestrator: pass release_tag to upload verified packages.
on:
workflow_dispatch:
inputs:
release_tag:
description: Existing GitHub release tag to receive Linux assets; blank only uploads Actions artifacts
required: false
type: string
workflow_call:
inputs:
release_tag:
required: false
type: string
secrets:
LINUX_EGUI_MINISIGN_SECRET_KEY:
required: false
permissions:
contents: write
jobs:
build-linux-egui:
runs-on: ubuntu-22.04
env:
RELEASE_TAG: ${{ inputs.release_tag }}
steps:
- uses: actions/checkout@v4
with:
submodules: false
- name: Install native build and packaging dependencies
run: |
sudo add-apt-repository -y universe || true
sudo apt-get update
sudo apt-get install -y \
appstream \
build-essential \
cmake \
clang \
desktop-file-utils \
extra-cmake-modules \
fcitx5-modules-dev \
file \
fuse \
libasound2-dev \
libdbus-1-dev \
libfcitx5config-dev \
libfcitx5core-dev \
libfcitx5utils-dev \
libopenblas-dev \
libkf5globalaccel-dev \
qtbase5-dev \
libatspi2.0-dev \
pulseaudio-utils \
fonts-noto-cjk \
libssl-dev \
libwayland-dev \
libx11-dev \
libxkbcommon-dev \
patchelf \
pkg-config \
ripgrep \
rpm \
ruby-dev \
wget
sudo gem install --no-document fpm -v 1.16.0
- name: Install appimagetool
env:
APPIMAGETOOL_SHA256: b90f4a8b18967545fda78a445b27680a1642f1ef9488ced28b65398f2be7add2
run: |
wget -q https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage \
-O /tmp/appimagetool
echo "$APPIMAGETOOL_SHA256 /tmp/appimagetool" | sha256sum --check --strict
chmod +x /tmp/appimagetool
sudo install -m 0755 /tmp/appimagetool /usr/local/bin/appimagetool
file /usr/local/bin/appimagetool | grep -q ELF
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: '1.94.0'
components: clippy
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
cache-dependency-path: openless-all/app/package-lock.json
- name: Build React baseline and generate native locale catalog
working-directory: openless-all/app
run: |
npm ci
npm run build
node ../scripts/sync-egui-locales.mjs
- name: Build GNOME and KDE desktop integration
run: |
node openless-all/scripts/linux-desktop/gnome/build.mjs
cmake -S openless-all/scripts/linux-desktop/kde -B openless-all/scripts/linux-desktop/kde/build -DCMAKE_BUILD_TYPE=Release
cmake --build openless-all/scripts/linux-desktop/kde/build --parallel
- name: Cache Cargo
uses: swatinem/rust-cache@v2
with:
workspaces: 'openless-all/app -> target'
- name: Build fcitx5 plugin
working-directory: openless-all/scripts/linux-fcitx5-plugin
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build --parallel
ctest --test-dir build --output-on-failure
test -s build/libopenless.so
test -s build/openless.conf
- name: Checkout pinned Qwen ASR runtime source
run: git submodule update --init --depth 1 -- openless-all/app/src-tauri/vendor/qwen-asr
- name: Build portable Qwen ASR runtime
working-directory: openless-all/app/src-tauri/vendor/qwen-asr
run: |
make blas CFLAGS_BASE="-Wall -Wextra -O3 -ffast-math -mtune=generic"
test -x qwen_asr
./qwen_asr --help >/dev/null 2>&1
- name: Verify framework-independent Linux contract
working-directory: openless-all/app
shell: bash
run: |
set -euo pipefail
cargo test --locked -p openless-core
cargo clippy --locked -p openless-core --all-targets -- -D warnings
cargo test --locked -p openless-linux-egui --lib --test host_contract
cargo check --locked -p openless-linux-egui --all-targets
pwsh -NoProfile -File ./scripts/check-core-deps.ps1
pwsh -NoProfile -File ./scripts/check-core-deps.ps1 openless-linux-egui
pwsh -NoProfile -File ./scripts/check-core-secret-surface.ps1
pwsh -NoProfile -File ./scripts/check-core-test-isolation.ps1
pwsh -NoProfile -File ./scripts/check-core-runtime-seam.ps1
pwsh -NoProfile -File ./scripts/check-linux-public-surface.ps1
- name: Validate release target and UI gate
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [ -z "${RELEASE_TAG:-}" ]; then
exit 0
fi
case "$RELEASE_TAG" in
v*-tauri) ;;
*)
echo "::error::release_tag must name an existing v*-tauri release"
exit 1
;;
esac
if grep -q 'openless-linux-egui host stub' openless-all/app/linux-egui/src/main.rs; then
echo "::error::The egui UI stub cannot be uploaded as a release asset"
exit 1
fi
gh release view "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" >/dev/null
- name: Validate Linux desktop metadata
run: |
desktop-file-validate openless-all/app/linux-egui/packaging/openless.desktop
appstreamcli validate --no-net openless-all/app/linux-egui/packaging/top.openless.OpenLess.metainfo.xml
- name: Build Linux egui host
working-directory: openless-all/app
run: cargo build --locked --release -p openless-linux-egui
- name: Resolve package version
id: version
shell: bash
working-directory: openless-all/app
run: |
if [ -n "${RELEASE_TAG:-}" ]; then
VERSION=${RELEASE_TAG#v}
VERSION=${VERSION%-tauri}
else
VERSION=$(sed -n 's/^version = "\([^"]*\)"/\1/p' src-tauri/Cargo.toml | head -1)
fi
test -n "$VERSION"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Package deb, rpm, and AppImage without Tauri
working-directory: openless-all/app
env:
OPENLESS_LINUX_VERSION: ${{ steps.version.outputs.version }}
OPENLESS_LINUX_ARCH: x86_64
APPIMAGE_EXTRACT_AND_RUN: '1'
run: bash scripts/package-linux-egui.sh
- name: Verify package contents and ELF dependencies
working-directory: openless-all/app
run: bash scripts/verify-linux-egui-packages.sh
- name: Sign AppImage and write independent updater manifest
working-directory: openless-all/app
env:
MINISIGN_SECRET: ${{ secrets.LINUX_EGUI_MINISIGN_SECRET_KEY }}
VERSION: ${{ steps.version.outputs.version }}
run: |
OUTPUT=target/linux-egui-packages
APPIMAGE=$(find "$OUTPUT" -maxdepth 1 -name '*.AppImage' -print -quit)
if [ -n "${RELEASE_TAG:-}" ] && [ -z "${MINISIGN_SECRET:-}" ]; then
echo "::error::LINUX_EGUI_MINISIGN_SECRET_KEY is required for release upload"
exit 1
fi
if [ -n "${MINISIGN_SECRET:-}" ]; then
if ! command -v minisign >/dev/null 2>&1; then
cargo install --locked --version 0.9.1 minisign
fi
printf '%s' "$MINISIGN_SECRET" > "$RUNNER_TEMP/linux-egui.minisign.key"
minisign -S -s "$RUNNER_TEMP/linux-egui.minisign.key" -m "$APPIMAGE" -x "$APPIMAGE.minisig"
fi
SHA256=$(sha256sum "$APPIMAGE" | cut -d' ' -f1)
ASSET=$(basename "$APPIMAGE")
RELEASE_REPOSITORY="${GITHUB_REPOSITORY:-Open-Less/openless}"
SIGNATURE=null
if [ -f "$APPIMAGE.minisig" ]; then
SIGNATURE=$(base64 -w0 "$APPIMAGE.minisig" | jq -R .)
fi
jq -n \
--arg version "$VERSION" \
--arg url "https://github.com/$RELEASE_REPOSITORY/releases/download/${RELEASE_TAG:-manual}/$ASSET" \
--arg sha256 "$SHA256" \
--argjson signature "$SIGNATURE" \
'{schemaVersion:1, host:"linux-egui", arch:"x86_64", version:$version, url:$url, sha256:$sha256, minisign:$signature}' \
> "$OUTPUT/latest-linux-egui-x86_64.json"
- name: Verify Linux updater manifest matches the artifact
working-directory: openless-all/app
run: |
set -euo pipefail
OUTPUT=target/linux-egui-packages
APPIMAGE=$(find "$OUTPUT" -maxdepth 1 -name '*.AppImage' -print -quit)
MANIFEST="$OUTPUT/latest-linux-egui-x86_64.json"
test -s "$APPIMAGE"
test -s "$MANIFEST"
SHA256=$(sha256sum "$APPIMAGE" | cut -d' ' -f1)
RELEASE_REPOSITORY="${GITHUB_REPOSITORY:-Open-Less/openless}"
jq -e \
--arg sha256 "$SHA256" \
--arg repository "$RELEASE_REPOSITORY" \
'.schemaVersion == 1 and .host == "linux-egui" and .arch == "x86_64" and .sha256 == $sha256 and (.url | startswith("https://github.com/" + $repository + "/releases/download/"))' \
"$MANIFEST" >/dev/null
- name: Upload Linux egui workflow artifacts
uses: actions/upload-artifact@v4
with:
name: openless-linux-egui-x86_64
path: openless-all/app/target/linux-egui-packages/*
if-no-files-found: error
- name: Upload Linux egui assets to existing release
if: inputs.release_tag != ''
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.release_tag }}
files: openless-all/app/target/linux-egui-packages/*
fail_on_unmatched_files: true