code-foundry 0.26.0 → 0.27.0

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.
Files changed (44) hide show
  1. package/.githooks/pre-commit +3 -4
  2. package/.github/CONTRIBUTING.md +10 -13
  3. package/.github/actions/setup/action.yml +50 -3
  4. package/.github/code-foundry.yml +6 -1
  5. package/.github/workflows/ci.yml +20 -23
  6. package/.github/workflows/ci_self-ci.yml +1 -1
  7. package/.github/workflows/codeql.yml +23 -29
  8. package/.github/workflows/codeql_self-ci.yml +1 -1
  9. package/.github/workflows/draft-pr.yml +2 -2
  10. package/.github/workflows/release-pr.yml +4 -4
  11. package/.github/workflows/release.yml +17 -29
  12. package/.github/workflows/security.yml +24 -19
  13. package/.github/workflows/security_self-ci.yml +1 -1
  14. package/.github/workflows/test.yml +20 -20
  15. package/.github/workflows/test_self-ci.yml +1 -1
  16. package/AGENTS.md +13 -10
  17. package/CHANGELOG.md +21 -0
  18. package/README.md +16 -6
  19. package/docs/CONFIGURATION.md +10 -1
  20. package/docs/INITIALIZATION.md +6 -5
  21. package/docs/RELEASES.md +5 -0
  22. package/docs/WORKFLOWS.md +12 -5
  23. package/package.json +7 -3
  24. package/src/cli.mjs +29 -25
  25. package/src/commands/doctor.mjs +70 -0
  26. package/src/commands/sync.mjs +224 -0
  27. package/src/lib/config.mjs +38 -0
  28. package/src/lib/profile.mjs +114 -0
  29. package/src/runtime.mjs +316 -0
  30. package/.github/scripts/bootstrap.sh +0 -21
  31. package/.github/scripts/changed-files.sh +0 -96
  32. package/.github/scripts/ci.sh +0 -641
  33. package/.github/scripts/codeql-languages.sh +0 -91
  34. package/.github/scripts/doctor.sh +0 -98
  35. package/.github/scripts/format-fast-path.sh +0 -80
  36. package/.github/scripts/init-repo.sh +0 -268
  37. package/.github/scripts/pre-commit.sh +0 -67
  38. package/.github/scripts/profile.sh +0 -186
  39. package/.github/scripts/security.sh +0 -214
  40. package/.github/scripts/sitecustomize.py +0 -17
  41. package/.github/scripts/sync-codeowners.sh +0 -76
  42. package/.github/scripts/sync-protection.sh +0 -138
  43. package/.github/scripts/sync-template.sh +0 -748
  44. package/.github/scripts/turbo-cache-probe.sh +0 -102
@@ -1,5 +1,4 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
1
+ #!/usr/bin/env sh
2
+ set -eu
3
3
 
4
- repo_root="$(git rev-parse --show-toplevel)"
5
- exec bash "$repo_root/.github/scripts/pre-commit.sh" "$@"
4
+ git diff --cached --check
@@ -48,14 +48,14 @@ docs/* test/* refactor/* │ │
48
48
  | `staging` | Integration branch | Target normal pull requests here. Required checks must pass before merge. |
49
49
  | `feat/*`, `fix/*`, `chore/*`, `refactor/*`, `docs/*`, `test/*` | Focused work | Branch from `staging`; keep changes small and reviewable. |
50
50
 
51
- Use squash merges unless the repository documents another strategy. Re-align `staging` with `main` after a release when needed.
51
+ The default Git workflow is `staging-release`: topic branches merge into `staging`, then a promotion PR moves validated changes into `main`, followed by the versioned release PR. The default merge strategy is `rebase`, which preserves the linear Conventional Commit history. Configure `merge_strategy` as `squash` or `merge` in `.github/code-foundry.yml` when the repository intentionally uses another policy. Re-align `staging` with `main` after a release when needed.
52
52
 
53
53
  ## Before you start
54
54
 
55
55
  ### Toolchain
56
56
 
57
- 1. Install [mise](https://mise.jdx.dev/).
58
- 2. Run `npx code-foundry init` to install the pinned toolchain, enable hooks, and validate the checkout.
57
+ 1. Run `npx code-foundry init` to detect the repository and enable hooks.
58
+ 2. Follow `toolchain: auto` in `.github/code-foundry.yml`; install mise only if the repository already uses it or explicitly selects it.
59
59
  3. Use `npx code-foundry doctor` when setup, lockfiles, or hooks appear out of sync.
60
60
  4. Use the repository's existing package manager and lockfile. Do not introduce a second package manager.
61
61
  5. Copy `.env.example` to the appropriate local environment file when provided. Never commit the copy.
@@ -74,17 +74,14 @@ If the worktree is dirty, stop and understand the existing changes before switch
74
74
 
75
75
  ## Local validation
76
76
 
77
- The template scripts detect supported tools and skip checks that do not apply:
77
+ The repository runtime detects supported tools and skips checks that do not apply:
78
78
 
79
79
  ```sh
80
- bash .github/scripts/ci.sh format
81
- bash .github/scripts/ci.sh lint
82
- bash .github/scripts/ci.sh type_check
83
- bash .github/scripts/ci.sh build
84
- bash .github/scripts/ci.sh unit
85
- bash .github/scripts/ci.sh integration
86
- bash .github/scripts/ci.sh e2e
87
- bash .github/scripts/ci.sh smoke
80
+ npx code-foundry doctor
81
+ npm run format:check # or the package manager's equivalent
82
+ npm run lint
83
+ npm run type-check
84
+ npm test
88
85
  Security and dependency audits run through the GitHub Security workflow.
89
86
  ```
90
87
 
@@ -110,7 +107,7 @@ For maintainers, trusted contributors, and automation agents:
110
107
 
111
108
  8. Push the branch and open a pull request into `staging`.
112
109
  9. Address review feedback and failed checks on the same branch.
113
- 10. Squash-merge only after required checks pass and the change is ready.
110
+ 10. Merge using the repository's configured `merge_strategy` after required checks pass and the change is ready.
114
111
 
115
112
  ### Internal agent handoff
116
113
 
@@ -1,5 +1,5 @@
1
1
  name: Repository Setup
2
- description: Install the pinned mise toolchain and optionally project dependencies.
2
+ description: Select mise or native language tooling and optionally install project dependencies.
3
3
 
4
4
  inputs:
5
5
  install:
@@ -85,6 +85,16 @@ runs:
85
85
  run: |
86
86
  tracked_files="$(git ls-files)"
87
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
+ fi
93
+ if [ "$toolchain" = auto ] && [ -f .mise.toml ]; then
94
+ toolchain=mise
95
+ fi
96
+ printf 'toolchain_mode=%s\n' "$toolchain" >> "$GITHUB_OUTPUT"
97
+
88
98
  has_tracked_regex() {
89
99
  printf '%s\n' "$tracked_files" | grep -Eq "$1"
90
100
  }
@@ -428,6 +438,43 @@ runs:
428
438
  REPO_FOUNDRY_TASK_RUST: ${{ inputs.task-rust }}
429
439
  REPO_FOUNDRY_CACHE_PACKAGES: ${{ inputs.cache-packages }}
430
440
 
441
+ - name: Setup Node
442
+ if: >-
443
+ steps.profile.outputs.toolchain_mode != 'mise' &&
444
+ steps.profile.outputs.javascript == 'true' &&
445
+ steps.profile.outputs.javascript_package_manager != 'bun'
446
+ uses: actions/setup-node@v5
447
+ with:
448
+ node-version: 24
449
+ 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' || '' }}
450
+
451
+ - name: Setup Bun
452
+ if: >-
453
+ steps.profile.outputs.toolchain_mode != 'mise' &&
454
+ steps.profile.outputs.javascript == 'true' &&
455
+ steps.profile.outputs.javascript_package_manager == 'bun'
456
+ uses: oven-sh/setup-bun@v2
457
+ with:
458
+ bun-version: 1.3.14
459
+
460
+ - name: Enable Corepack
461
+ if: >-
462
+ steps.profile.outputs.toolchain_mode != 'mise' &&
463
+ (steps.profile.outputs.javascript_package_manager == 'pnpm' ||
464
+ steps.profile.outputs.javascript_package_manager == 'yarn')
465
+ shell: bash
466
+ run: corepack enable
467
+
468
+ - name: Setup Python
469
+ if: steps.profile.outputs.toolchain_mode != 'mise' && steps.profile.outputs.python == 'true'
470
+ uses: actions/setup-python@v6
471
+ with:
472
+ python-version: '3.13'
473
+
474
+ - name: Setup Rust
475
+ if: steps.profile.outputs.toolchain_mode != 'mise' && steps.profile.outputs.rust == 'true'
476
+ uses: dtolnay/rust-toolchain@stable
477
+
431
478
  - name: Setup uv
432
479
  if: >-
433
480
  steps.profile.outputs.python == 'true' &&
@@ -658,7 +705,7 @@ runs:
658
705
  path: ~/.cargo/advisory-db
659
706
  # The advisory database is independent of project dependencies. Keep
660
707
  # it warm for Security without invalidating it on every lockfile edit.
661
- key: ${{ runner.os }}-rust-advisory-${{ hashFiles('.github/scripts/security.sh') }}
708
+ key: ${{ runner.os }}-rust-advisory-${{ hashFiles('.code-foundry/src/runtime.mjs') }}
662
709
  restore-keys: |
663
710
  ${{ runner.os }}-rust-advisory-
664
711
  - name: Cache Rust builds
@@ -701,7 +748,7 @@ runs:
701
748
  REPO_FOUNDRY_INSTALL_PYTHON: ${{ inputs.install-python }}
702
749
  REPO_FOUNDRY_INSTALL_RUST: ${{ inputs.install-rust }}
703
750
  REPO_FOUNDRY_TASK: ${{ inputs.task }}
704
- run: bash .github/scripts/ci.sh install
751
+ run: node .code-foundry/src/runtime.mjs ci install
705
752
  - name: Measure Bun dependencies
706
753
  id: javascript-bun-cache
707
754
  if: >-
@@ -3,12 +3,17 @@ version: 1
3
3
  profile: auto
4
4
  languages: typescript
5
5
  features: all
6
+ codeql: auto
7
+ dependency_review: auto
6
8
  package_manager: bun
9
+ toolchain: auto
7
10
  runtime_repository: 0xPlayerOne/code-foundry
8
- runtime_ref: v0.22.2
11
+ runtime_ref: v0.26.0
9
12
  release_type: node
10
13
  npm_publish: true
11
14
  license: agpl-3.0-or-later
15
+ git_workflow: staging-release
16
+ merge_strategy: rebase
12
17
  runner: ubuntu-latest
13
18
  unit_runner: ubuntu-slim
14
19
  cache_packages: auto
@@ -53,18 +53,15 @@ jobs:
53
53
  path: .code-foundry
54
54
  sparse-checkout: |
55
55
  .github/actions
56
- .github/scripts
56
+ src/lib
57
+ src/runtime.mjs
57
58
  - name: Install runtime
58
59
  run: |
59
- mkdir -p .github/actions .github/scripts
60
+ mkdir -p .github/actions
60
61
  cp -R .code-foundry/.github/actions/. .github/actions/
61
- cp -R .code-foundry/.github/scripts/. .github/scripts/
62
62
  - name: Detect
63
63
  id: applicability
64
- run: bash .github/scripts/ci.sh should_run format >> "$GITHUB_OUTPUT"
65
- - name: Fast path
66
- if: steps.applicability.outputs.applicable == 'true'
67
- run: bash .github/scripts/format-fast-path.sh
64
+ run: node .code-foundry/src/runtime.mjs ci should_run format >> "$GITHUB_OUTPUT"
68
65
  - name: Setup
69
66
  if: steps.applicability.outputs.applicable == 'true'
70
67
  uses: ./.github/actions/setup
@@ -79,7 +76,7 @@ jobs:
79
76
  task-rust: 'false'
80
77
  - name: Format
81
78
  if: steps.applicability.outputs.applicable == 'true'
82
- run: bash .github/scripts/ci.sh format
79
+ run: node .code-foundry/src/runtime.mjs ci format
83
80
 
84
81
  lint:
85
82
  name: Lint
@@ -95,15 +92,15 @@ jobs:
95
92
  path: .code-foundry
96
93
  sparse-checkout: |
97
94
  .github/actions
98
- .github/scripts
95
+ src/lib
96
+ src/runtime.mjs
99
97
  - name: Install runtime
100
98
  run: |
101
- mkdir -p .github/actions .github/scripts
99
+ mkdir -p .github/actions
102
100
  cp -R .code-foundry/.github/actions/. .github/actions/
103
- cp -R .code-foundry/.github/scripts/. .github/scripts/
104
101
  - name: Detect
105
102
  id: applicability
106
- run: bash .github/scripts/ci.sh should_run lint >> "$GITHUB_OUTPUT"
103
+ run: node .code-foundry/src/runtime.mjs ci should_run lint >> "$GITHUB_OUTPUT"
107
104
  - name: Setup
108
105
  if: steps.applicability.outputs.applicable == 'true'
109
106
  uses: ./.github/actions/setup
@@ -113,7 +110,7 @@ jobs:
113
110
  task: lint
114
111
  - name: Lint
115
112
  if: steps.applicability.outputs.applicable == 'true'
116
- run: bash .github/scripts/ci.sh lint
113
+ run: node .code-foundry/src/runtime.mjs ci lint
117
114
 
118
115
  type-check:
119
116
  name: Type-Check
@@ -129,15 +126,15 @@ jobs:
129
126
  path: .code-foundry
130
127
  sparse-checkout: |
131
128
  .github/actions
132
- .github/scripts
129
+ src/lib
130
+ src/runtime.mjs
133
131
  - name: Install runtime
134
132
  run: |
135
- mkdir -p .github/actions .github/scripts
133
+ mkdir -p .github/actions
136
134
  cp -R .code-foundry/.github/actions/. .github/actions/
137
- cp -R .code-foundry/.github/scripts/. .github/scripts/
138
135
  - name: Detect
139
136
  id: applicability
140
- run: bash .github/scripts/ci.sh should_run type_check >> "$GITHUB_OUTPUT"
137
+ run: node .code-foundry/src/runtime.mjs ci should_run type_check >> "$GITHUB_OUTPUT"
141
138
  - name: Setup
142
139
  if: steps.applicability.outputs.applicable == 'true'
143
140
  uses: ./.github/actions/setup
@@ -147,7 +144,7 @@ jobs:
147
144
  task: type_check
148
145
  - name: Type-Check
149
146
  if: steps.applicability.outputs.applicable == 'true'
150
- run: bash .github/scripts/ci.sh type_check
147
+ run: node .code-foundry/src/runtime.mjs ci type_check
151
148
 
152
149
  build:
153
150
  name: Build
@@ -163,15 +160,15 @@ jobs:
163
160
  path: .code-foundry
164
161
  sparse-checkout: |
165
162
  .github/actions
166
- .github/scripts
163
+ src/lib
164
+ src/runtime.mjs
167
165
  - name: Install runtime
168
166
  run: |
169
- mkdir -p .github/actions .github/scripts
167
+ mkdir -p .github/actions
170
168
  cp -R .code-foundry/.github/actions/. .github/actions/
171
- cp -R .code-foundry/.github/scripts/. .github/scripts/
172
169
  - name: Detect
173
170
  id: applicability
174
- run: bash .github/scripts/ci.sh should_run build >> "$GITHUB_OUTPUT"
171
+ run: node .code-foundry/src/runtime.mjs ci should_run build >> "$GITHUB_OUTPUT"
175
172
  - name: Setup
176
173
  if: steps.applicability.outputs.applicable == 'true'
177
174
  uses: ./.github/actions/setup
@@ -181,4 +178,4 @@ jobs:
181
178
  task: build
182
179
  - name: Build
183
180
  if: steps.applicability.outputs.applicable == 'true'
184
- run: bash .github/scripts/ci.sh build
181
+ run: node .code-foundry/src/runtime.mjs ci build
@@ -16,6 +16,6 @@ jobs:
16
16
  uses: ./.github/workflows/ci.yml
17
17
  with:
18
18
  runtime-repository: 0xPlayerOne/code-foundry
19
- runtime-ref: v0.22.0
19
+ runtime-ref: staging
20
20
  runner: ubuntu-latest
21
21
  secrets: inherit
@@ -41,6 +41,7 @@ jobs:
41
41
  timeout-minutes: 10
42
42
  outputs:
43
43
  languages: ${{ steps.languages.outputs.languages }}
44
+ enabled: ${{ steps.languages.outputs.enabled }}
44
45
  code_security: ${{ steps.security.outputs.status }}
45
46
  actions_available: ${{ steps.languages.outputs.actions_available }}
46
47
  actions_changed: ${{ steps.languages.outputs.actions_changed }}
@@ -61,14 +62,13 @@ jobs:
61
62
  GH_TOKEN: ${{ github.token }}
62
63
  run: |
63
64
  status="disabled"
64
- if [ "${{ github.event.repository.private }}" != "true" ]; then
65
+ if [ "${{ github.event.repository.visibility }}" = "public" ]; then
65
66
  status="enabled"
66
67
  else
67
68
  status="$(gh api "repos/${GITHUB_REPOSITORY}" --jq '.security_and_analysis.code_security.status // "disabled"' 2>/dev/null || printf 'disabled')"
68
69
  fi
69
70
  printf 'status=%s\n' "$status" >> "$GITHUB_OUTPUT"
70
71
  - name: Checkout
71
- if: ${{ !github.event.repository.private || steps.security.outputs.status == 'enabled' }}
72
72
  uses: actions/checkout@v7
73
73
  with:
74
74
  fetch-depth: 2
@@ -85,7 +85,6 @@ jobs:
85
85
  package-lock.json
86
86
  sparse-checkout-cone-mode: false
87
87
  - name: Runtime
88
- if: ${{ !github.event.repository.private || steps.security.outputs.status == 'enabled' }}
89
88
  uses: actions/checkout@v7
90
89
  with:
91
90
  repository: ${{ inputs.runtime-repository }}
@@ -93,31 +92,26 @@ jobs:
93
92
  path: .code-foundry
94
93
  sparse-checkout: |
95
94
  .github/actions
96
- .github/scripts
95
+ src/lib
96
+ src/runtime.mjs
97
97
  - name: Install runtime
98
- if: ${{ !github.event.repository.private || steps.security.outputs.status == 'enabled' }}
99
98
  run: |
100
- mkdir -p .github/actions .github/scripts
99
+ mkdir -p .github/actions
101
100
  cp -R .code-foundry/.github/actions/. .github/actions/
102
- cp -R .code-foundry/.github/scripts/. .github/scripts/
103
101
  - id: languages
104
102
  name: Detect languages
105
103
  env:
106
104
  CODEQL_BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
107
105
  REPO_FOUNDRY_CODE_SECURITY: ${{ steps.security.outputs.status }}
108
106
  REPO_FOUNDRY_PRIVATE: ${{ github.event.repository.private }}
109
- run: |
110
- if [ "$REPO_FOUNDRY_PRIVATE" = "true" ] && [ "$REPO_FOUNDRY_CODE_SECURITY" != "enabled" ]; then
111
- echo 'languages=[]' >> "$GITHUB_OUTPUT"
112
- else
113
- bash .github/scripts/codeql-languages.sh
114
- fi
107
+ REPO_FOUNDRY_VISIBILITY: ${{ github.event.repository.visibility }}
108
+ run: node .code-foundry/src/runtime.mjs codeql
115
109
 
116
110
  analyze-actions:
117
111
  name: Analyze (Actions)
118
112
  needs: detect
119
113
  if: >-
120
- ( !github.event.repository.private || needs.detect.outputs.code_security == 'enabled' ) &&
114
+ needs.detect.outputs.enabled == 'true' &&
121
115
  needs.detect.outputs.actions_available == 'true' &&
122
116
  needs.detect.outputs.actions_changed == 'true'
123
117
  runs-on: ${{ inputs.runner }}
@@ -133,12 +127,12 @@ jobs:
133
127
  path: .code-foundry
134
128
  sparse-checkout: |
135
129
  .github/actions
136
- .github/scripts
130
+ src/lib
131
+ src/runtime.mjs
137
132
  - name: Install runtime
138
133
  run: |
139
- mkdir -p .github/actions .github/scripts
134
+ mkdir -p .github/actions
140
135
  cp -R .code-foundry/.github/actions/. .github/actions/
141
- cp -R .code-foundry/.github/scripts/. .github/scripts/
142
136
  - name: Analyze
143
137
  uses: ./.github/actions/codeql
144
138
  with:
@@ -150,7 +144,7 @@ jobs:
150
144
  name: Analyze (TypeScript)
151
145
  needs: detect
152
146
  if: >-
153
- ( !github.event.repository.private || needs.detect.outputs.code_security == 'enabled' ) &&
147
+ needs.detect.outputs.enabled == 'true' &&
154
148
  needs.detect.outputs.javascript_available == 'true' &&
155
149
  needs.detect.outputs.javascript_changed == 'true'
156
150
  runs-on: ${{ inputs.runner }}
@@ -166,12 +160,12 @@ jobs:
166
160
  path: .code-foundry
167
161
  sparse-checkout: |
168
162
  .github/actions
169
- .github/scripts
163
+ src/lib
164
+ src/runtime.mjs
170
165
  - name: Install runtime
171
166
  run: |
172
- mkdir -p .github/actions .github/scripts
167
+ mkdir -p .github/actions
173
168
  cp -R .code-foundry/.github/actions/. .github/actions/
174
- cp -R .code-foundry/.github/scripts/. .github/scripts/
175
169
  - name: Analyze
176
170
  uses: ./.github/actions/codeql
177
171
  with:
@@ -183,7 +177,7 @@ jobs:
183
177
  name: Analyze (Python)
184
178
  needs: detect
185
179
  if: >-
186
- ( !github.event.repository.private || needs.detect.outputs.code_security == 'enabled' ) &&
180
+ needs.detect.outputs.enabled == 'true' &&
187
181
  needs.detect.outputs.python_available == 'true' &&
188
182
  needs.detect.outputs.python_changed == 'true'
189
183
  runs-on: ${{ inputs.runner }}
@@ -199,12 +193,12 @@ jobs:
199
193
  path: .code-foundry
200
194
  sparse-checkout: |
201
195
  .github/actions
202
- .github/scripts
196
+ src/lib
197
+ src/runtime.mjs
203
198
  - name: Install runtime
204
199
  run: |
205
- mkdir -p .github/actions .github/scripts
200
+ mkdir -p .github/actions
206
201
  cp -R .code-foundry/.github/actions/. .github/actions/
207
- cp -R .code-foundry/.github/scripts/. .github/scripts/
208
202
  - name: Analyze
209
203
  uses: ./.github/actions/codeql
210
204
  with:
@@ -216,7 +210,7 @@ jobs:
216
210
  name: Analyze (Rust)
217
211
  needs: detect
218
212
  if: >-
219
- ( !github.event.repository.private || needs.detect.outputs.code_security == 'enabled' ) &&
213
+ needs.detect.outputs.enabled == 'true' &&
220
214
  needs.detect.outputs.rust_available == 'true' &&
221
215
  needs.detect.outputs.rust_changed == 'true'
222
216
  runs-on: ${{ inputs.runner }}
@@ -232,12 +226,12 @@ jobs:
232
226
  path: .code-foundry
233
227
  sparse-checkout: |
234
228
  .github/actions
235
- .github/scripts
229
+ src/lib
230
+ src/runtime.mjs
236
231
  - name: Install runtime
237
232
  run: |
238
- mkdir -p .github/actions .github/scripts
233
+ mkdir -p .github/actions
239
234
  cp -R .code-foundry/.github/actions/. .github/actions/
240
- cp -R .code-foundry/.github/scripts/. .github/scripts/
241
235
  - name: Analyze
242
236
  uses: ./.github/actions/codeql
243
237
  with:
@@ -21,6 +21,6 @@ jobs:
21
21
  uses: ./.github/workflows/codeql.yml
22
22
  with:
23
23
  runtime-repository: 0xPlayerOne/code-foundry
24
- runtime-ref: v0.22.0
24
+ runtime-ref: staging
25
25
  runner: ubuntu-latest
26
26
  secrets: inherit
@@ -29,7 +29,7 @@ jobs:
29
29
  id: check-pr
30
30
  run: |
31
31
  BRANCH="${{ github.ref_name }}"
32
- EXISTING=$(gh pr list --limit 1 --base staging --head "$BRANCH" --state open --json number,title 2>/dev/null | jq 'length')
32
+ EXISTING=$(gh pr list --limit 1 --base staging --head "$BRANCH" --state open --json number,title 2>/dev/null | node -e 'let d=""; process.stdin.on("data", c => d += c).on("end", () => console.log(JSON.parse(d || "[]").length))')
33
33
  echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
34
34
 
35
35
  - name: Create
@@ -51,7 +51,7 @@ jobs:
51
51
  if: steps.check-pr.outputs.existing == '0'
52
52
  run: |
53
53
  BRANCH="${{ github.ref_name }}"
54
- PR_NUMBER=$(gh pr list --limit 1 --base staging --head "$BRANCH" --state open --json number 2>/dev/null | jq '.[0].number')
54
+ PR_NUMBER=$(gh pr list --limit 1 --base staging --head "$BRANCH" --state open --json number 2>/dev/null | node -e 'let d=""; process.stdin.on("data", c => d += c).on("end", () => console.log(JSON.parse(d || "[]")[0]?.number || ""))')
55
55
  if [ -n "$PR_NUMBER" ]; then
56
56
  gh pr ready "$PR_NUMBER"
57
57
  fi
@@ -35,7 +35,7 @@ jobs:
35
35
  --base main \
36
36
  --head staging \
37
37
  --state open \
38
- --json number | jq 'length')
38
+ --json number | node -e 'let d=""; process.stdin.on("data", c => d += c).on("end", () => console.log(JSON.parse(d || "[]").length))')
39
39
  COMPARE_URL="repos/${GITHUB_REPOSITORY}/compare/main...staging"
40
40
  TOTAL_COMMITS=$(gh api "$COMPARE_URL?per_page=1" --jq '.total_commits // 0')
41
41
  echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
@@ -53,12 +53,12 @@ jobs:
53
53
  COMPARE_URL="repos/${GITHUB_REPOSITORY}/compare/main...staging"
54
54
  COMPARE_FILE="$RUNNER_TEMP/release-compare.json"
55
55
  gh api "$COMPARE_URL?per_page=100" > "$COMPARE_FILE"
56
- TOTAL_COMMITS=$(jq -r '.total_commits // 0' "$COMPARE_FILE")
56
+ TOTAL_COMMITS=$(node -e 'const d=require(process.argv[1]); console.log(d.total_commits || 0)' "$COMPARE_FILE")
57
57
  if [ "$TOTAL_COMMITS" -gt 100 ]; then
58
58
  LAST_PAGE=$(( (TOTAL_COMMITS + 99) / 100 ))
59
59
  gh api "$COMPARE_URL?per_page=100&page=$LAST_PAGE" > "$COMPARE_FILE"
60
60
  fi
61
- COMMITS=$(jq -r '.commits[] | "- \(.commit.message | split("\\n")[0]) (\(.sha[0:7]))"' "$COMPARE_FILE")
61
+ COMMITS=$(node -e 'const d=require(process.argv[1]); for (const c of d.commits || []) console.log(`- ${c.commit.message.split("\\n")[0]} (${c.sha.slice(0, 7)})`)' "$COMPARE_FILE")
62
62
  if [ -z "$COMMITS" ]; then
63
63
  COMMITS='- No commits found since main.'
64
64
  fi
@@ -87,7 +87,7 @@ jobs:
87
87
  ### Validation
88
88
 
89
89
  - Required CI, test, security, and CodeQL checks must pass before merge.
90
- - Merge with **rebase** to preserve the linear Conventional Commit history.
90
+ - Merge using the repository's configured \`merge_strategy\` (default: **rebase**).
91
91
  - After merge, Release Please opens a separate versioned release PR with the changelog.
92
92
  EOF
93
93
 
@@ -41,36 +41,24 @@ jobs:
41
41
  filter: blob:none
42
42
  - name: Detect release profile
43
43
  id: profile
44
- shell: bash
45
44
  run: |
46
- if [ -x .github/scripts/profile.sh ]; then
47
- release_type="$(bash .github/scripts/profile.sh get release_type)"
48
- npm_publish="$(bash .github/scripts/profile.sh get npm_publish)"
49
- else
50
- config_file=.github/code-foundry.yml
51
- release_type="$(awk -F': ' '/^release_type:/ {print $2; exit}' "$config_file" 2>/dev/null || true)"
52
- npm_publish="$(awk -F': ' '/^npm_publish:/ {print $2; exit}' "$config_file" 2>/dev/null || true)"
53
- fi
54
- [ -n "$release_type" ] || release_type=auto
55
- [ -n "$npm_publish" ] || npm_publish=false
56
-
57
- if [ "$release_type" = auto ]; then
58
- if [ -f package.json ]; then release_type=node
59
- elif [ -f pyproject.toml ]; then release_type=python
60
- elif [ -f Cargo.toml ]; then release_type=rust
61
- elif [ -f version.txt ]; then release_type=simple
62
- else release_type=none
63
- fi
64
- fi
65
-
66
- case "$release_type" in
67
- node|python|rust|simple) ;;
68
- none) npm_publish=false ;;
69
- *) echo "Unsupported release_type: $release_type" >&2; exit 2 ;;
70
- esac
71
- if [ ! -f package.json ]; then npm_publish=false; fi
72
- printf 'release_type=%s\n' "$release_type" >> "$GITHUB_OUTPUT"
73
- printf 'npm_publish=%s\n' "$npm_publish" >> "$GITHUB_OUTPUT"
45
+ node <<'NODE'
46
+ const fs = require('node:fs')
47
+ const config = fs.existsSync('.github/code-foundry.yml')
48
+ ? Object.fromEntries(fs.readFileSync('.github/code-foundry.yml', 'utf8').split(/\r?\n/).flatMap((line) => {
49
+ const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*?)\s*$/)
50
+ return match ? [[match[1], match[2].replace(/\s+#.*$/, '').replace(/^['"]|['"]$/g, '')]] : []
51
+ }))
52
+ : {}
53
+ let releaseType = config.release_type || 'auto'
54
+ let npmPublish = config.npm_publish || 'false'
55
+ if (releaseType === 'auto') {
56
+ releaseType = fs.existsSync('package.json') ? 'node' : fs.existsSync('pyproject.toml') ? 'python' : fs.existsSync('Cargo.toml') ? 'rust' : fs.existsSync('version.txt') ? 'simple' : 'none'
57
+ }
58
+ if (!['node', 'python', 'rust', 'simple', 'none'].includes(releaseType)) throw new Error(`Unsupported release_type: ${releaseType}`)
59
+ if (releaseType === 'none' || !fs.existsSync('package.json')) npmPublish = 'false'
60
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, `release_type=${releaseType}\nnpm_publish=${npmPublish}\n`)
61
+ NODE
74
62
  - name: Release Please
75
63
  id: release
76
64
  if: steps.profile.outputs.release_type != 'none'