Build Docker e2e and desktop releases from the workspace root

This commit is contained in:
Rūdolfs Ošiņš
2026-10-29 16:27:03 +01:00
parent f79b23dde7
commit 7ce1deaf22
6 changed files with 86 additions and 48 deletions
+30 -13
View File
@@ -16,6 +16,8 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# The npm workspace that holds desktop and the shared UI code.
REPO_DIR="$(cd "$PROJECT_DIR/.." && pwd)"
# ---- Flags ----
@@ -65,8 +67,9 @@ ensure_image() {
VERSION="$(jq -r '.version' "$PROJECT_DIR/crates/radicle-tauri/tauri.conf.json")"
RELEASE_SHA="$(git -C "$PROJECT_DIR" rev-parse HEAD)"
SHORT_SHA="$(git -C "$PROJECT_DIR" rev-parse --short=8 HEAD)"
# The Linux containers only mount desktop/, which has no .git of its own, so
# build.rs can't ask git for the commit. Pass it in the way build.rs would get it.
# git in the Linux containers may refuse the bind-mounted checkout, which the
# container's root doesn't own, so build.rs can't rely on asking it for the
# commit. Pass it in the way build.rs would get it.
GIT_HEAD="$(git -C "$PROJECT_DIR" rev-parse --short HEAD)"
RELEASE_DIR="$PROJECT_DIR/releases/v$VERSION"
@@ -93,8 +96,10 @@ fi
if [[ "$CLEAN" == true ]]; then
step "Cleaning build artifacts"
rm -rf "$PROJECT_DIR/target-release"
rm -rf "$PROJECT_DIR/node_modules"
podman volume rm radicle-desktop-linux-target radicle-desktop-linux-nm radicle-desktop-linux-cargo 2>/dev/null || true
rm -rf "$REPO_DIR/node_modules" "$REPO_DIR"/{explorer,desktop,shared/ui}/node_modules
podman volume rm radicle-desktop-linux-target radicle-desktop-linux-cargo \
radicle-desktop-linux-nm radicle-desktop-linux-nm-explorer \
radicle-desktop-linux-nm-desktop radicle-desktop-linux-nm-shared 2>/dev/null || true
podman image rm radicle-desktop-release-builder 2>/dev/null || true
echo " Cleaned"
fi
@@ -103,8 +108,9 @@ fi
if [[ "$BUILD_DMG" == true ]]; then
step "Building macOS aarch64 DMG"
cd "$REPO_DIR"
npm install -w desktop
cd "$PROJECT_DIR"
npm install
CARGO_TARGET_DIR="$PROJECT_DIR/target-release" \
npm exec -- tauri build --bundles dmg
cp "target-release/release/bundle/dmg/Radicle_${VERSION}_aarch64.dmg" \
@@ -122,24 +128,32 @@ fi
# After a Rust toolchain bump or dependency change that confuses incremental
# compilation: podman volume rm radicle-desktop-linux-target radicle-desktop-linux-cargo
# After a major npm dependency change: podman volume rm radicle-desktop-linux-nm
# radicle-desktop-linux-nm-explorer radicle-desktop-linux-nm-desktop
# radicle-desktop-linux-nm-shared
#
# Every workspace package's node_modules is a volume, so that npm inside the
# container never writes Linux builds into the host's checkout.
if [[ "$BUILD_DEB" == true ]]; then
step "Building Linux amd64 deb"
ensure_image "radicle-desktop-release-builder" "Dockerfile.release" "linux/arm64"
podman run --rm \
-v "$PROJECT_DIR:/workspace:z" \
-v radicle-desktop-linux-target:/workspace/target:z \
-v "$REPO_DIR:/workspace:z" \
-v radicle-desktop-linux-target:/workspace/desktop/target:z \
-v radicle-desktop-linux-nm:/workspace/node_modules:z \
-v radicle-desktop-linux-nm-explorer:/workspace/explorer/node_modules:z \
-v radicle-desktop-linux-nm-desktop:/workspace/desktop/node_modules:z \
-v radicle-desktop-linux-nm-shared:/workspace/shared/ui/node_modules:z \
-v radicle-desktop-linux-cargo:/root/.cargo/registry:z \
-v "$RELEASE_DIR:/output:z" \
-w /workspace \
-w /workspace/desktop \
-e CI=true \
-e GIT_HEAD="$GIT_HEAD" \
radicle-desktop-release-builder \
bash -c "
set -euo pipefail
npm ci
(cd /workspace && npm ci -w desktop)
npm exec -- tauri build --target x86_64-unknown-linux-gnu --bundles deb
cp \"target/x86_64-unknown-linux-gnu/release/bundle/deb/radicle-desktop_${VERSION}_amd64.deb\" /output/
"
@@ -162,16 +176,19 @@ if [[ "$BUILD_APPIMAGE" == true ]]; then
podman run --rm \
--privileged \
-v "$PROJECT_DIR:/workspace:z" \
-v radicle-desktop-linux-target:/workspace/target:z \
-v "$REPO_DIR:/workspace:z" \
-v radicle-desktop-linux-target:/workspace/desktop/target:z \
-v radicle-desktop-linux-nm:/workspace/node_modules:z \
-v radicle-desktop-linux-nm-explorer:/workspace/explorer/node_modules:z \
-v radicle-desktop-linux-nm-desktop:/workspace/desktop/node_modules:z \
-v radicle-desktop-linux-nm-shared:/workspace/shared/ui/node_modules:z \
-v radicle-desktop-linux-cargo:/root/.cargo/registry:z \
-v "$RELEASE_DIR:/output:z" \
-w /workspace \
-w /workspace/desktop \
-e CI=true \
-e GIT_HEAD="$GIT_HEAD" \
radicle-desktop-release-builder \
bash /workspace/scripts/appimage-build
bash /workspace/desktop/scripts/appimage-build
# Strip the version so the filename matches what the website serves
# (the DMG above is renamed the same way).
-13
View File
@@ -1,13 +0,0 @@
node_modules
build
.svelte-kit
.git
tests/tmp
tests/artifacts
tests/visual/snapshots
data.ms
dumps
radicle-httpd/target
radicle-search/target
target
.wrangler
+11 -5
View File
@@ -26,15 +26,21 @@ WORKDIR /work
# Install Chromium plus its apt-level runtime dependencies, pinned to the
# Playwright version in package-lock.json so the baked browser matches the
# @playwright/test that npm ci installs into the volume at runtime. Copying
# only the lockfiles keeps this layer cached across source changes.
# only the npm manifests keeps this layer cached across source changes. The
# build context is the repository root, which holds the npm workspace: npm ci
# checks the lockfile against every workspace's package.json, even when it
# installs only explorer.
# --ignore-scripts: this layer only warms the browser cache, so dependency
# install scripts are not necessary.
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts \
COPY package.json package-lock.json .npmrc ./
COPY shared/ui/package.json shared/ui/
COPY explorer/package.json explorer/
COPY desktop/package.json desktop/
RUN npm ci -w explorer --ignore-scripts \
&& npx playwright install --with-deps chromium \
&& rm -rf node_modules
&& rm -rf node_modules explorer/node_modules
ENTRYPOINT ["/work/scripts/docker-e2e-entrypoint.sh"]
ENTRYPOINT ["/work/explorer/scripts/docker-e2e-entrypoint.sh"]
# --- local stage: adds Rust so the entrypoint can build radicle-httpd ---
FROM base AS local
+9
View File
@@ -0,0 +1,9 @@
# The build context is the repository root, and the image only copies the npm
# manifests: the repository itself is bind-mounted at runtime.
*
!package.json
!package-lock.json
!.npmrc
!shared/ui/package.json
!explorer/package.json
!desktop/package.json
+30 -12
View File
@@ -1,6 +1,6 @@
x-e2e-common: &e2e-common
init: true
working_dir: /work
working_dir: /work/explorer
environment:
PLAYWRIGHT_BROWSERS_PATH: /ms-playwright
@@ -9,35 +9,53 @@ services:
e2e:
<<: *e2e-common
build:
context: .
dockerfile: Dockerfile.e2e
# The repository root, which holds the npm workspace.
context: ..
dockerfile: explorer/Dockerfile.e2e
target: base
volumes:
# Repo bind-mounted so code edits, test artifacts, and the
# binary/fixture cache (tests/tmp) are shared with the host.
- .:/work
# Container-private node_modules: keeps the host's untouched and
# avoids a glibc mismatch with host-built native modules.
# Repo bind-mounted so code edits and test artifacts are shared with the
# host.
- ..:/work
# Container-private node_modules for every workspace package: keeps the
# host's untouched and avoids a glibc mismatch with host-built native
# modules. npm hoists most packages to the root and nests the rest under
# the package that needs them.
- e2e-node-modules:/work/node_modules
- e2e-explorer-node-modules:/work/explorer/node_modules
- e2e-desktop-node-modules:/work/desktop/node_modules
- e2e-shared-node-modules:/work/shared/ui/node_modules
# Container-private binaries and fixtures: the host's binaries may be
# built for another OS, and Radicle storage has to live on the
# container's own filesystem rather than a bind mount from a macOS host.
- e2e-tmp:/work/explorer/tests/tmp
# Compiles radicle-httpd from source and runs the suite against it.
# Used via `scripts/test-e2e-docker --local` when testing backend changes.
e2e-local:
<<: *e2e-common
build:
context: .
dockerfile: Dockerfile.e2e
context: ..
dockerfile: explorer/Dockerfile.e2e
target: local
volumes:
- .:/work
- ..:/work
- e2e-node-modules:/work/node_modules
- e2e-explorer-node-modules:/work/explorer/node_modules
- e2e-desktop-node-modules:/work/desktop/node_modules
- e2e-shared-node-modules:/work/shared/ui/node_modules
- e2e-tmp:/work/explorer/tests/tmp
# Container-private cargo crate cache and workspace build dir, so the
# Rust build is incremental across runs and never mixes with the
# host's (different glibc/rustc) target artifacts.
- e2e-cargo-registry:/usr/local/cargo/registry
- e2e-httpd-target:/work/target
- e2e-httpd-target:/work/explorer/target
volumes:
e2e-node-modules:
e2e-explorer-node-modules:
e2e-desktop-node-modules:
e2e-shared-node-modules:
e2e-tmp:
e2e-cargo-registry:
e2e-httpd-target:
+6 -5
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env bash
# Entrypoint for the e2e Docker container. Installs npm deps into the
# container-private node_modules volume (only when package-lock.json changes),
# container-private node_modules volumes (only when the workspace's
# package-lock.json changes),
# ensures the Radicle test binaries are present, then runs Playwright. Any
# arguments are forwarded to the test command.
#
@@ -8,7 +9,7 @@
# source and tests the frontend against it) instead of test:e2e.
set -euo pipefail
cd /work
cd /work/explorer
# The container runs as root, so anything it writes into the bind-mounted repo
# would otherwise be root-owned on the host. Hand those paths back to the
@@ -23,11 +24,11 @@ cleanup() {
}
trap cleanup EXIT
LOCK_HASH=$(md5sum package-lock.json | cut -d' ' -f1)
STAMP=node_modules/.lockhash
LOCK_HASH=$(md5sum ../package-lock.json | cut -d' ' -f1)
STAMP=../node_modules/.lockhash
if [ ! -f "$STAMP" ] || [ "$(cat "$STAMP")" != "$LOCK_HASH" ]; then
echo "📦 Installing npm dependencies..."
npm ci
(cd .. && npm ci -w explorer)
echo "$LOCK_HASH" >"$STAMP"
else
echo "📦 npm dependencies up to date."