From 2590b2e8280ec1204c7d3bc8b485b3588d1eb7b6 Mon Sep 17 00:00:00 2001 From: CRT Date: Tue, 13 Oct 2026 07:44:17 +0800 Subject: [PATCH] Releases on git.crt.fyi from a workflow: a v* tag push runs .forgejo/workflows/release.yml (tag = package.json version and every version copy, the full CI, Linux AppImage + deb and Windows NSIS on the VDS runners, privacy scan with the private terms, one Forgejo release with short CHANGELOG-summary notes, the installers and SHA256SUMS, older release entries deleted, tags kept); workflow_dispatch dry run makes a draft test- and deletes it; desktop.yml folded in, ci.yml and release.yml share .forgejo/actions/linux-setup and ci-run; tools/forgejo-release.ts (notes, upsert, prune, delete; uploads over 100 MB go to the origin because Cloudflare refuses them); desktop-release.ts upload-forgejo adds the notarized DMG and updater bundle from the Mac; docs/desktop-release.md release order --- .forgejo/actions/ci-run/action.yml | 45 ++++ .forgejo/actions/linux-setup/action.yml | 42 ++++ .forgejo/workflows/ci.yml | 60 +---- .forgejo/workflows/desktop.yml | 162 ------------- .forgejo/workflows/release.yml | 305 ++++++++++++++++++++++++ CHANGELOG.md | 6 + docs/desktop-release.md | 64 ++++- tests/desktop-release.test.ts | 12 +- tests/forgejo-release.test.ts | 78 ++++++ tools/desktop-release.ts | 37 ++- tools/forgejo-release.ts | 289 ++++++++++++++++++++++ 11 files changed, 871 insertions(+), 229 deletions(-) create mode 100644 .forgejo/actions/ci-run/action.yml create mode 100644 .forgejo/actions/linux-setup/action.yml delete mode 100644 .forgejo/workflows/desktop.yml create mode 100644 .forgejo/workflows/release.yml create mode 100644 tests/forgejo-release.test.ts create mode 100644 tools/forgejo-release.ts diff --git a/.forgejo/actions/ci-run/action.yml b/.forgejo/actions/ci-run/action.yml new file mode 100644 index 0000000..51b31be --- /dev/null +++ b/.forgejo/actions/ci-run/action.yml @@ -0,0 +1,45 @@ +# `bun run ci` after .forgejo/actions/linux-setup: the target / timings / Playwright caches, bun install, headless +# Chromium, Node 20 (the npm bundle's oldest supported Node) and the full CI. Shared by ci.yml and release.yml. +name: ci-run +description: storebound's full CI (bun run ci) on the Linux runner +runs: + using: composite + steps: + - uses: actions/cache@v4 + with: + path: apps/desktop/src-tauri/target + key: ci-target-${{ runner.os }}-${{ hashFiles('apps/desktop/src-tauri/Cargo.lock') }} + restore-keys: ci-target-${{ runner.os }}- + # recorded test durations (shard balance) and tsc's incremental build info + - uses: actions/cache@v4 + with: + path: node_modules/.cache/storebound-ci + key: ci-timings-${{ runner.os }}-${{ github.sha }} + restore-keys: ci-timings-${{ runner.os }}- + - name: Install + shell: bash + run: | + bun --version && cargo --version + bun install --frozen-lockfile + # Playwright's Chromium and headless shell (~280 MB), keyed by the browser builds the installed playwright-core + # wants (its browsers.json); the system libraries and fonts (--with-deps) are installed on every run, the job + # container starts clean + - uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ hashFiles('node_modules/playwright-core/browsers.json') }} + restore-keys: playwright-${{ runner.os }}- + # the job runs as root in a container: storebound adds --no-sandbox to the Chromium it starts itself there + # (cli/shots/browser.ts sandboxArgs), Playwright's own launches already pass it + - name: Headless Chromium (browser tests, desktop boot check) + shell: bash + run: bunx playwright install --with-deps chromium + # the npm bundle runs on Node 20+: tools/ci.ts smoke-tests dist/storebound.mjs with the oldest supported Node + - uses: actions/setup-node@v4 + with: + node-version: '20' + # the runner sets CI=true in the job and it wins over the workflow env above: set CI=full for the command + # itself, or tools/ci.ts skips the desktop Rust tests and clippy when the push did not touch src-tauri + - name: bun run ci + shell: bash + run: CI=full bun run ci diff --git a/.forgejo/actions/linux-setup/action.yml b/.forgejo/actions/linux-setup/action.yml new file mode 100644 index 0000000..a16be63 --- /dev/null +++ b/.forgejo/actions/linux-setup/action.yml @@ -0,0 +1,42 @@ +# Shared setup of the Linux jobs (ci.yml; release.yml's ci and linux jobs) on the VDS runner (label ubuntu-22.04, the +# catthehacker act image): Tauri's system packages plus `packages`, the Bun / Cargo caches, Bun and Rust on PATH. +name: linux-setup +description: System packages, caches, Bun and Rust for storebound's Linux jobs +inputs: + packages: + description: Extra apt packages + default: '' + cache-key: + description: Cache key prefix (separate caches for CI and the installer build) + default: ci + rust-components: + description: Extra rustup components (for example clippy) + default: '' +runs: + using: composite + steps: + - name: System packages + shell: bash + run: | + sudo apt-get update -qq + sudo apt-get install -y -qq --no-install-recommends libwebkit2gtk-4.1-dev libgtk-3-dev \ + libayatana-appindicator3-dev librsvg2-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev libssl-dev libxdo-dev \ + build-essential curl unzip pkg-config ${{ inputs.packages }} >/dev/null + - uses: actions/cache@v4 + with: + path: | + ~/.bun/install/cache + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + key: ${{ inputs.cache-key }}-${{ runner.os }}-${{ hashFiles('bun.lock', 'apps/desktop/src-tauri/Cargo.lock') }} + restore-keys: ${{ inputs.cache-key }}-${{ runner.os }}- + - name: Bun and Rust + shell: bash + run: | + P="${FORGEJO_PATH:-$GITHUB_PATH}" + curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}" >/dev/null + echo "$HOME/.bun/bin" >> "$P" + command -v rustup || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal + echo "$HOME/.cargo/bin" >> "$P" + for c in ${{ inputs.rust-components }}; do "$HOME/.cargo/bin/rustup" component add "$c"; done diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 5fc7078..63d25c3 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -2,7 +2,8 @@ # desktop i18n / typecheck / build, desktop boot check (headless Chromium), desktop Rust tests and clippy, scrub. Runs on the VDS runner (docs/desktop-release.md). # tools/ci.ts runs the steps as a task graph and the tests as parallel shards (CPU cores - 1, max 8) on the one # self-hosted runner, so a job matrix would only queue; CI=full makes it run the Rust steps on every push. -# Publishes nothing: site/ is still published by Jenkins. +# Publishes nothing: site/ is still published by Jenkins; releases come from release.yml (a v* tag). +# release.yml's ci job runs the same steps (the setup is shared: .forgejo/actions/linux-setup). name: ci on: @@ -27,57 +28,8 @@ jobs: timeout-minutes: 60 steps: - uses: actions/checkout@v4 - - name: System packages (Tauri on Linux) - run: | - sudo apt-get update -qq - sudo apt-get install -y -qq --no-install-recommends libwebkit2gtk-4.1-dev libgtk-3-dev \ - libayatana-appindicator3-dev librsvg2-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev libssl-dev libxdo-dev \ - build-essential curl unzip pkg-config >/dev/null - - uses: actions/cache@v4 + - uses: ./.forgejo/actions/linux-setup with: - path: | - ~/.bun/install/cache - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git/db - apps/desktop/src-tauri/target - key: ci-${{ runner.os }}-${{ hashFiles('bun.lock', 'apps/desktop/src-tauri/Cargo.lock') }} - restore-keys: ci-${{ runner.os }}- - # recorded test durations (shard balance) and tsc's incremental build info - - uses: actions/cache@v4 - with: - path: node_modules/.cache/storebound-ci - key: ci-timings-${{ runner.os }}-${{ github.sha }} - restore-keys: ci-timings-${{ runner.os }}- - - name: Bun and Rust - run: | - P="${FORGEJO_PATH:-$GITHUB_PATH}" - curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}" >/dev/null - echo "$HOME/.bun/bin" >> "$P" - command -v rustup || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --component clippy - echo "$HOME/.cargo/bin" >> "$P" - - name: Install - run: | - rustup component add clippy - bun --version && cargo --version - bun install --frozen-lockfile - # Playwright's Chromium and headless shell (~280 MB), keyed by the browser builds the installed playwright-core - # wants (its browsers.json); the system libraries and fonts (--with-deps) are installed on every run, the job - # container starts clean - - uses: actions/cache@v4 - with: - path: ~/.cache/ms-playwright - key: playwright-${{ runner.os }}-${{ hashFiles('node_modules/playwright-core/browsers.json') }} - restore-keys: playwright-${{ runner.os }}- - # the job runs as root in a container: storebound adds --no-sandbox to the Chromium it starts itself there - # (cli/shots/browser.ts sandboxArgs), Playwright's own launches already pass it - - name: Headless Chromium (browser tests, desktop boot check) - run: bunx playwright install --with-deps chromium - # the npm bundle runs on Node 20+: tools/ci.ts smoke-tests dist/storebound.mjs with the oldest supported Node - - uses: actions/setup-node@v4 - with: - node-version: '20' - # the runner sets CI=true in the job and it wins over the workflow env above: set CI=full for the command - # itself, or tools/ci.ts skips the desktop Rust tests and clippy when the push did not touch src-tauri - - name: bun run ci - run: CI=full bun run ci + cache-key: ci + rust-components: clippy + - uses: ./.forgejo/actions/ci-run diff --git a/.forgejo/workflows/desktop.yml b/.forgejo/workflows/desktop.yml deleted file mode 100644 index b012b6e..0000000 --- a/.forgejo/workflows/desktop.yml +++ /dev/null @@ -1,162 +0,0 @@ -# storebound desktop: Linux (AppImage + deb) and Windows (NSIS, per user, unsigned) installers. -# macOS is built, signed and notarized on the owner's Mac (tools/desktop-release.ts mac); the updater signing key -# never reaches a runner: the Mac signs these installers after downloading them (tools/desktop-release.ts add). -# Runner setup (Forgejo runners on the VDS: Linux in Docker, Windows in a KVM VM): docs/desktop-release.md. -# Publishes nothing: the installers are workflow artifacts only (14 days); `tools/desktop-release.ts add` on the Mac -# signs and stages them, and only `publish` puts anything on storebound.dev. -name: desktop - -on: - workflow_dispatch: - inputs: - windows: - description: Build Windows too (needs a runner with the "windows" label) - type: boolean - default: false - push: - tags: ['desktop-v*'] - -env: - BUN_VERSION: '1.4.0' - # the path-free build keeps the target folder outside every home folder - CARGO_TARGET_DIR: /tmp/storebound-target - CARGO_TERM_COLOR: never - -jobs: - linux: - # runner label: ubuntu-22.04:docker://ghcr.io/catthehacker/ubuntu:act-22.04 (glibc 2.35: the AppImage and the - # deb then run on Ubuntu 22.04 and newer, Debian 12) - runs-on: ubuntu-22.04 - timeout-minutes: 90 - env: - # linuxdeploy (AppImage) runs without FUSE inside the container - APPIMAGE_EXTRACT_AND_RUN: '1' - # linuxdeploy must not strip: the storebound sidecar is a `bun build --compile` executable whose JS payload strip - # removes (it then starts as plain bun). The Rust binary is already stripped by Cargo (profile.release strip). - NO_STRIP: '1' - # WebKitGTK's DMABUF renderer leaves the window blank on some GPU / VM setups; the app sets this itself at - # start (src-tauri/src/lib.rs linux_webkit_env) unless the user did; set here too for anything run in CI - WEBKIT_DISABLE_DMABUF_RENDERER: '1' - steps: - - uses: actions/checkout@v4 - - name: System packages - run: | - sudo apt-get update -qq - sudo apt-get install -y -qq --no-install-recommends libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev \ - librsvg2-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev libssl-dev libxdo-dev patchelf file build-essential \ - curl unzip squashfs-tools p7zip-full xz-utils >/dev/null - - uses: actions/cache@v4 - with: - path: | - ~/.bun/install/cache - ~/.cargo/registry/index - ~/.cargo/registry/cache - ~/.cargo/git/db - key: desktop-${{ runner.os }}-${{ hashFiles('bun.lock', 'apps/desktop/src-tauri/Cargo.lock') }} - restore-keys: desktop-${{ runner.os }}- - - name: Bun and Rust - run: | - P="${FORGEJO_PATH:-$GITHUB_PATH}" - curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}" >/dev/null - echo "$HOME/.bun/bin" >> "$P" - command -v rustup || curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal - echo "$HOME/.cargo/bin" >> "$P" - - name: Install and check - run: | - bun install --frozen-lockfile - bun tools/desktop-version.ts - bun tools/build-sidecars.ts --target bun-linux-x64 - # linuxdeploy (AppImage) sets the rpath of every executable with its own patchelf, which corrupts the bun - # sidecar (segfault, then ldd fails in the gtk plugin). With the rpath already set (Ubuntu's patchelf, which - # keeps it working), linuxdeploy leaves the file as it is. The sidecar needs only libc, so the rpath is inert. - patchelf --set-rpath '$ORIGIN/../lib' apps/desktop/src-tauri/binaries/storebound-x86_64-unknown-linux-gnu - apps/desktop/src-tauri/binaries/storebound-x86_64-unknown-linux-gnu version - - name: Build AppImage and deb (path-free) - working-directory: apps/desktop - run: bun ../../tools/desktop-release.ts exec -- bunx tauri build --bundles appimage,deb --ci - - name: Self-test the exact artifacts - run: | - V=$(bun tools/desktop-version.ts --print) - B="$CARGO_TARGET_DIR/release/bundle" - mkdir -p out && cp "$B/appimage/storebound_${V}_amd64.AppImage" "$B/deb/storebound_${V}_amd64.deb" out/ - chmod +x out/*.AppImage - (cd /tmp && rm -rf squashfs-root && "$GITHUB_WORKSPACE/out/storebound_${V}_amd64.AppImage" --appimage-extract >/dev/null && squashfs-root/usr/bin/storebound-desktop --self-test) - rm -rf /tmp/deb && dpkg-deb -x "out/storebound_${V}_amd64.deb" /tmp/deb && /tmp/deb/usr/bin/storebound-desktop --self-test - dpkg-deb -I "out/storebound_${V}_amd64.deb" | sed -n '1,20p' - - name: Start the app under Xvfb (AppImage and deb) - # --self-test checks only the sidecar; this opens the real window (GTK, WebKitGTK, the bundled libraries of the - # AppImage) on a virtual display. "sidecar started" in host.log means the webview ran the UI and called the host. - run: | - sudo apt-get install -y -qq --no-install-recommends xvfb xauth dbus-x11 >/dev/null - V=$(bun tools/desktop-version.ts --print) - smoke() { #