Files
Dylan M. Taylor 4bf1b20a75 ci: add signed Linux release matrix, packaging lint, and FreeBSD CI (#2758)
Adds the complete signed Linux release matrix, FreeBSD CI, and packaging
lint to ArtCraft Studio, aligned with the Craft suite standards in
`craft-common-actions`.

| Architecture | Formats |

|:-------------|:------------------------------------------------------------------------|
| x86_64 | AppImage and zsync, DEB, RPM, tar.gz, Arch package, Flatpak
bundle, OCI |
| aarch64 | AppImage and zsync, DEB, RPM, tar.gz, Arch package, Flatpak
bundle, OCI |
| riscv64 | DEB, RPM, tar.gz |

### Changes

- **Linux Packaging Matrix**: Builds and packages ArtCraft Studio across
x86_64, aarch64, and riscv64 using `storytold/craft-common-actions`.
Produces DEB, RPM, AppImage, tarball, Arch package, and Flatpak
bundle/OCI artifacts. Cross-compiles riscv64 DEB and RPM via BoringSSL
CMake configuration. Signed Linux artifacts join existing
`artcraft-v<version>` release drafts while retaining macOS and Windows
assets (storytold/craft-common-actions#160 and #161).
- **Release Trigger Alignment**: Like macOS and Windows release
workflows, Linux release builds run on release branches (`release`,
`artcraft-release`, `artcraft-linux`) and `workflow_dispatch` rather
than on PRs.
- **Documentation**: Updated `README.md` to include Linux under download
options and reference `packaging/linux/README.md`. Added
`packaging/windows/README.md` placeholder.
- **Packaging Lint**: Added `.github/workflows/packaging-lint.yml`
calling `craft-common-actions/packaging-lint.yml@main`. Fixed
pre-existing actionlint and shellcheck issues in macOS and Windows
publish workflows (`shell: pwsh` defaults and variable quoting).
- **FreeBSD CI**: Added `.github/workflows/freebsd.yml` calling
`craft-common-actions/freebsd.yml@main` on scheduled nightly runs,
release branches, and manual dispatch (not on pull requests).
- **SQLx Build Fallback**: Updated
`crates/schema/database/sqlite_tasks/build.rs` to fall back to
`SQLX_OFFLINE=true` using committed `.sqlx/` query data when no live
`/tmp/tasks.sqlite` database file exists, fixing nextest coverage
archives under CI.

### Validation

- `actionlint` passes cleanly across all `.github/workflows/*.yml`
files.
- `shellcheck` passes across all scripts in `packaging/linux/*.sh`.
- `xmllint` validates `packaging/linux/ai.artcraft.app.metainfo.xml`.
- `cargo check -p sqlite_tasks`, `cargo test -p sqlite_tasks`, and
`cargo test --no-run -p sqlite_tasks` pass locally without database
environment variables.
- Packaging lint passes 100% green on CI.
- SonarCloud / nextest instrumented test archive build passes on CI.
- Linux package scripts (`package.sh`, `package-test.sh`, `flatpak.sh`)
verified locally and on CI runners.
2026-11-06 20:02:06 -05:00

55 lines
2.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Normalize Tauri packages and derive the suite's bin/share tarball from its Debian package.
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
arch="${1:?architecture required}"
target="${2:?Rust target required}"
version="$(jq -r .version crates/desktop/artcraft/tauri.conf.json)"
case "$arch" in x86_64|aarch64|riscv64) ;; *) exit 2 ;; esac
base="artcraft-$version-linux-$arch"
bundle="target/$target/release/bundle"
mkdir -p dist/release
for format in deb rpm AppImage; do
mapfile -t files < <(find "$bundle" -type f -name "*.$format")
if [[ "$arch" == riscv64 && "$format" == AppImage ]]; then continue; fi
[[ ${#files[@]} == 1 ]] || { echo "Expected one $format in $bundle, found ${#files[@]}" >&2; exit 1; }
cp "${files[0]}" "dist/release/$base.$format"
done
if [[ "$arch" != riscv64 ]]; then
zsyncmake -u "https://github.com/storytold/artcraft/releases/download/artcraft-v$version/$base.AppImage" \
-o "dist/release/$base.AppImage.zsync" "dist/release/$base.AppImage"
fi
work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT
dpkg-deb -x "dist/release/$base.deb" "$work/deb"
mkdir -p "$work/$base"
cp -a "$work/deb/usr/." "$work/$base/"
mapfile -t desktops < <(find "$work/$base/share/applications" -name '*.desktop')
[[ ${#desktops[@]} == 1 ]] || { echo 'Expected one desktop entry' >&2; exit 1; }
if [[ "${desktops[0]}" != "$work/$base/share/applications/ai.artcraft.app.desktop" ]]; then
mv "${desktops[0]}" "$work/$base/share/applications/ai.artcraft.app.desktop"
fi
install -Dm644 "$script_dir/ai.artcraft.app.metainfo.xml" "$work/$base/share/metainfo/ai.artcraft.app.metainfo.xml"
sed -i 's/^Name=.*/Name=ArtCraft Studio/' "$work/$base/share/applications/ai.artcraft.app.desktop"
test -x "$work/$base/bin/artcraft"
case "$arch" in
x86_64) machine='Advanced Micro Devices X86-64' ;;
aarch64) machine='AArch64' ;;
riscv64) machine='RISC-V' ;;
esac
readelf -h "$work/$base/bin/artcraft" | grep -F "$machine"
if [[ "$arch" == "$(uname -m)" ]]; then
dependencies="$(ldd "$work/$base/bin/artcraft")"
if grep -q 'not found' <<< "$dependencies"; then
printf '%s\n' "$dependencies" >&2
exit 1
fi
fi
# The tarball layout is consumed by the launcher, Arch packaging and Flatpak.
tar -czf "dist/release/$base.tar.gz" -C "$work" "$base"
case "$arch" in x86_64) deb_arch=amd64 ;; aarch64) deb_arch=arm64 ;; riscv64) deb_arch=riscv64 ;; esac
[[ "$(dpkg-deb -f "dist/release/$base.deb" Architecture)" == "$deb_arch" ]]
[[ "$(rpm -qp --qf '%{ARCH}' "dist/release/$base.rpm")" == "$arch" ]]
dpkg-deb --info "dist/release/$base.deb"
rpm -qp --requires "dist/release/$base.rpm"