@stll/oxlint-config 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -11
- package/dist/cloud-setup-cli.cjs +1 -1
- package/dist/cloud-setup-cli.cjs.map +1 -1
- package/dist/cloud-setup-cli.mjs +2 -2
- package/dist/cloud-setup-cli.mjs.map +1 -1
- package/dist/toolchain-changed.cjs +80 -9
- package/dist/toolchain-changed.cjs.map +1 -1
- package/dist/toolchain-changed.mjs +80 -9
- package/dist/toolchain-changed.mjs.map +1 -1
- package/dist/toolchain-guard.cjs +10 -2
- package/dist/toolchain-guard.cjs.map +1 -1
- package/dist/toolchain-guard.mjs +11 -3
- package/dist/toolchain-guard.mjs.map +1 -1
- package/dist/toolchain-inputs.cjs +182 -57
- package/dist/toolchain-inputs.cjs.map +1 -1
- package/dist/toolchain-inputs.mjs +169 -56
- package/dist/toolchain-inputs.mjs.map +1 -1
- package/dist/toolchain-schema.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -306,7 +306,8 @@ Add an explicit declaration to tracked root `stll-toolchain.json`:
|
|
|
306
306
|
"tools": {
|
|
307
307
|
"cargo-nextest": "0.9.148",
|
|
308
308
|
"wasm-bindgen-cli": "0.2.126",
|
|
309
|
-
"uv": "0.13.1"
|
|
309
|
+
"uv": "0.13.1",
|
|
310
|
+
"time": "1.9"
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
313
|
}
|
|
@@ -336,10 +337,15 @@ setup also provisions Ubuntu's `build-essential` package for native compilation
|
|
|
336
337
|
and linking.
|
|
337
338
|
|
|
338
339
|
`cloud.tools` is a closed object: the supported keys are `cargo-nextest`,
|
|
339
|
-
`wasm-bindgen-cli`, and `
|
|
340
|
+
`wasm-bindgen-cli`, `uv`, and `time`. Each value must be an exact release supported by
|
|
340
341
|
the installed tooling package. Unknown tools and unsupported versions fail
|
|
341
|
-
generation.
|
|
342
|
+
generation. `cargo-nextest`, `wasm-bindgen-cli`, and `uv` use versioned upstream Linux binaries with committed
|
|
342
343
|
SHA256 pins for amd64 and arm64; setup does not build them with `cargo install`.
|
|
344
|
+
`time` installs GNU time (`/usr/bin/time`, needed for `/usr/bin/time -v`) from
|
|
345
|
+
Ubuntu's `time` package with bounded apt; its value is the upstream release
|
|
346
|
+
(`1.9` on Ubuntu 24.04). GNU time reports its version as `UNKNOWN`, so setup
|
|
347
|
+
verifies the binary's GNU identity and the installed package release. A present,
|
|
348
|
+
matching package is reused without network access.
|
|
343
349
|
`wasm-bindgen-cli` requires the matching `wasm-bindgen` crate version in tracked
|
|
344
350
|
root `Cargo.lock`. Regenerate after updating the lockfile or any tool pin.
|
|
345
351
|
|
|
@@ -353,17 +359,22 @@ SHA256 pins, and installs those local files with apt. It does not resolve Valkey
|
|
|
353
359
|
from a mutable package index.
|
|
354
360
|
The command writes `.agents/cloud-setup.sh` with executable permissions and
|
|
355
361
|
merges a `SessionStart` hook into `.claude/settings.json`. The hook runs
|
|
356
|
-
`bash
|
|
357
|
-
sessions that reuse cached filesystems
|
|
362
|
+
`bash "$CLAUDE_PROJECT_DIR/.agents/cloud-setup.sh" start` only when
|
|
363
|
+
`CLAUDE_CODE_REMOTE=true`, including sessions that reuse cached filesystems and
|
|
364
|
+
sessions started from a repository subdirectory. Generation replaces the
|
|
365
|
+
relative-path hook written by 1.1.0 in place. After successful startup, it appends the
|
|
358
366
|
managed shell profile's literal exports to `CLAUDE_ENV_FILE` when available, so
|
|
359
367
|
subsequent Claude commands select pinned runtimes and tools before preinstalled
|
|
360
|
-
versions while retaining their inherited `PATH`.
|
|
368
|
+
versions while retaining their inherited `PATH`. The settings also set
|
|
369
|
+
`"attribution": {"commit": "", "pr": ""}`, so cloud sessions add no tool
|
|
370
|
+
attribution to commits or pull requests. Existing environment-file
|
|
361
371
|
content, unrelated settings, and hooks are preserved. Invalid JSON, disabled
|
|
362
|
-
hooks,
|
|
363
|
-
instruction. Commit both generated files.
|
|
372
|
+
hooks, conflicting cloud startup entries, or a different `attribution` value stop
|
|
373
|
+
generation with a repair instruction. Commit both generated files.
|
|
364
374
|
Generation refuses symlink parents or destinations and hard-linked destinations.
|
|
365
|
-
`stll-toolchain-check` rejects missing, drifted, or undeclared tracked scripts
|
|
366
|
-
missing or conflicting startup hooks
|
|
375
|
+
`stll-toolchain-check` rejects missing, drifted, or undeclared tracked scripts,
|
|
376
|
+
missing or conflicting startup hooks, and missing or different attribution
|
|
377
|
+
settings with mandatory `cloud-setup-drift`.
|
|
367
378
|
Regenerate after changing the policy or declaration. `stll-cloud-setup --help`
|
|
368
379
|
prints usage without reading repository configuration.
|
|
369
380
|
|
|
@@ -425,7 +436,8 @@ GitHub release downloads redirect to `release-assets.githubusercontent.com`;
|
|
|
425
436
|
allow that host as well. This includes Bun and the optional prebuilt tools.
|
|
426
437
|
Rust provisioning uses `static.rust-lang.org` for both distribution and update endpoints.
|
|
427
438
|
|
|
428
|
-
System prerequisites use the image's configured
|
|
439
|
+
System prerequisites and the optional `time` package use the image's configured
|
|
440
|
+
Ubuntu apt repositories:
|
|
429
441
|
standard Ubuntu 24.04 images use `archive.ubuntu.com`, `security.ubuntu.com`,
|
|
430
442
|
or `ports.ubuntu.com`, depending on architecture. Images configured with a
|
|
431
443
|
mirror need that mirror's host instead. Frozen Bun installation also needs
|
package/dist/cloud-setup-cli.cjs
CHANGED
|
@@ -84,7 +84,7 @@ const main = async () => {
|
|
|
84
84
|
await checkOutput(destination);
|
|
85
85
|
const settingsDestination = (0, node_path.join)(root, require_toolchain_inputs.cloudClaudeSettingsPath);
|
|
86
86
|
const settings = await readClaudeSettings(settingsDestination);
|
|
87
|
-
const mergedSettings = require_toolchain_inputs.
|
|
87
|
+
const mergedSettings = require_toolchain_inputs.mergeCloudClaudeSettings(settings?.text);
|
|
88
88
|
await writeOutput({
|
|
89
89
|
destination,
|
|
90
90
|
text: script,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-setup-cli.cjs","names":["lstat","dirname","mkdir","open","constants","cloudClaudeSettingsPath","cloudSessionStartFix","realpath","readToolchainInputs","parseToolchainConfiguration","parseToolchainPolicy","readFile","generateCloudSetup","join","cloudSetupPath","
|
|
1
|
+
{"version":3,"file":"cloud-setup-cli.cjs","names":["lstat","dirname","mkdir","open","constants","cloudClaudeSettingsPath","cloudSessionStartFix","realpath","readToolchainInputs","parseToolchainConfiguration","parseToolchainPolicy","readFile","generateCloudSetup","join","cloudSetupPath","mergeCloudClaudeSettings"],"sources":["../src/cloud-setup-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { constants } from \"node:fs\";\nimport { lstat, mkdir, open, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { cloudSetupPath, generateCloudSetup } from \"./cloud-setup\";\nimport {\n cloudClaudeSettingsPath,\n cloudSessionStartFix,\n mergeCloudClaudeSettings,\n} from \"./cloud-setup-claude\";\nimport {\n parseToolchainConfiguration,\n readToolchainInputs,\n} from \"./toolchain-guard\";\nimport { parseToolchainPolicy } from \"./toolchain-schema\";\n\nconst usage =\n \"Usage: stll-cloud-setup (run from repository root)\\n stll-cloud-setup --help\";\nconst optionalStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n return undefined;\n throw error;\n }\n};\n\nconst checkOutput = async (destination: string) => {\n const parent = dirname(destination);\n const parentStat = await optionalStat(parent);\n if (\n parentStat !== undefined &&\n (parentStat.isSymbolicLink() || !parentStat.isDirectory())\n )\n throw new Error(\"cloud setup parent must be a real repository directory\");\n const destinationStat = await optionalStat(destination);\n if (\n destinationStat !== undefined &&\n (destinationStat.isSymbolicLink() ||\n !destinationStat.isFile() ||\n destinationStat.nlink !== 1)\n )\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n return destinationStat;\n};\n\ntype WriteOutputOptions = {\n destination: string;\n text: string;\n mode: number;\n};\n\nconst writeOutput = async ({ destination, text, mode }: WriteOutputOptions) => {\n await checkOutput(destination);\n await mkdir(dirname(destination), { recursive: true });\n const output = await open(\n destination,\n constants.O_WRONLY | constants.O_CREAT | constants.O_NOFOLLOW,\n mode,\n );\n try {\n const opened = await output.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n await output.truncate(0);\n await output.writeFile(text, \"utf8\");\n await output.chmod(mode);\n } finally {\n await output.close();\n }\n};\n\nconst readClaudeSettings = async (destination: string) => {\n try {\n if ((await checkOutput(destination)) === undefined) return undefined;\n const input = await open(\n destination,\n constants.O_RDONLY | constants.O_NOFOLLOW,\n );\n try {\n const opened = await input.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"settings must be a single-link regular repository file\",\n );\n return { text: await input.readFile(\"utf8\"), mode: opened.mode & 0o777 };\n } finally {\n await input.close();\n }\n } catch (error) {\n throw new Error(\n `cannot safely merge ${cloudClaudeSettingsPath}: ${error instanceof Error ? error.message : String(error)}; ${cloudSessionStartFix}`,\n );\n }\n};\n\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n if (args.length !== 0) throw new Error(usage);\n const root = await realpath(process.cwd());\n const { files, diagnostics } = readToolchainInputs(root);\n if (diagnostics.length > 0)\n throw new Error(\n diagnostics\n .map(\n ({ path, message }) =>\n `${path}: ${message}${path === cloudClaudeSettingsPath ? `; ${cloudSessionStartFix}` : \"\"}`,\n )\n .join(\"\\n\"),\n );\n const text = files[\"stll-toolchain.json\"];\n if (text === undefined)\n throw new Error(\"requires tracked stll-toolchain.json\");\n const { cloud, rustExceptions } = parseToolchainConfiguration(\n JSON.parse(text),\n );\n if (cloud === undefined)\n throw new Error(\"requires an explicit cloud declaration\");\n const nodeVersion = files[\".node-version\"];\n if (nodeVersion === undefined)\n throw new Error(\"requires tracked root .node-version\");\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const script = generateCloudSetup({\n policy,\n cloud,\n nodeVersion: nodeVersion.trim(),\n files,\n rustExceptions,\n });\n const destination = join(root, cloudSetupPath);\n await checkOutput(destination);\n const settingsDestination = join(root, cloudClaudeSettingsPath);\n const settings = await readClaudeSettings(settingsDestination);\n const mergedSettings = mergeCloudClaudeSettings(settings?.text);\n await writeOutput({ destination, text: script, mode: 0o755 });\n if (mergedSettings !== settings?.text)\n await writeOutput({\n destination: settingsDestination,\n text: mergedSettings,\n mode: settings?.mode ?? 0o644,\n });\n process.stdout.write(\n `Generated ${cloudSetupPath} and ${cloudClaudeSettingsPath}\\n`,\n );\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `cloud-setup: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
|
package/dist/cloud-setup-cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { b as cloudSetupPath, g as cloudSessionStartFix, h as cloudClaudeSettingsPath, x as generateCloudSetup, y as mergeCloudClaudeSettings } from "./toolchain-inputs.mjs";
|
|
3
3
|
import { n as parseToolchainConfiguration, r as readToolchainInputs } from "./toolchain-guard.mjs";
|
|
4
4
|
import { t as parseToolchainPolicy } from "./toolchain-schema.mjs";
|
|
5
5
|
import { constants } from "node:fs";
|
|
@@ -83,7 +83,7 @@ const main = async () => {
|
|
|
83
83
|
await checkOutput(destination);
|
|
84
84
|
const settingsDestination = join(root, cloudClaudeSettingsPath);
|
|
85
85
|
const settings = await readClaudeSettings(settingsDestination);
|
|
86
|
-
const mergedSettings =
|
|
86
|
+
const mergedSettings = mergeCloudClaudeSettings(settings?.text);
|
|
87
87
|
await writeOutput({
|
|
88
88
|
destination,
|
|
89
89
|
text: script,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-setup-cli.mjs","names":[],"sources":["../src/cloud-setup-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { constants } from \"node:fs\";\nimport { lstat, mkdir, open, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { cloudSetupPath, generateCloudSetup } from \"./cloud-setup\";\nimport {\n cloudClaudeSettingsPath,\n cloudSessionStartFix,\n
|
|
1
|
+
{"version":3,"file":"cloud-setup-cli.mjs","names":[],"sources":["../src/cloud-setup-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { constants } from \"node:fs\";\nimport { lstat, mkdir, open, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { cloudSetupPath, generateCloudSetup } from \"./cloud-setup\";\nimport {\n cloudClaudeSettingsPath,\n cloudSessionStartFix,\n mergeCloudClaudeSettings,\n} from \"./cloud-setup-claude\";\nimport {\n parseToolchainConfiguration,\n readToolchainInputs,\n} from \"./toolchain-guard\";\nimport { parseToolchainPolicy } from \"./toolchain-schema\";\n\nconst usage =\n \"Usage: stll-cloud-setup (run from repository root)\\n stll-cloud-setup --help\";\nconst optionalStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n return undefined;\n throw error;\n }\n};\n\nconst checkOutput = async (destination: string) => {\n const parent = dirname(destination);\n const parentStat = await optionalStat(parent);\n if (\n parentStat !== undefined &&\n (parentStat.isSymbolicLink() || !parentStat.isDirectory())\n )\n throw new Error(\"cloud setup parent must be a real repository directory\");\n const destinationStat = await optionalStat(destination);\n if (\n destinationStat !== undefined &&\n (destinationStat.isSymbolicLink() ||\n !destinationStat.isFile() ||\n destinationStat.nlink !== 1)\n )\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n return destinationStat;\n};\n\ntype WriteOutputOptions = {\n destination: string;\n text: string;\n mode: number;\n};\n\nconst writeOutput = async ({ destination, text, mode }: WriteOutputOptions) => {\n await checkOutput(destination);\n await mkdir(dirname(destination), { recursive: true });\n const output = await open(\n destination,\n constants.O_WRONLY | constants.O_CREAT | constants.O_NOFOLLOW,\n mode,\n );\n try {\n const opened = await output.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n await output.truncate(0);\n await output.writeFile(text, \"utf8\");\n await output.chmod(mode);\n } finally {\n await output.close();\n }\n};\n\nconst readClaudeSettings = async (destination: string) => {\n try {\n if ((await checkOutput(destination)) === undefined) return undefined;\n const input = await open(\n destination,\n constants.O_RDONLY | constants.O_NOFOLLOW,\n );\n try {\n const opened = await input.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"settings must be a single-link regular repository file\",\n );\n return { text: await input.readFile(\"utf8\"), mode: opened.mode & 0o777 };\n } finally {\n await input.close();\n }\n } catch (error) {\n throw new Error(\n `cannot safely merge ${cloudClaudeSettingsPath}: ${error instanceof Error ? error.message : String(error)}; ${cloudSessionStartFix}`,\n );\n }\n};\n\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n if (args.length !== 0) throw new Error(usage);\n const root = await realpath(process.cwd());\n const { files, diagnostics } = readToolchainInputs(root);\n if (diagnostics.length > 0)\n throw new Error(\n diagnostics\n .map(\n ({ path, message }) =>\n `${path}: ${message}${path === cloudClaudeSettingsPath ? `; ${cloudSessionStartFix}` : \"\"}`,\n )\n .join(\"\\n\"),\n );\n const text = files[\"stll-toolchain.json\"];\n if (text === undefined)\n throw new Error(\"requires tracked stll-toolchain.json\");\n const { cloud, rustExceptions } = parseToolchainConfiguration(\n JSON.parse(text),\n );\n if (cloud === undefined)\n throw new Error(\"requires an explicit cloud declaration\");\n const nodeVersion = files[\".node-version\"];\n if (nodeVersion === undefined)\n throw new Error(\"requires tracked root .node-version\");\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const script = generateCloudSetup({\n policy,\n cloud,\n nodeVersion: nodeVersion.trim(),\n files,\n rustExceptions,\n });\n const destination = join(root, cloudSetupPath);\n await checkOutput(destination);\n const settingsDestination = join(root, cloudClaudeSettingsPath);\n const settings = await readClaudeSettings(settingsDestination);\n const mergedSettings = mergeCloudClaudeSettings(settings?.text);\n await writeOutput({ destination, text: script, mode: 0o755 });\n if (mergedSettings !== settings?.text)\n await writeOutput({\n destination: settingsDestination,\n text: mergedSettings,\n mode: settings?.mode ?? 0o644,\n });\n process.stdout.write(\n `Generated ${cloudSetupPath} and ${cloudClaudeSettingsPath}\\n`,\n );\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `cloud-setup: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
|
|
@@ -278,12 +278,17 @@ const importerDependencies = (value) => {
|
|
|
278
278
|
}
|
|
279
279
|
return result;
|
|
280
280
|
};
|
|
281
|
+
const BUN_TEXT_LOCKFILE_VERSIONS = /* @__PURE__ */ new Set([
|
|
282
|
+
0,
|
|
283
|
+
1,
|
|
284
|
+
2
|
|
285
|
+
]);
|
|
281
286
|
const parseChangedLock = ({ file, text }) => {
|
|
282
287
|
const resolutions = [];
|
|
283
288
|
const importers = {};
|
|
284
289
|
if (file.endsWith("bun.lock")) {
|
|
285
290
|
const parsed = parseChangedJson(text);
|
|
286
|
-
if (!changedRecord(parsed) || !
|
|
291
|
+
if (!changedRecord(parsed) || !BUN_TEXT_LOCKFILE_VERSIONS.has(Number(parsed["lockfileVersion"])) || !changedRecord(parsed["packages"]) || !changedRecord(parsed["workspaces"])) throw new Error("Unsupported Bun lockfile shape");
|
|
287
292
|
for (const [directory, workspace] of Object.entries(parsed["workspaces"])) importers[directory || "."] = importerDependencies(workspace);
|
|
288
293
|
for (const [location, value] of Object.entries(parsed["packages"])) {
|
|
289
294
|
const dependency = dependencyName(location);
|
|
@@ -581,27 +586,93 @@ const snapshotText = ({ snapshot, file, visited = /* @__PURE__ */ new Set() }) =
|
|
|
581
586
|
visited
|
|
582
587
|
});
|
|
583
588
|
};
|
|
584
|
-
/**
|
|
589
|
+
/**
|
|
590
|
+
* What one `actions/checkout` step puts where, or `undefined` for any other step.
|
|
591
|
+
*
|
|
592
|
+
* A selector such as `base/package.json` after a checkout of this repository
|
|
593
|
+
* with `path: base` names the repository's own `package.json` at another ref,
|
|
594
|
+
* so it is read as that tracked file. A path built from an expression could
|
|
595
|
+
* replace any directory, so it is `unknown`.
|
|
596
|
+
*/
|
|
597
|
+
const checkoutStep = (step) => {
|
|
598
|
+
if (!changedRecord(step)) return void 0;
|
|
599
|
+
const uses = step["uses"];
|
|
600
|
+
if (typeof uses !== "string" || !uses.startsWith("actions/checkout@")) return void 0;
|
|
601
|
+
const options = changedRecord(step["with"]) ? step["with"] : {};
|
|
602
|
+
const repository = options["repository"];
|
|
603
|
+
const sameRepository = repository === void 0 || repository === "${{ github.repository }}";
|
|
604
|
+
const checkoutPath = options["path"];
|
|
605
|
+
if (checkoutPath === void 0) return {
|
|
606
|
+
kind: "root",
|
|
607
|
+
sameRepository
|
|
608
|
+
};
|
|
609
|
+
if (typeof checkoutPath !== "string" || checkoutPath.includes("${{") || node_path.default.posix.isAbsolute(checkoutPath)) return { kind: "unknown" };
|
|
610
|
+
const normalized = node_path.default.posix.normalize(checkoutPath).replace(/\/+$/, "");
|
|
611
|
+
if (normalized === "" || normalized === ".") return {
|
|
612
|
+
kind: "root",
|
|
613
|
+
sameRepository
|
|
614
|
+
};
|
|
615
|
+
if (normalized.split("/").includes("..")) return { kind: "unknown" };
|
|
616
|
+
return {
|
|
617
|
+
kind: "path",
|
|
618
|
+
path: normalized,
|
|
619
|
+
sameRepository
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
/**
|
|
623
|
+
* The tracked file a declared selector names under the checkouts preceding
|
|
624
|
+
* its step. The most specific checkout directory decides; a selector inside
|
|
625
|
+
* another repository's checkout is not a tracked file, whatever this
|
|
626
|
+
* repository tracks at the same path.
|
|
627
|
+
*/
|
|
628
|
+
const resolveCheckoutSelector = (declared, checkouts) => {
|
|
629
|
+
const file = node_path.default.posix.normalize(declared);
|
|
630
|
+
let owner;
|
|
631
|
+
for (const directory of checkouts.keys()) if ((directory === "" || file.startsWith(`${directory}/`)) && (owner === void 0 || directory.length > owner.length)) owner = directory;
|
|
632
|
+
if (owner === void 0) return file;
|
|
633
|
+
if (checkouts.get(owner) !== true) throw new Error(`Setup version-file names a file outside this repository: ${declared}`);
|
|
634
|
+
return owner === "" ? file : file.slice(owner.length + 1);
|
|
635
|
+
};
|
|
636
|
+
/** Visit each step with only the checkouts that precede it. */
|
|
637
|
+
const visitStepsInOrder = (steps, checkouts, visitStep) => {
|
|
638
|
+
const scope = new Map(checkouts);
|
|
639
|
+
for (const step of steps) {
|
|
640
|
+
visitStep(step, scope);
|
|
641
|
+
const checkout = checkoutStep(step);
|
|
642
|
+
if (checkout === void 0) continue;
|
|
643
|
+
if (checkout.kind !== "path") {
|
|
644
|
+
scope.clear();
|
|
645
|
+
scope.set("", checkout.kind === "root" && checkout.sameRepository);
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
648
|
+
for (const directory of scope.keys()) if (directory === checkout.path || directory.startsWith(`${checkout.path}/`)) scope.delete(directory);
|
|
649
|
+
scope.set(checkout.path, checkout.sameRepository);
|
|
650
|
+
}
|
|
651
|
+
};
|
|
585
652
|
const selectorFiles = (snapshot) => {
|
|
586
653
|
const files = /* @__PURE__ */ new Map();
|
|
587
|
-
const visit = (value) => {
|
|
654
|
+
const visit = (value, checkouts = /* @__PURE__ */ new Map()) => {
|
|
588
655
|
if (Array.isArray(value)) {
|
|
589
|
-
for (const entry of value) visit(entry);
|
|
656
|
+
for (const entry of value) visit(entry, checkouts);
|
|
590
657
|
return;
|
|
591
658
|
}
|
|
592
659
|
if (!changedRecord(value)) return;
|
|
593
660
|
for (const [key, entry] of Object.entries(value)) {
|
|
661
|
+
if (key === "steps" && Array.isArray(entry)) {
|
|
662
|
+
visitStepsInOrder(entry, checkouts, visit);
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
594
665
|
const input = key.toLowerCase();
|
|
595
666
|
if (!/(?:^|-)version-file$/.test(input) && ![
|
|
596
667
|
"toolchain-file",
|
|
597
668
|
"rust-toolchain-file",
|
|
598
669
|
"global-json-file"
|
|
599
670
|
].includes(input)) {
|
|
600
|
-
visit(entry);
|
|
671
|
+
visit(entry, checkouts);
|
|
601
672
|
continue;
|
|
602
673
|
}
|
|
603
674
|
if (typeof entry !== "string" || entry.trim() === "" || entry.includes("${{") || node_path.default.posix.isAbsolute(entry) || entry.split("/").includes("..")) throw new Error("Unclassifiable setup version-file declaration");
|
|
604
|
-
const file =
|
|
675
|
+
const file = resolveCheckoutSelector(entry, checkouts);
|
|
605
676
|
if (file === "." || file.split("/").some((part) => part === "vendor" || part === "node_modules")) throw new Error("Setup version-file leaves the tracked toolchain scope");
|
|
606
677
|
let tool = "shared";
|
|
607
678
|
if (input === "node-version-file") tool = "node";
|
|
@@ -957,7 +1028,7 @@ const setupRuntimeFileVersion = ({ snapshot, file, runtime }) => {
|
|
|
957
1028
|
};
|
|
958
1029
|
const setupRuntimeVersions = (snapshot) => {
|
|
959
1030
|
const versions = [];
|
|
960
|
-
const step = (value, file) => {
|
|
1031
|
+
const step = (value, file, checkouts) => {
|
|
961
1032
|
if (!changedRecord(value) || typeof value["uses"] !== "string") return;
|
|
962
1033
|
const action = value["uses"].split("@").at(0)?.toLowerCase();
|
|
963
1034
|
let runtime = /(?:^|\/)setup-([^/]+)$/.exec(action ?? "")?.[1];
|
|
@@ -1008,7 +1079,7 @@ const setupRuntimeVersions = (snapshot) => {
|
|
|
1008
1079
|
if (typeof input !== "string" || input.trim() === "" || input.includes("${{")) throw new Error("Unclassifiable setup version-file declaration");
|
|
1009
1080
|
version = setupRuntimeFileVersion({
|
|
1010
1081
|
snapshot,
|
|
1011
|
-
file:
|
|
1082
|
+
file: resolveCheckoutSelector(input, checkouts),
|
|
1012
1083
|
runtime: inputRuntime
|
|
1013
1084
|
});
|
|
1014
1085
|
} else version = setupRuntimeVersion(input);
|
|
@@ -1026,7 +1097,7 @@ const setupRuntimeVersions = (snapshot) => {
|
|
|
1026
1097
|
return;
|
|
1027
1098
|
}
|
|
1028
1099
|
if (!changedRecord(value)) return;
|
|
1029
|
-
for (const [key, entry] of Object.entries(value)) if (key === "steps" && Array.isArray(entry))
|
|
1100
|
+
for (const [key, entry] of Object.entries(value)) if (key === "steps" && Array.isArray(entry)) visitStepsInOrder(entry, /* @__PURE__ */ new Map(), (child, checkouts) => step(child, file, checkouts));
|
|
1030
1101
|
else visit(entry, file);
|
|
1031
1102
|
};
|
|
1032
1103
|
for (const file of snapshot.entries.keys()) {
|