implement-prepare-environment-script

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Implement Prepare Environment Script

实现Prepare Environment脚本

This skill produces a single executable script that performs the one-time per-build setup that precedes a conformance-test run, following a consistent, language-agnostic pattern.
The reference implementation is assets/prepare_environment_java.sh and assets/prepare_environment_python.sh. Read it first — every script you produce must be a faithful translation of that pattern into the target language's tooling and the user's shell environment.
本方案会生成一个可执行脚本,用于在一致性测试运行前执行单次构建前置准备,遵循一套与语言无关的统一模式。
参考实现为assets/prepare_environment_java.shassets/prepare_environment_python.sh。请先阅读这些脚本——你生成的每一个脚本都必须将该模式忠实地转换为目标语言的工具链以及用户的Shell环境。

What a prepare-environment script is for

Prepare Environment脚本的用途

prepare_environment_<lang>
is an optional sibling of
run_conformance_tests_<lang>
. It runs immediately before the conformance script and exists to:
  1. Stage the build into a working folder (the same one the conformance script will use).
  2. Pre-warm the dependency cache / build artifacts so the conformance script can start cold without re-downloading or re-compiling anything.
When this script exists for a project, the corresponding conformance script's own dependency-install phase degrades to "activate only" (see
implement-conformance-testing-script/SKILL.md
→ "Skipping setup when
prepare_environment
exists"). When it doesn't exist, the conformance script does the setup inline.
prepare_environment_<lang>
run_conformance_tests_<lang>
的可选配套脚本。它会在一致性脚本执行前立即运行,主要作用是:
  1. 将构建内容暂存到工作目录(与一致性脚本将使用的目录相同)。
  2. 预加载依赖缓存/构建产物,这样一致性脚本可以直接启动,无需重新下载或重新编译任何内容。
当项目中存在该脚本时,对应的一致性脚本自身的依赖安装阶段会降级为“仅激活”模式(详见
implement-conformance-testing-script/SKILL.md
→ "当
prepare_environment
存在时跳过设置")。如果不存在该脚本,一致性脚本会在内部完成所有设置。

Why this script exists at all (the structural reason)

该脚本存在的核心原因

The conformance test runner is invoked once per functional spec by the renderer — not once per render. Each functional spec in a module has its own
conformance_tests/<module>/<spec>/
folder, and after the renderer finishes generating code for a new spec, it runs the conformance tests of every previous spec in the same module to detect regressions. For a module with N functional specs, the conformance script is invoked roughly N times on every render.
Without a prepare script, every one of those N invocations does the full dependency install (Python venv +
pip install
, full Maven dependency tree,
npm ci
,
cargo build
, ...) from scratch. That cost — paid N times per render — dominates the wall-clock time of rendering a non-trivial project.
prepare_environment_<lang>
exists to amortize that cost to one install per render:
  • Prepare runs once, installs everything, populates the project-local isolation location inside
    .tmp/<lang>_<arg>/
    (
    ./.venv
    ,
    ./node_modules
    ,
    ./.m2
    ,
    ./.gocache
    ,
    ./.cargo
    ,
    ./.pub-cache
    ).
  • The conformance script then runs N times, each invocation in its activate-only variant, attaching to the already-populated working folder and skipping the install step entirely.
  • Net effect: install cost goes from
    N × install-cost
    to
    1 × install-cost + N × cheap-attach-cost
    .
This is the whole reason the prepare-then-conformance split exists. If a project has so few functional specs that the install overhead is negligible, generating a prepare script is wasted effort — the install-inline variant of the conformance script is fine. If a project has many specs (or expensive dependencies, GPU builds, browser binaries, etc.), prepare is mandatory in practice. The user decides per project; this skill is the tool to execute that decision.
一致性测试运行器会被渲染器针对每个功能规范调用一次,而非针对每次渲染调用一次。模块中的每个功能规范都有自己的
conformance_tests/<module>/<spec>/
目录,当渲染器完成新规范的代码生成后,它会运行同一模块中所有之前的规范的一致性测试,以检测回归问题。对于一个包含N个功能规范的模块,每次渲染时一致性脚本会被调用大约N次。
如果没有prepare脚本,这N次调用中的每一次都会从头开始完成完整的依赖安装(Python虚拟环境+
pip install
、完整的Maven依赖树、
npm ci
cargo build
等)。这种成本——每次渲染支付N次——在非 trivial 项目的渲染耗时中占主导地位。
prepare_environment_<lang>
的存在是为了将该成本分摊为每次渲染仅支付一次
  • Prepare脚本运行一次,安装所有依赖,将项目本地隔离位置填充到
    .tmp/<lang>_<arg>/
    (如
    ./.venv
    ./node_modules
    ./.m2
    ./.gocache
    ./.cargo
    ./.pub-cache
    )。
  • 随后一致性脚本运行N次,每次调用都采用仅激活变体,连接到已填充的工作目录并完全跳过安装步骤。
  • 最终效果:安装成本从
    N × 安装成本
    变为
    1 × 安装成本 + N × 低成本连接成本
这就是prepare与一致性脚本拆分存在的全部原因。如果项目的功能规范极少,安装开销可以忽略不计,那么生成prepare脚本就是浪费精力——一致性脚本的内联安装变体就足够了。如果项目有很多规范(或者依赖安装成本很高,比如GPU构建、浏览器二进制文件等),那么prepare脚本在实践中是必不可少的。用户可根据项目情况决定是否使用,本方案就是执行该决策的工具。

prepare_environment
is conformance-only — NOT for unit tests

prepare_environment
仅服务于一致性测试——与单元测试无关

Common and costly mistake: assuming
prepare_environment_<lang>
is a generic "warm up the environment for all the testing scripts" step that the unit-test runner also depends on. It is not.
prepare_environment_<lang>
exists solely to set up the working folder that
run_conformance_tests_<lang>
then attaches to (via the activate-only variant of the conformance script). It has no relationship to
run_unittests_<lang>
:
  • The unit-test runner is fully self-contained. It does its own staging into its own
    .tmp/<lang>_<arg>/
    working folder, and it installs its own dependencies inline (
    pip install -r requirements.txt
    ,
    npm ci
    ,
    mvn
    ,
    cargo fetch
    , ...) every run.
  • The unit-test runner never reads from the working folder
    prepare_environment
    populates. The two scripts use independent working folders even when they happen to share a
    .tmp/<lang>_<arg>/
    naming convention — each script wipes and rebuilds its own copy.
  • The unit-test runner does not require
    prepare_environment
    to have run first. Users and CI systems routinely run unit tests as a smoke check without ever invoking conformance, and that must keep working.
  • There is no activate-only variant of the unit-test runner.
    implement-unit-testing-script
    emits a self-contained script every time — the two-variant pattern is exclusive to the conformance runner.
When authoring
prepare_environment_<lang>
, scope it strictly to what the conformance script needs. Do not bake in dependency installs the unit-test runner needs but conformance doesn't; do not stage files the unit-test runner reads; do not assume the unit-test runner will be the one consuming what you produce. If you find yourself reaching for those, stop — the right answer is to leave
prepare_environment
alone and let the unit-test runner handle its own dependencies inline.
常见且代价高昂的错误: 认为
prepare_environment_<lang>
是一个通用的“为所有测试脚本预热环境”的步骤,单元测试运行器也依赖它。事实并非如此。
prepare_environment_<lang>
的存在是为
run_conformance_tests_<lang>
设置工作目录(通过一致性脚本的仅激活变体连接)。它与
run_unittests_<lang>
没有任何关系
  • 单元测试运行器是完全独立的。它会将内容暂存到自己的
    .tmp/<lang>_<arg>/
    工作目录,并且每次运行都会在内部安装自己的依赖(
    pip install -r requirements.txt
    npm ci
    mvn
    cargo fetch
    等)。
  • 单元测试运行器从不读取
    prepare_environment
    填充的工作目录。即使两个脚本碰巧共享
    .tmp/<lang>_<arg>/
    命名约定,它们也使用独立的工作目录——每个脚本都会清空并重建自己的副本。
  • 单元测试运行器不需要先运行
    prepare_environment
    。用户和CI系统通常会在不调用一致性测试的情况下运行单元测试作为冒烟检查,这种场景必须能够正常工作。
  • 单元测试运行器没有仅激活变体
    implement-unit-testing-script
    每次都会生成一个独立的脚本——双变体模式仅适用于一致性运行器。
编写
prepare_environment_<lang>
时,严格将其范围限定为一致性脚本所需的内容。不要添加单元测试运行器需要但一致性测试不需要的依赖安装;不要暂存单元测试运行器读取的文件;不要假设单元测试运行器会使用你生成的内容。如果你发现自己正在做这些事情,请立即停止——正确的做法是让
prepare_environment
保持原样,让单元测试运行器自行处理其依赖。

How prepare-environment scripts differ from the others

Prepare Environment脚本与其他脚本的区别

This script shares most of its structure with its two siblings (
run_unittests_<lang>
and
run_conformance_tests_<lang>
) but with these differences:
  1. One positional argument:
    <build_folder>
    .
    No conformance tests folder — that's the conformance script's input, not this one's.
  2. No test execution step. This script only stages and installs/builds. It never runs unit tests or conformance tests.
  3. No "no tests discovered" guard. Same reason — no tests are run here.
  4. Side effects must be visible to the conformance script. Anything this script does (working-folder name, dependency isolation location, installed artifacts) must match exactly what the conformance script expects to find. See Coordination contract.
Everything else — toolchain check, build staging, dependency isolation, exit codes — is the same.
该脚本与它的两个兄弟脚本(
run_unittests_<lang>
run_conformance_tests_<lang>
)共享大部分结构,但存在以下差异:
  1. 一个位置参数:
    <build_folder>
    。不需要一致性测试目录——这是一致性脚本的输入,而非本脚本的输入。
  2. 无测试执行步骤。本脚本仅执行暂存和安装/构建操作,从不运行单元测试或一致性测试。
  3. 无“未发现测试”检查。原因同上——本脚本不运行任何测试。
  4. 副作用必须对一致性脚本可见。本脚本执行的任何操作(工作目录名称、依赖隔离位置、已安装产物)必须与一致性脚本期望找到的内容完全匹配。详见协调约定
其他所有部分——工具链检查、构建暂存、依赖隔离、退出码——都是相同的。

Pick the Shell First

先选择Shell类型

Before writing anything, decide which shell flavor the script must target — it depends on the host machine running this skill, not on the language. Detect the host OS proactively; do not default to Bash.
Host OSEmitHow to detect
macOS
.sh
uname -s
returns
Darwin
Linux (incl. WSL, CI runners)
.sh
uname -s
returns
Linux
Native Windows (PowerShell, cmd)
.ps1
$OS
env var contains
Windows_NT
, or
uname -s
returns
MINGW*
/
MSYS*
/
CYGWIN*
(Git Bash / MSYS2 / Cygwin shells on Windows)
Run
uname -s 2>/dev/null || echo "$OS"
if unsure — don't ask the user before checking.
If the project will be used on both macOS/Linux and Windows by different team members or CI runners, generate both
.sh
and
.ps1
versions of this script — they're mechanical translations of each other, share exit codes and isolation paths, and the orchestrator (or the user's CI) picks the right one at runtime. The corresponding
run_conformance_tests_<lang>
script must be produced in matching pairs too.
If you genuinely can't tell (e.g. running in a sandbox with no shell access), ask the user — but only after the detection above failed.
The same pattern applies to both shell flavors. Only the syntax changes.
在编写任何内容之前,先确定脚本必须针对的Shell类型——这取决于运行本方案的主机机器,而非目标语言。主动检测主机操作系统;不要默认使用Bash。
主机操作系统生成脚本类型检测方式
macOS
.sh
uname -s
返回
Darwin
Linux(包括WSL、CI运行器)
.sh
uname -s
返回
Linux
原生Windows(PowerShell、cmd)
.ps1
$OS
环境变量包含
Windows_NT
,或
uname -s
返回
MINGW*
/
MSYS*
/
CYGWIN*
(Windows上的Git Bash/MSYS2/Cygwin Shell)
如果不确定,运行
uname -s 2>/dev/null || echo "$OS"
——在检查之前不要询问用户。
如果项目将被不同团队成员或CI运行器同时在macOS/Linux和Windows上使用,请生成该脚本的**.sh和.ps1两个版本**——它们是彼此的机械翻译,共享退出码和隔离路径,编排器(或用户的CI)会在运行时选择正确的版本。对应的
run_conformance_tests_<lang>
脚本也必须生成匹配的成对版本。
如果你确实无法检测到(例如在没有Shell访问权限的沙箱中运行),请询问用户——但仅在上述检测失败后。
两种Shell类型遵循相同的模式,仅语法不同。

The Pattern

脚本模式

Every prepare-environment script must implement these steps in this order:
  1. Toolchain check. Verify that the required language runtime / build tool (and the required version, if any) is installed. If not, print an error and exit with code
    69
    .
  2. Argument validation. Require one positional argument:
    <build_folder>
    . If missing, print usage and exit with code
    69
    .
  3. Working directory setup. Define a working folder at
    .tmp/<lang>_<arg>
    identical to the path the conformance script will use. Wipe it (
    rm -rf
    /
    Remove-Item -Recurse -Force
    ) and recreate it. This folder — and only this folder — is where every subsequent write must land.
  4. Copy the build. Recursively copy everything from
    <build_folder>
    (
    $1
    ) into the working folder. After this step the source folder (
    $1
    ) is treated as read-only for the rest of the script.
  5. Enter the working directory.
    cd
    /
    Set-Location
    into
    .tmp/<lang>_<arg>
    . If that fails, exit with code
    69
    . All remaining steps run from inside the working folder; they must never write back to
    $1
    .
  6. Install dependencies / pre-build artifacts into an isolated environment inside
    .tmp/<lang>_<arg>
    .
    Set up a per-working-folder dependency location (a Python venv at
    ./.venv
    , a local
    ./node_modules
    , a project-scoped Maven repo at
    ./.m2
    , etc.) and install/resolve all dependencies into it. Where the language requires building before tests can run (Java, Rust, Go), also produce the build artifact and place it where the conformance script can find it — inside the working folder, never inside
    $1
    and never in the user's home directory. Never install into the source build folder (
    $1
    ), the user's global cache (
    ~/.m2
    , system-wide
    pip
    ,
    ~/.cargo
    ,
    ~/.npm
    , ...), or anywhere outside
    .tmp/<lang>_<arg>
    . If any sub-step fails, exit with code
    69
    (do not propagate Maven/pip/npm exit codes — a half-prepared environment is itself an unrecoverable error). See Dependency isolation for per-language specifics.
That's it. There is no step 7. Once dependencies are installed and (where applicable) the build artifact is in the local repo, this script's job is done.
每个prepare-environment脚本必须按以下顺序实现这些步骤:
  1. 工具链检查。验证所需的语言运行时/构建工具(以及所需版本,如果有)已安装。如果未安装,打印错误并以代码
    69
    退出。
  2. 参数验证。要求一个位置参数:
    <build_folder>
    。如果缺失,打印用法说明并以代码
    69
    退出。
  3. 工作目录设置。在
    .tmp/<lang>_<arg>
    定义一个工作目录——与一致性脚本将使用的路径完全相同。清空该目录(
    rm -rf
    /
    Remove-Item -Recurse -Force
    )并重新创建。后续所有写入操作必须仅在该目录中进行。
  4. 复制构建内容。将
    <build_folder>
    $1
    )中的所有内容递归复制到工作目录。完成此步骤后,源目录(
    $1
    )在脚本的剩余部分中将被视为只读
  5. 进入工作目录。使用
    cd
    /
    Set-Location
    进入
    .tmp/<lang>_<arg>
    。如果失败,以代码
    69
    退出。剩余所有步骤都在工作目录内运行;绝对不能写回
    $1
  6. 将依赖/预构建产物安装到
    .tmp/<lang>_<arg>
    内的隔离环境中
    。设置每个工作目录的依赖位置(Python虚拟环境在
    ./.venv
    、本地
    ./node_modules
    、项目范围的Maven仓库在
    ./.m2
    等),并将所有依赖安装/解析到其中。对于需要在测试前构建的语言(Java、Rust、Go),还需生成构建产物并放置在一致性脚本可以找到的位置——必须在工作目录内,绝对不能在
    $1
    内或用户的主目录中。绝对不要安装到源构建目录(
    $1
    )、用户的全局缓存(
    ~/.m2
    、系统级
    pip
    ~/.cargo
    ~/.npm
    等)或
    .tmp/<lang>_<arg>
    之外的任何位置。如果任何子步骤失败,以代码
    69
    退出(不要传播Maven/pip/npm的退出码——半准备好的环境本身就是不可恢复的错误)。有关各语言的具体细节,请参阅依赖隔离
到此结束,没有第7步。一旦依赖安装完成,并且(如适用)构建产物已在本地仓库中,本脚本的任务就完成了。

The build folder is read-only — hard rule

构建目录是只读的——硬性规则

The source build folder passed in as
$1
is input only. Prepare reads from it once in step 4 to populate the working folder, and after that the script must never:
  • install dependencies into it (no
    pip install
    inside
    $1
    , no
    npm install
    inside
    $1
    , no
    mvn install
    writing into
    $1
    , no Cargo build artifacts ending up under
    $1
    ),
  • write a virtualenv /
    node_modules
    /
    .m2
    /
    .gocache
    /
    .cargo
    /
    .pub-cache
    directory inside it,
  • pre-build into it (every compile output —
    target/
    ,
    build/
    ,
    dist/
    , native binaries, generated sources — lives inside
    .tmp/<lang>_<arg>
    ),
  • create logs, caches, or temp files inside it.
The build folder is shared with the renderer (
plain_modules/...
by default) and with the conformance script, which staging-checks it via
if [ ! -d ".tmp/<lang>_$1" ]
and expects
$1
itself to look the same as it did right after rendering. Writing into
$1
corrupts the renderer's view of "what was generated", churns git status if the project commits
$1
, and (if the conformance script ever does an
rm -rf $1
during its own setup) silently destroys work prepare did.
The whole point of staging via
.tmp/<lang>_<arg>
is so the source build folder stays a clean, reproducible artifact of the render. Every dependency, every compiled class, every binary, every cache must land inside the working folder — because that is exactly what the conformance script's activate-only variant attaches to.
If you find yourself about to issue any command whose
cwd
is
$1
, or whose target path starts with
$1/
, stop. Either move the operation into
.tmp/<lang>_<arg>
, or you're doing something the script must not do.
作为
$1
传入的源构建目录是仅输入的。Prepare脚本在步骤4中从该目录读取一次内容以填充工作目录,之后绝对不能:
  • 在其中安装依赖(不要在
    $1
    内运行
    pip install
    npm install
    mvn install
    ,不要让Cargo构建产物出现在
    $1
    下),
  • 在其中创建virtualenv/
    node_modules
    /
    .m2
    /
    .gocache
    /
    .cargo
    /
    .pub-cache
    目录,
  • 在其中预构建(所有编译输出——
    target/
    build/
    dist/
    、原生二进制文件、生成的源代码——必须位于
    .tmp/<lang>_<arg>
    内),
  • 在其中创建日志、缓存或临时文件。
构建目录与渲染器(默认是
plain_modules/...
)和一致性脚本共享,一致性脚本会通过
if [ ! -d ".tmp/<lang>_$1" ]
检查暂存情况,并期望
$1
本身与渲染完成后的状态一致。写入
$1
会破坏渲染器对“生成内容”的认知,如果项目提交
$1
会导致git状态混乱,并且(如果一致性脚本在自己的设置过程中执行
rm -rf $1
)会静默销毁prepare脚本完成的工作。
通过
.tmp/<lang>_<arg>
进行暂存的全部意义在于让源构建目录保持为渲染的干净、可复现产物。所有依赖、编译类、二进制文件、缓存必须位于工作目录内——因为这正是一致性脚本的仅激活变体将连接的位置。
如果你发现自己要执行任何以
$1
为当前工作目录,或目标路径以
$1/
开头的命令,请立即停止。要么将操作移到
.tmp/<lang>_<arg>
内,要么你正在做脚本不允许的事情。

Coordination contract

协调约定

This is the most important part of the skill. A prepare-environment script that doesn't agree with its conformance sibling on where it puts things is worse than no prepare script at all — it costs time and creates the appearance of a warm environment without actually warming the right one.
The two scripts must agree on:
WhatWhy it matters
Working folder path (
.tmp/<lang>_$1
)
The conformance script
cd
s into this folder. If prepare uses a different name, the conformance script sees an empty / freshly-staged folder and re-does all the work.
Dependency isolation location (
./.venv
,
./.m2
,
./node_modules
,
./.gocache
,
./.cargo
, …) — relative to the working folder
If prepare populates
~/.m2
and conformance reads from
./.m2
, the warm cache is invisible. Always use the project-local path inside the working folder, in both scripts.
Build artifact location (Java/Rust/Go)The conformance test project depends on the build's artifact. It must be findable at the exact coordinates the conformance script expects (e.g. installed into the same project-local
./.m2
for Java).
Toolchain versionIf prepare runs under Java 21 and conformance runs under Java 17, classfile incompatibilities will surface at test time, not prepare time. Both scripts should perform the same toolchain check.
When in doubt, read the conformance script first and mirror its assumptions exactly.
这是本方案最重要的部分。如果prepare-environment脚本与其对应的一致性脚本在放置内容的位置上不一致,那么还不如没有prepare脚本——它会浪费时间,并且营造出环境已预热的假象,但实际上并没有预热正确的环境。
两个脚本必须在以下方面达成一致:
内容重要性原因
工作目录路径
.tmp/<lang>_$1
一致性脚本会
cd
到该目录。如果prepare使用不同的名称,一致性脚本会看到一个空的/刚暂存的目录,并重新完成所有工作。
依赖隔离位置
./.venv
./.m2
./node_modules
./.gocache
./.cargo
等)——相对于工作目录
如果prepare填充
~/.m2
而一致性脚本从
./.m2
读取,预热的缓存将不可见。在两个脚本中始终使用工作目录内的项目本地路径。
构建产物位置(Java/Rust/Go)一致性测试项目依赖构建产物。必须在一致性脚本期望的精确位置找到它(例如,Java的情况是安装到相同的项目本地
./.m2
)。
工具链版本如果prepare在Java 21下运行而一致性脚本在Java 17下运行,测试时会出现类文件不兼容问题,而不是在prepare阶段。两个脚本应执行相同的工具链检查。
如有疑问,请先阅读一致性脚本并完全镜像其假设。

Conventions

约定

Shared across both shell flavors:
  • Exit codes:
    • 69
      — unrecoverable: missing argument, missing toolchain, can't enter working folder, dependency install / build failed. Treat all failures as unrecoverable here — there is no "soft" failure mode for prepare.
    • 0
      — success.
  • Working folder naming:
    .tmp/<lang>_<arg>
    where
    <lang>
    is a short identifier for the language (
    java
    ,
    python
    ,
    node
    ,
    go
    ,
    rust
    , ...). Use the first (and only) argument in the path. All dependency installs, build outputs, caches, and pre-built artifacts live inside this folder. Nothing the script does should touch
    $1
    after step 4.
  • Logging: print short progress lines (
    "Preparing <lang> build subfolder: ..."
    ,
    "Copied from ... to ..."
    ,
    "Installing <lang> dependencies into ..."
    ,
    "Pre-build completed in X.XX seconds"
    ) so failures are easy to triage. Wrap noisy "preparing" lines in a
    VERBOSE
    check if matching the Java reference.
  • Time the dependency setup with
    date +%s.%N
    (Bash) /
    Get-Date
    (PowerShell) and print a duration line at the end. This is the slowest phase and the whole reason this script exists; the duration tells you whether it's actually saving time.
两种Shell类型共享以下约定:
  • 退出码:
    • 69
      ——不可恢复:缺失参数、缺失工具链、无法进入工作目录、依赖安装/构建失败。在此处将所有失败视为不可恢复——prepare没有“软”失败模式。
    • 0
      ——成功。
  • 工作目录命名:
    .tmp/<lang>_<arg>
    ,其中
    <lang>
    是语言的短标识符(
    java
    python
    node
    go
    rust
    等)。路径中使用第一个(也是唯一一个)参数。所有依赖安装、构建输出、缓存和预构建产物都位于该目录内。脚本执行的任何操作都不应在步骤4后触碰
    $1
  • **日志:**打印简短的进度行(如
    "正在准备<lang>构建子目录: ..."
    "已从...复制到..."
    "正在将<lang>依赖安装到..."
    "预构建已完成,耗时X.XX秒"
    ),以便轻松排查故障。如果匹配Java参考脚本,可将嘈杂的“准备中”行包装在
    VERBOSE
    检查中。
  • 记录依赖设置耗时:使用
    date +%s.%N
    (Bash)/
    Get-Date
    (PowerShell)计时,并在最后打印耗时行。这是最慢的阶段,也是本脚本存在的全部原因;耗时信息可以告诉你它是否真的在节省时间。

Dependency isolation

依赖隔离

The dependency environment must live inside
$WORKING_FOLDER
so the conformance script can find it and so concurrent runs of other languages / projects can't interfere. Pick the most idiomatic isolation mechanism for the language — and make sure it matches what the conformance script reads from:
LanguageIsolation mechanismPrepare command (run inside
$WORKING_FOLDER
)
Python
venv
at
./.venv
python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
Node.jslocal
./node_modules
(default)
npm ci
(preferred) or
npm install
Javaproject-scoped Maven repo at
./.m2
mvn -Dmaven.repo.local="$(pwd)/.m2" install -DskipTests
(builds and installs the project's own jar into the repo so dependent test projects can resolve it)
Gomodule cache at
./.gocache
GOMODCACHE="$PWD/.gocache" go mod download && GOMODCACHE="$PWD/.gocache" go build ./...
Rustcargo home at
./.cargo
CARGO_HOME="$PWD/.cargo" cargo build --tests
(compiles deps + tests in one shot)
Flutterpub cache at
./.pub-cache
PUB_CACHE="$PWD/.pub-cache" flutter pub get && flutter precache
Notes:
  • Every path in the install / pre-build command is relative to
    .tmp/<lang>_<arg>
    .
    That's why the script
    cd
    s into the working folder in step 5 — from that point on,
    ./.venv
    ,
    ./node_modules
    ,
    ./.m2
    ,
    ./.gocache
    ,
    ./.cargo
    ,
    ./.pub-cache
    , and any compile output (
    target/
    ,
    build/
    ,
    dist/
    , native binaries) all resolve under
    .tmp/<lang>_<arg>
    , never under
    $1
    and never under the user's home directory.
  • Java/Rust/Go must compile, not just download. The conformance script will time-out / re-compile from scratch if you only resolve metadata. Use
    mvn install
    ,
    cargo build --tests
    ,
    go build ./...
    (not just
    dependency:resolve
    /
    cargo fetch
    /
    go mod download
    ).
  • Python and Node.js only need to install — they're interpreted/JIT-compiled at test time, so
    pip install
    /
    npm ci
    is sufficient.
  • Always pass the isolation flag/env var.
    mvn
    without
    -Dmaven.repo.local
    ,
    cargo
    without
    CARGO_HOME
    , etc., write to the user's home directory instead of
    $WORKING_FOLDER
    . The conformance script will look in the wrong place and the warming was wasted — and the user's home dir gets polluted.
  • Treat install failures as
    exit 69
    .
    Unlike the conformance script (which propagates the test command's exit code), prepare has no notion of "the user's tests legitimately failed" — every failure here means the environment isn't usable, period.
依赖环境必须位于**
$WORKING_FOLDER
内**,这样一致性脚本才能找到它,并且其他语言/项目的并发运行不会产生干扰。为语言选择最符合惯例的隔离机制——并确保它与一致性脚本读取的路径匹配:
语言隔离机制
$WORKING_FOLDER
内运行的Prepare命令
Python
venv
位于
./.venv
python3 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
Node.js本地
./node_modules
(默认)
npm ci
(首选)或
npm install
Java项目范围的Maven仓库位于
./.m2
mvn -Dmaven.repo.local="$(pwd)/.m2" install -DskipTests
(构建并将项目自身的jar安装到仓库中,以便依赖的测试项目可以解析它)
Go模块缓存位于
./.gocache
GOMODCACHE="$PWD/.gocache" go mod download && GOMODCACHE="$PWD/.gocache" go build ./...
RustCargo主目录位于
./.cargo
CARGO_HOME="$PWD/.cargo" cargo build --tests
(一次性编译依赖和测试)
FlutterPub缓存位于
./.pub-cache
PUB_CACHE="$PWD/.pub-cache" flutter pub get && flutter precache
注意:
  • 安装/预构建命令中的每个路径都相对于
    .tmp/<lang>_<arg>
    。这就是脚本在步骤5中
    cd
    到工作目录的原因——从那时起,
    ./.venv
    ./node_modules
    ./.m2
    ./.gocache
    ./.cargo
    ./.pub-cache
    以及任何编译输出(
    target/
    build/
    dist/
    、原生二进制文件)都解析到
    .tmp/<lang>_<arg>
    下,绝对不会在
    $1
    下或用户的主目录下。
  • Java/Rust/Go必须编译,而不仅仅是下载。如果你只解析元数据,一致性脚本会超时/从头开始重新编译。使用
    mvn install
    cargo build --tests
    go build ./...
    (而不仅仅是
    dependency:resolve
    /
    cargo fetch
    /
    go mod download
    )。
  • Python和Node.js只需要安装——它们在测试时是解释型/JIT编译的,所以
    pip install
    /
    npm ci
    就足够了。
  • 始终传递隔离标志/环境变量。不带
    -Dmaven.repo.local
    mvn
    、不带
    CARGO_HOME
    cargo
    等会写入用户的主目录而不是
    $WORKING_FOLDER
    。一致性脚本会查找错误的位置,预热工作就白费了——而且用户的主目录会被污染。
  • 将安装失败视为
    exit 69
    。与一致性脚本(传播测试命令的退出码)不同,prepare没有“用户的测试合法失败”的概念——此处的任何失败都意味着环境不可用。

Bash specifics

Bash特定约定

  • Shebang:
    #!/bin/bash
    .
  • File naming:
    prepare_environment_<lang>.sh
    , placed in
    assets/
    .
  • Argument:
    $1
    .
  • Make it executable:
    chmod +x assets/prepare_environment_<lang>.sh
    .
  • cd
    failure check:
    use the
    cd ... 2>/dev/null
    +
    [ $? -ne 0 ]
    pattern from the reference. Put the success log line after the failure check, not before — otherwise it lies on failure.
  • Shebang:
    #!/bin/bash
  • 文件命名:
    prepare_environment_<lang>.sh
    ,放在
    assets/
    目录下。
  • 参数:
    $1
  • 设置可执行权限:
    chmod +x assets/prepare_environment_<lang>.sh
  • cd
    失败检查:使用参考脚本中的
    cd ... 2>/dev/null
    +
    [ $? -ne 0 ]
    模式。将成功日志行放在失败检查
    之后
    ,而不是之前——否则失败时会显示错误信息。

PowerShell specifics

PowerShell特定约定

  • No shebang. Use a
    param([Parameter(Mandatory=$true)][string]$BuildFolder)
    block at the top instead.
  • File naming:
    prepare_environment_<lang>.ps1
    , placed in
    assets/
    .
  • Exit codes: use
    exit 69
    etc. (PowerShell honors them just like Bash).
  • Toolchain check: prefer
    Get-Command <tool> -ErrorAction SilentlyContinue
    and, where a specific version is needed, parse the tool's
    --version
    output.
  • Filesystem: use
    Test-Path
    ,
    Remove-Item -Recurse -Force
    ,
    New-Item -ItemType Directory
    ,
    Copy-Item -Recurse
    ,
    Set-Location
    . Quote paths to handle spaces.
  • No
    chmod
    step needed.
    If execution policy is likely to block the script, mention
    Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
    to the user — don't bake it into the script.
  • 无Shebang。在顶部使用
    param([Parameter(Mandatory=$true)][string]$BuildFolder)
    块代替。
  • 文件命名:
    prepare_environment_<lang>.ps1
    ,放在
    assets/
    目录下。
  • **退出码:**使用
    exit 69
    等(PowerShell与Bash一样遵循这些退出码)。
  • **工具链检查:**优先使用
    Get-Command <tool> -ErrorAction SilentlyContinue
    ,如果需要特定版本,解析工具的
    --version
    输出。
  • **文件系统操作:**使用
    Test-Path
    Remove-Item -Recurse -Force
    New-Item -ItemType Directory
    Copy-Item -Recurse
    Set-Location
    。为路径添加引号以处理空格。
  • 无需
    chmod
    步骤
    。如果执行策略可能阻止脚本运行,请告知用户使用
    Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
    ——不要将其写入脚本。

Workflow

工作流程

  1. Detect the host OS to pick the script flavor. Run
    uname -s 2>/dev/null || echo "$OS"
    and apply the rules in Pick the Shell First:
    Darwin
    /
    Linux
    .sh
    ,
    Windows_NT
    /
    MINGW*
    /
    MSYS*
    /
    CYGWIN*
    .ps1
    . If the project targets both macOS/Linux and Windows (multi-OS team or CI), plan to produce both
    .sh
    and
    .ps1
    files — repeat steps 3–7 for each.
  2. Confirm the target language, dependency manifest (
    pom.xml
    ,
    requirements.txt
    /
    pyproject.toml
    ,
    package.json
    ,
    go.mod
    ,
    Cargo.toml
    , ...), and — critically — read the corresponding
    run_conformance_tests_<lang>
    script first
    if one already exists, so you know what isolation paths and toolchain versions to mirror. Ask if any is unclear.
  3. Read assets/prepare_environment_java.sh to refresh the exact structure. Note: that reference still has divergences from the contract above (see Anti-Patterns) — follow the contract, not the bugs.
  4. Translate each of the six pattern steps into the equivalent commands for the target language and shell. The toolchain check and dependency install/build are the language-specific parts; the rest is mechanical translation between Bash and PowerShell syntax.
  5. Pick the dependency-isolation mechanism from the Dependency isolation table. Verify it matches the path used by the corresponding
    run_conformance_tests_<lang>
    script.
  6. Save the new script to the appropriate
    test_scripts/
    location (e.g.
    test_scripts/prepare_environment_<lang>.sh
    /
    .ps1
    ). For Bash,
    chmod +x
    it.
  7. Reconcile the conformance script (see next section). This is mandatory whenever a matching
    run_conformance_tests_<lang>
    already exists in the project.
  8. After both scripts are in place, do a paired re-read: open prepare and conformance side by side and confirm they agree on working folder name, isolation path, and toolchain version.
  1. 检测主机操作系统以选择脚本类型。运行
    uname -s 2>/dev/null || echo "$OS"
    并应用先选择Shell类型中的规则:
    Darwin
    /
    Linux
    .sh
    Windows_NT
    /
    MINGW*
    /
    MSYS*
    /
    CYGWIN*
    .ps1
    。如果项目同时面向macOS/LinuxWindows(跨OS团队或CI),计划生成**.sh和.ps1两个文件**——对每个文件重复步骤3-7。
  2. 确认目标语言依赖清单
    pom.xml
    requirements.txt
    /
    pyproject.toml
    package.json
    go.mod
    Cargo.toml
    等),并且——至关重要的是——如果已经存在对应的
    run_conformance_tests_<lang>
    脚本,请先阅读该脚本,以便了解要镜像的隔离路径和工具链版本。如有任何不清楚的地方,请询问用户。
  3. 阅读assets/prepare_environment_java.sh以刷新对精确结构的记忆。注意:该参考脚本仍与上述约定存在差异(详见反模式)——请遵循约定,而非参考脚本中的错误。
  4. 将六个模式步骤转换为目标语言Shell的等效命令。工具链检查和依赖安装/构建是语言特定的部分;其余部分是Bash和PowerShell语法之间的机械转换。
  5. 依赖隔离表中选择依赖隔离机制。验证它与对应的
    run_conformance_tests_<lang>
    脚本使用的路径匹配
  6. 将新脚本保存到合适的
    test_scripts/
    位置(例如
    test_scripts/prepare_environment_<lang>.sh
    /
    .ps1
    )。对于Bash脚本,设置
    chmod +x
    权限。
  7. 协调一致性脚本(见下一节)。只要项目中已经存在匹配的
    run_conformance_tests_<lang>
    脚本,这一步就是强制性的。
  8. 两个脚本都到位后,并排重新阅读:打开prepare和一致性脚本,确认它们在工作目录名称、隔离路径和工具链版本上达成一致。

Reconcile the existing conformance script

协调现有的一致性脚本

Adding a
prepare_environment_<lang>
script changes the contract for the corresponding
run_conformance_tests_<lang>
script — anything prepare now handles must be removed from conformance, otherwise prepare's work is wiped (by re-staging) or duplicated (by re-installing). Run this reconciliation every time this skill is used.
添加
prepare_environment_<lang>
脚本会改变对应的
run_conformance_tests_<lang>
脚本的约定——prepare现在处理的任何步骤都必须从一致性脚本中移除,否则prepare的工作会被(重新暂存)清除或(重新安装)重复,从而失去意义。每次使用本方案时都必须执行此协调步骤。

Step-by-step

分步操作

  1. Look for an existing conformance script in the project. Check the conventional locations (
    test_scripts/run_conformance_tests_<lang>.sh
    /
    .ps1
    , or wherever the project's
    config.yaml
    points its
    conformance-tests-script:
    key).
  2. If it doesn't exist → stop. Nothing to reconcile. The conformance script will be generated later by
    implement-conformance-testing-script
    , which already knows about the activate-only variant.
  3. If it does exist → patch it. Identify and remove the steps that prepare now owns:
Step in conformanceIf prepare exists, you must...
Staging block (
rm -rf .tmp/<lang>_$1
+
mkdir -p
+
cp -R $1/* .tmp/...
)
Remove entirely. Replace with a guard:
if [ ! -d ".tmp/<lang>_$1" ]; then echo "Error: build folder missing — run prepare_environment_<lang>.sh first."; exit 69; fi
Dependency install / pre-build (
pip install
,
mvn install -DskipTests
,
npm ci
,
cargo build --tests
, etc.)
Remove entirely. Replace with a guard that the isolation location exists (
.venv/bin/activate
for Python,
.m2/
for Java,
node_modules/
for Node, etc.) and exit
69
if missing.
Activation step (Python
source .venv/bin/activate
, Java
-Dmaven.repo.local=$(pwd)/.m2
)
Keep. Without it the test command can't see the prepared deps.
Test execution + "no tests discovered" guard + exit-code propagationKeep unchanged.
  1. Verify the conformance script's exit codes still follow
    implement-conformance-testing-script
    — the new "missing prepared environment" guard should exit
    69
    (unrecoverable invocation error), the no-tests guard should still exit
    1
    , and the test command's exit code should still propagate.
  2. Run a smoke check:
    prepare_environment_<lang>.sh <build_folder> && run_conformance_tests_<lang>.sh <build_folder> <conformance_tests_folder>
    should succeed end-to-end. If conformance fails with "missing prepared environment" right after a successful prepare, the two scripts disagree on either the working-folder path or the isolation location — go back to Coordination contract.
  1. 查找项目中现有的一致性脚本。检查常规位置(
    test_scripts/run_conformance_tests_<lang>.sh
    /
    .ps1
    ,或项目
    config.yaml
    conformance-tests-script:
    键指向的位置)。
  2. 如果不存在→停止。无需协调。 一致性脚本稍后会由
    implement-conformance-testing-script
    生成,该方案已经了解仅激活变体。
  3. 如果存在→修补它。识别并移除现在由prepare负责的步骤:
一致性脚本中的步骤如果存在prepare脚本,你必须...
暂存块(
rm -rf .tmp/<lang>_$1
+
mkdir -p
+
cp -R $1/* .tmp/...
完全移除。替换为检查:
if [ ! -d ".tmp/<lang>_$1" ]; then echo "错误:构建目录缺失——请先运行prepare_environment_<lang>.sh。"; exit 69; fi
依赖安装/预构建(
pip install
mvn install -DskipTests
npm ci
cargo build --tests
等)
完全移除。替换为检查隔离位置是否存在(Python的
.venv/bin/activate
、Java的
.m2/
、Node的
node_modules/
等),如果缺失则以
69
退出。
激活步骤(Python的
source .venv/bin/activate
、Java的
-Dmaven.repo.local=$(pwd)/.m2
保留。没有它,测试命令无法看到已准备好的依赖。
测试执行 + “未发现测试”检查 + 退出码传播保持不变
  1. 验证一致性脚本的退出码仍符合
    implement-conformance-testing-script
    ——新的“缺失已准备环境”检查应以
    69
    退出(不可恢复的调用错误),未发现测试的检查仍应以
    1
    退出,测试命令的退出码仍应传播。
  2. 运行冒烟测试
    prepare_environment_<lang>.sh <build_folder> && run_conformance_tests_<lang>.sh <build_folder> <conformance_tests_folder>
    应能端到端成功运行。如果prepare成功运行后,一致性脚本仍因“缺失已准备环境”失败,则两个脚本在工作目录路径或隔离位置上不一致——请回到协调约定

When to skip this reconciliation

何时跳过此协调步骤

  • The conformance script doesn't exist yet. Nothing to reconcile.
  • The conformance script already shows no signs of inline staging or install. It was previously generated as the activate-only variant — leave it alone.
  • The user explicitly asks to keep prepare and conformance independent (e.g. so conformance can run standalone without prepare). Document this clearly in a comment at the top of both scripts and skip the reconciliation. Note that this loses all the speedup prepare was meant to provide.
  • 一致性脚本尚未存在。无需协调。
  • 一致性脚本已没有内联暂存或安装的迹象。它之前已生成为仅激活变体——保持原样即可。
  • 用户明确要求让prepare和一致性脚本保持独立(例如,让一致性脚本无需prepare即可独立运行)。在两个脚本的顶部添加清晰的注释记录此情况,并跳过协调步骤。请注意,这会失去prepare原本要提供的所有加速效果。

Anti-Patterns

反模式

  • (Hard mistake) Don't pre-warm the unit-test runner from this script.
    prepare_environment_<lang>
    is for the conformance script only. The unit-test runner (
    implement-unit-testing-script
    ) is always fully self-contained — it stages, installs, and runs in one shot, every invocation, regardless of whether a prepare script exists. Do not add a unit-test dependency-install step to
    prepare_environment
    "to save time"; the unit-test runner will not read what you produce, and the coupling breaks the activate-only contract between prepare and conformance. See
    prepare_environment
    is conformance-only — NOT for unit tests
    above.
  • (Hard mistake) Don't install into, build into, or otherwise write to the source build folder (
    $1
    ).
    The build folder passed as
    $1
    is read-only input after step 4. Every install, cache, build artifact (
    target/
    ,
    build/
    ,
    dist/
    , native binaries, generated sources), log, and temp file must land in
    .tmp/<lang>_<arg>
    . This includes never running
    pip install
    ,
    npm install
    ,
    mvn install
    ,
    cargo build
    , or
    go build
    with
    $1
    as their
    cwd
    or target; never letting a venv /
    node_modules
    /
    .m2
    /
    .gocache
    /
    .cargo
    /
    .pub-cache
    directory appear inside
    $1
    ; and never producing a pre-built artifact at any path under
    $1/
    . The whole point of staging into
    .tmp/
    is so the build folder remains a clean artifact of the render — writing to it corrupts the renderer's view, churns git status, and can be silently destroyed if the conformance script ever re-stages
    $1
    on its own.
  • Don't write to the user's global dependency cache (
    ~/.m2
    , system-wide
    pip
    ,
    ~/.cargo
    ,
    ~/.npm
    , etc.). The conformance script reads from the project-local cache; a global write is invisible to it and pollutes the user's home dir.
  • Don't use a different working folder name than the conformance script. They must match exactly. If you change one, change the other.
  • Don't run tests — not unit tests, not conformance tests, not smoke tests. Prepare's contract is "set up the environment"; running tests belongs to its siblings.
  • Don't propagate non-
    69
    exit codes from
    mvn
    /
    pip
    /
    npm
    .
    A failed install means the environment isn't usable. Treat every failure as
    exit 69
    so the orchestrator can tell "prepare failed" apart from "tests failed".
  • Don't skip the toolchain check, even when "everyone has it installed" — exit code
    69
    is what the calling system relies on to detect a missing runtime, and prepare is usually the first script to run, so it's the cheapest place to surface a missing JDK / Python / Node.
  • Don't print the "moved to ..." line before the
    cd
    success check.
    The reference script does this and it lies on failure. Put the log after the guard, or print "attempting to enter ..." instead.
  • Don't reuse the source folder in place. Always copy into
    .tmp/<lang>_<arg>
    first; the conformance script relies on this isolation.
  • Don't change the exit-code contract between Bash and PowerShell variants. The
    .sh
    and
    .ps1
    for the same language must use identical exit codes for identical failure modes.
  • Don't write a cross-shell hybrid (e.g. a
    .sh
    that detects PowerShell, or vice versa). Ship one script per shell, named with the appropriate extension.
  • Don't forget to time the install. Without the duration log, there's no way to tell whether prepare is actually saving wall-clock time vs. doing the same work the conformance script would have done inline.
  • Don't leave an existing
    run_conformance_tests_<lang>
    script untouched after generating prepare.
    If the conformance script still does its own staging and install, prepare's work is wiped (by the
    rm -rf
    ) or duplicated (by re-running install) on every run — defeating the purpose of this skill entirely. Always run the Reconcile the existing conformance script step.
  • Don't default to Bash without checking the host OS. A
    .sh
    script on native Windows (outside Git Bash / WSL) won't even run, and a
    .ps1
    script on macOS/Linux is equally useless. Always run the detection in Pick the Shell First before deciding the file extension. If the project supports both, produce both files — and remember to reconcile the matching conformance script in both flavors too.
  • (严重错误)不要从本脚本预热单元测试运行器
    prepare_environment_<lang>
    仅服务于一致性脚本。单元测试运行器(
    implement-unit-testing-script
    )始终是完全独立的——它每次调用都会一次性完成暂存、安装和运行,无论是否存在prepare脚本。不要在
    prepare_environment
    中添加单元测试依赖安装步骤“以节省时间”;单元测试运行器不会读取你生成的内容,这种耦合会破坏prepare和一致性脚本之间的仅激活约定。详见上文
    prepare_environment
    仅服务于一致性测试——与单元测试无关
  • (严重错误)不要安装到、构建到或以其他方式写入源构建目录(
    $1
    。作为
    $1
    传入的构建目录在步骤4后是只读输入。所有安装、缓存、构建产物(
    target/
    build/
    dist/
    、原生二进制文件、生成的源代码)、日志和临时文件必须位于
    .tmp/<lang>_<arg>
    内。这包括绝对不要在
    $1
    作为当前工作目录或目标路径时运行
    pip install
    npm install
    mvn install
    cargo build
    go build
    ;绝对不要让venv/
    node_modules
    /
    .m2
    /
    .gocache
    /
    .cargo
    /
    .pub-cache
    目录出现在
    $1
    内;绝对不要在
    $1/
    下的任何路径生成预构建产物。暂存到
    .tmp/
    的全部意义在于让构建目录保持为渲染的干净产物——写入该目录会破坏渲染器的认知,导致git状态混乱,并且如果一致性脚本自行重新暂存
    $1
    ,会静默销毁prepare完成的工作。
  • 不要写入用户的全局依赖缓存
    ~/.m2
    、系统级
    pip
    ~/.cargo
    ~/.npm
    等)。一致性脚本从项目本地缓存读取;全局写入对它不可见,还会污染用户的主目录。
  • 不要使用与一致性脚本不同的工作目录名称。它们必须完全匹配。如果你更改了其中一个,请同时更改另一个。
  • 不要运行测试——不要运行单元测试、一致性测试或冒烟测试。Prepare的约定是“设置环境”;运行测试是其兄弟脚本的职责。
  • 不要从
    mvn
    /
    pip
    /
    npm
    传播非
    69
    的退出码
    。安装失败意味着环境不可用。将所有失败视为
    exit 69
    ,这样编排器可以区分“prepare失败”和“测试失败”。
  • 不要跳过工具链检查,即使“每个人都已安装”——退出码
    69
    是调用系统检测缺失运行时的依据,而prepare通常是第一个运行的脚本,因此是发现缺失JDK/Python/Node的最廉价位置。
  • 不要在
    cd
    成功检查之前打印“已移动到...”行
    。参考脚本这样做了,但失败时会显示错误信息。将日志放在检查之后,或者打印“尝试进入...”。
  • 不要原地复用源目录。始终先复制到
    .tmp/<lang>_<arg>
    ;一致性脚本依赖这种隔离。
  • 不要更改Bash和PowerShell变体之间的退出码约定。同一语言的
    .sh
    .ps1
    脚本必须对相同的失败模式使用相同的退出码。
  • 不要编写跨Shell混合脚本(例如检测PowerShell的
    .sh
    脚本,反之亦然)。为每个Shell提供一个脚本,使用适当的扩展名命名。
  • 不要忘记记录安装耗时。没有耗时日志,就无法判断prepare是否真的在节省实际时间,还是在做一致性脚本原本会内联完成的相同工作。
  • 生成prepare脚本后不要让现有的
    run_conformance_tests_<lang>
    脚本保持不变
    。如果一致性脚本仍自行执行暂存和安装,prepare的工作会在每次运行时被(
    rm -rf
    )清除或(重新运行安装)重复——完全违背了本方案的目的。始终执行协调现有的一致性脚本步骤。
  • 不要在未检查主机操作系统的情况下默认使用Bash。原生Windows上的
    .sh
    脚本(Git Bash/WSL之外)甚至无法运行,macOS/Linux上的
    .ps1
    脚本同样无用。在决定文件扩展名之前,始终执行先选择Shell类型中的检测。如果项目支持两种操作系统,请生成两个文件——并且记得也要协调两种类型的匹配一致性脚本。