You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
paritytech/playground-app#118 was a path-config bug: `dot init` installed rustup, but the new `~/.cargo/bin` was not applied to the running init process, so the next step (`rustup toolchain install nightly`) failed with `rustup: command not found` on a fresh machine.
The bug went undetected by the e2e suite because every CI runner already has rustup on PATH from its base image — init's "install rustup" branch never runs in CI.
The follow-up (#114) added a daily-cron container smoke test that runs init in a fresh `ubuntu:22.04` to catch this class of bug. That works, but it gives a slow signal (minutes per run) and only fires nightly. The fast complement is a unit test, but `src/utils/toolchain.ts` doesn't currently expose a seam for one — install and path patching are fused inside per-tool `install` shell pipelines.
What
Refactor `src/utils/toolchain.ts` so the path-update logic is a pure function that takes the install result and the current env, and returns the env to use for subsequent steps. Roughly:
// After:
{
name: "rustup",
check: () => commandExists("rustup"),
install: (onData) => runPiped('curl ... | sh -s -- -y', onData),
/**
* Pure: given the current env after install, return the env the
* next step should run with. For rustup that means prepending
* $HOME/.cargo/bin to PATH if it isn't already there.
*/
patchEnv: (env) => ({
...env,
PATH: prependPath(env.PATH, `${env.HOME}/.cargo/bin`),
}),
manualHint: "https://rustup.rs\",
}
```
Then the orchestrator threads the env through:
```ts
let env = { ...process.env };
for (const step of TOOL_STEPS) {
if (await step.check(env)) continue;
await step.install(env, onData);
if (step.patchEnv) env = step.patchEnv(env);
}
```
Acceptance criteria
`patchEnv` (or whatever it ends up being called) is a pure function with no I/O.
Unit test in `src/utils/toolchain.test.ts`: given an env where `PATH=/usr/bin` and `HOME=/root`, after the rustup step `patchEnv` returns an env whose `PATH` starts with `/root/.cargo/bin`. (The exact [BUG] Apps uploaded as moddable with private repos trigger failure #118 regression — landing in milliseconds on every PR.)
Equivalent unit tests for the foundry, IPFS, and cdm steps.
The orchestrator path-threads the patched env through subsequent `check` and `install` calls. (`check` will need to take an `env` parameter and pass it down to `commandExists`.)
The cold-start container smoke test (`init-cold-smoke` in `.github/workflows/e2e.yml`) keeps passing — this refactor is meant to add fast feedback, not replace the slow end-to-end signal.
Out of scope
Changing what gets installed or how installs are wired up.
The TUI rendering (`src/commands/init/InitScreen.tsx`).
Notes
The orchestrator should fail loudly if a `check` returns true after `patchEnv` but the same `check` returned false before `install` — that's a smoke signal that env patching went the wrong direction.
Don't `process.env = ...` mutate the global. Pass env down explicitly. Tests need to be hermetic.
Why
paritytech/playground-app#118 was a path-config bug: `dot init` installed rustup, but the new `~/.cargo/bin` was not applied to the running init process, so the next step (`rustup toolchain install nightly`) failed with `rustup: command not found` on a fresh machine.
The bug went undetected by the e2e suite because every CI runner already has rustup on PATH from its base image — init's "install rustup" branch never runs in CI.
The follow-up (#114) added a daily-cron container smoke test that runs init in a fresh `ubuntu:22.04` to catch this class of bug. That works, but it gives a slow signal (minutes per run) and only fires nightly. The fast complement is a unit test, but `src/utils/toolchain.ts` doesn't currently expose a seam for one — install and path patching are fused inside per-tool `install` shell pipelines.
What
Refactor `src/utils/toolchain.ts` so the path-update logic is a pure function that takes the install result and the current env, and returns the env to use for subsequent steps. Roughly:
```ts
// Today (sketch):
{
name: "rustup",
check: () => commandExists("rustup"),
install: (onData) => runPiped('curl ... | sh -s -- -y', onData),
manualHint: "https://rustup.rs\",
}
// After:
{
name: "rustup",
check: () => commandExists("rustup"),
install: (onData) => runPiped('curl ... | sh -s -- -y', onData),
/**
* Pure: given the current env after install, return the env the
* next step should run with. For rustup that means prepending
* $HOME/.cargo/bin to PATH if it isn't already there.
*/
patchEnv: (env) => ({
...env,
PATH: prependPath(env.PATH, `${env.HOME}/.cargo/bin`),
}),
manualHint: "https://rustup.rs\",
}
```
Then the orchestrator threads the env through:
```ts
let env = { ...process.env };
for (const step of TOOL_STEPS) {
if (await step.check(env)) continue;
await step.install(env, onData);
if (step.patchEnv) env = step.patchEnv(env);
}
```
Acceptance criteria
Out of scope
Notes