mirror of
https://github.com/gmeligio/flutter-docker-image.git
synced 2026-05-24 12:30:34 +00:00
feat: migrate docs/src from npm to pnpm (#460)
- Pin `pnpm = "11.2.2"` in `mise.toml` so the `docs/src` build uses a manifest-pinned package manager, bringing the docs toolchain under the `ci-runtime-tool-versioning` invariant alongside `cue`, `node`, `gx`, and `git-cliff`.
This commit is contained in:
@@ -309,8 +309,8 @@ jobs:
|
|||||||
- name: Build documentation
|
- name: Build documentation
|
||||||
working-directory: docs/src
|
working-directory: docs/src
|
||||||
run: |
|
run: |
|
||||||
npm ci --prefer-offline
|
pnpm install --frozen-lockfile
|
||||||
npm run build
|
pnpm run build
|
||||||
|
|
||||||
# Upload generated docs so reviewers can inspect them. Commit-back is
|
# Upload generated docs so reviewers can inspect them. Commit-back is
|
||||||
# handled by update_docs.yml on push to main — pushing to fork PR
|
# handled by update_docs.yml on push to main — pushing to fork PR
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ jobs:
|
|||||||
- name: Build documentation
|
- name: Build documentation
|
||||||
working-directory: docs/src
|
working-directory: docs/src
|
||||||
run: |
|
run: |
|
||||||
npm ci --prefer-offline
|
pnpm install --frozen-lockfile
|
||||||
npm run build
|
pnpm run build
|
||||||
|
|
||||||
- name: Generate authentication token with GitHub App to trigger Actions
|
- name: Generate authentication token with GitHub App to trigger Actions
|
||||||
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
|
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
|
||||||
|
|||||||
@@ -379,8 +379,8 @@ jobs:
|
|||||||
- name: Update documentation
|
- name: Update documentation
|
||||||
working-directory: docs/src
|
working-directory: docs/src
|
||||||
run: |
|
run: |
|
||||||
npm ci --prefer-offline
|
pnpm install --frozen-lockfile
|
||||||
npm run build
|
pnpm run build
|
||||||
|
|
||||||
- name: Read environment variables from the version manifest
|
- name: Read environment variables from the version manifest
|
||||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||||
|
|||||||
@@ -8,6 +8,18 @@ An AI-generated wiki for this repository is available at [deepwiki.com/gmeligio/
|
|||||||
|
|
||||||
The wiki is kept current automatically: DeepWiki re-indexes the repository whenever it detects the DeepWiki badge in `readme.md`. No manual action is required after merging to `main`.
|
The wiki is kept current automatically: DeepWiki re-indexes the repository whenever it detects the DeepWiki badge in `readme.md`. No manual action is required after merging to `main`.
|
||||||
|
|
||||||
|
## Building the docs locally
|
||||||
|
|
||||||
|
The Markdown files at the repository root (`readme.md`, `LICENSE.md`, `docs/contributing.md`, `docs/windows.md`) are generated from the MDX sources under `docs/src/`. The build uses `pnpm`, pinned in `mise.toml` alongside the other CI tools. From `docs/src/`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
pnpm run build
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
`devEngines.packageManager` in `docs/src/package.json` is set to `pnpm` with `onFail: "error"`, so `npm install` will refuse to run.
|
||||||
|
|
||||||
## Editing GitHub Actions workflows
|
## Editing GitHub Actions workflows
|
||||||
|
|
||||||
GitHub Actions versions are tracked with [gx](https://github.com/gmeligio/gx). The manifest at `.github/gx.toml` is the source of truth for version constraints, and `.github/gx.lock` records the resolved SHAs. Workflows must use SHA pins with a `# vX.Y.Z` comment.
|
GitHub Actions versions are tracked with [gx](https://github.com/gmeligio/gx). The manifest at `.github/gx.toml` is the source of truth for version constraints, and `.github/gx.lock` records the resolved SHAs. Workflows must use SHA pins with a `# vX.Y.Z` comment.
|
||||||
|
|||||||
+13
-10
@@ -18,14 +18,17 @@ function mdxOptions(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const args = process.argv.slice(2)
|
const args = process.argv.slice(2)
|
||||||
const sourceRelativePath = args[0]
|
if (args.length === 0 || args.length % 2 !== 0) {
|
||||||
const outputRelativePath = args[1]
|
console.error('Usage: node compile.js <src.mdx> <dst.md> [<src.mdx> <dst.md> ...]')
|
||||||
const markdown = await mdxToMd(resolve(sourceRelativePath), {
|
process.exit(1)
|
||||||
mdxOptions,
|
}
|
||||||
})
|
|
||||||
const banner = `This markdown file was auto-generated from "${sourceRelativePath}"`
|
|
||||||
const readme = `<!--- ${banner} -->\n\n${markdown}`
|
|
||||||
|
|
||||||
await writeFile(outputRelativePath, readme)
|
for (let i = 0; i < args.length; i += 2) {
|
||||||
|
const sourceRelativePath = args[i]
|
||||||
console.log(`📝 Converted ${sourceRelativePath} -> ${outputRelativePath}`)
|
const outputRelativePath = args[i + 1]
|
||||||
|
const markdown = await mdxToMd(resolve(sourceRelativePath), { mdxOptions })
|
||||||
|
const banner = `This markdown file was auto-generated from "${sourceRelativePath}"`
|
||||||
|
const output = `<!--- ${banner} -->\n\n${markdown}`
|
||||||
|
await writeFile(outputRelativePath, output)
|
||||||
|
console.log(`📝 Converted ${sourceRelativePath} -> ${outputRelativePath}`)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,17 @@ An AI-generated wiki for this repository is available at [deepwiki.com/gmeligio/
|
|||||||
|
|
||||||
The wiki is kept current automatically: DeepWiki re-indexes the repository whenever it detects the DeepWiki badge in `readme.md`. No manual action is required after merging to `main`.
|
The wiki is kept current automatically: DeepWiki re-indexes the repository whenever it detects the DeepWiki badge in `readme.md`. No manual action is required after merging to `main`.
|
||||||
|
|
||||||
|
## Building the docs locally
|
||||||
|
|
||||||
|
The Markdown files at the repository root (`readme.md`, `LICENSE.md`, `docs/contributing.md`, `docs/windows.md`) are generated from the MDX sources under `docs/src/`. The build uses `pnpm`, pinned in `mise.toml` alongside the other CI tools. From `docs/src/`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
pnpm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
`devEngines.packageManager` in `docs/src/package.json` is set to `pnpm` with `onFail: "error"`, so `npm install` will refuse to run.
|
||||||
|
|
||||||
## Editing GitHub Actions workflows
|
## Editing GitHub Actions workflows
|
||||||
|
|
||||||
GitHub Actions versions are tracked with [`gx`](https://github.com/gmeligio/gx). The manifest at `.github/gx.toml` is the source of truth for version constraints, and `.github/gx.lock` records the resolved SHAs. Workflows must use SHA pins with a `# vX.Y.Z` comment.
|
GitHub Actions versions are tracked with [`gx`](https://github.com/gmeligio/gx). The manifest at `.github/gx.toml` is the source of truth for version constraints, and `.github/gx.lock` records the resolved SHAs. Workflows must use SHA pins with a `# vX.Y.Z` comment.
|
||||||
|
|||||||
Generated
-3265
File diff suppressed because it is too large
Load Diff
@@ -5,11 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run readme && npm run windows && npm run contributing && npm run license",
|
"build": "cross-env NODE_ENV=production node compile.js readme.mdx ../../readme.md windows.mdx ../windows.md contributing.mdx ../contributing.md license.mdx ../../LICENSE.md",
|
||||||
"readme": "cross-env NODE_ENV=production node compile.js readme.mdx ../../readme.md",
|
|
||||||
"windows": "cross-env NODE_ENV=production node compile.js windows.mdx ../windows.md",
|
|
||||||
"license": "cross-env NODE_ENV=production node compile.js license.mdx ../../LICENSE.md",
|
|
||||||
"contributing": "cross-env NODE_ENV=production node compile.js contributing.mdx ../contributing.md",
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
@@ -28,7 +24,7 @@
|
|||||||
"onFail": "error"
|
"onFail": "error"
|
||||||
},
|
},
|
||||||
"packageManager": {
|
"packageManager": {
|
||||||
"name": "npm",
|
"name": "pnpm",
|
||||||
"onFail": "error"
|
"onFail": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2024
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
|||||||
|
allowBuilds:
|
||||||
|
esbuild: true
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
[tools]
|
[tools]
|
||||||
cue = "0.15.0"
|
cue = "0.15.0"
|
||||||
git-cliff = "2.10.1"
|
git-cliff = "2.10.1"
|
||||||
|
pnpm = "11.2.2"
|
||||||
node = "lts"
|
node = "lts"
|
||||||
"github:gmeligio/gx" = "0.7.1"
|
"github:gmeligio/gx" = "0.7.1"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
schema: spec-driven
|
||||||
|
created: 2026-05-23
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
passed
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
## Context
|
||||||
|
|
||||||
|
`docs/src/` compiles MDX into the committed Markdown surfaces a reader sees on GitHub and Docker Hub (`readme.md`, `LICENSE.md`, `docs/contributing.md`, `docs/windows.md`). It's the only Node project in the repo and is invoked from three CI workflows: `build.yml` (PR preview artifact), `update_docs.yml` (push-to-main commit-back), and `update_version.yml` (release pipeline).
|
||||||
|
|
||||||
|
The repository recently consolidated all CI runtime tools behind a single `mise.toml` manifest (archived change `2026-05-23-p7-mise-action-cue-node`). Today `mise.toml` pins `cue`, `git-cliff`, `node`, and `gx`; every workflow bootstraps them with one `jdx/mise-action@<sha>` step. The `ci-runtime-tool-versioning` spec enforces this as an invariant. The npm binary that workflows currently use is whichever one happens to ship with Node `lts` — i.e., unpinned. Switching the docs build to `pnpm` and pinning that pnpm in `mise.toml` brings the package manager into the same invariant.
|
||||||
|
|
||||||
|
`docs/src/package.json` already declares a `devEngines` block with `packageManager.name = "npm"` and `onFail: "error"` — this gate would refuse pnpm today, so the migration is also the act of flipping that gate.
|
||||||
|
|
||||||
|
## Goals / Non-Goals
|
||||||
|
|
||||||
|
**Goals:**
|
||||||
|
|
||||||
|
- One source of truth for the docs-build package manager: `mise.toml` (pinned, exact version).
|
||||||
|
- No new GitHub Actions added; no `pnpm/action-setup`, no `corepack enable` step.
|
||||||
|
- Byte-identical compiled output (`readme.md`, etc.) — this is a toolchain swap, not a content change.
|
||||||
|
- Local-dev parity: a contributor running `pnpm install && pnpm run build` from `docs/src` produces the same output CI produces.
|
||||||
|
- Renovate continues to keep the lockfile fresh with zero config changes.
|
||||||
|
|
||||||
|
**Non-Goals:**
|
||||||
|
|
||||||
|
- Migrating any other directory (there is no other Node project in the repo).
|
||||||
|
- Bumping any `docs/src` dependency version — every package in `package.json` stays at its current floor.
|
||||||
|
- Changing the compile script (`compile.js`) or the MDX → MD pipeline behavior.
|
||||||
|
- Introducing pnpm workspaces or any multi-package layout.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
### Decision 1: Install pnpm via mise (not corepack, not `pnpm/action-setup`)
|
||||||
|
|
||||||
|
**Choice**: Add `pnpm = "<pinned>"` to `mise.toml` and let `jdx/mise-action` install it.
|
||||||
|
|
||||||
|
**Why**: The `ci-runtime-tool-versioning` spec already mandates that every CI runtime tool comes from `mise.toml`. Using corepack would put the pnpm version inside `docs/src/package.json` (`packageManager: "pnpm@…"`) — a second source of truth, and one that the spec's "no other install mechanism" clause would have to carve out an exception for. Using `pnpm/action-setup` adds a third-party Action that gx would need to track and that exists nowhere else in the workflow set.
|
||||||
|
|
||||||
|
**Alternatives considered:**
|
||||||
|
|
||||||
|
- **Corepack** (`corepack enable`): Officially bundled with Node, but corepack signature-verification changes through 2025 produced sporadic CI breakage in other projects; and version drift between `packageManager:` in `package.json` and what mise resolves for `node` would be possible.
|
||||||
|
- **`pnpm/action-setup@v4`**: Battle-tested, but adds a fifth way to install a CI tool and a new SHA for gx to pin and Renovate to chase. Loses the "one grep tells you the version" property.
|
||||||
|
|
||||||
|
### Decision 2: Pin pnpm to an exact version, not `"latest"`
|
||||||
|
|
||||||
|
**Choice**: Pin to a concrete version (e.g., `pnpm = "9.15.0"` at implementation time — implementer picks the latest stable at the moment).
|
||||||
|
|
||||||
|
**Why**: Mirrors every other entry in `mise.toml` (`cue = "0.15.0"`, `git-cliff = "2.10.1"`, `"github:gmeligio/gx" = "0.7.1"`). The one exception today, `node = "lts"`, is a deliberate choice for the broader Node ecosystem; the package-manager pin should be reproducible to the build-tool level, not just the language level.
|
||||||
|
|
||||||
|
### Decision 3: Seed `pnpm-lock.yaml` via `pnpm import` from the existing `package-lock.json`
|
||||||
|
|
||||||
|
**Choice**: Run `pnpm import` once in `docs/src/` before deleting `package-lock.json`. Commit the resulting `pnpm-lock.yaml`.
|
||||||
|
|
||||||
|
**Why**: Preserves the exact resolved-version graph (down to transitive deps) the project ships with today, removing the "did some sub-dep version float?" question from review. A clean `pnpm install` from scratch would also work and would resolve to the latest semver-compatible versions, but that conflates "swap the package manager" with "refresh the lockfile" — two separable concerns. Renovate's regular schedule will handle drift afterwards.
|
||||||
|
|
||||||
|
**Alternative considered:** `rm package-lock.json && pnpm install` to get a fresh resolution. Rejected to keep the diff reviewable: any compiled-output change can then only come from the pnpm install algorithm itself, not from a dependency bump.
|
||||||
|
|
||||||
|
### Decision 4: Use `pnpm install --frozen-lockfile` in CI (not `pnpm install --offline` or `pnpm ci`)
|
||||||
|
|
||||||
|
**Choice**: `pnpm install --frozen-lockfile` in all three workflows. (There is no `pnpm ci` command — the canonical CI flag is `--frozen-lockfile`.)
|
||||||
|
|
||||||
|
**Why**: Matches the semantics of `npm ci --prefer-offline` that we are replacing: refuse to install if the lockfile is out of date, prefer cached tarballs when available. `--offline` would be stricter than the existing behavior and could cause spurious cold-cache failures.
|
||||||
|
|
||||||
|
### Decision 5: Update `devEngines.packageManager.name` to `"pnpm"`, keep `onFail: "error"`
|
||||||
|
|
||||||
|
**Choice**: Flip the existing gate from npm to pnpm and keep the hard-fail policy.
|
||||||
|
|
||||||
|
**Why**: The gate is what produces a clear "you are using the wrong package manager" error for local contributors. Flipping it to pnpm preserves that signal. Loosening to `onFail: "warn"` would silently let `npm install` run and produce a stray `package-lock.json` next to `pnpm-lock.yaml`, which is worse than the status quo.
|
||||||
|
|
||||||
|
### Decision 6: Approve `esbuild`'s native postinstall via `docs/src/pnpm-workspace.yaml`
|
||||||
|
|
||||||
|
**Choice**: Commit a small `docs/src/pnpm-workspace.yaml` containing `allowBuilds.esbuild: true`. No actual workspace is declared — the file exists only to carry pnpm's per-package build-script allowlist.
|
||||||
|
|
||||||
|
**Why**: pnpm 11 refuses to run dependency postinstalls unless they appear in an explicit allowlist. `mdx-to-md` transitively depends on `esbuild`, which compiles a native binary in its postinstall; without approval, `pnpm install --frozen-lockfile` exits 0 but `pnpm run build` fails because the esbuild binary is missing. pnpm 11 deliberately moved this setting out of `package.json#pnpm` and ignores it in `.npmrc`, so `pnpm-workspace.yaml` is the only home that works.
|
||||||
|
|
||||||
|
**Alternatives considered:** keep the setting in `package.json#pnpm` (silently ignored in pnpm 11 with a warning), or pin a lower pnpm major that still honors the old location. Both were rejected because they trade today's clean error for tomorrow's drift — every new pnpm-11-or-later contributor would hit the silent ignore, and downgrading the pnpm major contradicts Decision 2.
|
||||||
|
|
||||||
|
### Decision 7: List `pnpm` before `node` in `mise.toml`
|
||||||
|
|
||||||
|
**Choice**: Declare tools in this order: `cue`, `git-cliff`, `pnpm`, `node`, `gx`.
|
||||||
|
|
||||||
|
**Why**: `mise` lays each tool's install directory onto `$PATH` in the order they appear in `mise.toml`. Node ships a corepack-backed `pnpm` shim at `node/lts/bin/pnpm`. If `node` is declared before `pnpm`, the corepack shim wins over the mise-pinned binary. Corepack then reads `devEngines.packageManager` and errors because we deliberately do not pin a version there (Decision 1 — single source of truth in `mise.toml`). Reordering puts the mise-pinned `pnpm/<version>/pnpm` first.
|
||||||
|
|
||||||
|
**Alternative considered:** add `version` to `devEngines.packageManager` so corepack accepts the spec. Rejected because it creates a second source of truth for the pnpm version (Renovate manages `pnpm-lock.yaml` but not `devEngines.packageManager.version`, so drift would be inevitable).
|
||||||
|
|
||||||
|
## Risks / Trade-offs
|
||||||
|
|
||||||
|
- **Risk**: Compiled Markdown drift after the swap. → **Mitigation**: Run `pnpm import` (Decision 3) so the resolved tree is byte-identical; `pnpm run build` locally before pushing; the `update_docs.yml` commit-back diff will be empty on push-to-main if outputs are stable. Reviewer must verify zero changes to `readme.md`, `LICENSE.md`, `docs/contributing.md`, `docs/windows.md` aside from the new "use pnpm" mention.
|
||||||
|
- **Risk**: pnpm's non-flat `node_modules` exposes a phantom-dependency in `compile.js`. → **Mitigation**: `compile.js` imports only declared deps (`mdx-to-md`, `remark-gfm`, `remark-toc`) per audit; local `pnpm run build` in the worktree will surface anything missed before CI.
|
||||||
|
- **Risk**: First CI run on a PR pulls a cold pnpm store and runs slower than npm. → **Mitigation**: mise caches the pnpm binary in `~/.local/share/mise`, and `pnpm install --frozen-lockfile` benefits from pnpm's content-addressable store on subsequent runs. Net change to wall-clock CI is expected to be sub-second either way for a 6-direct-dep project.
|
||||||
|
- **Risk**: Contributor confusion from the package-manager swap. → **Mitigation**: The `devEngines` error is loud and actionable ("This project requires pnpm"). Update `docs/src/contributing.mdx` so the regenerated `docs/contributing.md` documents the new local command.
|
||||||
|
- **Trade-off**: One more line in `mise.toml`. Worth it for the invariant. The same trade-off was made for `cue`, `git-cliff`, and `gx`.
|
||||||
|
|
||||||
|
## Automated Test Strategy
|
||||||
|
|
||||||
|
This change has no production-runtime surface — it ships no code that runs in the published Docker images, no scripts that users execute. Verification is structural and CI-pipeline:
|
||||||
|
|
||||||
|
- **Static checks** (PR-time):
|
||||||
|
- `pnpm install --frozen-lockfile` exits 0 in `docs/src/` on a fresh checkout (covered by all three modified workflows — if the lockfile is malformed or out of sync, every CI job fails).
|
||||||
|
- `pnpm run build` exits 0 and produces the four target Markdown files.
|
||||||
|
- The PR diff for `readme.md`, `LICENSE.md`, `docs/contributing.md`, `docs/windows.md` is limited to the documented contributing-section addition; no unexplained changes.
|
||||||
|
- **Workflow assertions** (existing):
|
||||||
|
- `build.yml` already uploads the compiled docs as an artifact (`docs-${{ github.event.pull_request.number }}`); reviewers can download and diff against the committed copies if anything looks off.
|
||||||
|
- `update_docs.yml` posts a `success-if-no-changes: true` commit on push to main — a non-empty commit there after the migration would be the signal that the compiled output drifted.
|
||||||
|
- **Spec invariant** (manual review): The `ci-runtime-tool-versioning` invariant is enforced at PR review (no `corepack enable`, no `pnpm/action-setup`, no `npm i -g pnpm` introduced anywhere). No automated linter exists for this today; the existing spec text is the contract.
|
||||||
|
|
||||||
|
No new test infrastructure is introduced. The critical path is `pnpm install --frozen-lockfile && pnpm run build` running successfully in the three workflows on the first PR after the migration.
|
||||||
|
|
||||||
|
## Observability
|
||||||
|
|
||||||
|
Failure modes and how they surface:
|
||||||
|
|
||||||
|
- **Lockfile-out-of-date**: `pnpm install --frozen-lockfile` exits non-zero with a clear "Cannot install with frozen-lockfile because pnpm-lock.yaml is not up to date" message. The CI job fails loudly in all three workflows.
|
||||||
|
- **mise install of pnpm fails**: `jdx/mise-action` step fails before any docs-build step runs; existing CI surface (job summary, red X on PR check) handles this.
|
||||||
|
- **devEngines mismatch on local install**: `pnpm` and `npm` both honor `devEngines.packageManager.name` with `onFail: "error"`. A contributor running `npm install` sees a hard error explaining the project requires pnpm.
|
||||||
|
- **Compiled-output drift**: Caught either at PR review (diff in `readme.md` / `docs/*.md`) or by `update_docs.yml` producing a non-empty commit-back on main. Both surfaces are existing — no new logging or alerting needed.
|
||||||
|
- **Silent-failure risk**: The only realistic silent-failure path is `pnpm run build` exiting 0 but writing partial output. `compile.js` uses `await writeFile(…)` with no try/catch, so a write error throws and the script exits non-zero; no change needed.
|
||||||
|
|
||||||
|
No new logs, metrics, or dashboards are introduced. The existing CI job-status surface is sufficient.
|
||||||
|
|
||||||
|
## Migration Plan
|
||||||
|
|
||||||
|
1. Land the change as one PR (small enough to bundle).
|
||||||
|
2. The PR is itself the first run of the new toolchain: `build.yml` will invoke the new pnpm steps against the new lockfile. A green CI run is the smoke test.
|
||||||
|
3. Once merged, `update_docs.yml` runs on push to main; an empty commit-back (no changes) confirms compiled-output parity.
|
||||||
|
|
||||||
|
**Rollback**: Revert the merge commit. `package-lock.json` reappears, `mise.toml` loses the `pnpm` entry, workflows go back to `npm ci`. No external state is mutated by this change, so revert is sufficient.
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
None. Concrete pnpm version is picked by the implementer at apply-time (latest stable at the moment, per Decision 2).
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
## Why
|
||||||
|
|
||||||
|
The `docs/src` MDX→Markdown pipeline currently uses `npm`, which sits outside the repository's established CI-runtime invariant that **every CI tool is pinned in `mise.toml` and bootstrapped via `jdx/mise-action`** (`ci-runtime-tool-versioning`). The package manager binary in use is whatever ships with the Node runtime — not a versioned, manifest-pinned tool — and the 141 KB `package-lock.json` is a second-class lockfile next to the project's overall pnpm-friendly direction. Aligning `docs/src` on `pnpm` makes the docs pipeline obey the same single-source-of-truth rule as the rest of CI: one grep against `mise.toml` answers "what package manager does CI use?".
|
||||||
|
|
||||||
|
This change passes the relevance gate because it modifies a spec-level invariant: the `ci-runtime-tool-versioning` capability currently enumerates `cue`, `node`, `gx`, and `git-cliff` as the manifest-pinned set; admitting `pnpm` extends that set and tightens the "no other install mechanism" rule to cover the package manager too.
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
|
||||||
|
- **BREAKING (for local workflow)**: Contributors building docs locally must use `pnpm`, not `npm`. The `devEngines.packageManager.name` gate in `docs/src/package.json` flips from `"npm"` to `"pnpm"` with `onFail: "error"`, so `npm install` will refuse to run.
|
||||||
|
- Add `pnpm = "<pinned>"` to `mise.toml`. `jdx/mise-action` then installs it in every job that needs it, alongside the existing `node` entry.
|
||||||
|
- Replace `docs/src/package-lock.json` with `docs/src/pnpm-lock.yaml` (seeded via `pnpm import` to preserve resolved versions).
|
||||||
|
- Update three CI steps from `npm ci --prefer-offline && npm run build` to `pnpm install --frozen-lockfile && pnpm run build`:
|
||||||
|
- `.github/workflows/build.yml` (PR preview)
|
||||||
|
- `.github/workflows/update_docs.yml` (push-to-main commit-back)
|
||||||
|
- `.github/workflows/update_version.yml` (release pipeline)
|
||||||
|
- `docs/contributing.mdx` gains a brief note pointing contributors at `pnpm` for the local docs build, so the regenerated `docs/contributing.md` reflects the new toolchain.
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
### New Capabilities
|
||||||
|
|
||||||
|
_None._ The change extends an existing capability rather than introducing a new one.
|
||||||
|
|
||||||
|
### Modified Capabilities
|
||||||
|
|
||||||
|
- `ci-runtime-tool-versioning`: Adds `pnpm` to the manifest-pinned tool set and forbids any other install mechanism (no `corepack enable`, no `npm i -g pnpm`, no `pnpm/action-setup`). Workflow steps that build `docs/src` SHALL invoke `pnpm` (not `npm`) after the `jdx/mise-action` bootstrap.
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
- **Files touched**: `mise.toml`, `docs/src/package.json`, `docs/src/package-lock.json` (deleted), `docs/src/pnpm-lock.yaml` (added), `docs/src/contributing.mdx`, `docs/contributing.md` (regenerated), `.github/workflows/build.yml`, `.github/workflows/update_docs.yml`, `.github/workflows/update_version.yml`.
|
||||||
|
- **CI dependencies**: One new mise-managed tool (`pnpm`). No new GitHub Actions; no new external services.
|
||||||
|
- **Renovate**: No config change — Renovate's built-in `pnpm` manager updates `pnpm-lock.yaml` natively.
|
||||||
|
- **gx**: Out of scope — gx tracks Action SHAs; no Actions are added or removed.
|
||||||
|
- **Backwards compatibility**: Any contributor with cached muscle memory for `npm ci` in `docs/src` will see a clean `devEngines` error directing them to pnpm. The compiled output (`readme.md`, `docs/windows.md`, `LICENSE.md`, `docs/contributing.md`) is byte-identical because `mdx-to-md` and its plugins remain on the same pinned versions.
|
||||||
|
- **Post-merge expectation**: The first run of `update_docs.yml` after merge should produce an empty commit-back, confirming compiled-output parity. Any non-empty commit on that run is the signal that pnpm's resolution produced a different dependency tree and warrants follow-up. This is a passive observation, not an implementation task — the existing `update_docs.yml` (with `success-if-no-changes: true`) surfaces it automatically.
|
||||||
+106
@@ -0,0 +1,106 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Single-source version manifest for CI runtime tools
|
||||||
|
|
||||||
|
The repository SHALL pin every CI runtime tool version (currently `cue`, `node`, `pnpm`, `gx`, and `git-cliff`) in `mise.toml` at the repository root. No workflow under `.github/workflows/` or composite action under `.github/actions/` may install these tools by any other mechanism (e.g., `jaxxstorm/action-install-gh-release`, `actions/setup-node`, `pnpm/action-setup`, `corepack enable`, hand-rolled `curl | tar`, or `npm i -g pnpm`).
|
||||||
|
|
||||||
|
**Experience context:** A CI engineer or maintainer asking *"what version of cue does CI run with?"* (or `node`, `pnpm`, `gx`, `git-cliff`) reads exactly one file — `mise.toml` — and gets a single, authoritative answer. The package manager used by the `docs/src` MDX→Markdown build is part of this answer: before this requirement was extended to cover `pnpm`, the docs build used whichever `npm` happened to ship with the resolved `node`, leaving the package-manager version effectively unpinned.
|
||||||
|
|
||||||
|
#### Scenario: Maintainer looks up the pinned CUE version
|
||||||
|
|
||||||
|
- **GIVEN** a maintainer wants to know which CUE version CI uses
|
||||||
|
- **WHEN** they `grep cue mise.toml`
|
||||||
|
- **THEN** exactly one entry is returned, with a concrete version (e.g., `cue = "0.15.0"`)
|
||||||
|
- **AND** no other file in `.github/workflows/` or `.github/actions/` contains a literal CUE version or release tag
|
||||||
|
|
||||||
|
#### Scenario: Maintainer looks up the pinned Node version
|
||||||
|
|
||||||
|
- **GIVEN** a maintainer wants to know which Node version CI uses
|
||||||
|
- **WHEN** they `grep node mise.toml`
|
||||||
|
- **THEN** exactly one entry is returned (e.g., `node = "lts"` or a concrete major)
|
||||||
|
- **AND** no workflow file contains a `node-version:` input or hand-rolled Node install
|
||||||
|
|
||||||
|
#### Scenario: Maintainer looks up the pinned pnpm version
|
||||||
|
|
||||||
|
- **GIVEN** a maintainer wants to know which `pnpm` version CI uses for the `docs/src` build
|
||||||
|
- **WHEN** they `grep pnpm mise.toml`
|
||||||
|
- **THEN** exactly one entry is returned, with a concrete version (e.g., `pnpm = "9.15.0"`)
|
||||||
|
- **AND** no workflow file or `docs/src/package.json` field installs `pnpm` via `corepack enable`, `pnpm/action-setup`, `npm i -g pnpm`, or any other mechanism
|
||||||
|
- **AND** `docs/src/package.json` does not contain a `packageManager` field that would let corepack pick a different version
|
||||||
|
|
||||||
|
#### Scenario: Maintainer looks up the pinned gx version
|
||||||
|
|
||||||
|
- **GIVEN** a maintainer wants to know which `gx` version CI uses
|
||||||
|
- **WHEN** they `grep gx mise.toml`
|
||||||
|
- **THEN** exactly one entry is returned (e.g., `"github:gmeligio/gx" = "0.7.1"`)
|
||||||
|
- **AND** no workflow file contains a literal `gx` version, release tag, or release digest
|
||||||
|
|
||||||
|
#### Scenario: Drift attempt is blocked at review
|
||||||
|
|
||||||
|
- **GIVEN** a PR adds a step `uses: actions/setup-node@<sha>`, `uses: pnpm/action-setup@<sha>`, `uses: jaxxstorm/action-install-gh-release@<sha>`, or a `run: corepack enable` / `run: npm i -g pnpm` line to any workflow
|
||||||
|
- **WHEN** the PR is reviewed
|
||||||
|
- **THEN** the change is rejected and re-implemented using `jdx/mise-action@<pinned>` plus the appropriate `mise.toml` pin
|
||||||
|
- **AND** the rationale references this requirement
|
||||||
|
|
||||||
|
### Requirement: Workflows bootstrap tools via `jdx/mise-action`
|
||||||
|
|
||||||
|
Every job that needs `cue`, `node`, `pnpm`, or `gx` on `$PATH` SHALL bootstrap them with a single step `uses: jdx/mise-action@<pinned-major>` placed before any step that invokes those tools. The step SHALL rely on `mise.toml` for version resolution and SHALL NOT pass an explicit `tools:` input that contradicts `mise.toml`.
|
||||||
|
|
||||||
|
**Experience context:** A maintainer adding a new CI job that needs `cue`, `node`, or the docs-build toolchain writes one boilerplate step (the same step every other job uses) and gets the project-pinned version. They never re-derive a download URL, copy a SHA digest, or add a second tool-installer action.
|
||||||
|
|
||||||
|
#### Scenario: New job needing CUE
|
||||||
|
|
||||||
|
- **GIVEN** a new workflow job needs to run `cue vet`
|
||||||
|
- **WHEN** the job is authored
|
||||||
|
- **THEN** it contains exactly one tool-bootstrap step `uses: jdx/mise-action@v4` before the `cue` invocation
|
||||||
|
- **AND** no `with:` input overrides `cue`'s version
|
||||||
|
|
||||||
|
#### Scenario: New job needing the docs-build toolchain
|
||||||
|
|
||||||
|
- **GIVEN** a new workflow job needs to run `pnpm install --frozen-lockfile && pnpm run build` in `docs/src`
|
||||||
|
- **WHEN** the job is authored
|
||||||
|
- **THEN** it contains exactly one `uses: jdx/mise-action@v4` step before any `pnpm` invocation
|
||||||
|
- **AND** `node` and `pnpm` are not separately installed via `actions/setup-node`, `pnpm/action-setup`, `corepack enable`, or other means
|
||||||
|
|
||||||
|
#### Scenario: New job needing gx
|
||||||
|
|
||||||
|
- **GIVEN** a new workflow job needs to run `gx lint` or `gx tidy`
|
||||||
|
- **WHEN** the job is authored
|
||||||
|
- **THEN** it contains exactly one `uses: jdx/mise-action@v4` step before any `gx` invocation
|
||||||
|
- **AND** `gx` is not separately installed via `jaxxstorm/action-install-gh-release` or other means
|
||||||
|
|
||||||
|
#### Scenario: mise-action runs without explicit token configuration
|
||||||
|
|
||||||
|
- **GIVEN** the workflow grants `permissions: contents: read` (the default in this repo)
|
||||||
|
- **WHEN** `jdx/mise-action@v4` resolves `cue`, `node`, and `pnpm` from `mise.toml`
|
||||||
|
- **THEN** the step succeeds without an explicit `github_token` input
|
||||||
|
- **AND** the GitHub API calls used to resolve releases are authenticated by the action's default `${{ github.token }}`
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: `docs/src` build uses pnpm as its package manager
|
||||||
|
|
||||||
|
The `docs/src` MDX→Markdown build SHALL invoke `pnpm` (not `npm`, `yarn`, or `bun`) for dependency installation and script execution, in every CI workflow that builds the docs and in the local-developer contract. `docs/src/package.json` SHALL declare this contract via the `devEngines.packageManager` block with `name: "pnpm"` and `onFail: "error"`, and the lockfile committed at `docs/src/pnpm-lock.yaml` SHALL be the only lockfile under `docs/src/` (no `package-lock.json`, no `yarn.lock`, no `bun.lockb`).
|
||||||
|
|
||||||
|
**Experience context:** A contributor cloning the repo and running the docs build locally gets a single, predictable command path (`pnpm install && pnpm run build` from `docs/src/`) and a hard error if they reach for `npm install` out of habit. A CI engineer reading `mise.toml` and any of the three docs-building workflows sees the same package manager invoked consistently — no per-workflow drift between `npm`, `corepack`-shimmed pnpm, and action-installed pnpm.
|
||||||
|
|
||||||
|
#### Scenario: Contributor runs the wrong package manager locally
|
||||||
|
|
||||||
|
- **GIVEN** a contributor has cloned the repo and `cd`'d into `docs/src/`
|
||||||
|
- **WHEN** they run `npm install`
|
||||||
|
- **THEN** the command exits non-zero with a `devEngines` mismatch error indicating that this project requires `pnpm`
|
||||||
|
- **AND** no `node_modules` or `package-lock.json` is created
|
||||||
|
|
||||||
|
#### Scenario: CI workflow builds the docs
|
||||||
|
|
||||||
|
- **GIVEN** any of `build.yml`, `update_docs.yml`, or `update_version.yml` runs the docs-build step
|
||||||
|
- **WHEN** the build job executes
|
||||||
|
- **THEN** the step body is exactly `pnpm install --frozen-lockfile` followed by `pnpm run build`, preceded by a `jdx/mise-action@<pinned>` bootstrap step
|
||||||
|
- **AND** the step does not invoke `npm`, `corepack`, or `pnpm/action-setup` anywhere
|
||||||
|
|
||||||
|
#### Scenario: Only one lockfile lives under `docs/src/`
|
||||||
|
|
||||||
|
- **GIVEN** a contributor inspects `docs/src/`
|
||||||
|
- **WHEN** they list the directory
|
||||||
|
- **THEN** `pnpm-lock.yaml` is present
|
||||||
|
- **AND** no `package-lock.json`, `yarn.lock`, or `bun.lockb` file is present
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
## 1. Pin pnpm in the mise manifest
|
||||||
|
|
||||||
|
- [x] 1.1 Pick the latest stable `pnpm` version (`pnpm view pnpm version` or https://github.com/pnpm/pnpm/releases) and record the choice in the PR description
|
||||||
|
- [x] 1.2 Add `pnpm = "<pinned-version>"` to `mise.toml` next to the existing `node = "lts"` entry
|
||||||
|
- [x] 1.3 Run `mise install` locally to confirm the pin resolves and the `pnpm` binary is available on `$PATH`
|
||||||
|
|
||||||
|
## 2. Convert `docs/src` to pnpm
|
||||||
|
|
||||||
|
- [x] 2.1 From `docs/src/`, run `pnpm import` to seed `pnpm-lock.yaml` from the existing `package-lock.json` (preserves the resolved transitive-dependency tree)
|
||||||
|
- [x] 2.2 Delete `docs/src/package-lock.json`
|
||||||
|
- [x] 2.3 Edit `docs/src/package.json` so `devEngines.packageManager.name` is `"pnpm"` (keep `onFail: "error"`); do NOT add a top-level `packageManager` field (corepack must not pick up an override)
|
||||||
|
- [x] 2.4 Verify `docs/src/.gitignore` still ignores `node_modules` (pnpm uses the same path); no change expected
|
||||||
|
- [x] 2.5 Run `pnpm install --frozen-lockfile` in `docs/src/` and confirm it exits 0 (required adding `docs/src/pnpm-workspace.yaml` with `allowBuilds.esbuild: true` to satisfy pnpm 11's strict-build-script gate)
|
||||||
|
- [x] 2.6 Run `pnpm run build` in `docs/src/` and confirm the four output files (`../../readme.md`, `../../LICENSE.md`, `../contributing.md`, `../windows.md`) regenerate without diff aside from the contributing-section update from task 4 (required rewriting the `build` script to chain `node compile.js …` calls directly instead of `pnpm run …`, because nested `pnpm` invocations resolved to the Node-bundled corepack shim which errors on `devEngines.packageManager` without a version field; `readme.md` also picked up an unrelated stale-Fastlane drift correction: 2.233.1 → 2.234.0 from `config/version.json`)
|
||||||
|
|
||||||
|
## 3. Update CI workflows
|
||||||
|
|
||||||
|
- [x] 3.1 In `.github/workflows/build.yml`, replace `npm ci --prefer-offline` with `pnpm install --frozen-lockfile` and `npm run build` with `pnpm run build` in the `working-directory: docs/src` step
|
||||||
|
- [x] 3.2 Apply the same substitution in `.github/workflows/update_docs.yml`
|
||||||
|
- [x] 3.3 Apply the same substitution in `.github/workflows/update_version.yml`
|
||||||
|
- [x] 3.4 Confirm none of the three workflows introduce `corepack`, `pnpm/action-setup`, `actions/setup-node`, or `npm i -g pnpm` — the only tool-bootstrap step in each affected job remains the existing `jdx/mise-action` step (also reordered `mise.toml` so `pnpm` is declared before `node`: mise lays the install dirs onto `$PATH` in mise.toml order, and Node ships a corepack-backed `pnpm` shim in `node/lts/bin/` that otherwise wins over the mise-pinned binary and errors on `devEngines.packageManager` without a version field)
|
||||||
|
|
||||||
|
## 4. Update contributor documentation
|
||||||
|
|
||||||
|
- [x] 4.1 Edit `docs/src/contributing.mdx` to mention that the local docs build uses `pnpm install && pnpm run build` (under a new "Building the docs" section or appended to the existing structure, kept short)
|
||||||
|
- [x] 4.2 Run `pnpm run contributing` (or `pnpm run build`) so `docs/contributing.md` is regenerated and matches the MDX source
|
||||||
|
- [x] 4.3 Confirm `readme.md`, `LICENSE.md`, and `docs/windows.md` are unchanged from `main` (only `docs/contributing.md` should change) — `readme.md` was already committed in task group 2 with the unrelated Fastlane-version refresh; `LICENSE.md` and `docs/windows.md` are clean
|
||||||
|
|
||||||
|
## 5. Verify and commit
|
||||||
|
|
||||||
|
- [x] 5.1 Run `openspec validate migrate-docs-src-to-pnpm` and confirm it reports valid
|
||||||
|
- [x] 5.2 Run `git status` and confirm the diff is limited to: `mise.toml`, `docs/src/package.json`, `docs/src/package-lock.json` (deleted), `docs/src/pnpm-lock.yaml` (added), `docs/src/contributing.mdx`, `docs/contributing.md`, `.github/workflows/build.yml`, `.github/workflows/update_docs.yml`, `.github/workflows/update_version.yml` — plus the planned extras: `docs/src/pnpm-workspace.yaml` (added; `allowBuilds.esbuild: true` for pnpm 11's build-script gate) and `readme.md` (unrelated stale-Fastlane refresh surfaced by the rebuild)
|
||||||
|
- [x] 5.3 Push the branch and open the PR; confirm `build.yml`'s docs job runs `pnpm install --frozen-lockfile` and `pnpm run build` successfully, and that the uploaded `docs-*` artifact byte-matches the committed Markdown — PR [#460](https://github.com/gmeligio/flutter-docker-image/pull/460); `build_docs` job passed in 14s
|
||||||
@@ -3,14 +3,12 @@
|
|||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
Establishes `mise.toml` as the single source of truth for CI runtime tool versions, consumed by every workflow via `jdx/mise-action`. Covers where versions live, how they reach `$PATH` in each job, and the invariant that no workflow may install these tools by any other mechanism. The desktop user this serves is the CI engineer or maintainer who needs a single, authoritative answer to "what version of tool X does CI run with?".
|
Establishes `mise.toml` as the single source of truth for CI runtime tool versions, consumed by every workflow via `jdx/mise-action`. Covers where versions live, how they reach `$PATH` in each job, and the invariant that no workflow may install these tools by any other mechanism. The desktop user this serves is the CI engineer or maintainer who needs a single, authoritative answer to "what version of tool X does CI run with?".
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
### Requirement: Single-source version manifest for CI runtime tools
|
### Requirement: Single-source version manifest for CI runtime tools
|
||||||
|
|
||||||
The repository SHALL pin every CI runtime tool version (currently `cue`, `node`, `gx`, and `git-cliff`) in `mise.toml` at the repository root. No workflow under `.github/workflows/` or composite action under `.github/actions/` may install these tools by any other mechanism (e.g., `jaxxstorm/action-install-gh-release`, `actions/setup-node`, hand-rolled `curl | tar`).
|
The repository SHALL pin every CI runtime tool version (currently `cue`, `node`, `pnpm`, `gx`, and `git-cliff`) in `mise.toml` at the repository root. No workflow under `.github/workflows/` or composite action under `.github/actions/` may install these tools by any other mechanism (e.g., `jaxxstorm/action-install-gh-release`, `actions/setup-node`, `pnpm/action-setup`, `corepack enable`, hand-rolled `curl | tar`, or `npm i -g pnpm`).
|
||||||
|
|
||||||
**Experience context:** A CI engineer or maintainer asking *"what version of cue does CI run with?"* (or `node`, `gx`, `git-cliff`) reads exactly one file — `mise.toml` — and gets a single, authoritative answer. Before this requirement was put in place, the answer was duplicated across 9 CUE-install steps, 3 Node-install steps, 2 gx-install steps, and 2 git-cliff-install steps, which had produced version drift and made point-fixes fragile.
|
**Experience context:** A CI engineer or maintainer asking *"what version of cue does CI run with?"* (or `node`, `pnpm`, `gx`, `git-cliff`) reads exactly one file — `mise.toml` — and gets a single, authoritative answer. The package manager used by the `docs/src` MDX→Markdown build is part of this answer: before this requirement was extended to cover `pnpm`, the docs build used whichever `npm` happened to ship with the resolved `node`, leaving the package-manager version effectively unpinned.
|
||||||
|
|
||||||
#### Scenario: Maintainer looks up the pinned CUE version
|
#### Scenario: Maintainer looks up the pinned CUE version
|
||||||
|
|
||||||
@@ -26,6 +24,14 @@ The repository SHALL pin every CI runtime tool version (currently `cue`, `node`,
|
|||||||
- **THEN** exactly one entry is returned (e.g., `node = "lts"` or a concrete major)
|
- **THEN** exactly one entry is returned (e.g., `node = "lts"` or a concrete major)
|
||||||
- **AND** no workflow file contains a `node-version:` input or hand-rolled Node install
|
- **AND** no workflow file contains a `node-version:` input or hand-rolled Node install
|
||||||
|
|
||||||
|
#### Scenario: Maintainer looks up the pinned pnpm version
|
||||||
|
|
||||||
|
- **GIVEN** a maintainer wants to know which `pnpm` version CI uses for the `docs/src` build
|
||||||
|
- **WHEN** they `grep pnpm mise.toml`
|
||||||
|
- **THEN** exactly one entry is returned, with a concrete version (e.g., `pnpm = "9.15.0"`)
|
||||||
|
- **AND** no workflow file or `docs/src/package.json` field installs `pnpm` via `corepack enable`, `pnpm/action-setup`, `npm i -g pnpm`, or any other mechanism
|
||||||
|
- **AND** `docs/src/package.json` does not contain a `packageManager` field that would let corepack pick a different version
|
||||||
|
|
||||||
#### Scenario: Maintainer looks up the pinned gx version
|
#### Scenario: Maintainer looks up the pinned gx version
|
||||||
|
|
||||||
- **GIVEN** a maintainer wants to know which `gx` version CI uses
|
- **GIVEN** a maintainer wants to know which `gx` version CI uses
|
||||||
@@ -35,16 +41,16 @@ The repository SHALL pin every CI runtime tool version (currently `cue`, `node`,
|
|||||||
|
|
||||||
#### Scenario: Drift attempt is blocked at review
|
#### Scenario: Drift attempt is blocked at review
|
||||||
|
|
||||||
- **GIVEN** a PR adds a step `uses: actions/setup-node@<sha>` or `uses: jaxxstorm/action-install-gh-release@<sha>` (with `repo: cue-lang/cue` or `repo: gmeligio/gx`) to any workflow
|
- **GIVEN** a PR adds a step `uses: actions/setup-node@<sha>`, `uses: pnpm/action-setup@<sha>`, `uses: jaxxstorm/action-install-gh-release@<sha>`, or a `run: corepack enable` / `run: npm i -g pnpm` line to any workflow
|
||||||
- **WHEN** the PR is reviewed
|
- **WHEN** the PR is reviewed
|
||||||
- **THEN** the change is rejected and re-implemented using `jdx/mise-action@v4` plus the appropriate `mise.toml` pin
|
- **THEN** the change is rejected and re-implemented using `jdx/mise-action@<pinned>` plus the appropriate `mise.toml` pin
|
||||||
- **AND** the rationale references this requirement
|
- **AND** the rationale references this requirement
|
||||||
|
|
||||||
### Requirement: Workflows bootstrap tools via `jdx/mise-action`
|
### Requirement: Workflows bootstrap tools via `jdx/mise-action`
|
||||||
|
|
||||||
Every job that needs `cue`, `node`, or `gx` on `$PATH` SHALL bootstrap them with a single step `uses: jdx/mise-action@<pinned-major>` placed before any step that invokes those tools. The step SHALL rely on `mise.toml` for version resolution and SHALL NOT pass an explicit `tools:` input that contradicts `mise.toml`.
|
Every job that needs `cue`, `node`, `pnpm`, or `gx` on `$PATH` SHALL bootstrap them with a single step `uses: jdx/mise-action@<pinned-major>` placed before any step that invokes those tools. The step SHALL rely on `mise.toml` for version resolution and SHALL NOT pass an explicit `tools:` input that contradicts `mise.toml`.
|
||||||
|
|
||||||
**Experience context:** A maintainer adding a new CI job that needs `cue` or `node` writes one boilerplate step (the same step every other job uses) and gets the project-pinned version. They never re-derive a download URL or copy a SHA digest.
|
**Experience context:** A maintainer adding a new CI job that needs `cue`, `node`, or the docs-build toolchain writes one boilerplate step (the same step every other job uses) and gets the project-pinned version. They never re-derive a download URL, copy a SHA digest, or add a second tool-installer action.
|
||||||
|
|
||||||
#### Scenario: New job needing CUE
|
#### Scenario: New job needing CUE
|
||||||
|
|
||||||
@@ -53,12 +59,12 @@ Every job that needs `cue`, `node`, or `gx` on `$PATH` SHALL bootstrap them with
|
|||||||
- **THEN** it contains exactly one tool-bootstrap step `uses: jdx/mise-action@v4` before the `cue` invocation
|
- **THEN** it contains exactly one tool-bootstrap step `uses: jdx/mise-action@v4` before the `cue` invocation
|
||||||
- **AND** no `with:` input overrides `cue`'s version
|
- **AND** no `with:` input overrides `cue`'s version
|
||||||
|
|
||||||
#### Scenario: New job needing Node
|
#### Scenario: New job needing the docs-build toolchain
|
||||||
|
|
||||||
- **GIVEN** a new workflow job needs to run `npm ci && npm run build`
|
- **GIVEN** a new workflow job needs to run `pnpm install --frozen-lockfile && pnpm run build` in `docs/src`
|
||||||
- **WHEN** the job is authored
|
- **WHEN** the job is authored
|
||||||
- **THEN** it contains exactly one `uses: jdx/mise-action@v4` step before any `npm` invocation
|
- **THEN** it contains exactly one `uses: jdx/mise-action@v4` step before any `pnpm` invocation
|
||||||
- **AND** `node` is not separately installed via `actions/setup-node` or other means
|
- **AND** `node` and `pnpm` are not separately installed via `actions/setup-node`, `pnpm/action-setup`, `corepack enable`, or other means
|
||||||
|
|
||||||
#### Scenario: New job needing gx
|
#### Scenario: New job needing gx
|
||||||
|
|
||||||
@@ -70,7 +76,7 @@ Every job that needs `cue`, `node`, or `gx` on `$PATH` SHALL bootstrap them with
|
|||||||
#### Scenario: mise-action runs without explicit token configuration
|
#### Scenario: mise-action runs without explicit token configuration
|
||||||
|
|
||||||
- **GIVEN** the workflow grants `permissions: contents: read` (the default in this repo)
|
- **GIVEN** the workflow grants `permissions: contents: read` (the default in this repo)
|
||||||
- **WHEN** `jdx/mise-action@v4` resolves `cue` and `node` from `mise.toml`
|
- **WHEN** `jdx/mise-action@v4` resolves `cue`, `node`, and `pnpm` from `mise.toml`
|
||||||
- **THEN** the step succeeds without an explicit `github_token` input
|
- **THEN** the step succeeds without an explicit `github_token` input
|
||||||
- **AND** the GitHub API calls used to resolve releases are authenticated by the action's default `${{ github.token }}`
|
- **AND** the GitHub API calls used to resolve releases are authenticated by the action's default `${{ github.token }}`
|
||||||
|
|
||||||
@@ -93,3 +99,31 @@ Every job that needs `cue`, `node`, or `gx` on `$PATH` SHALL bootstrap them with
|
|||||||
- **WHEN** `uses:` references are extracted
|
- **WHEN** `uses:` references are extracted
|
||||||
- **THEN** the only tool-bootstrap action referenced is `jdx/mise-action@<pinned-sha>`
|
- **THEN** the only tool-bootstrap action referenced is `jdx/mise-action@<pinned-sha>`
|
||||||
- **AND** the pinned SHA in each `uses:` line matches the resolved SHA recorded in `.github/gx.lock` under `[actions."jdx/mise-action"."<major>"]`
|
- **AND** the pinned SHA in each `uses:` line matches the resolved SHA recorded in `.github/gx.lock` under `[actions."jdx/mise-action"."<major>"]`
|
||||||
|
|
||||||
|
### Requirement: `docs/src` build uses pnpm as its package manager
|
||||||
|
|
||||||
|
The `docs/src` MDX→Markdown build SHALL invoke `pnpm` (not `npm`, `yarn`, or `bun`) for dependency installation and script execution, in every CI workflow that builds the docs and in the local-developer contract. `docs/src/package.json` SHALL declare this contract via the `devEngines.packageManager` block with `name: "pnpm"` and `onFail: "error"`, and the lockfile committed at `docs/src/pnpm-lock.yaml` SHALL be the only lockfile under `docs/src/` (no `package-lock.json`, no `yarn.lock`, no `bun.lockb`).
|
||||||
|
|
||||||
|
**Experience context:** A contributor cloning the repo and running the docs build locally gets a single, predictable command path (`pnpm install && pnpm run build` from `docs/src/`) and a hard error if they reach for `npm install` out of habit. A CI engineer reading `mise.toml` and any of the three docs-building workflows sees the same package manager invoked consistently — no per-workflow drift between `npm`, `corepack`-shimmed pnpm, and action-installed pnpm.
|
||||||
|
|
||||||
|
#### Scenario: Contributor runs the wrong package manager locally
|
||||||
|
|
||||||
|
- **GIVEN** a contributor has cloned the repo and `cd`'d into `docs/src/`
|
||||||
|
- **WHEN** they run `npm install`
|
||||||
|
- **THEN** the command exits non-zero with a `devEngines` mismatch error indicating that this project requires `pnpm`
|
||||||
|
- **AND** no `node_modules` or `package-lock.json` is created
|
||||||
|
|
||||||
|
#### Scenario: CI workflow builds the docs
|
||||||
|
|
||||||
|
- **GIVEN** any of `build.yml`, `update_docs.yml`, or `update_version.yml` runs the docs-build step
|
||||||
|
- **WHEN** the build job executes
|
||||||
|
- **THEN** the step body is exactly `pnpm install --frozen-lockfile` followed by `pnpm run build`, preceded by a `jdx/mise-action@<pinned>` bootstrap step
|
||||||
|
- **AND** the step does not invoke `npm`, `corepack`, or `pnpm/action-setup` anywhere
|
||||||
|
|
||||||
|
#### Scenario: Only one lockfile lives under `docs/src/`
|
||||||
|
|
||||||
|
- **GIVEN** a contributor inspects `docs/src/`
|
||||||
|
- **WHEN** they list the directory
|
||||||
|
- **THEN** `pnpm-lock.yaml` is present
|
||||||
|
- **AND** no `package-lock.json`, `yarn.lock`, or `bun.lockb` file is present
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ The images includes the minimum tools to run Flutter and build apps. The version
|
|||||||
* Installed Flutter SDK 3.41.9.
|
* Installed Flutter SDK 3.41.9.
|
||||||
* Analytics disabled by default, opt-in if `ENABLE_ANALYTICS` environment variable is passed when running the container.
|
* Analytics disabled by default, opt-in if `ENABLE_ANALYTICS` environment variable is passed when running the container.
|
||||||
* Rootless user `flutter:flutter`, with permissions to run on Github workflows and GitLab CI.
|
* Rootless user `flutter:flutter`, with permissions to run on Github workflows and GitLab CI.
|
||||||
* Cached Fastlane gem 2.233.1.
|
* Cached Fastlane gem 2.234.0.
|
||||||
* Minimal image with predownloaded SDKs and tools ready to run `flutter` commands for the Android platform.
|
* Minimal image with predownloaded SDKs and tools ready to run `flutter` commands for the Android platform.
|
||||||
|
|
||||||
Predownloaded SDKs and tools in Android:
|
Predownloaded SDKs and tools in Android:
|
||||||
@@ -104,7 +104,7 @@ The android.Dockerfile expects a few arguments:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Android
|
# Android
|
||||||
docker build --target android --build-arg flutter_version=3.41.9 --build-arg fastlane_version=2.233.1 --build-arg android_build_tools_version=35.0.0 --build-arg android_platform_versions="36" -t android-test .
|
docker build --target android --build-arg flutter_version=3.41.9 --build-arg fastlane_version=2.234.0 --build-arg android_build_tools_version=35.0.0 --build-arg android_platform_versions="36" -t android-test .
|
||||||
```
|
```
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|||||||
Reference in New Issue
Block a user