From 80d23f0e3da84ce5d7eead8fe5ab522ed0f1b0d0 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Mon, 2 Nov 2026 21:54:14 +0800 Subject: [PATCH] Improve Docker dependency caching and isolate Python runtime --- .dockerignore | 15 +++++++++++++++ .gitea/workflows/brand.yml | 2 ++ .gitea/workflows/creative-workspace.yml | 4 ++++ .gitea/workflows/python.yml | 9 ++++++++- .gitea/workflows/waterfall-wiki.yml | 2 ++ Dockerfile | 4 +++- apps/python/Dockerfile | 18 ++++++++++++++++-- apps/studio/Dockerfile | 4 +++- apps/waterfall-wiki/Dockerfile | 4 +++- docs/docker-build-cache.md | 23 +++++++++++++++++++++++ packages/brand/Dockerfile | 4 ++-- 11 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 docs/docker-build-cache.md diff --git a/.dockerignore b/.dockerignore index 4401a39..faa33ee 100644 --- a/.dockerignore +++ b/.dockerignore @@ -22,3 +22,18 @@ coverage # Local authoring assets are uploaded via APIs, never application build inputs. /content + +# Apply local metadata, secrets and generated-output exclusions at every depth. +**/.git +**/.worktrees +**/.pnpm-store +**/.turbo +**/.nx +**/coverage +**/artifacts +**/.pytest_cache +**/*.egg-info +**/*.tsbuildinfo +**/.env +**/.env.* +!**/.env.example diff --git a/.gitea/workflows/brand.yml b/.gitea/workflows/brand.yml index da4a5aa..436bc88 100644 --- a/.gitea/workflows/brand.yml +++ b/.gitea/workflows/brand.yml @@ -3,6 +3,7 @@ on: pull_request: branches: [main] paths: + - '.dockerignore' - 'packages/brand/**' - 'pnpm-workspace.yaml' - 'package.json' @@ -11,6 +12,7 @@ on: push: branches: [main] paths: + - '.dockerignore' - 'packages/brand/**' - 'pnpm-workspace.yaml' - '.gitea/workflows/brand.yml' diff --git a/.gitea/workflows/creative-workspace.yml b/.gitea/workflows/creative-workspace.yml index ee90d9a..cbb2b86 100644 --- a/.gitea/workflows/creative-workspace.yml +++ b/.gitea/workflows/creative-workspace.yml @@ -3,7 +3,11 @@ on: pull_request: branches: [main] paths: + - '.dockerignore' + - 'Dockerfile' + - 'pnpm-workspace.yaml' - 'apps/studio/**' + - 'packages/brand/**' - 'apps/waterfall-wiki/**' - '.gitea/workflows/**' - 'scripts/*studio*' diff --git a/.gitea/workflows/python.yml b/.gitea/workflows/python.yml index bb5b5d6..64c0cba 100644 --- a/.gitea/workflows/python.yml +++ b/.gitea/workflows/python.yml @@ -1,15 +1,22 @@ name: python CI and deployment on: + pull_request: + branches: [main] + paths: + - '.dockerignore' + - 'apps/python/**' + - 'scripts/deploy-python.sh' + - '.gitea/workflows/python.yml' push: branches: [main] paths: + - '.dockerignore' - 'apps/python/**' - 'scripts/deploy-python.sh' - '.gitea/workflows/python.yml' jobs: verify-and-deploy: - if: gitea.ref == 'refs/heads/main' && gitea.event_name == 'push' runs-on: ces-control timeout-minutes: 45 steps: diff --git a/.gitea/workflows/waterfall-wiki.yml b/.gitea/workflows/waterfall-wiki.yml index dba9b29..9d10db1 100644 --- a/.gitea/workflows/waterfall-wiki.yml +++ b/.gitea/workflows/waterfall-wiki.yml @@ -3,8 +3,10 @@ on: push: branches: [main] paths: + - '.dockerignore' - 'apps/waterfall-wiki/**' - 'apps/studio/**' + - 'packages/brand/**' - 'scripts/*studio*' - 'content/studio-examples/**' - 'content/studio-tools/layouts-api.md' diff --git a/Dockerfile b/Dockerfile index 245d4e4..363449f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,12 +12,14 @@ LABEL io.entroia.wiki.build="true" RUN corepack enable && corepack prepare pnpm@11.25.0 --activate COPY apps/waterfall-wiki/pnpm-lock.yaml ./ COPY pnpm-workspace.yaml /repo/pnpm-workspace.yaml -COPY packages/brand/ /repo/packages/brand/ +COPY packages/brand/package.json /repo/packages/brand/package.json COPY apps/waterfall-wiki/package.json ./ RUN pnpm --filter @prompt/waterfall-wiki install --frozen-lockfile --fetch-timeout=300000 --network-concurrency=8 FROM dependencies AS build # .dockerignore excludes docs and operational notes without extra legacy COPY snapshots. +# Brand source changes invalidate compilation, not dependency installation. +COPY packages/brand/ /repo/packages/brand/ COPY apps/waterfall-wiki/ . RUN pnpm typecheck && pnpm test && pnpm build && pnpm test:smoke diff --git a/apps/python/Dockerfile b/apps/python/Dockerfile index 7a025c0..ac6498f 100644 --- a/apps/python/Dockerfile +++ b/apps/python/Dockerfile @@ -1,8 +1,22 @@ -FROM python:3.12-slim +FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg fonts-noto-cjk && rm -rf /var/lib/apt/lists/* + +FROM base AS dependencies +ENV PATH="/opt/venv/bin:$PATH" WORKDIR /app +RUN python -m venv /opt/venv +COPY apps/python/pyproject.toml ./ +# Read the pinned requirements from the package metadata before copying source. +RUN python -c 'import subprocess, tomllib; p = tomllib.load(open("pyproject.toml", "rb")); subprocess.check_call(["python", "-m", "pip", "install", "--no-cache-dir", *p["build-system"]["requires"], *p["project"]["dependencies"]])' + +FROM dependencies AS build COPY apps/python/ . -RUN pip install --no-cache-dir . && python -m unittest discover -s tests -v +RUN pip install --no-cache-dir --no-deps --no-build-isolation . && python -m unittest discover -s tests -v + +FROM base AS runtime +WORKDIR /app +ENV PATH="/opt/venv/bin:$PATH" +COPY --from=build /opt/venv /opt/venv RUN useradd --create-home exporter USER exporter ENTRYPOINT ["prompt-export"] diff --git a/apps/studio/Dockerfile b/apps/studio/Dockerfile index 37ada5b..d73b6b4 100644 --- a/apps/studio/Dockerfile +++ b/apps/studio/Dockerfile @@ -3,9 +3,11 @@ WORKDIR /repo/apps/studio RUN corepack enable && corepack prepare pnpm@11.25.0 --activate COPY apps/studio/pnpm-lock.yaml ./ COPY pnpm-workspace.yaml /repo/pnpm-workspace.yaml -COPY packages/brand/ /repo/packages/brand/ +COPY packages/brand/package.json /repo/packages/brand/package.json COPY apps/studio/package.json ./ RUN pnpm --filter @prompt/studio install --frozen-lockfile --fetch-timeout=300000 --network-concurrency=8 +# Brand source changes invalidate compilation, not dependency installation. +COPY packages/brand/ /repo/packages/brand/ COPY apps/studio/ . # Compare the two public parameter validators inside the isolated CI build. COPY apps/waterfall-wiki/src/lib/layout-parameters.ts /repo/apps/waterfall-wiki/src/lib/layout-parameters.ts diff --git a/apps/waterfall-wiki/Dockerfile b/apps/waterfall-wiki/Dockerfile index 0d77b6a..d38cebb 100644 --- a/apps/waterfall-wiki/Dockerfile +++ b/apps/waterfall-wiki/Dockerfile @@ -10,12 +10,14 @@ WORKDIR /repo/apps/waterfall-wiki RUN corepack enable && corepack prepare pnpm@11.25.0 --activate COPY apps/waterfall-wiki/pnpm-lock.yaml ./ COPY pnpm-workspace.yaml /repo/pnpm-workspace.yaml -COPY packages/brand/ /repo/packages/brand/ +COPY packages/brand/package.json /repo/packages/brand/package.json COPY apps/waterfall-wiki/package.json ./ RUN pnpm --filter @prompt/waterfall-wiki install --frozen-lockfile --fetch-timeout=300000 --network-concurrency=8 FROM dependencies AS build # .dockerignore excludes docs and operational notes without extra legacy COPY snapshots. +# Brand source changes invalidate compilation, not dependency installation. +COPY packages/brand/ /repo/packages/brand/ COPY apps/waterfall-wiki/ . RUN pnpm typecheck && pnpm test && pnpm build && pnpm test:smoke diff --git a/docs/docker-build-cache.md b/docs/docker-build-cache.md new file mode 100644 index 0000000..72aa2c8 --- /dev/null +++ b/docs/docker-build-cache.md @@ -0,0 +1,23 @@ +# Docker 构建上下文与缓存 + +## 入口与忽略规则 + +所有 CI 构建命令都在仓库根目录使用 `.` 作为 context,包括以 `-f` 选择的子项目 Dockerfile。统一使用根 `.dockerignore`,递归排除依赖目录、Git 元数据、本机环境文件、编译输出、测试证据及缓存;保留 `.env.example` 供 Compose 校验使用。 + +普通的子目录 `.dockerignore` 不会自动叠加到根 context。当前 runner 使用 legacy builder,不依赖 Dockerfile 专属忽略文件或 BuildKit cache mount。若以后改用子目录 context,必须同时调整共享包与跨应用文件的输入路径,不能只在子目录添加忽略文件。 + +## 依赖层与源码层 + +- Wiki 的根 Dockerfile 是实际 CI 入口,`apps/waterfall-wiki/Dockerfile` 是对应副本,两者的功能内容保持同步;根文件额外保留镜像生命周期标签。 +- Web 应用安装前只复制自身清单、锁文件、workspace 配置和品牌包清单,满足 `workspace:*` 依赖发现。完整品牌包在安装后复制;颜色、Logo 或品牌脚本变化仍会重新编译应用,但不会仅因此重新下载依赖。 +- Python 从 `pyproject.toml` 读取固定运行依赖与构建后端要求,在独立依赖阶段安装。源码阶段安装当前包并运行单测,最终镜像仅继承系统运行环境并复制已验证的虚拟环境,不携带应用源码目录和测试目录。虚拟环境仍包含 pip 和构建后端,未声称完全剥离构建工具。 +- 品牌检查镜像只用于 CI。其 Python 图片校验依赖安装放在品牌源码之前,避免源码变化重新下载这些依赖。 +- 不因共享包缓存命中而漏掉消费者:品牌变更需触发 Wiki/Studio PR 检查和 main 发布。根忽略规则变化也触发相关检查。 + +## 验证与限制 + +构建、打包与产物验证只在已确认的 `ces-control` runner 执行。Python PR 运行镜像构建和单测,但只有 main push 才会发布 latest 标签。Web PR 与品牌检查沿用现有远程 Docker 验证流程。 + +本次没有升级 Docker builder,也没有承诺消除 legacy builder 的镜像层提交耗时;缓存层调整后的实际收益需比较后续 CI 日志。源码变化仍需构建,持久测试环境和按影响范围选择测试属于后续 CI 调整。 + +本机不新增 Dev Containers/Tilt 启动方式;这类方案需要单独确认本地运行和编译授权。 diff --git a/packages/brand/Dockerfile b/packages/brand/Dockerfile index e512558..2778ff8 100644 --- a/packages/brand/Dockerfile +++ b/packages/brand/Dockerfile @@ -3,10 +3,10 @@ WORKDIR /repo RUN corepack enable && corepack prepare pnpm@11.25.0 --activate COPY packages/brand/package.json packages/brand/pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile --ignore-scripts -COPY packages/brand/ ./ -RUN pnpm test && pnpm build && pnpm test:tailwind && pnpm test:types RUN apt-get update && apt-get install -y --no-install-recommends python3 python3-venv \ && rm -rf /var/lib/apt/lists/* \ && python3 -m venv /opt/brand-python \ && /opt/brand-python/bin/pip install --only-binary=:all: Pillow==13.0.0 resvg-py==0.5.0 +COPY packages/brand/ ./ +RUN pnpm test && pnpm build && pnpm test:tailwind && pnpm test:types RUN /opt/brand-python/bin/python tests/assets.py