# Release pipeline for the Linux fork.
#
# The runner exports the repo with `git archive`, which does NOT include submodule
# contents - which is why the transform plugins are vendored at Transforms/ rather
# than pulled from the IFSTransforms submodule.
#
# `artifacts:` is files-only (no globs, no directory walk), so each artifact must
# be a single file. A listed file that does not exist fails the publish, so only
# steps proven to produce their output belong here.
steps:
- name: Environment
run: 'echo "HOME=[$HOME]"; echo "USER=[$(id -un)]"; echo "PWD=[$(pwd)]"; echo "PATH=[$PATH]"; echo "--- dotnet ---"; ls -la "$HOME/.dotnet/dotnet" 2>&1; command -v dotnet 2>&1; echo "--- tree ---"; ls'
timeout: 60
# UI regression suite. Headless Avalonia - no display server, no GPU - so it runs
# anywhere the build does. Same log-to-file pattern as the build below, because the
# runner discards output from a failing step.
- name: Run UI regression tests
run: sh packaging/run-tests.sh > test.log 2>&1 || true
timeout: 600
- name: Test log
run: tail -40 test.log
timeout: 60
# Gate the release on the suite: a red test must not produce an artifact.
- name: Verify tests passed
run: grep -qE "^ *Passed! " test.log
timeout: 60
# The runner appears to discard output from a FAILING step, so the build writes
# to a file and a separate (always-succeeding) step prints it. The artifact
# check is then its own step, so a failure still leaves the log visible.
- name: Build release tarball
run: sh packaging/build-tarball.sh > build.log 2>&1 || true
timeout: 900
- name: Build log
run: tail -60 build.log
timeout: 60
- name: Build AppImage
run: sh packaging/build-appimage.sh > appimage.log 2>&1 || true
timeout: 600
- name: AppImage log
run: tail -25 appimage.log
timeout: 60
- name: Verify artifacts
run: test -f dist/ifsrenderer-linux-x86_64.tar.gz && test -f dist/IFSRenderer-x86_64.AppImage
timeout: 60
# Stage the layout `pear install` expects, so the published drive is directly
# installable: /package.json + /by-arch/<platform>-<arch>/app/<name>.AppImage.
#
# The name must be `ifsrenderer`, NOT a prettier productName: pear install
# derives appName from `productName ?? name`, then extracts `<appName>.desktop`
# from the AppImage and THROWS if it is absent. The AppImage carries
# `ifsrenderer.desktop`, so those two have to agree.
- name: Stage pear-install layout
run: |
mkdir -p by-arch/linux-x64/app
cp dist/IFSRenderer-x86_64.AppImage by-arch/linux-x64/app/ifsrenderer.AppImage
printf '{\n "name": "ifsrenderer",\n "version": "%s"\n}\n' "${GIT_COMMIT_SHORT:-dev}" > package.json
ls -la by-arch/linux-x64/app package.json
timeout: 120
artifacts:
- dist/ifsrenderer-linux-x86_64.tar.gz
- dist/IFSRenderer-x86_64.AppImage
- by-arch
- package.json
# Publish each release into this repo's virtual Hyperdrive as well, so it has a
# durable pear:// link. The drive stores pointers, not bytes: three real 49MB
# AppImage builds measured 519KB of drive for 148MB of input.
vdrive: true
channels:
experimental:
branches: [linux-port, master]
production:
tags: ["v*"]
# vdrive second-release check 2026-08-25T00:10Z