mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-07 06:40:09 -05:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87448cf858 | ||
|
|
b4026c4f23 |
@@ -0,0 +1,194 @@
|
||||
name: ArtCraft Linux release
|
||||
on:
|
||||
push:
|
||||
branches: [release, artcraft-release, artcraft-linux]
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: read
|
||||
concurrency:
|
||||
group: linux-release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
jobs:
|
||||
packaging-check:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: storytold/craft-common-actions/actions/install-apt-packages@main
|
||||
with:
|
||||
packages: rpm jq binutils zsync
|
||||
- run: packaging/linux/package-test.sh
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {arch: x86_64, runner: ubuntu-22.04, target: x86_64-unknown-linux-gnu, bundles: "deb,rpm,appimage"}
|
||||
- {arch: aarch64, runner: ubuntu-22.04-arm, target: aarch64-unknown-linux-gnu, bundles: "deb,rpm,appimage"}
|
||||
- {arch: riscv64, runner: ubuntu-24.04, target: riscv64gc-unknown-linux-gnu, bundles: "deb,rpm"}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
SQLX_OFFLINE: 'true'
|
||||
VITE_ENVIRONMENT_TYPE: production
|
||||
TAURI_FRONTEND_PATH: ${{ github.workspace }}/frontend
|
||||
TAURI_APP_PATH: ${{ github.workspace }}/crates/desktop/artcraft
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: storytold/craft-common-actions/actions/install-apt-packages@main
|
||||
with:
|
||||
packages: libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev libclang-dev libasound2-dev libxdo-dev libdbus-1-dev build-essential clang file jq perl cmake nasm rpm zsync gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-libav
|
||||
- uses: storytold/craft-common-actions/actions/install-riscv64-cross@main
|
||||
if: matrix.arch == 'riscv64'
|
||||
- name: Remove conflicting host Pango development files
|
||||
if: matrix.arch == 'riscv64'
|
||||
# Ubuntu's Pango GIR differs by architecture despite being in a shared path.
|
||||
# Only the target GTK development packages are needed for this cross build.
|
||||
run: sudo apt-get remove -y libpango1.0-dev:amd64
|
||||
- name: Install RISC-V WebKitGTK dependencies
|
||||
if: matrix.arch == 'riscv64'
|
||||
uses: storytold/craft-common-actions/actions/install-apt-packages@main
|
||||
with:
|
||||
packages: libwebkit2gtk-4.1-dev:riscv64 libappindicator3-dev:riscv64 libssl-dev:riscv64 libxdo-dev:riscv64 libdbus-1-dev:riscv64 g++-riscv64-linux-gnu
|
||||
- name: Configure RISC-V cross compilation
|
||||
if: matrix.arch == 'riscv64'
|
||||
run: |
|
||||
cat >> "$GITHUB_ENV" <<'ENV'
|
||||
CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc
|
||||
CC_riscv64gc_unknown_linux_gnu=riscv64-linux-gnu-gcc
|
||||
CXX_riscv64gc_unknown_linux_gnu=riscv64-linux-gnu-g++
|
||||
AR_riscv64gc_unknown_linux_gnu=riscv64-linux-gnu-ar
|
||||
PKG_CONFIG_ALLOW_CROSS=1
|
||||
PKG_CONFIG_PATH_riscv64gc_unknown_linux_gnu=/usr/lib/riscv64-linux-gnu/pkgconfig:/usr/share/pkgconfig
|
||||
PKG_CONFIG_LIBDIR_riscv64gc_unknown_linux_gnu=/usr/lib/riscv64-linux-gnu/pkgconfig:/usr/share/pkgconfig
|
||||
ENV
|
||||
echo "CMAKE_TOOLCHAIN_FILE_riscv64gc_unknown_linux_gnu=$GITHUB_WORKSPACE/packaging/linux/riscv64.cmake" >> "$GITHUB_ENV"
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: npm
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
- uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # v1
|
||||
with:
|
||||
toolchain: stable
|
||||
targets: ${{ matrix.target }}
|
||||
- uses: Swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0 # v2.9.3
|
||||
with:
|
||||
key: tauri-linux-${{ matrix.arch }}
|
||||
cache-on-failure: true
|
||||
- run: npm ci --ignore-scripts
|
||||
working-directory: frontend
|
||||
- run: ./node_modules/.bin/nx run artcraft:build
|
||||
working-directory: frontend
|
||||
- uses: tauri-apps/tauri-action@fce9c6108b31ea247710505d3aaaa893ee6768d4 # v0
|
||||
with:
|
||||
projectPath: crates/desktop/artcraft
|
||||
args: --target ${{ matrix.target }} --bundles ${{ matrix.bundles }} --config ${{ github.workspace }}/packaging/linux/tauri.conf.json
|
||||
- name: Package and verify Linux outputs
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
TARGET: ${{ matrix.target }}
|
||||
run: packaging/linux/package.sh "$ARCH" "$TARGET"
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-linux-${{ matrix.arch }}
|
||||
path: dist/release/*
|
||||
if-no-files-found: error
|
||||
arch:
|
||||
if: always() && !cancelled()
|
||||
needs: build
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [x86_64, aarch64]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-linux-${{ matrix.arch }}
|
||||
path: dist/linux
|
||||
- name: Find tarball
|
||||
id: tarball
|
||||
env:
|
||||
ARCH: ${{ matrix.arch }}
|
||||
run: |
|
||||
shopt -s nullglob
|
||||
files=(dist/linux/artcraft-*-linux-"$ARCH".tar.gz)
|
||||
test "${#files[@]}" -eq 1
|
||||
echo "path=${files[0]}" >> "$GITHUB_OUTPUT"
|
||||
- uses: storytold/craft-common-actions/actions/arch-package@9d6790582b4997aa2120f4413cdb55c0b6f77fae # extra-depends support (#161)
|
||||
with:
|
||||
tarball: ${{ steps.tarball.outputs.path }}
|
||||
arch: ${{ matrix.arch }}
|
||||
extra-depends: webkit2gtk-4.1 gtk3 openssl
|
||||
- name: Verify Arch runtime dependencies
|
||||
run: |
|
||||
for package in dist/release/*.pkg.tar.zst; do
|
||||
tar --zstd -xOf "$package" .PKGINFO | grep -Fx 'depend = webkit2gtk-4.1'
|
||||
done
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-arch-${{ matrix.arch }}
|
||||
path: dist/release/*.pkg.tar.zst
|
||||
if-no-files-found: error
|
||||
flatpak:
|
||||
if: always() && !cancelled()
|
||||
needs: build
|
||||
runs-on: ${{ matrix.runner }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- {arch: x86_64, runner: ubuntu-24.04}
|
||||
- {arch: aarch64, runner: ubuntu-24.04-arm}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-linux-${{ matrix.arch }}
|
||||
path: dist/linux
|
||||
- uses: storytold/craft-common-actions/actions/install-apt-packages@main
|
||||
with:
|
||||
packages: flatpak flatpak-builder elfutils librsvg2-common skopeo
|
||||
- name: Allow Flatpak build sandboxes
|
||||
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||
- uses: storytold/craft-common-actions/actions/import-signing-key@main
|
||||
with:
|
||||
key: ${{ secrets.LINUX_SIGNING_KEY }}
|
||||
- name: Build Flatpak and publish OCI
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: packaging/linux/flatpak.sh
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-flatpak-${{ matrix.arch }}
|
||||
path: |
|
||||
dist/release/*.flatpak
|
||||
dist/release/*.oci-manifest.json
|
||||
if-no-files-found: error
|
||||
release:
|
||||
needs: [packaging-check, build, arch, flatpak]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Read version
|
||||
id: version
|
||||
run: echo "value=$(jq -r .version crates/desktop/artcraft/tauri.conf.json)" >> "$GITHUB_OUTPUT"
|
||||
- name: Require signing key
|
||||
env:
|
||||
SIGNING_KEY: ${{ secrets.LINUX_SIGNING_KEY }}
|
||||
run: test -n "$SIGNING_KEY"
|
||||
- uses: storytold/craft-common-actions/actions/draft-release@main
|
||||
with:
|
||||
version: ${{ steps.version.outputs.value }}
|
||||
app-title: ArtCraft
|
||||
tag-prefix: artcraft-v
|
||||
retain: "true"
|
||||
allow-published: "true"
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
signing-key: ${{ secrets.LINUX_SIGNING_KEY }}
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
echo "Starting certificate import process..."
|
||||
|
||||
# Create certificate file
|
||||
echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12
|
||||
echo "$APPLE_CERTIFICATE" | base64 --decode > certificate.p12
|
||||
|
||||
# Debug: Check if certificate file exists and has content
|
||||
echo "Certificate file info:"
|
||||
@@ -93,25 +93,25 @@ jobs:
|
||||
|
||||
# Debug: Check certificate contents without password (just structure)
|
||||
echo "Certificate structure (may show error if password protected):"
|
||||
openssl pkcs12 -info -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -noout || echo "Could not read certificate structure"
|
||||
openssl pkcs12 -info -in certificate.p12 -passin pass:"$APPLE_CERTIFICATE_PASSWORD" -noout || echo "Could not read certificate structure"
|
||||
|
||||
# Debug: Try to list what's in the p12 file
|
||||
echo "Attempting to list certificate contents:"
|
||||
security cms -D -i certificate.p12 || echo "Not a CMS file, trying PKCS12..."
|
||||
openssl pkcs12 -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -info -nodes 2>&1 | head -20 || echo "Failed to read PKCS12 contents"
|
||||
openssl pkcs12 -in certificate.p12 -passin pass:"$APPLE_CERTIFICATE_PASSWORD" -info -nodes 2>&1 | head -20 || echo "Failed to read PKCS12 contents"
|
||||
|
||||
# Debug: Extract certificate details to verify type and expiration
|
||||
echo "Extracting certificate details..."
|
||||
# Extract just the certificate portion and examine it
|
||||
openssl pkcs12 -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -nokeys 2>/dev/null | openssl x509 -text -noout | grep -E "(Subject:|Issuer:|Not Before|Not After)" || echo "Failed to parse certificate details"
|
||||
openssl pkcs12 -in certificate.p12 -passin pass:"$APPLE_CERTIFICATE_PASSWORD" -nokeys 2>/dev/null | openssl x509 -text -noout | grep -E "(Subject:|Issuer:|Not Before|Not After)" || echo "Failed to parse certificate details"
|
||||
|
||||
# Also try to see what type of certificate this is
|
||||
echo "Certificate type check:"
|
||||
openssl pkcs12 -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -nokeys 2>/dev/null | openssl x509 -text -noout | grep -E "(CN=|OU=)" || echo "Could not determine certificate type"
|
||||
openssl pkcs12 -in certificate.p12 -passin pass:"$APPLE_CERTIFICATE_PASSWORD" -nokeys 2>/dev/null | openssl x509 -text -noout | grep -E "(CN=|OU=)" || echo "Could not determine certificate type"
|
||||
|
||||
# Debug: Check if private key exists
|
||||
echo "Checking for private key..."
|
||||
openssl pkcs12 -in certificate.p12 -passin pass:$APPLE_CERTIFICATE_PASSWORD -nocerts -nodes 2>&1 | grep -E "(PRIVATE KEY|RSA KEY)" | head -5 || echo "No private key found"
|
||||
openssl pkcs12 -in certificate.p12 -passin pass:"$APPLE_CERTIFICATE_PASSWORD" -nocerts -nodes 2>&1 | grep -E "(PRIVATE KEY|RSA KEY)" | head -5 || echo "No private key found"
|
||||
|
||||
# Create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
@@ -139,6 +139,7 @@ jobs:
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
# Add the keychain to the search list
|
||||
# shellcheck disable=SC2046
|
||||
security list-keychains -d user -s build.keychain $(security list-keychains -d user | sed 's/^[[:space:]]*"//;s/"$//')
|
||||
|
||||
# List all certificates to debug
|
||||
@@ -181,11 +182,11 @@ jobs:
|
||||
security find-certificate -c "Learning Machines" build.keychain -p | openssl x509 -text -noout | grep -E "(Subject:|CN=)" || echo "Could not parse certificate"
|
||||
|
||||
# Set the correct signing identity
|
||||
echo "APPLE_SIGNING_IDENTITY=Developer ID Application: Learning Machines LLC (DJ6XS33FX8)" >> $GITHUB_ENV
|
||||
echo "APPLE_SIGNING_IDENTITY=Developer ID Application: Learning Machines LLC (DJ6XS33FX8)" >> "$GITHUB_ENV"
|
||||
echo "Proceeding with identity: Developer ID Application: Learning Machines LLC (DJ6XS33FX8)"
|
||||
|
||||
# Also set the team ID
|
||||
echo "APPLE_DEVELOPMENT_TEAM=DJ6XS33FX8" >> $GITHUB_ENV
|
||||
echo "APPLE_DEVELOPMENT_TEAM=DJ6XS33FX8" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Pre-build frontend to avoid Tauri build issues
|
||||
run: |
|
||||
@@ -200,6 +201,7 @@ jobs:
|
||||
npx nx run artcraft:build
|
||||
|
||||
echo "Checking build output..."
|
||||
# shellcheck disable=SC2012
|
||||
ls -la apps/artcraft/dist/ | head -10
|
||||
|
||||
# Update Tauri config to skip the build (since we already built)
|
||||
|
||||
@@ -44,6 +44,7 @@ jobs:
|
||||
node-version: lts/*
|
||||
|
||||
- name: install frontend dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
# Navigate to the frontend directory to install dependencies
|
||||
cd ./frontend
|
||||
@@ -63,6 +64,7 @@ jobs:
|
||||
npm list --depth=0 | findstr nx
|
||||
|
||||
- name: Pre-build frontend to avoid Tauri build issues
|
||||
shell: pwsh
|
||||
run: |
|
||||
# Build the frontend app from the correct directory
|
||||
cd ./frontend
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Builds and tests the workspace on FreeBSD, inside a FreeBSD VM on a Linux runner
|
||||
# (GitHub has no FreeBSD runners).
|
||||
name: FreeBSD
|
||||
|
||||
# The VM build is slow, so it runs nightly on main and on pushes to `release`, not on pull requests.
|
||||
on:
|
||||
schedule:
|
||||
- cron: "27 4 * * *"
|
||||
push:
|
||||
branches: [release]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: freebsd-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
freebsd:
|
||||
# Intentionally tracked at @main (not SHA-pinned) so org-wide CI improvements, security fixes, and build optimizations propagate without PR churn across all craftapp repos.
|
||||
uses: storytold/craft-common-actions/.github/workflows/freebsd.yml@main
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Quick static checks for the release pipeline (seconds, no Rust build): workflow syntax,
|
||||
# packaging shell/PowerShell scripts, and the Linux desktop/AppStream/Flatpak metadata.
|
||||
name: Packaging lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, release]
|
||||
paths: [".github/workflows/**", "packaging/**"]
|
||||
pull_request:
|
||||
paths: [".github/workflows/**", "packaging/**"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: packaging-lint-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
# Intentionally tracked at @main (not SHA-pinned) so org-wide CI improvements, security fixes, and build optimizations propagate without PR churn across all craftapp repos.
|
||||
uses: storytold/craft-common-actions/.github/workflows/packaging-lint.yml@main
|
||||
@@ -1,7 +1,20 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn main() {
|
||||
println!("cargo:rerun-if-env-changed=DATABASE_URL");
|
||||
println!("cargo:rerun-if-env-changed=SQLX_OFFLINE");
|
||||
|
||||
if let Ok(url) = env::var("DATABASE_URL") {
|
||||
println!("cargo:rustc-env=DATABASE_URL={}", url);
|
||||
return;
|
||||
}
|
||||
|
||||
if env::var("SQLX_OFFLINE").as_deref() == Ok("true") || env::var("SQLX_OFFLINE").as_deref() == Ok("1") {
|
||||
println!("cargo:rustc-env=SQLX_OFFLINE=true");
|
||||
return;
|
||||
}
|
||||
|
||||
// NB: This should help JetBrains' RustRover from highlighting failing query macros,
|
||||
// but we do not want to interfere with the following:
|
||||
//
|
||||
@@ -14,27 +27,29 @@ pub fn main() {
|
||||
Some("unix") => unix_temp_database_pathing(),
|
||||
Some("windows") => windows_temp_database_pathing(),
|
||||
_ => {
|
||||
println!("cargo:warning=Unsupported target family, using Unix temp database pathing.");
|
||||
unix_temp_database_pathing();
|
||||
println!("cargo:rustc-env=SQLX_OFFLINE=true");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn unix_temp_database_pathing() {
|
||||
println!("cargo:rustc-env=DATABASE_URL=sqlite:/tmp/tasks.sqlite");
|
||||
println!("cargo:rerun-if-changed=/tmp/tasks.sqlite");
|
||||
if Path::new("/tmp/tasks.sqlite").exists() {
|
||||
println!("cargo:rustc-env=DATABASE_URL=sqlite:/tmp/tasks.sqlite");
|
||||
} else {
|
||||
println!("cargo:rustc-env=SQLX_OFFLINE=true");
|
||||
}
|
||||
}
|
||||
|
||||
fn windows_temp_database_pathing() {
|
||||
if let Ok(local_app_data) = env::var("LOCALAPPDATA") {
|
||||
let path = PathBuf::from(local_app_data);
|
||||
let path = path.join("Temp\\tasks.sqlite");
|
||||
let path = path
|
||||
.to_str()
|
||||
.expect("path should be valid")
|
||||
.to_string();
|
||||
println!("cargo:warning=LocalAppData path: {}", path);
|
||||
println!("cargo:rustc-env=DATABASE_URL=sqlite:{}", path);
|
||||
} else {
|
||||
panic!("LOCALAPPDATA environment variable not set");
|
||||
let path = PathBuf::from(local_app_data).join("Temp\\tasks.sqlite");
|
||||
if path.exists() {
|
||||
let path_str = path.to_str().expect("path should be valid");
|
||||
println!("cargo:warning=LocalAppData path: {}", path_str);
|
||||
println!("cargo:rustc-env=DATABASE_URL=sqlite:{}", path_str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
println!("cargo:rustc-env=SQLX_OFFLINE=true");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# ArtCraft Studio Linux releases
|
||||
|
||||
The Linux workflow builds every package before the release job signs and uploads them to the
|
||||
existing `artcraft-v<version>` draft, retaining Windows and macOS assets. The version comes from
|
||||
`crates/desktop/artcraft/tauri.conf.json`.
|
||||
|
||||
| Architecture | Outputs | Builder |
|
||||
|--------------|---------------------------------------------------------------|----------------------------|
|
||||
| x86_64 | AppImage, DEB, RPM, tar.gz, Arch pkg.tar.zst, Flatpak bundle, OCI | Ubuntu 22.04 native |
|
||||
| aarch64 | AppImage, DEB, RPM, tar.gz, Arch pkg.tar.zst, Flatpak bundle, OCI | Ubuntu 22.04 ARM native |
|
||||
| riscv64 | DEB, RPM, tar.gz | Ubuntu 24.04 cross compiler |
|
||||
|
||||
Native AppImages also include zsync delta-update metadata.
|
||||
|
||||
Flatpak uses native Ubuntu 24.04 runners and GNOME 51 for GTK3/WebKitGTK 4.1. Its build checks
|
||||
for missing ELF dependencies inside the sandbox. RISC-V packages require Ubuntu 24.04-era
|
||||
libraries; x86_64 and ARM64 use Ubuntu 22.04 as their build baseline. The suite does not publish
|
||||
RISC-V AppImages, Arch packages or Flatpaks.
|
||||
|
||||
`package.sh <architecture> <rust-target>` normalizes Tauri's DEB/RPM/AppImage filenames and
|
||||
extracts the DEB's `/usr` tree into the suite's `bin/` and `share/` tarball layout. Shared Craft
|
||||
Arch packaging consumes that tarball, with WebKitGTK, GTK3 and OpenSSL dependencies added.
|
||||
`flatpak.sh` consumes the same tarball, builds the bundle, and exports the OCI layout.
|
||||
|
||||
Release runs import `LINUX_SIGNING_KEY` for Flatpak commit signatures and OCI publishing. The final shared
|
||||
`draft-release` action signs RPMs, DEBs, Arch packages, AppImages, tarballs, OCI manifests and
|
||||
checksums. Only a stable version on `release` or `artcraft-release` moves the OCI stable architecture tags.
|
||||
Like the macOS and Windows release workflows, Linux release packaging runs on release branches
|
||||
(`release`, `artcraft-release`, `artcraft-linux`) and workflow dispatch rather than on pull requests.
|
||||
|
||||
APT, RPM and pacman repositories are generated by `artcraft-services` from the release assets
|
||||
and checksums. Its release catalog must be updated only after the signed release is published.
|
||||
Installing a DEB manually is separate from publishing that DEB in the website's APT repository.
|
||||
|
||||
A successful build proves artifact production and metadata/dependency checks. It does not replace
|
||||
installation and interactive testing on physical RISC-V, ARM64 and x86_64 desktops.
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>ai.artcraft.app</id>
|
||||
<name>ArtCraft Studio</name>
|
||||
<summary>Create AI images and video</summary>
|
||||
<metadata_license>MIT</metadata_license>
|
||||
<project_license>MIT OR Apache-2.0</project_license>
|
||||
<description><p>ArtCraft Studio is a desktop workspace for generating AI images and video with connected AI providers.</p></description>
|
||||
<launchable type="desktop-id">ai.artcraft.app.desktop</launchable>
|
||||
<url type="homepage">https://getartcraft.com</url>
|
||||
<developer id="ai.artcraft"><name>ArtCraft</name></developer>
|
||||
<categories><category>Graphics</category><category>AudioVideo</category></categories>
|
||||
<provides><binary>artcraft</binary></provides>
|
||||
</component>
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
arch="$(uname -m)"
|
||||
version="$(jq -r .version crates/desktop/artcraft/tauri.conf.json)"
|
||||
base="artcraft-$version-linux-$arch"
|
||||
work="$(mktemp -d)"
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
mkdir -p "$work/stage" dist/release
|
||||
tar -xzf "dist/linux/$base.tar.gz" --strip-components=1 -C "$work/stage"
|
||||
cp packaging/linux/flatpak.yml "$work/manifest.yml"
|
||||
flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
sign=()
|
||||
keys=()
|
||||
if [[ -n "${SIGNING_FPR:-}" ]]; then
|
||||
sign=(--gpg-sign="$SIGNING_FPR" --gpg-homedir="$GNUPGHOME")
|
||||
gpg --batch --armor --export "$SIGNING_FPR" > "$work/public.asc"
|
||||
keys=(--gpg-keys="$work/public.asc")
|
||||
fi
|
||||
flatpak-builder --user --install-deps-from=flathub --disable-rofiles-fuse --force-clean \
|
||||
--default-branch=stable --repo="$work/repo" "${sign[@]}" "$work/build" "$work/manifest.yml"
|
||||
# Fail on missing WebKitGTK or other runtime libraries rather than shipping an unloadable binary.
|
||||
# shellcheck disable=SC2016 # Expand these variables inside the Flatpak runtime shell.
|
||||
flatpak build --runtime "$work/build" sh -c '
|
||||
dependencies=$(ldd /app/bin/artcraft) || exit 1
|
||||
printf "%s\n" "$dependencies"
|
||||
case "$dependencies" in *"not found"*) exit 1 ;; esac
|
||||
'
|
||||
flatpak build-bundle --runtime-repo=https://dl.flathub.org/repo/flathub.flatpakrepo \
|
||||
"${keys[@]}" "$work/repo" "dist/release/$base.flatpak" ai.artcraft.app stable
|
||||
flatpak build-bundle --oci "$work/repo" "dist/release/$base-oci" ai.artcraft.app stable
|
||||
skopeo inspect "oci:dist/release/$base-oci" >/dev/null
|
||||
if [[ -n "${SIGNING_FPR:-}" ]]; then
|
||||
registry="ghcr.io/${GITHUB_REPOSITORY,,}"
|
||||
creds="$GITHUB_ACTOR:$GITHUB_TOKEN"
|
||||
skopeo copy --format oci --dest-creds "$creds" "oci:dist/release/$base-oci" "docker://$registry:$version-$arch"
|
||||
if [[ "$version" != *-* && ( "$GITHUB_REF" == refs/heads/release || "$GITHUB_REF" == refs/heads/artcraft-release ) ]]; then
|
||||
skopeo copy --format oci --dest-creds "$creds" "oci:dist/release/$base-oci" "docker://$registry:stable-$arch"
|
||||
fi
|
||||
skopeo inspect --raw --creds "$creds" "docker://$registry:$version-$arch" >"dist/release/$base.oci-manifest.json"
|
||||
fi
|
||||
@@ -0,0 +1,25 @@
|
||||
app-id: ai.artcraft.app
|
||||
runtime: org.gnome.Platform
|
||||
runtime-version: '51'
|
||||
sdk: org.gnome.Sdk
|
||||
command: artcraft
|
||||
finish-args:
|
||||
- --socket=wayland
|
||||
- --socket=fallback-x11
|
||||
- --socket=pulseaudio
|
||||
- --share=ipc
|
||||
- --share=network
|
||||
- --device=dri
|
||||
- --filesystem=xdg-pictures
|
||||
- --filesystem=xdg-videos
|
||||
- --filesystem=xdg-download
|
||||
modules:
|
||||
- name: artcraft
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- cp -a . /app/
|
||||
- install -Dm644 /app/share/icons/hicolor/128x128/apps/artcraft.png /app/share/icons/hicolor/128x128/apps/ai.artcraft.app.png
|
||||
- sed -i 's/^Icon=.*/Icon=ai.artcraft.app/' /app/share/applications/ai.artcraft.app.desktop
|
||||
sources:
|
||||
- type: dir
|
||||
path: stage
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
# Integration fixture: real DEB/RPM archives, with no Rust compilation or signing key.
|
||||
set -euo pipefail
|
||||
script="$(realpath "$(dirname "$0")/package.sh")"
|
||||
work="$(mktemp -d)"
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
cd "$work"
|
||||
mkdir -p crates/desktop/artcraft target/x86_64-unknown-linux-gnu/release/bundle/{deb,rpm,appimage}
|
||||
printf '{"version":"0.42.0"}\n' > crates/desktop/artcraft/tauri.conf.json
|
||||
mkdir -p stage/{DEBIAN,usr/bin,usr/share/applications}
|
||||
cp /bin/true stage/usr/bin/artcraft
|
||||
printf '[Desktop Entry]\nType=Application\nName=ArtCraft\nExec=artcraft\n' > stage/usr/share/applications/ArtCraft.desktop
|
||||
cat > stage/DEBIAN/control <<'CONTROL'
|
||||
Package: artcraft
|
||||
Version: 0.42.0
|
||||
Architecture: amd64
|
||||
Maintainer: Fixture <fixture@example.invalid>
|
||||
Description: Packaging fixture
|
||||
CONTROL
|
||||
dpkg-deb --build stage target/x86_64-unknown-linux-gnu/release/bundle/deb/ArtCraft.deb
|
||||
mkdir -p rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||
cat > rpmbuild/SPECS/artcraft.spec <<'SPEC'
|
||||
Name: artcraft
|
||||
Version: 0.42.0
|
||||
Release: 1
|
||||
Summary: Packaging fixture
|
||||
License: MIT
|
||||
%description
|
||||
Packaging fixture
|
||||
%install
|
||||
mkdir -p %{buildroot}/usr/bin
|
||||
cp /bin/true %{buildroot}/usr/bin/artcraft
|
||||
%files
|
||||
/usr/bin/artcraft
|
||||
SPEC
|
||||
rpmbuild --define "_topdir $work/rpmbuild" -bb rpmbuild/SPECS/artcraft.spec
|
||||
find rpmbuild/RPMS -name '*.rpm' -exec cp {} target/x86_64-unknown-linux-gnu/release/bundle/rpm/ \;
|
||||
printf 'appimage fixture\n' > target/x86_64-unknown-linux-gnu/release/bundle/appimage/ArtCraft.AppImage
|
||||
"$script" x86_64 x86_64-unknown-linux-gnu
|
||||
for format in deb rpm AppImage AppImage.zsync tar.gz; do test -s "dist/release/artcraft-0.42.0-linux-x86_64.$format"; done
|
||||
mkdir unpacked
|
||||
tar -xzf dist/release/artcraft-0.42.0-linux-x86_64.tar.gz -C unpacked
|
||||
test -x unpacked/artcraft-0.42.0-linux-x86_64/bin/artcraft
|
||||
test -f unpacked/artcraft-0.42.0-linux-x86_64/share/applications/ai.artcraft.app.desktop
|
||||
rm target/x86_64-unknown-linux-gnu/release/bundle/rpm/*.rpm
|
||||
if "$script" x86_64 x86_64-unknown-linux-gnu; then
|
||||
echo 'Packaging accepted a missing RPM' >&2
|
||||
exit 1
|
||||
fi
|
||||
echo 'Package integration checks passed'
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/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"
|
||||
@@ -0,0 +1,7 @@
|
||||
# boring-sys2 has built-in ARM toolchains but no RISC-V toolchain. Set the target
|
||||
# explicitly so BoringSSL does not select the x86_64 runner's assembly sources.
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR riscv64)
|
||||
set(CMAKE_C_COMPILER riscv64-linux-gnu-gcc)
|
||||
set(CMAKE_CXX_COMPILER riscv64-linux-gnu-g++)
|
||||
set(OPENSSL_NO_ASM ON CACHE BOOL "Use BoringSSL's portable RISC-V implementation")
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"build": {
|
||||
"beforeBuildCommand": ""
|
||||
},
|
||||
"bundle": {
|
||||
"category": "GraphicsAndDesign",
|
||||
"shortDescription": "AI image and video creation",
|
||||
"longDescription": "ArtCraft Studio is a desktop workspace for generating AI images and video.",
|
||||
"linux": {
|
||||
"appimage": {
|
||||
"bundleMediaFramework": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Windows Packaging
|
||||
|
||||
ArtCraft Studio Windows release packaging assets and configuration.
|
||||
Reference in New Issue
Block a user