code-foundry 1.47.5 → 1.48.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.
@@ -1,890 +0,0 @@
1
- name: Repository Setup
2
- description: Select mise or native language tooling and optionally install project dependencies.
3
-
4
- inputs:
5
- install:
6
- description: Install dependencies for the detected project ecosystems.
7
- required: false
8
- default: 'false'
9
- install-javascript:
10
- description: Install JavaScript/TypeScript package dependencies when install is enabled.
11
- required: false
12
- default: 'true'
13
- install-python:
14
- description: Install Python project dependencies when install is enabled.
15
- required: false
16
- default: 'true'
17
- install-rust:
18
- description: Fetch Rust project dependencies when install is enabled.
19
- required: false
20
- default: 'true'
21
- mise-scope:
22
- description: Limit mise installation and language package caches to auto, all, javascript, python, or rust.
23
- required: false
24
- default: auto
25
- cache-build:
26
- description: Restore JavaScript framework, Rust dependency, and incremental compiler caches.
27
- required: false
28
- default: 'true'
29
- cache-environment:
30
- description: Restore materialized Python virtual environments; disable for parallel test jobs with large environments.
31
- required: false
32
- default: 'true'
33
- cache-installed:
34
- description: Cache materialized JavaScript dependencies; auto skips large Bun node_modules trees and keeps compact link-based installs.
35
- required: false
36
- default: auto
37
- cache-save:
38
- description: Save restored caches after the job completes; disable to avoid post-job archive work in parallel jobs.
39
- required: false
40
- default: 'true'
41
- cache-packages:
42
- description: Restore JavaScript package-manager caches; auto skips large Bun lockfiles, or use true/false to override.
43
- required: false
44
- default: auto
45
- cache-lint:
46
- description: Restore the JavaScript/TypeScript lint cache.
47
- required: false
48
- default: 'false'
49
- cache-format:
50
- description: Restore the Prettier format cache.
51
- required: false
52
- default: 'false'
53
- cache-turbo:
54
- description: Cache local Turborepo artifacts; auto skips duplicate archives when TURBO_TOKEN enables remote caching.
55
- required: false
56
- default: auto
57
- task:
58
- description: Optional CI task used to scope test dependency installation.
59
- required: false
60
- default: ''
61
- task-javascript:
62
- description: Whether the selected task has a JavaScript suite; auto preserves default detection.
63
- required: false
64
- default: auto
65
- task-python:
66
- description: Whether the selected task has a Python suite; auto preserves default detection.
67
- required: false
68
- default: auto
69
- task-rust:
70
- description: Whether the selected task has a Rust suite; auto preserves default detection.
71
- required: false
72
- default: auto
73
-
74
- runs:
75
- using: composite
76
- steps:
77
- - name: Disable framework telemetry
78
- shell: bash
79
- run: |
80
- echo 'TURBO_TELEMETRY_DISABLED=1' >> "$GITHUB_ENV"
81
- echo 'NEXT_TELEMETRY_DISABLED=1' >> "$GITHUB_ENV"
82
- - name: Detect project profile
83
- id: profile
84
- shell: bash
85
- run: |
86
- tracked_files="$(git ls-files)"
87
-
88
- toolchain="auto"
89
- if [ -f .github/code-foundry.yml ]; then
90
- configured_toolchain="$(awk -F': ' '/^toolchain:/ {print $2; exit}' .github/code-foundry.yml)"
91
- [ -n "$configured_toolchain" ] && toolchain="$configured_toolchain"
92
- for flag in rust_sccache rust_nextest; do
93
- if grep -Eq "^${flag}:\\s*[\"']?true[\"']?\\s*$" .github/code-foundry.yml; then
94
- printf '%s=true\n' "$flag" >> "$GITHUB_OUTPUT"
95
- else
96
- printf '%s=false\n' "$flag" >> "$GITHUB_OUTPUT"
97
- fi
98
- done
99
- else
100
- printf 'rust_sccache=false\nrust_nextest=false\n' >> "$GITHUB_OUTPUT"
101
- fi
102
- if [ "$toolchain" = auto ] && [ -f .mise.toml ]; then
103
- toolchain=mise
104
- fi
105
- printf 'toolchain_mode=%s\n' "$toolchain" >> "$GITHUB_OUTPUT"
106
-
107
- has_tracked_regex() {
108
- printf '%s\n' "$tracked_files" | grep -Eq "$1"
109
- }
110
-
111
- has_python_source() {
112
- awk '!/^\.github\// && /(^|\/)[^\/]+\.py$/ { found=1; exit } END { exit !found }' <<< "$tracked_files"
113
- }
114
-
115
- has_package_script() {
116
- [ -f package.json ] || return 1
117
- node - "$1" <<'NODE'
118
- const fs = require('node:fs');
119
- const script = process.argv[2];
120
- const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
121
- process.exit(packageJson.scripts?.[script] ? 0 : 1);
122
- NODE
123
- }
124
-
125
- script_uses_turbo() {
126
- [ -f package.json ] || return 1
127
- REPO_FOUNDRY_TURBO_TASK="$REPO_FOUNDRY_TASK" node <<'NODE'
128
- const fs = require('node:fs');
129
- const task = process.env.REPO_FOUNDRY_TURBO_TASK || '';
130
- const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
131
- const scripts = packageJson.scripts || {};
132
- const candidates = {
133
- format: ['format:check', 'format', 'fmt'],
134
- lint: ['lint'],
135
- type_check: ['type-check', 'typecheck', 'type:check'],
136
- build: ['build'],
137
- unit: ['test:unit', 'test:coverage', 'test'],
138
- integration: ['test:integration'],
139
- e2e: ['test:e2e', 'e2e'],
140
- smoke: ['test:smoke', 'smoke'],
141
- performance: ['performance:check', 'perf:check'],
142
- }[task] || [];
143
- const selected = candidates.find((name) => scripts[name]);
144
- const usesTurbo = Boolean(selected && /\bturbo(?:\s|$)/.test(scripts[selected]));
145
- process.exit(usesTurbo ? 0 : 1);
146
- NODE
147
- }
148
-
149
- uses_prettier() {
150
- [ -f package.json ] || return 0
151
- node <<'NODE'
152
- const fs = require('node:fs');
153
- const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
154
- const scripts = p.scripts || {};
155
- const dependencies = {
156
- ...p.dependencies,
157
- ...p.devDependencies,
158
- ...p.optionalDependencies,
159
- ...p.peerDependencies,
160
- };
161
- const usesPrettier = Boolean(dependencies.prettier) || Object.values(scripts).some((value) => /\bprettier\b/.test(value));
162
- const hasFormatScript = Boolean(scripts['format:check'] || scripts.format || scripts.fmt);
163
- process.exit(usesPrettier || !hasFormatScript ? 0 : 1);
164
- NODE
165
- }
166
-
167
- uses_eslint() {
168
- [ -f package.json ] || return 1
169
- node <<'NODE'
170
- const fs = require('node:fs');
171
- const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
172
- const scripts = p.scripts || {};
173
- const dependencies = {
174
- ...p.dependencies,
175
- ...p.devDependencies,
176
- ...p.optionalDependencies,
177
- ...p.peerDependencies,
178
- };
179
- const usesEslint = Boolean(dependencies.eslint) || Object.values(scripts).some((value) => /\beslint\b/.test(value));
180
- process.exit(usesEslint ? 0 : 1);
181
- NODE
182
- }
183
-
184
- javascript=false
185
- if [ -f package.json ] || [ -f bun.lock ] || [ -f bun.lockb ] ||
186
- [ -f pnpm-lock.yaml ] || [ -f yarn.lock ] || [ -f package-lock.json ] ||
187
- has_tracked_regex '(^|/)[^/]+\.(js|jsx|mjs|cjs|ts|tsx|mts|cts)$'; then
188
- javascript=true
189
- echo 'javascript=true' >> "$GITHUB_OUTPUT"
190
- else
191
- echo 'javascript=false' >> "$GITHUB_OUTPUT"
192
- fi
193
-
194
- if [ -f bun.lock ] || [ -f bun.lockb ] || [ -f pnpm-lock.yaml ] ||
195
- [ -f yarn.lock ] || [ -f package-lock.json ]; then
196
- javascript_dependencies=true
197
- echo 'javascript_dependencies=true' >> "$GITHUB_OUTPUT"
198
- elif [ -f package.json ] && REPO_FOUNDRY_PACKAGE_FILES="$tracked_files" node <<'NODE'
199
- const fs = require('node:fs');
200
-
201
- const files = (process.env.REPO_FOUNDRY_PACKAGE_FILES || '')
202
- .trim()
203
- .split('\n')
204
- .filter((file) => /(^|\/)package\.json$/.test(file));
205
- const groups = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'];
206
- const hasDependencies = files.some((file) => {
207
- try {
208
- const packageJson = JSON.parse(fs.readFileSync(file, 'utf8'));
209
- return groups.some((group) => packageJson[group] && Object.keys(packageJson[group]).length > 0) ||
210
- Array.isArray(packageJson.workspaces) ||
211
- (packageJson.workspaces && typeof packageJson.workspaces === 'object');
212
- } catch {
213
- return true;
214
- }
215
- });
216
- process.exit(hasDependencies ? 0 : 1);
217
- NODE
218
- then
219
- javascript_dependencies=true
220
- echo 'javascript_dependencies=true' >> "$GITHUB_OUTPUT"
221
- else
222
- javascript_dependencies=false
223
- echo 'javascript_dependencies=false' >> "$GITHUB_OUTPUT"
224
- fi
225
-
226
- javascript_package_manager=none
227
- configured_package_manager=""
228
- config_file=.github/code-foundry.yml
229
- if [ -f "$config_file" ]; then
230
- configured_package_manager="$(awk -F': ' '/^package_manager:/ {print $2; exit}' "$config_file")"
231
- fi
232
- case "$configured_package_manager" in
233
- bun|pnpm|yarn|npm) javascript_package_manager="$configured_package_manager" ;;
234
- *)
235
- if [ -f bun.lock ] || [ -f bun.lockb ]; then javascript_package_manager=bun
236
- elif [ -f pnpm-lock.yaml ]; then javascript_package_manager=pnpm
237
- elif [ -f yarn.lock ]; then javascript_package_manager=yarn
238
- elif [ -f package-lock.json ]; then javascript_package_manager=npm
239
- elif [ "$javascript_dependencies" = true ]; then javascript_package_manager=bun
240
- fi
241
- ;;
242
- esac
243
- printf 'javascript_package_manager=%s\n' "$javascript_package_manager" >> "$GITHUB_OUTPUT"
244
-
245
- javascript_packages_cache=true
246
- case "$REPO_FOUNDRY_CACHE_PACKAGES" in
247
- false) javascript_packages_cache=false ;;
248
- true) : ;;
249
- auto)
250
- # Large Bun stores can take longer to transfer and extract than a
251
- # clean registry install. Keep normal projects cached, but avoid
252
- # the expensive archive for workspace graphs and once the tracked
253
- # Bun lockfiles exceed 512 KiB in total. Workspace installs often
254
- # resolve quickly from the registry, while their shared Bun store
255
- # is expensive to archive. Set REPO_FOUNDRY_CACHE_PACKAGES=true
256
- # when a repository has measured a cache win.
257
- if [ "$javascript_package_manager" = bun ]; then
258
- bun_workspace=false
259
- if [ -f package.json ] && node -e '
260
- const p = require("./package.json");
261
- const workspaces = p.workspaces;
262
- process.exit(
263
- Array.isArray(workspaces) ||
264
- Boolean(workspaces && typeof workspaces === "object") ? 0 : 1,
265
- );
266
- ' 2>/dev/null; then
267
- bun_workspace=true
268
- fi
269
- bun_lock_bytes=0
270
- while IFS= read -r lockfile; do
271
- [ -f "$lockfile" ] || continue
272
- lock_bytes="$(wc -c < "$lockfile")"
273
- bun_lock_bytes=$((bun_lock_bytes + lock_bytes))
274
- done < <(printf '%s\n' "$tracked_files" | awk '/(^|\/)bun\.lock(b)?$/')
275
- if [ "$bun_workspace" = true ] || [ "$bun_lock_bytes" -gt 524288 ]; then
276
- javascript_packages_cache=false
277
- fi
278
- fi
279
- ;;
280
- *) echo "Unsupported cache-packages value: $REPO_FOUNDRY_CACHE_PACKAGES" >&2; exit 2 ;;
281
- esac
282
- printf 'javascript_packages_cache=%s\n' "$javascript_packages_cache" >> "$GITHUB_OUTPUT"
283
-
284
- python=false
285
- if has_python_source || [ -f pyproject.toml ] ||
286
- [ -f requirements.txt ] || [ -f requirements-dev.txt ]; then
287
- python=true
288
- echo 'python=true' >> "$GITHUB_OUTPUT"
289
- else
290
- echo 'python=false' >> "$GITHUB_OUTPUT"
291
- fi
292
-
293
- rust=false
294
- if [ -f Cargo.toml ] || [ -f Cargo.lock ]; then
295
- rust=true
296
- echo 'rust=true' >> "$GITHUB_OUTPUT"
297
- else
298
- echo 'rust=false' >> "$GITHUB_OUTPUT"
299
- fi
300
-
301
- turbo=false
302
- if [ -f turbo.json ] || [ -f turbo.jsonc ] || has_tracked_regex '(^|/)turbo\.jsonc?$'; then
303
- turbo=true
304
- echo 'turbo=true' >> "$GITHUB_OUTPUT"
305
- else
306
- echo 'turbo=false' >> "$GITHUB_OUTPUT"
307
- fi
308
-
309
- eslint=false
310
- if [ -f .eslintrc ] || [ -f .eslintrc.js ] || [ -f .eslintrc.cjs ] ||
311
- [ -f .eslintrc.json ] || has_tracked_regex '(^|/)(\.eslintrc[^/]*|eslint\.config\.[^/]*)$' ||
312
- uses_eslint; then
313
- eslint=true
314
- echo 'eslint=true' >> "$GITHUB_OUTPUT"
315
- else
316
- echo 'eslint=false' >> "$GITHUB_OUTPUT"
317
- fi
318
-
319
- prettier=false
320
- if [ "$javascript" = true ]; then
321
- # Cache the fallback formatter for projects without a dedicated
322
- # config, but avoid probing an empty cache when a repository-owned
323
- # format script does not use Prettier.
324
- if uses_prettier; then
325
- prettier=true
326
- fi
327
- fi
328
- printf 'prettier=%s\n' "$prettier" >> "$GITHUB_OUTPUT"
329
-
330
- # Repository-owned format/lint scripts are authoritative and commonly
331
- # do not create the generic tool caches. Avoid recursive cache-path
332
- # scans and post-job archive work unless the fallback runner is used.
333
- prettier_fallback=false
334
- if [ "$prettier" = true ] && ! has_package_script format:check; then
335
- prettier_fallback=true
336
- fi
337
- eslint_fallback=false
338
- if [ "$eslint" = true ] && ! has_package_script lint; then
339
- eslint_fallback=true
340
- fi
341
- printf 'prettier_fallback=%s\n' "$prettier_fallback" >> "$GITHUB_OUTPUT"
342
- printf 'eslint_fallback=%s\n' "$eslint_fallback" >> "$GITHUB_OUTPUT"
343
-
344
- turbo_task=false
345
- if [ -z "$REPO_FOUNDRY_TASK" ] || script_uses_turbo; then
346
- turbo_task=true
347
- fi
348
- printf 'turbo_task=%s\n' "$turbo_task" >> "$GITHUB_OUTPUT"
349
-
350
- build=false
351
- if has_tracked_regex '(^|/)(next\.config\.[^/]*|vite\.config\.[^/]*|tsconfig[^/]*\.json)$'; then
352
- build=true
353
- echo 'build=true' >> "$GITHUB_OUTPUT"
354
- else
355
- echo 'build=false' >> "$GITHUB_OUTPUT"
356
- fi
357
-
358
- python_dependencies=false
359
- if [ -f pyproject.toml ] || [ -f uv.lock ] ||
360
- has_tracked_regex '(^|/)requirements[^/]*\.txt$' ||
361
- [ -f Pipfile.lock ] || [ -f poetry.lock ]; then
362
- python_dependencies=true
363
- echo 'python_dependencies=true' >> "$GITHUB_OUTPUT"
364
- else
365
- echo 'python_dependencies=false' >> "$GITHUB_OUTPUT"
366
- fi
367
-
368
- configured_tool() {
369
- [ -f .mise.toml ] && grep -Eq "^$1[[:space:]]*=" .mise.toml
370
- }
371
-
372
- ruff=false
373
- if [ "$python" = true ] &&
374
- { [ -f ruff.toml ] || configured_tool ruff ||
375
- { [ -f pyproject.toml ] && grep -Eiq 'ruff|\[tool\.ruff' pyproject.toml; } ||
376
- { [ -f requirements.txt ] && grep -Eiq '(^|[-_.])ruff([<>=[:space:]]|$)' requirements.txt; } ||
377
- { [ -f requirements-dev.txt ] && grep -Eiq '(^|[-_.])ruff([<>=[:space:]]|$)' requirements-dev.txt; }; }; then
378
- ruff=true
379
- fi
380
- printf 'ruff=%s\n' "$ruff" >> "$GITHUB_OUTPUT"
381
-
382
- mise_tools=()
383
- add_configured_tool() {
384
- # Optional tools are expected to be absent in single-language repos.
385
- # Keep that a successful probe so Bash strict mode does not abort
386
- # profile detection before the actual setup step runs.
387
- if configured_tool "$1"; then
388
- mise_tools+=("$1")
389
- fi
390
- return 0
391
- }
392
-
393
- case "$REPO_FOUNDRY_MISE_SCOPE" in
394
- all)
395
- for tool in node bun python uv ruff rust; do add_configured_tool "$tool"; done
396
- ;;
397
- auto)
398
- task_language_needed() {
399
- local language="$1" flag
400
- case "$language" in
401
- javascript) flag="$REPO_FOUNDRY_TASK_JAVASCRIPT" ;;
402
- python) flag="$REPO_FOUNDRY_TASK_PYTHON" ;;
403
- rust) flag="$REPO_FOUNDRY_TASK_RUST" ;;
404
- *) return 0 ;;
405
- esac
406
- [ -z "$REPO_FOUNDRY_TASK" ] || [ "$flag" = auto ] || [ "$flag" = true ]
407
- }
408
- if [ "$javascript" = true ] && task_language_needed javascript; then
409
- add_configured_tool node
410
- if { [ -f bun.lock ] || [ -f bun.lockb ] ||
411
- config_file=.github/code-foundry.yml; awk -F': ' '/^package_manager:/ {print $2; exit}' "$config_file" 2>/dev/null | grep -qx bun; }; then
412
- add_configured_tool bun
413
- fi
414
- fi
415
- if [ "$python" = true ] && task_language_needed python; then
416
- add_configured_tool python
417
- add_configured_tool uv
418
- add_configured_tool ruff
419
- fi
420
- if [ "$rust" = true ] && task_language_needed rust; then add_configured_tool rust; fi
421
- ;;
422
- javascript)
423
- configured_tool node && mise_tools+=(node)
424
- if { [ -f bun.lock ] || [ -f bun.lockb ] ||
425
- config_file=.github/code-foundry.yml; awk -F': ' '/^package_manager:/ {print $2; exit}' "$config_file" 2>/dev/null | grep -qx bun; } && configured_tool bun; then
426
- mise_tools+=(bun)
427
- fi
428
- ;;
429
- python)
430
- configured_tool python && mise_tools+=(python)
431
- configured_tool uv && mise_tools+=(uv)
432
- configured_tool ruff && mise_tools+=(ruff)
433
- ;;
434
- rust) configured_tool rust && mise_tools+=(rust) ;;
435
- *) echo "Unsupported mise-scope: $REPO_FOUNDRY_MISE_SCOPE" >&2; exit 2 ;;
436
- esac
437
- printf 'mise_tools=%s\n' "${mise_tools[*]}" >> "$GITHUB_OUTPUT"
438
- if [ "${#mise_tools[@]}" -gt 0 ]; then
439
- printf 'mise_required=true\n' >> "$GITHUB_OUTPUT"
440
- else
441
- printf 'mise_required=false\n' >> "$GITHUB_OUTPUT"
442
- fi
443
- env:
444
- REPO_FOUNDRY_MISE_SCOPE: ${{ inputs.mise-scope }}
445
- REPO_FOUNDRY_TASK: ${{ inputs.task }}
446
- REPO_FOUNDRY_TASK_JAVASCRIPT: ${{ inputs.task-javascript }}
447
- REPO_FOUNDRY_TASK_PYTHON: ${{ inputs.task-python }}
448
- REPO_FOUNDRY_TASK_RUST: ${{ inputs.task-rust }}
449
- REPO_FOUNDRY_CACHE_PACKAGES: ${{ inputs.cache-packages }}
450
-
451
- - name: Install native test libraries
452
- if: >-
453
- inputs.install == 'true' &&
454
- (inputs.task == 'unit' || inputs.task == 'performance') &&
455
- hashFiles('**/package.json') != '' &&
456
- steps.profile.outputs.javascript == 'true'
457
- shell: bash
458
- run: |
459
- if node -e '
460
- const fs = require("node:fs");
461
- const p = JSON.parse(fs.readFileSync("package.json", "utf8"));
462
- const all = { ...p.dependencies, ...p.devDependencies, ...p.optionalDependencies };
463
- process.exit(all["matchstick-as"] ? 0 : 1);
464
- ' 2>/dev/null; then
465
- sudo apt-get update -qq
466
- sudo apt-get install -y -qq libpq5
467
- fi
468
-
469
- - name: Setup Node
470
- if: >-
471
- steps.profile.outputs.toolchain_mode != 'mise' &&
472
- steps.profile.outputs.javascript == 'true' &&
473
- steps.profile.outputs.javascript_package_manager != 'bun'
474
- uses: actions/setup-node@v5
475
- with:
476
- node-version: 24
477
- cache: ${{ steps.profile.outputs.javascript_package_manager == 'npm' && 'npm' || steps.profile.outputs.javascript_package_manager == 'pnpm' && 'pnpm' || steps.profile.outputs.javascript_package_manager == 'yarn' && 'yarn' || '' }}
478
-
479
- - name: Setup Bun
480
- if: >-
481
- steps.profile.outputs.toolchain_mode != 'mise' &&
482
- steps.profile.outputs.javascript == 'true' &&
483
- steps.profile.outputs.javascript_package_manager == 'bun'
484
- uses: oven-sh/setup-bun@v2
485
- with:
486
- bun-version: 1.4.0
487
-
488
- - name: Enable Corepack
489
- if: >-
490
- steps.profile.outputs.toolchain_mode != 'mise' &&
491
- (steps.profile.outputs.javascript_package_manager == 'pnpm' ||
492
- steps.profile.outputs.javascript_package_manager == 'yarn')
493
- shell: bash
494
- run: corepack enable
495
-
496
- - name: Setup Python
497
- if: steps.profile.outputs.toolchain_mode != 'mise' && steps.profile.outputs.python == 'true'
498
- uses: actions/setup-python@v6
499
- with:
500
- python-version: '3.13'
501
-
502
- - name: Setup Rust
503
- if: steps.profile.outputs.toolchain_mode != 'mise' && steps.profile.outputs.rust == 'true'
504
- uses: dtolnay/rust-toolchain@stable
505
-
506
- - name: Setup uv
507
- if: >-
508
- steps.profile.outputs.python == 'true' &&
509
- (inputs.mise-scope == 'python' ||
510
- (inputs.install == 'true' && inputs.install-python == 'true')) &&
511
- !contains(steps.profile.outputs.mise_tools, 'uv')
512
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
513
- with:
514
- version: 0.11.32
515
- enable-cache: false
516
-
517
- - name: Cache installed JavaScript dependencies
518
- id: javascript-dependencies
519
- if: >-
520
- inputs.install == 'true' &&
521
- inputs.install-javascript == 'true' &&
522
- inputs.cache-installed != 'false' &&
523
- steps.profile.outputs.javascript_dependencies == 'true' &&
524
- steps.profile.outputs.javascript_package_manager != 'npm' &&
525
- (inputs.cache-installed == 'true' ||
526
- steps.profile.outputs.javascript_package_manager == 'pnpm' ||
527
- steps.profile.outputs.javascript_package_manager == 'yarn') &&
528
- hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/.npmrc', '**/.yarnrc*', '**/.pnpmfile.cjs', '.github/code-foundry.yml', '.mise.toml', 'mise.lock') != ''
529
- uses: actions/cache/restore@v5
530
- with:
531
- path: |
532
- **/node_modules
533
- key: ${{ runner.os }}-javascript-installed-v3-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/.npmrc', '**/.yarnrc*', '**/.pnpmfile.cjs', '.github/code-foundry.yml', '.mise.toml', 'mise.lock') }}
534
- - name: Restore Bun dependencies
535
- id: javascript-bun-cache-restore
536
- if: >-
537
- inputs.install == 'true' &&
538
- inputs.install-javascript == 'true' &&
539
- inputs.cache-installed != 'false' &&
540
- steps.profile.outputs.javascript_dependencies == 'true' &&
541
- steps.profile.outputs.javascript_package_manager == 'bun' &&
542
- hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/.npmrc', '.github/code-foundry.yml', '.mise.toml', 'mise.lock') != ''
543
- uses: actions/cache/restore@v5
544
- with:
545
- path: |
546
- **/node_modules
547
- key: ${{ runner.os }}-javascript-installed-v4-bun-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/.npmrc', '.github/code-foundry.yml', '.mise.toml', 'mise.lock') }}
548
- - name: Detect Bun dependencies
549
- id: javascript-bun-dependencies
550
- if: >-
551
- inputs.install == 'true' &&
552
- inputs.install-javascript == 'true' &&
553
- inputs.cache-installed != 'false' &&
554
- steps.profile.outputs.javascript_dependencies == 'true' &&
555
- steps.profile.outputs.javascript_package_manager == 'bun'
556
- shell: bash
557
- run: |
558
- if find . -path './.git' -prune -o -type d -name node_modules -print -quit | grep -q .; then
559
- echo 'restored=true' >> "$GITHUB_OUTPUT"
560
- else
561
- echo 'restored=false' >> "$GITHUB_OUTPUT"
562
- fi
563
- - name: Cache Corepack managers
564
- if: (inputs.mise-scope == 'javascript' || steps.javascript-dependencies.outputs.cache-hit == 'true') && inputs.install-javascript == 'true' && steps.profile.outputs.javascript == 'true' && hashFiles('**/pnpm-lock.yaml', '**/yarn.lock') != ''
565
- uses: ./.github/actions/cache
566
- with:
567
- save: ${{ inputs.cache-save }}
568
- path: ~/.cache/node/corepack
569
- # Corepack shims are independent of the project toolchain; keep this
570
- # cache warm when Node, Bun, or other mise-managed tools change.
571
- key: ${{ runner.os }}-corepack-${{ hashFiles('**/package.json', '**/pnpm-lock.yaml', '**/yarn.lock') }}
572
- restore-keys: |
573
- ${{ runner.os }}-corepack-
574
- - name: Cache JavaScript packages
575
- id: javascript-packages
576
- if: inputs.install == 'true' && inputs.install-javascript == 'true' && steps.profile.outputs.javascript_packages_cache == 'true' && steps.profile.outputs.javascript == 'true' && hashFiles('**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json') != '' && steps.javascript-dependencies.outputs.cache-hit != 'true' && steps.javascript-bun-dependencies.outputs.restored != 'true'
577
- uses: actions/cache/restore@v5
578
- with:
579
- path: |
580
- ~/.bun/install/cache
581
- ~/.cache/node/corepack
582
- ~/.npm
583
- ~/.cache/yarn
584
- ~/.local/share/pnpm/store
585
- key: ${{ runner.os }}-javascript-${{ hashFiles('**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json') }}
586
- restore-keys: |
587
- ${{ runner.os }}-javascript-
588
- - name: Cache JavaScript lint state
589
- # Fallback ESLint mode is valid without a dedicated config file; use the
590
- # manifest/lockfile as the cache identity in that case as well.
591
- if: inputs.install == 'true' && inputs.cache-lint == 'true' && steps.profile.outputs.eslint_fallback == 'true' && hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/.eslintrc*', '**/eslint.config.*') != ''
592
- uses: ./.github/actions/cache
593
- with:
594
- save: ${{ inputs.cache-save }}
595
- path: |
596
- **/.eslintcache
597
- key: ${{ runner.os }}-javascript-lint-${{ github.workflow }}-${{ github.job }}-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/.eslintrc*', '**/eslint.config.*') }}
598
- restore-keys: |
599
- ${{ runner.os }}-javascript-lint-${{ github.workflow }}-${{ github.job }}-
600
- - name: Cache JavaScript format state
601
- if: inputs.install == 'true' && inputs.cache-format == 'true' && steps.profile.outputs.prettier_fallback == 'true' && hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/.prettierrc*', '**/prettier.config.*') != ''
602
- uses: ./.github/actions/cache
603
- with:
604
- save: ${{ inputs.cache-save }}
605
- path: |
606
- **/node_modules/.cache/prettier
607
- key: ${{ runner.os }}-javascript-format-${{ github.workflow }}-${{ github.job }}-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/.prettierrc*', '**/prettier.config.*') }}
608
- # Keep primary saves isolated so parallel jobs cannot race. A cache
609
- # from another workflow job is still a valid warm fallback.
610
- restore-keys: |
611
- ${{ runner.os }}-javascript-format-
612
- - name: Cache JavaScript build state
613
- if: >-
614
- inputs.install == 'true' &&
615
- inputs.cache-build == 'true' &&
616
- (steps.profile.outputs.build == 'true' || inputs.task == 'build') &&
617
- (inputs.task != 'type_check' ||
618
- steps.profile.outputs.turbo != 'true' ||
619
- steps.profile.outputs.turbo_task != 'true') &&
620
- (env.TURBO_TOKEN == '' ||
621
- env.TURBO_TEAM == '' ||
622
- steps.profile.outputs.turbo != 'true' ||
623
- steps.profile.outputs.turbo_task != 'true')
624
- uses: ./.github/actions/cache
625
- with:
626
- save: ${{ inputs.cache-save }}
627
- # Remote Turbo already stores task outputs for Turbo-backed builds.
628
- # Avoid a second, often-empty framework cache archive in that mode;
629
- # Turbo Type-Check tasks do not need framework build state either.
630
- path: |
631
- **/.next/cache
632
- **/node_modules/.vite
633
- **/*.tsbuildinfo
634
- key: ${{ runner.os }}-javascript-build-${{ github.workflow }}-${{ github.job }}-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/next.config.*', '**/vite.config.*', '**/tsconfig*.json', '.mise.toml', 'mise.lock') }}
635
- # Keep primary saves isolated so parallel jobs cannot race. A cache
636
- # from another workflow job is still a valid warm fallback.
637
- restore-keys: |
638
- ${{ runner.os }}-javascript-build-
639
- - name: Cache Python environment
640
- id: python-environment
641
- if: inputs.install == 'true' && inputs.install-python == 'true' && inputs.cache-environment == 'true' && steps.profile.outputs.python == 'true' && hashFiles('**/pyproject.toml', '**/uv.lock', '**/requirements*.txt', '**/Pipfile.lock', '**/poetry.lock', '.mise.toml', 'mise.lock') != ''
642
- uses: ./.github/actions/cache
643
- with:
644
- save: ${{ inputs.cache-save }}
645
- path: |
646
- .venv
647
- **/.venv
648
- key: ${{ runner.os }}-python-environment-${{ hashFiles('**/pyproject.toml', '**/uv.lock', '**/requirements*.txt', '**/Pipfile.lock', '**/poetry.lock', '.mise.toml', 'mise.lock') }}
649
- - name: Cache Python packages
650
- if: inputs.install == 'true' && (inputs.mise-scope == 'auto' || inputs.mise-scope == 'all' || inputs.mise-scope == 'python') && inputs.install-python == 'true' && steps.profile.outputs.python_dependencies == 'true' && hashFiles('**/pyproject.toml', '**/uv.lock', '**/requirements*.txt', '**/Pipfile.lock', '**/poetry.lock') != '' && steps.python-environment.outputs.cache-hit != 'true'
651
- uses: ./.github/actions/cache
652
- with:
653
- save: ${{ inputs.cache-save }}
654
- path: |
655
- ~/.cache/pip
656
- ~/.cache/uv
657
- key: ${{ runner.os }}-python-${{ hashFiles('**/pyproject.toml', '**/uv.lock', '**/requirements*.txt', '**/Pipfile.lock', '**/poetry.lock') }}
658
- restore-keys: |
659
- ${{ runner.os }}-python-
660
- - name: Cache Python audit tools
661
- id: python-audit-tools
662
- if: inputs.install == 'false' && (inputs.mise-scope == 'auto' || inputs.mise-scope == 'all' || inputs.mise-scope == 'python') && inputs.install-python == 'true' && steps.profile.outputs.python_dependencies == 'true' && hashFiles('**/pyproject.toml', '**/uv.lock', '**/requirements*.txt', '**/Pipfile.lock', '**/poetry.lock') != ''
663
- uses: ./.github/actions/cache
664
- with:
665
- save: ${{ inputs.cache-save }}
666
- path: ~/.cache/uv-audit
667
- # Keep scanner wheels and metadata warm across application and script
668
- # changes. Bump v2 only when the pinned scanner version changes.
669
- key: ${{ runner.os }}-python-audit-v2
670
- restore-keys: |
671
- ${{ runner.os }}-python-audit-
672
- - name: Enable offline Python audit
673
- if: steps.python-audit-tools.outputs.cache-hit == 'true'
674
- shell: bash
675
- run: echo 'REPO_FOUNDRY_UV_AUDIT_OFFLINE=true' >> "$GITHUB_ENV"
676
- - name: Cache Python lint state
677
- if: inputs.install == 'true' && inputs.cache-lint == 'true' && steps.profile.outputs.ruff == 'true' && hashFiles('**/pyproject.toml', '**/ruff.toml', '.mise.toml', 'mise.lock') != ''
678
- uses: ./.github/actions/cache
679
- with:
680
- save: ${{ inputs.cache-save }}
681
- path: |
682
- **/.ruff_cache
683
- key: ${{ runner.os }}-python-lint-${{ github.workflow }}-${{ github.job }}-${{ hashFiles('**/pyproject.toml', '**/ruff.toml', '.mise.toml', 'mise.lock') }}
684
- # Primary saves remain job-specific; another job's Ruff cache is a
685
- # useful warm fallback because Ruff validates entries by file state.
686
- restore-keys: |
687
- ${{ runner.os }}-python-lint-${{ github.workflow }}-
688
- - name: Cache Turborepo
689
- if: >-
690
- inputs.install == 'true' &&
691
- inputs.install-javascript == 'true' &&
692
- inputs.cache-turbo != 'false' &&
693
- steps.profile.outputs.turbo == 'true' &&
694
- steps.profile.outputs.turbo_task == 'true' &&
695
- hashFiles('**/turbo.json', '**/turbo.jsonc') != '' &&
696
- (inputs.cache-turbo == 'true' || env.TURBO_TOKEN == '' || env.TURBO_TEAM == '')
697
- uses: ./.github/actions/cache
698
- with:
699
- save: ${{ inputs.cache-save }}
700
- path: |
701
- .turbo/cache
702
- **/.turbo/cache
703
- key: ${{ runner.os }}-turbo-${{ github.workflow }}-${{ github.job }}-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/turbo.json', '**/turbo.jsonc', '.mise.toml', 'mise.lock') }}
704
- restore-keys: |
705
- ${{ runner.os }}-turbo-
706
- - name: Configure remote Turbo
707
- if: >-
708
- inputs.install == 'true' &&
709
- inputs.cache-turbo != 'true' &&
710
- env.TURBO_TOKEN != '' &&
711
- env.TURBO_TEAM != '' &&
712
- steps.profile.outputs.turbo_task == 'true' &&
713
- steps.profile.outputs.turbo == 'true'
714
- shell: bash
715
- run: echo 'REPO_FOUNDRY_TURBO_REMOTE_ONLY=true' >> "$GITHUB_ENV"
716
- - name: Cache Rust packages
717
- id: rust-packages
718
- if: (inputs.mise-scope == 'auto' || inputs.mise-scope == 'all' || inputs.mise-scope == 'rust') && inputs.install-rust == 'true' && steps.profile.outputs.rust == 'true' && hashFiles('**/Cargo.toml', '**/Cargo.lock') != ''
719
- uses: ./.github/actions/cache
720
- with:
721
- save: ${{ inputs.cache-save }}
722
- path: |
723
- ~/.cargo/registry
724
- ~/.cargo/git
725
- key: ${{ runner.os }}-rust-${{ hashFiles('**/Cargo.toml', '**/Cargo.lock') }}
726
- restore-keys: |
727
- ${{ runner.os }}-rust-
728
- - name: Cache Rust advisory database
729
- if: inputs.install == 'false' && (inputs.mise-scope == 'auto' || inputs.mise-scope == 'all' || inputs.mise-scope == 'rust') && inputs.install-rust == 'true' && steps.profile.outputs.rust == 'true' && hashFiles('**/Cargo.toml', '**/Cargo.lock') != ''
730
- uses: ./.github/actions/cache
731
- with:
732
- save: ${{ inputs.cache-save }}
733
- path: ~/.cargo/advisory-db
734
- # The advisory database is independent of project dependencies. Keep
735
- # it warm for Security without invalidating it on every lockfile edit.
736
- key: ${{ runner.os }}-rust-advisory-code-foundry-v1
737
- restore-keys: |
738
- ${{ runner.os }}-rust-advisory-
739
- - name: Cache Rust builds
740
- if: inputs.install == 'true' && inputs.install-rust == 'true' && inputs.cache-build == 'true' && steps.profile.outputs.rust == 'true' && hashFiles('**/Cargo.toml', '**/Cargo.lock') != ''
741
- uses: ./.github/actions/cache
742
- with:
743
- save: ${{ inputs.cache-save }}
744
- # Keep reusable dependency/build-script artifacts for the Build job;
745
- # exclude target/incremental and release output, which are large and
746
- # provide little value on a fresh hosted runner.
747
- path: |
748
- target/.rustc_info.json
749
- target/debug/deps
750
- target/debug/build
751
- target/debug/.fingerprint
752
- target/debug/*.d
753
- key: ${{ runner.os }}-rust-build-v2-${{ github.workflow }}-${{ github.job }}-${{ hashFiles('**/Cargo.toml', '**/Cargo.lock', '.mise.toml', 'mise.lock') }}
754
- # Cargo fingerprints validate restored artifacts; keep job-specific
755
- # primary saves but reuse a prior workflow's dependency artifacts.
756
- restore-keys: |
757
- ${{ runner.os }}-rust-build-v2-
758
- # sccache is opt-in (`rust_sccache: true` in code-foundry.yml): it caches
759
- # per-compilation objects keyed by content, so dependency artifacts
760
- # survive Cargo.toml/Cargo.lock churn that busts the target/ cache above.
761
- - name: Cache sccache artifacts
762
- if: inputs.install == 'true' && inputs.install-rust == 'true' && steps.profile.outputs.rust == 'true' && steps.profile.outputs.rust_sccache == 'true'
763
- uses: ./.github/actions/cache
764
- with:
765
- save: ${{ inputs.cache-save }}
766
- path: ~/.cache/sccache
767
- key: ${{ runner.os }}-rust-sccache-${{ github.workflow }}-${{ github.job }}-${{ hashFiles('rust-toolchain.toml', 'rust-toolchain', '.cargo/config*', '.mise.toml', 'mise.lock') }}
768
- restore-keys: |
769
- ${{ runner.os }}-rust-sccache-
770
- - name: Install sccache
771
- if: inputs.install == 'true' && inputs.install-rust == 'true' && steps.profile.outputs.rust == 'true' && steps.profile.outputs.rust_sccache == 'true'
772
- uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2
773
- with:
774
- tool: sccache
775
- - name: Wrap rustc with sccache
776
- if: inputs.install == 'true' && inputs.install-rust == 'true' && steps.profile.outputs.rust == 'true' && steps.profile.outputs.rust_sccache == 'true'
777
- shell: bash
778
- run: |
779
- echo 'RUSTC_WRAPPER=sccache' >> "$GITHUB_ENV"
780
- echo "SCCACHE_DIR=$HOME/.cache/sccache" >> "$GITHUB_ENV"
781
- # cargo-nextest is opt-in (`rust_nextest: true`): the runtime uses
782
- # `cargo nextest run` when the binary is present.
783
- - name: Install cargo-nextest
784
- if: inputs.install == 'true' && inputs.install-rust == 'true' && steps.profile.outputs.rust == 'true' && steps.profile.outputs.rust_nextest == 'true'
785
- uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2
786
- with:
787
- tool: cargo-nextest
788
- - name: Setup
789
- if: ${{ steps.profile.outputs.mise_required == 'true' }}
790
- uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4
791
- with:
792
- version: 2026.9.2
793
- cache: true
794
- install_args: ${{ steps.profile.outputs.mise_tools }}
795
- - name: Setup Rust components
796
- if: >-
797
- steps.profile.outputs.rust == 'true' &&
798
- (steps.profile.outputs.mise_required == 'true' ||
799
- steps.profile.outputs.toolchain_mode != 'mise')
800
- shell: bash
801
- run: rustup component add rustfmt clippy
802
- - name: Use offline Cargo cache
803
- if: inputs.install == 'true' && inputs.install-rust == 'true' && steps.rust-packages.outputs.cache-hit == 'true' && hashFiles('**/Cargo.lock') != ''
804
- shell: bash
805
- run: echo 'CARGO_NET_OFFLINE=true' >> "$GITHUB_ENV"
806
- - name: Install
807
- if: inputs.install == 'true'
808
- shell: bash
809
- env:
810
- REPO_FOUNDRY_JAVASCRIPT_CACHE_HIT: ${{ steps.javascript-dependencies.outputs.cache-hit == 'true' || steps.javascript-bun-dependencies.outputs.restored == 'true' }}
811
- REPO_FOUNDRY_PYTHON_CACHE_HIT: ${{ steps.python-environment.outputs.cache-hit }}
812
- REPO_FOUNDRY_RUST_CACHE_HIT: ${{ steps.rust-packages.outputs.cache-hit }}
813
- REPO_FOUNDRY_INSTALL_JAVASCRIPT: ${{ inputs.install-javascript }}
814
- REPO_FOUNDRY_INSTALL_PYTHON: ${{ inputs.install-python }}
815
- REPO_FOUNDRY_INSTALL_RUST: ${{ inputs.install-rust }}
816
- REPO_FOUNDRY_TASK: ${{ inputs.task }}
817
- run: node $RUNNER_TEMP/code-foundry/src/runtime.mjs ci install
818
- - name: Measure Bun dependencies
819
- id: javascript-bun-cache
820
- if: >-
821
- inputs.cache-save == 'true' &&
822
- inputs.install == 'true' &&
823
- inputs.install-javascript == 'true' &&
824
- inputs.cache-installed != 'false' &&
825
- steps.profile.outputs.javascript_package_manager == 'bun' &&
826
- steps.profile.outputs.javascript_dependencies == 'true' &&
827
- steps.javascript-bun-dependencies.outputs.restored != 'true' &&
828
- !cancelled()
829
- shell: bash
830
- run: |
831
- total_kib="$(find . -path './.git' -prune -o -type d -name node_modules -print0 |
832
- xargs -0 -r du -sk |
833
- awk '{ total += $1 } END { print total + 0 }')"
834
- # Small Bun installs benefit from reuse; large monorepos are faster
835
- # with the package cache and a clean linker pass.
836
- if [ "$total_kib" -le 262144 ]; then
837
- echo 'cacheable=true' >> "$GITHUB_OUTPUT"
838
- else
839
- echo "Skipping Bun dependency cache (${total_kib} KiB > 256 MiB)"
840
- echo 'cacheable=false' >> "$GITHUB_OUTPUT"
841
- fi
842
- - name: Save Bun dependencies
843
- if: >-
844
- inputs.cache-save == 'true' &&
845
- steps.javascript-bun-cache.outputs.cacheable == 'true' &&
846
- !cancelled()
847
- continue-on-error: true
848
- uses: actions/cache/save@v5
849
- with:
850
- path: |
851
- **/node_modules
852
- key: ${{ runner.os }}-javascript-installed-v4-bun-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/.npmrc', '.github/code-foundry.yml', '.mise.toml', 'mise.lock') }}
853
- - name: Save installed JavaScript dependencies
854
- if: >-
855
- inputs.cache-save == 'true' &&
856
- inputs.install == 'true' &&
857
- inputs.install-javascript == 'true' &&
858
- steps.javascript-dependencies.outputs.cache-hit != 'true' &&
859
- steps.profile.outputs.javascript_dependencies == 'true' &&
860
- (steps.profile.outputs.javascript_package_manager == 'pnpm' ||
861
- steps.profile.outputs.javascript_package_manager == 'yarn') &&
862
- !cancelled()
863
- continue-on-error: true
864
- uses: actions/cache/save@v5
865
- with:
866
- path: |
867
- **/node_modules
868
- key: ${{ runner.os }}-javascript-installed-v3-${{ hashFiles('**/package.json', '**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json', '**/.npmrc', '**/.yarnrc*', '**/.pnpmfile.cjs', '.github/code-foundry.yml', '.mise.toml', 'mise.lock') }}
869
- - name: Save JavaScript packages
870
- if: >-
871
- inputs.cache-save == 'true' &&
872
- inputs.install == 'true' &&
873
- inputs.install-javascript == 'true' &&
874
- steps.javascript-packages.outputs.cache-hit != 'true' &&
875
- steps.profile.outputs.javascript_packages_cache == 'true' &&
876
- steps.profile.outputs.javascript == 'true' &&
877
- hashFiles('**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json') != '' &&
878
- steps.javascript-dependencies.outputs.cache-hit != 'true' &&
879
- steps.javascript-bun-dependencies.outputs.restored != 'true' &&
880
- !cancelled()
881
- continue-on-error: true
882
- uses: actions/cache/save@v5
883
- with:
884
- path: |
885
- ~/.bun/install/cache
886
- ~/.cache/node/corepack
887
- ~/.npm
888
- ~/.cache/yarn
889
- ~/.local/share/pnpm/store
890
- key: ${{ runner.os }}-javascript-${{ hashFiles('**/bun.lock', '**/bun.lockb', '**/pnpm-lock.yaml', '**/yarn.lock', '**/package-lock.json') }}