code-foundry 0.37.1 → 0.37.3
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/.github/workflows/codeql.yml +2 -2
- package/.github/workflows/release-pr.yml +1 -1
- package/.github/workflows/release.yml +10 -40
- package/.github/workflows/security.yml +1 -1
- package/CHANGELOG.md +14 -0
- package/docs/RELEASES.md +5 -4
- package/docs/WORKFLOWS.md +5 -3
- package/package.json +1 -1
- package/src/commands/sync.mjs +6 -0
- package/src/lib/release-policy.mjs +10 -6
|
@@ -402,7 +402,7 @@ jobs:
|
|
|
402
402
|
needs.detect.outputs.enabled == 'true' &&
|
|
403
403
|
needs.detect.outputs.rust_available == 'true' &&
|
|
404
404
|
needs.detect.outputs.rust_changed == 'true'
|
|
405
|
-
uses: github/codeql-action/init@
|
|
405
|
+
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
|
|
406
406
|
with:
|
|
407
407
|
languages: rust
|
|
408
408
|
build-mode: ${{ needs.detect.outputs.rust_build_mode }}
|
|
@@ -413,7 +413,7 @@ jobs:
|
|
|
413
413
|
needs.detect.outputs.enabled == 'true' &&
|
|
414
414
|
needs.detect.outputs.rust_available == 'true' &&
|
|
415
415
|
needs.detect.outputs.rust_changed == 'true'
|
|
416
|
-
uses: github/codeql-action/analyze@
|
|
416
|
+
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4
|
|
417
417
|
with:
|
|
418
418
|
category: /language:rust/${{ steps.scope.outputs.scope_id }}
|
|
419
419
|
upload-database: false
|
|
@@ -31,7 +31,7 @@ jobs:
|
|
|
31
31
|
cancel-in-progress: true
|
|
32
32
|
steps:
|
|
33
33
|
- name: Checkout
|
|
34
|
-
uses: actions/checkout@
|
|
34
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
35
35
|
with:
|
|
36
36
|
persist-credentials: false
|
|
37
37
|
fetch-depth: 0
|
|
@@ -245,44 +245,14 @@ jobs:
|
|
|
245
245
|
fi
|
|
246
246
|
node "$RUNNER_TEMP/code-foundry/src/cli.mjs" release validate-prs
|
|
247
247
|
for pr in "${release_prs[@]}"; do
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
--jq 'length' 2>/dev/null); then
|
|
257
|
-
if [ "$required_count" -gt 0 ]; then
|
|
258
|
-
checks_seen=true
|
|
259
|
-
break
|
|
260
|
-
fi
|
|
261
|
-
fi
|
|
262
|
-
sleep 5
|
|
263
|
-
done
|
|
264
|
-
if [ "$checks_seen" != true ]; then
|
|
265
|
-
echo "Required checks were not registered for release PR #$pr within the readiness window." >&2
|
|
266
|
-
exit 1
|
|
267
|
-
fi
|
|
268
|
-
gh pr checks "$pr" \
|
|
269
|
-
--repo "$GITHUB_REPOSITORY" \
|
|
270
|
-
--required \
|
|
271
|
-
--watch \
|
|
272
|
-
--fail-fast \
|
|
273
|
-
--interval 10
|
|
274
|
-
# gh pr checks --watch only waits for checks registered when the
|
|
275
|
-
# watch starts; a ruleset may register additional required checks
|
|
276
|
-
# afterwards (observed: "Validation / Gate" appearing after
|
|
277
|
-
# "Tauri 2 / Linux" had passed), which leaves the PR blocked by
|
|
278
|
-
# branch policy at merge time. Poll mergeStateStatus and accept
|
|
279
|
-
# only states GitHub reports as mergeable: CLEAN, or UNSTABLE with
|
|
280
|
-
# mergeable MERGEABLE. UNSTABLE is still mergeable when only
|
|
281
|
-
# non-required checks are failing or still running (observed: Kilo
|
|
282
|
-
# Code Review running after every required check passed); keep
|
|
283
|
-
# waiting for BLOCKED/BEHIND/UNKNOWN, fail fast on
|
|
284
|
-
# DIRTY/CONFLICTING, and fail closed on a bounded timeout so the
|
|
285
|
-
# workflow never sleeps indefinitely.
|
|
248
|
+
# GitHub's merge state is the authoritative required-check gate.
|
|
249
|
+
# `gh pr checks --required` is not reliable for ruleset-backed
|
|
250
|
+
# required contexts in private repositories: it can return an
|
|
251
|
+
# empty result even while the required aggregate check is present
|
|
252
|
+
# and green. Polling mergeStateStatus avoids that discovery race;
|
|
253
|
+
# GitHub reports MERGEABLE only after branch policy permits the
|
|
254
|
+
# requested merge strategy. Non-required checks may leave the PR
|
|
255
|
+
# UNSTABLE, so accept that state only with mergeable MERGEABLE.
|
|
286
256
|
echo "Waiting for release PR #$pr to become mergeable under branch policy"
|
|
287
257
|
merge_state=UNKNOWN
|
|
288
258
|
mergeable=UNKNOWN
|
|
@@ -506,12 +476,12 @@ jobs:
|
|
|
506
476
|
ref: ${{ needs.release.outputs.tag_name }}
|
|
507
477
|
- name: Setup Node (trusted)
|
|
508
478
|
if: env.NPM_TOKEN == ''
|
|
509
|
-
uses: actions/setup-node@
|
|
479
|
+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
510
480
|
with:
|
|
511
481
|
node-version: 24
|
|
512
482
|
- name: Setup Node (token)
|
|
513
483
|
if: env.NPM_TOKEN != ''
|
|
514
|
-
uses: actions/setup-node@
|
|
484
|
+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
515
485
|
with:
|
|
516
486
|
node-version: 24
|
|
517
487
|
registry-url: https://registry.npmjs.org
|
|
@@ -215,7 +215,7 @@ jobs:
|
|
|
215
215
|
cache-save: ${{ github.event_name != 'pull_request' }}
|
|
216
216
|
- name: Install cargo-audit
|
|
217
217
|
if: steps.applicability.outputs.applicable == 'true'
|
|
218
|
-
uses: taiki-e/install-action@
|
|
218
|
+
uses: taiki-e/install-action@cb33e69fad06166ca28a42b2575e4dadabf62ee8 # v2
|
|
219
219
|
with:
|
|
220
220
|
tool: cargo-audit
|
|
221
221
|
- name: Audit dependencies
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.37.3](https://github.com/0xPlayerOne/code-foundry/compare/v0.37.2...v0.37.3) (2026-08-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* release-required-check-discovery ([#392](https://github.com/0xPlayerOne/code-foundry/issues/392)) ([d086cb5](https://github.com/0xPlayerOne/code-foundry/commit/d086cb5b6d1dc25eb28b6551ae56467887637296))
|
|
9
|
+
|
|
10
|
+
## [0.37.2](https://github.com/0xPlayerOne/code-foundry/compare/v0.37.1...v0.37.2) (2026-08-23)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **ci:** stabilize runners and release reconciliation ([#387](https://github.com/0xPlayerOne/code-foundry/issues/387)) ([ea2c503](https://github.com/0xPlayerOne/code-foundry/commit/ea2c503cb6ea9b944ffa5b70ff7fbfc3d56d3a10))
|
|
16
|
+
|
|
3
17
|
## [0.37.1](https://github.com/0xPlayerOne/code-foundry/compare/v0.37.0...v0.37.1) (2026-08-08)
|
|
4
18
|
|
|
5
19
|
|
package/docs/RELEASES.md
CHANGED
|
@@ -57,8 +57,9 @@ reject any non-`rebase` `merge_strategy` only when `staging-release` is
|
|
|
57
57
|
configured, and always reject a non-`rebase` `release_merge_strategy`; the
|
|
58
58
|
release workflow fails closed instead of falling back to `merge`. Both keep
|
|
59
59
|
`main` fully linear, which is what makes the post-release reconciliation
|
|
60
|
-
possible
|
|
61
|
-
|
|
60
|
+
possible. The final branch trees are inspected before mutation; validated
|
|
61
|
+
main-only changes are inherited by `staging`, while unpromoted staging work is
|
|
62
|
+
replayed on top of `main`.
|
|
62
63
|
|
|
63
64
|
The `staging` → `main` reconciliation exists only in the `staging-release`
|
|
64
65
|
topology. Patch-equivalent divergence between `main` and `staging` is treated
|
|
@@ -67,8 +68,8 @@ as aligned. When `staging` has pending commits that are not yet represented on
|
|
|
67
68
|
detached worktree rooted at `main`, and then updates `staging` with an exact
|
|
68
69
|
`--force-with-lease` to prevent
|
|
69
70
|
unintended branch rewrites. There is no unconditional mirror force-push and no
|
|
70
|
-
fallback synchronization commit path.
|
|
71
|
-
entirely.
|
|
71
|
+
fallback synchronization commit path. Indeterminate history, replay conflicts,
|
|
72
|
+
and stale leases fail closed. `direct` repositories skip this step entirely.
|
|
72
73
|
|
|
73
74
|
`auto` selects a supported manifest. Use `simple` with `version.txt` for a
|
|
74
75
|
repository without a package manifest and `none` for a repository that should
|
package/docs/WORKFLOWS.md
CHANGED
|
@@ -97,9 +97,11 @@ it opens (or reuses) a generated `code-foundry/reconcile/main-to-staging`
|
|
|
97
97
|
pull request whose head contains the exact target tip (the `main` tip for a
|
|
98
98
|
fast-forward, the replay tip when staging-only commits are replayed) and whose
|
|
99
99
|
body documents the reconciliation. Reruns reuse the open pull request instead
|
|
100
|
-
of duplicating it
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
of duplicating it. Validated changes that landed directly on `main` are synced
|
|
101
|
+
back into `staging`; unpromoted staging commits are replayed on top. Indeterminate
|
|
102
|
+
history, replay conflicts, authentication errors, and ambiguous or stale pull
|
|
103
|
+
request state still fail the job closed, and exact-lease protection stays in
|
|
104
|
+
place for every direct push.
|
|
103
105
|
|
|
104
106
|
For this reconciliation path, maintainer PATs and administrator roles are not
|
|
105
107
|
authorized bypasses; the job deliberately authenticates with `github.token`,
|
package/package.json
CHANGED
package/src/commands/sync.mjs
CHANGED
|
@@ -361,6 +361,12 @@ function renderWorkflow(content, config, repository, ref, rustCodeql) {
|
|
|
361
361
|
rendered = rendered.replace(/^(\s+unit-runner:)\s+.*$/m, `$1 ${config.unit_runner}`)
|
|
362
362
|
}
|
|
363
363
|
if (workflow === 'validation') {
|
|
364
|
+
// The mode classifier is a normal runner job in the caller rather than a
|
|
365
|
+
// reusable-workflow input. Keep it on the configured default runner so
|
|
366
|
+
// consumers that cannot use ubuntu-slim do not fail before validation.
|
|
367
|
+
if (config.runner) {
|
|
368
|
+
rendered = rendered.replace(/^ mode:\n name: Mode\n runs-on:\s+.*$/m, ` mode:\n name: Mode\n runs-on: ${config.runner}`)
|
|
369
|
+
}
|
|
364
370
|
/** @type {Record<string, string|undefined>} */
|
|
365
371
|
const runnerInputs = {
|
|
366
372
|
'ci-runner': config.ci_runner ?? config.runner,
|
|
@@ -220,7 +220,7 @@ function compareVersions(a, b) {
|
|
|
220
220
|
* Classify the relationship between main and staging using the final tree delta
|
|
221
221
|
* when available. Historical commit paths can include equivalent workflow or
|
|
222
222
|
* configuration changes that are no longer present in the branch delta, so the
|
|
223
|
-
* final trees are the source of truth for
|
|
223
|
+
* final trees are the source of truth for reconciliation. When
|
|
224
224
|
* directChangedPaths is supplied, unexpected paths in historical main-only
|
|
225
225
|
* commits are ignored only when they are absent from the final tree delta
|
|
226
226
|
* (their content is already identical in both branches); unexpected main-only
|
|
@@ -281,9 +281,9 @@ export function classifyReconciliation(input) {
|
|
|
281
281
|
}
|
|
282
282
|
if (!stagingOnlyCommits.length) {
|
|
283
283
|
return {
|
|
284
|
-
action: '
|
|
285
|
-
|
|
286
|
-
|
|
284
|
+
action: 'fast-forward',
|
|
285
|
+
targetSha: mainSha,
|
|
286
|
+
reason: 'main contains validated changes that staging must inherit.',
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
}
|
|
@@ -300,7 +300,11 @@ export function classifyReconciliation(input) {
|
|
|
300
300
|
[...new Set(mainOnlyCommits.flatMap((commit) => commit.changedPaths || []))],
|
|
301
301
|
allowed,
|
|
302
302
|
).filter((path) => directTreePaths === null || directTreePaths.has(path))
|
|
303
|
-
|
|
303
|
+
// Without a final-tree comparison, retain the historical fail-closed
|
|
304
|
+
// behavior. When the final delta is known, main is the validated release
|
|
305
|
+
// source of truth: replay any staging-only work on top instead of deadlocking
|
|
306
|
+
// every later release because a hotfix landed directly on main.
|
|
307
|
+
if (unexpectedMain.length && directTreePaths === null) {
|
|
304
308
|
return {
|
|
305
309
|
action: 'fail',
|
|
306
310
|
reason: 'main contains commits that are not release metadata.',
|
|
@@ -373,7 +377,7 @@ export function buildReconciliationPullRequestBody(input) {
|
|
|
373
377
|
'',
|
|
374
378
|
`Merging this pull request synchronizes \`${targetHead}\` with the exact target tip above; no other commits are introduced.`,
|
|
375
379
|
'',
|
|
376
|
-
|
|
380
|
+
`Code Foundry treats validated \`${sourceBase}\` as the shipped source of truth and preserves unpromoted \`${targetHead}\` work by replaying it on top. Indeterminate history, replay conflicts, authentication failures, and ambiguous or stale state fail the release job closed and are never pushed around branch protection. Later releases retry the direct push first; when branch policy still rejects it, this pull request is updated instead of duplicated.`,
|
|
377
381
|
)
|
|
378
382
|
return lines.join('\n')
|
|
379
383
|
}
|