code-foundry 0.37.1 → 0.37.2
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/CHANGELOG.md +7 -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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.37.2](https://github.com/0xPlayerOne/code-foundry/compare/v0.37.1...v0.37.2) (2026-08-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **ci:** stabilize runners and release reconciliation ([#387](https://github.com/0xPlayerOne/code-foundry/issues/387)) ([ea2c503](https://github.com/0xPlayerOne/code-foundry/commit/ea2c503cb6ea9b944ffa5b70ff7fbfc3d56d3a10))
|
|
9
|
+
|
|
3
10
|
## [0.37.1](https://github.com/0xPlayerOne/code-foundry/compare/v0.37.0...v0.37.1) (2026-08-08)
|
|
4
11
|
|
|
5
12
|
|
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
|
}
|