Files
Genarrative/deploy/container/gitea-ci-job.Dockerfile
kdletters 4b788fa73a
Project CI / AI game creator shell Rust shard 3/4 (push) Failing after 7m25s
Project CI / AI game creator shell Rust shard 4/4 (push) Failing after 7m39s
Project CI / AI game creator shell Rust shard 2/4 (push) Failing after 7m48s
Project CI / AI game creator shell Rust crates (push) Successful in 1m11s
Project CI / AI game creator shell Rust shard 1/4 (push) Failing after 9m55s
Project CI / AI game creator shell Rust smoke (push) Successful in 2m29s
Project CI / Repository checks (push) Successful in 4m9s
Project CI / Backend tests (push) Successful in 6m18s
Project CI / Frontend tests (push) Successful in 6m17s
Project CI / Native shell tests (push) Successful in 9m22s
Project CI / AI game creator shell web tests (push) Successful in 5m21s
修复 Gitea CI 镜像构建并刷新到 1.98.1 工具链 (#438)
修复 CI job 镜像无法构建的问题,并换用 Rust 1.98.1 工具链镜像,跑通 PR 门禁。

Reviewed-on: http://192.168.35.82/git/GenarrativeAI/Genarrative/pulls/438
Co-authored-by: kdletters <kdletters@qq.com>
Co-committed-by: kdletters <kdletters@qq.com>
2026-09-21 06:15:57 +08:00

268 lines
13 KiB
Docker
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
ARG RUST_IMAGE=rust:1.98-bookworm@sha256:93ce27a88655056a51dbdd8f5f2d7ddc071c7b0070fb288a37b5a285fc83971e
ARG RUNNER_IMAGE=docker.gitea.com/runner-images:ubuntu-latest@sha256:58ea92624c7c09582e05594d95488331045053d3a3f34cf09649f2a32313a614
FROM ${RUST_IMAGE} AS rust-toolchain
RUN rustup component add rustfmt \
&& rustc --version \
&& cargo --version \
&& rustfmt --version
FROM rust-toolchain AS rust-dependency-cache
ENV CARGO_HTTP_MULTIPLEXING=false \
CARGO_NET_RETRY=10
COPY server-rs /tmp/genarrative-cargo-cache/server-rs
COPY apps/desktop-shell/src-tauri /tmp/genarrative-cargo-cache/desktop-shell
COPY apps/ai-game-creator-shell/src-tauri /tmp/genarrative-cargo-cache/apps/ai-game-creator-shell/src-tauri
COPY plugins/agc-cocos-editor/native/cocos-editor-bridge /tmp/genarrative-cargo-cache/plugins/agc-cocos-editor/native/cocos-editor-bridge
COPY plugins/agc-unity-editor/native/unity-editor-bridge /tmp/genarrative-cargo-cache/plugins/agc-unity-editor/native/unity-editor-bridge
COPY plugins/agc-godot-editor/native/godot-editor-bridge /tmp/genarrative-cargo-cache/plugins/agc-godot-editor/native/godot-editor-bridge
RUN find /tmp/genarrative-cargo-cache -name Cargo.toml -exec dirname {} \; \
| while IFS= read -r crate_dir; do \
mkdir -p "${crate_dir}/src"; \
: > "${crate_dir}/src/lib.rs"; \
: > "${crate_dir}/src/main.rs"; \
: > "${crate_dir}/src/active.rs"; \
done \
&& cargo_fetch_with_retry() { \
manifest_path="$1"; \
for attempt in 1 2 3 4 5; do \
if cargo fetch --locked \
--target x86_64-unknown-linux-gnu \
--manifest-path "${manifest_path}"; then \
return 0; \
fi; \
if [ "${attempt}" -eq 5 ]; then \
return 1; \
fi; \
sleep "$((attempt * 5))"; \
done; \
} \
&& cargo_fetch_with_retry /tmp/genarrative-cargo-cache/server-rs/Cargo.toml \
&& cargo_fetch_with_retry /tmp/genarrative-cargo-cache/desktop-shell/Cargo.toml \
&& cargo_fetch_with_retry /tmp/genarrative-cargo-cache/apps/ai-game-creator-shell/src-tauri/Cargo.toml \
&& CARGO_NET_OFFLINE=true cargo fetch --locked \
--target x86_64-unknown-linux-gnu \
--manifest-path /tmp/genarrative-cargo-cache/server-rs/Cargo.toml \
&& CARGO_NET_OFFLINE=true cargo fetch --locked \
--target x86_64-unknown-linux-gnu \
--manifest-path /tmp/genarrative-cargo-cache/desktop-shell/Cargo.toml \
&& CARGO_NET_OFFLINE=true cargo fetch --locked \
--target x86_64-unknown-linux-gnu \
--manifest-path /tmp/genarrative-cargo-cache/apps/ai-game-creator-shell/src-tauri/Cargo.toml \
&& rm -rf /tmp/genarrative-cargo-cache
FROM ${RUNNER_IMAGE}
ARG NODE_VERSION=22.23.1
ARG NODE_LINUX_X64_SHA256=9749e988f437343b7fa832c69ded82a312e41a03116d766797ac14f6f9eee578
ARG NPM_VERSION=10.9.7
ARG GOOGLE_CHROME_VERSION=153.0.8010.52-1
ARG GOOGLE_LINUX_SIGNING_KEY_FINGERPRINT=EB4C1BFD4F042F6DDDCCEC917721F63BD38B4796
LABEL org.opencontainers.image.title="Genarrative Gitea CI job image" \
org.opencontainers.image.description="Ubuntu 24.04 CI image with fixed toolchains and prewarmed npm/Cargo caches" \
org.opencontainers.image.version="2026.09.20.2"
RUN test "$(dpkg --print-architecture)" = "amd64" \
&& find /etc/apt/sources.list.d -maxdepth 1 -type f \
! -name ubuntu.sources -delete \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
bubblewrap \
build-essential \
ca-certificates \
clang \
cmake \
curl \
ffmpeg \
file \
libayatana-appindicator3-dev \
libclang-dev \
libcurl4-openssl-dev \
librsvg2-dev \
libssl-dev \
libwebkit2gtk-4.1-dev \
libxdo-dev \
lld \
patchelf \
pkg-config \
ripgrep \
wget \
xz-utils \
&& google_key="$(mktemp)" \
&& curl --retry 3 --retry-all-errors --retry-delay 2 \
--proto '=https' --tlsv1.2 -fsSL \
https://dl.google.com/linux/linux_signing_key.pub \
-o "${google_key}" \
&& test "$(gpg --batch --show-keys --with-colons "${google_key}" \
| awk -F: '$1 == "fpr" { print $10; exit }')" \
= "${GOOGLE_LINUX_SIGNING_KEY_FINGERPRINT}" \
&& install -d -m 0755 /etc/apt/keyrings \
&& install -m 0644 "${google_key}" /etc/apt/keyrings/google-chrome.asc \
&& printf '%s\n' \
'deb [arch=amd64 signed-by=/etc/apt/keyrings/google-chrome.asc] https://dl.google.com/linux/chrome/deb/ stable main' \
> /etc/apt/sources.list.d/google-chrome.list \
&& rm -f "${google_key}" \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
"google-chrome-stable=${GOOGLE_CHROME_VERSION}" \
&& rm -rf /var/lib/apt/lists/*
RUN node_archive="node-v${NODE_VERSION}-linux-x64.tar.xz" \
&& curl --retry 3 --retry-all-errors --retry-delay 2 \
--proto '=https' --tlsv1.2 -fsSLO \
"https://nodejs.org/dist/v${NODE_VERSION}/${node_archive}" \
&& printf '%s %s\n' "${NODE_LINUX_X64_SHA256}" "${node_archive}" \
| sha256sum --check --strict \
&& install -d -m 0755 /usr/local/lib/genarrative-node \
&& tar -xJf "${node_archive}" \
--strip-components=1 \
--directory /usr/local/lib/genarrative-node \
&& rm -f "${node_archive}" \
&& ln -sfn /usr/local/lib/genarrative-node/bin/npx /usr/local/bin/npx \
&& ln -sfn /usr/local/lib/genarrative-node/bin/corepack /usr/local/bin/corepack
COPY --from=rust-dependency-cache /usr/local/cargo /usr/local/cargo
COPY --from=rust-dependency-cache /usr/local/rustup /usr/local/rustup
ARG NPM_LOCK_SHA256
ARG SERVER_RUST_LOCK_SHA256
ARG DESKTOP_RUST_LOCK_SHA256
ARG AGC_RUST_LOCK_SHA256
COPY package.json package-lock.json /usr/local/share/genarrative-ci/npm/
COPY apps/admin-web/package.json /usr/local/share/genarrative-ci/npm/apps/admin-web/package.json
COPY apps/ai-game-creator-shell/package.json /usr/local/share/genarrative-ci/npm/apps/ai-game-creator-shell/package.json
COPY apps/desktop-shell/package.json /usr/local/share/genarrative-ci/npm/apps/desktop-shell/package.json
COPY apps/mobile-shell/package.json /usr/local/share/genarrative-ci/npm/apps/mobile-shell/package.json
COPY apps/preview-deployer-web/package.json /usr/local/share/genarrative-ci/npm/apps/preview-deployer-web/package.json
COPY packages/image-canvas-core/package.json /usr/local/share/genarrative-ci/npm/packages/image-canvas-core/package.json
COPY packages/image-canvas-react/package.json /usr/local/share/genarrative-ci/npm/packages/image-canvas-react/package.json
COPY packages/shared/package.json /usr/local/share/genarrative-ci/npm/packages/shared/package.json
COPY tools/spine-json-export-validator/package.json /usr/local/share/genarrative-ci/npm/tools/spine-json-export-validator/package.json
COPY server-rs/Cargo.lock /usr/local/share/genarrative-ci/locks/server-rs.Cargo.lock
COPY apps/desktop-shell/src-tauri/Cargo.lock /usr/local/share/genarrative-ci/locks/desktop-shell.Cargo.lock
COPY apps/ai-game-creator-shell/src-tauri/Cargo.lock /usr/local/share/genarrative-ci/locks/ai-game-creator-shell.Cargo.lock
COPY deploy/container/gitea-ci-checkout.sh /usr/local/bin/genarrative-gitea-checkout
# npm registry 偶发 ECONNRESET,镜像预热也需要整命令级有界重试;
# 失败重试复用同一 npm cache,不会重复下载已完成的包。
RUN test -n "${NPM_LOCK_SHA256}" \
&& test -n "${SERVER_RUST_LOCK_SHA256}" \
&& test -n "${DESKTOP_RUST_LOCK_SHA256}" \
&& test -n "${AGC_RUST_LOCK_SHA256}" \
&& printf '%s %s\n' \
"${NPM_LOCK_SHA256}" \
/usr/local/share/genarrative-ci/npm/package-lock.json \
| sha256sum --check --strict \
&& printf '%s %s\n' \
"${SERVER_RUST_LOCK_SHA256}" \
/usr/local/share/genarrative-ci/locks/server-rs.Cargo.lock \
| sha256sum --check --strict \
&& printf '%s %s\n' \
"${DESKTOP_RUST_LOCK_SHA256}" \
/usr/local/share/genarrative-ci/locks/desktop-shell.Cargo.lock \
| sha256sum --check --strict \
&& printf '%s %s\n' \
"${AGC_RUST_LOCK_SHA256}" \
/usr/local/share/genarrative-ci/locks/ai-game-creator-shell.Cargo.lock \
| sha256sum --check --strict \
&& chmod 0755 /usr/local/bin/genarrative-gitea-checkout \
&& npm_ci_with_retry() { \
for attempt in 1 2 3 4 5; do \
if npm ci \
--ignore-scripts \
--no-audit \
--no-fund \
--prefer-offline \
--prefix /usr/local/share/genarrative-ci/npm; then \
return 0; \
fi; \
if [ "${attempt}" -eq 5 ]; then \
return 1; \
fi; \
sleep "$((attempt * 5))"; \
done; \
} \
&& npm_ci_with_retry \
&& rm -rf \
/usr/local/share/genarrative-ci/npm/node_modules \
/usr/local/share/genarrative-ci/npm/apps/*/node_modules \
/usr/local/share/genarrative-ci/npm/packages/*/node_modules \
/usr/local/share/genarrative-ci/npm/tools/*/node_modules \
&& npm cache verify
# 依赖预热会在 workspace 内解析出 Node 发行包自带的 npm(例如 10.9.8),
# 并通过 PATH 里的 node_modules/.bin 影子化固定版本,因此全局固定版本在预热之后安装。
# 基础 runner 镜像把 /opt/acttoolcache/node/24.18.0/x64/bin 放在 PATH 最前,会影子化固定 Node / npm;
# 而 command.exec 只信任 /usr/local/bin 等系统目录,Node 必须在那里可见。
# 因此固定工具链写成绝对路径 wrapper,并用同一组链接覆盖 base 镜像残留的 toolcache bin
# 避免 shell 是否登录改变解析结果,同时保证 command.exec 能找到受信任 node。
RUN npm install --global --prefix /usr/local/lib/genarrative-node \
--no-audit --no-fund "npm@${NPM_VERSION}" \
&& test "$(/usr/local/lib/genarrative-node/bin/node /usr/local/lib/genarrative-node/lib/node_modules/npm/bin/npm-cli.js --version)" = "${NPM_VERSION}" \
&& ln -sfn /usr/local/lib/genarrative-node/bin/node /usr/local/bin/node \
&& rm -f /usr/local/bin/npm \
&& printf '%s\n' '#!/bin/sh' \
'exec /usr/local/lib/genarrative-node/bin/node /usr/local/lib/genarrative-node/lib/node_modules/npm/bin/npm-cli.js "$@"' \
> /usr/local/bin/npm \
&& chmod 0755 /usr/local/bin/npm \
&& rm -rf /opt/acttoolcache/node/24.18.0/x64/bin \
&& mkdir -p /opt/acttoolcache/node/24.18.0/x64/bin \
&& ln -sfn /usr/local/lib/genarrative-node/bin/node /opt/acttoolcache/node/24.18.0/x64/bin/node \
&& ln -sfn /usr/local/bin/npm /opt/acttoolcache/node/24.18.0/x64/bin/npm \
&& ln -sfn /usr/local/lib/genarrative-node/bin/npx /opt/acttoolcache/node/24.18.0/x64/bin/npx \
&& test "$(readlink -f "$(command -v node)")" = "/usr/local/lib/genarrative-node/bin/node" \
&& test "$(node --version)" = "v${NODE_VERSION}" \
&& test "$(npm --version)" = "${NPM_VERSION}"
RUN install -m 0755 /usr/local/cargo/bin/rustup /usr/local/bin/rustup \
&& for command_name in cargo cargo-fmt rustc rustdoc rustfmt; do \
ln -sfn rustup "/usr/local/bin/${command_name}"; \
done
ENV CARGO_HOME=/usr/local/cargo \
GENARRATIVE_GITEA_CI_AGC_RUST_LOCK_SHA256=${AGC_RUST_LOCK_SHA256} \
GENARRATIVE_GITEA_CI_DESKTOP_RUST_LOCK_SHA256=${DESKTOP_RUST_LOCK_SHA256} \
GENARRATIVE_GITEA_CI_NPM_LOCK_SHA256=${NPM_LOCK_SHA256} \
GENARRATIVE_GITEA_CI_NPM_VERSION=${NPM_VERSION} \
GENARRATIVE_GITEA_CI_SERVER_RUST_LOCK_SHA256=${SERVER_RUST_LOCK_SHA256} \
NPM_CONFIG_AUDIT=false \
NPM_CONFIG_FETCH_RETRIES=10 \
NPM_CONFIG_FETCH_RETRY_FACTOR=2 \
NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT=60000 \
NPM_CONFIG_FETCH_RETRY_MINTIMEOUT=2000 \
NPM_CONFIG_FUND=false \
NPM_CONFIG_PREFER_OFFLINE=true \
RUSTUP_AUTO_INSTALL=0 \
RUSTUP_HOME=/usr/local/rustup \
PATH=/usr/local/lib/genarrative-node/bin:/usr/local/bin:/usr/local/cargo/bin:/opt/acttoolcache/node/24.18.0/x64/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ARG IMAGE_REVISION=uncommitted
LABEL org.opencontainers.image.vendor="GenarrativeAI" \
org.opencontainers.image.version="2026.09.20.2" \
org.opencontainers.image.source="https://git.genarrative.world/GenarrativeAI/Genarrative" \
org.opencontainers.image.revision="${IMAGE_REVISION}" \
org.opencontainers.image.base.name="docker.gitea.com/runner-images:ubuntu-latest@sha256:58ea92624c7c09582e05594d95488331045053d3a3f34cf09649f2a32313a614" \
com.genarrative.ci.dockerfile="deploy/container/gitea-ci-job.Dockerfile" \
com.genarrative.ci.definition-sha256="${IMAGE_REVISION}"
RUN node --version \
&& test "$(npm --version)" = "${NPM_VERSION}" \
&& rustup show active-toolchain \
&& rustc --version \
&& cargo --version \
&& rustfmt --version \
&& google-chrome --version \
&& bwrap --version \
&& test -x /usr/local/bin/genarrative-gitea-checkout \
&& bash -n /usr/local/bin/genarrative-gitea-checkout \
&& test -d /root/.npm/_cacache \
&& test -d /usr/local/cargo/registry/cache \
&& rg --version \
&& ffmpeg -version | head -n 1