code-foundry 1.33.1 → 1.33.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.
|
@@ -285,12 +285,12 @@ jobs:
|
|
|
285
285
|
set -euo pipefail
|
|
286
286
|
if [ "$WRANGLER_VERSION" = local ]; then
|
|
287
287
|
if [ -n "$BUILD_SCRIPT" ]; then
|
|
288
|
-
wrangler=(
|
|
288
|
+
wrangler=(npx --no-install wrangler)
|
|
289
289
|
else
|
|
290
290
|
wrangler=(npx --no-install wrangler)
|
|
291
291
|
fi
|
|
292
292
|
elif [ -n "$BUILD_SCRIPT" ]; then
|
|
293
|
-
wrangler=(
|
|
293
|
+
wrangler=(npx -y "wrangler@$WRANGLER_VERSION")
|
|
294
294
|
else
|
|
295
295
|
wrangler=(npx -y "wrangler@$WRANGLER_VERSION")
|
|
296
296
|
fi
|
|
@@ -260,7 +260,7 @@ jobs:
|
|
|
260
260
|
--state open \
|
|
261
261
|
--base main \
|
|
262
262
|
--json number,headRefName \
|
|
263
|
-
--jq '.[] | select(.headRefName | startswith("release-please--branches--main")) | .number'
|
|
263
|
+
--jq '.[] | select(.headRefName == "release-please--branches--main" or (.headRefName | startswith("release-please--branches--main--"))) | .number'
|
|
264
264
|
)
|
|
265
265
|
|
|
266
266
|
if [ ${#release_prs[@]} -eq 0 ]; then
|
|
@@ -301,71 +301,40 @@ jobs:
|
|
|
301
301
|
--state open \
|
|
302
302
|
--base main \
|
|
303
303
|
--json number,title,headRefName \
|
|
304
|
-
--jq '.[] | select(.title | startswith("chore(main): release ")) | select(.headRefName | startswith("release-please--branches--main")) | .number'
|
|
304
|
+
--jq '.[] | select(.title | startswith("chore(main): release ")) | select(.headRefName == "release-please--branches--main" or (.headRefName | startswith("release-please--branches--main--"))) | .number'
|
|
305
305
|
)
|
|
306
306
|
if [ "${#release_prs[@]}" -eq 0 ]; then
|
|
307
307
|
echo 'No generated release pull request is open; nothing to merge.'
|
|
308
308
|
exit 0
|
|
309
309
|
fi
|
|
310
|
-
node "$RUNNER_TEMP/code-foundry/src/cli.mjs" release validate-prs
|
|
310
|
+
release_validation=$(node "$RUNNER_TEMP/code-foundry/src/cli.mjs" release validate-prs)
|
|
311
|
+
printf '%s\n' "$release_validation"
|
|
311
312
|
for pr in "${release_prs[@]}"; do
|
|
312
|
-
#
|
|
313
|
-
#
|
|
314
|
-
#
|
|
315
|
-
#
|
|
316
|
-
#
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
mergeable=UNKNOWN
|
|
323
|
-
for attempt in $(seq 1 90); do
|
|
324
|
-
: "$attempt"
|
|
325
|
-
if read -r merge_state mergeable < <(
|
|
326
|
-
gh pr view "$pr" \
|
|
327
|
-
--repo "$GITHUB_REPOSITORY" \
|
|
328
|
-
--json mergeStateStatus,mergeable \
|
|
329
|
-
--jq '[.mergeStateStatus, .mergeable] | @tsv' 2>/dev/null
|
|
330
|
-
); then
|
|
331
|
-
case "$merge_state" in
|
|
332
|
-
CLEAN|UNSTABLE)
|
|
333
|
-
if [ "$mergeable" = MERGEABLE ]; then
|
|
334
|
-
break
|
|
335
|
-
fi
|
|
336
|
-
;;
|
|
337
|
-
DIRTY)
|
|
338
|
-
echo "Release PR #$pr is not mergeable (mergeStateStatus=$merge_state); resolve conflicts before retrying the release." >&2
|
|
339
|
-
exit 1
|
|
340
|
-
;;
|
|
341
|
-
esac
|
|
342
|
-
if [ "$mergeable" = CONFLICTING ]; then
|
|
343
|
-
echo "Release PR #$pr is not mergeable (mergeable=$mergeable); resolve conflicts before retrying the release." >&2
|
|
344
|
-
exit 1
|
|
345
|
-
fi
|
|
346
|
-
else
|
|
347
|
-
# gh API failure: read leaves the variables empty on EOF;
|
|
348
|
-
# treat the state as unknown and keep polling.
|
|
349
|
-
merge_state=UNKNOWN
|
|
350
|
-
mergeable=UNKNOWN
|
|
351
|
-
fi
|
|
352
|
-
sleep 10
|
|
353
|
-
done
|
|
354
|
-
if { [ "$merge_state" != CLEAN ] && [ "$merge_state" != UNSTABLE ]; } || [ "$mergeable" != MERGEABLE ]; then
|
|
355
|
-
echo "Release PR #$pr did not become mergeable within the mergeability window (last mergeStateStatus=$merge_state, mergeable=$mergeable). Required checks may still be pending or branch policy blocks the merge; review the pull request before retrying." >&2
|
|
356
|
-
exit 1
|
|
357
|
-
fi
|
|
358
|
-
release_head=$(gh pr view "$pr" \
|
|
313
|
+
# Keep the generated-PR audit above, then let GitHub wait for the
|
|
314
|
+
# actual branch policy. A synchronous poll here made a healthy
|
|
315
|
+
# release fail when required workflows outlasted the runner's
|
|
316
|
+
# mergeability window. --auto does not bypass checks or reviews;
|
|
317
|
+
# GitHub merges only after every required condition is satisfied.
|
|
318
|
+
echo "Requesting branch-policy-gated auto-merge for release PR #$pr"
|
|
319
|
+
release_head=$(jq -er --arg number "$pr" \
|
|
320
|
+
'.generated[] | select((.number | tostring) == $number) | .headRefOid | strings | select(length > 0)' \
|
|
321
|
+
<<< "$release_validation")
|
|
322
|
+
current_release_head=$(gh pr view "$pr" \
|
|
359
323
|
--repo "$GITHUB_REPOSITORY" \
|
|
360
324
|
--json headRefOid \
|
|
361
325
|
--jq '.headRefOid')
|
|
362
|
-
if [ -z "$release_head" ]; then
|
|
363
|
-
echo "
|
|
326
|
+
if [ -z "$release_head" ] || [ "$current_release_head" != "$release_head" ]; then
|
|
327
|
+
echo "Release PR #$pr changed after its path diff was validated; refusing to enqueue a stale validation result." >&2
|
|
364
328
|
exit 1
|
|
365
329
|
fi
|
|
330
|
+
# --match-head-commit binds this queue request. GitHub may keep
|
|
331
|
+
# auto-merge enabled if Release Please later updates the branch;
|
|
332
|
+
# the latest head must still pass the required Validation / Gate,
|
|
333
|
+
# including its release-diff policy, before GitHub can merge it.
|
|
366
334
|
gh pr merge "$pr" \
|
|
367
335
|
--repo "$GITHUB_REPOSITORY" \
|
|
368
336
|
--${{ steps.profile.outputs.release_merge_strategy }} \
|
|
337
|
+
--auto \
|
|
369
338
|
--match-head-commit "$release_head" \
|
|
370
339
|
--delete-branch
|
|
371
340
|
done
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.33.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.33.2...v1.33.3) (2026-09-29)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **ci:** launch wrangler under Node in the cloudflare deploy step ([#649](https://github.com/0xPlayerOne/code-foundry/issues/649)) ([e797934](https://github.com/0xPlayerOne/code-foundry/commit/e7979343d3ff4d1fe5dc1520568a501cce0c47f3))
|
|
9
|
+
|
|
10
|
+
## [1.33.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.33.1...v1.33.2) (2026-09-26)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **release:** queue version PR merges on branch policy ([#646](https://github.com/0xPlayerOne/code-foundry/issues/646)) ([ca492c8](https://github.com/0xPlayerOne/code-foundry/commit/ca492c8402bfc43ef718c0a6443ee06fcb33e957))
|
|
16
|
+
|
|
3
17
|
## [1.33.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.33.0...v1.33.1) (2026-09-25)
|
|
4
18
|
|
|
5
19
|
|
package/docs/RELEASES.md
CHANGED
|
@@ -128,15 +128,29 @@ repository or organization secret to enable guarded
|
|
|
128
128
|
automatic merging and downstream workflows triggered by the resulting
|
|
129
129
|
release. The token needs `contents`, `issues`, and `pull-requests` write
|
|
130
130
|
permissions. Code Foundry validates every changed path in the generated
|
|
131
|
-
version pull request before
|
|
132
|
-
|
|
133
|
-
`
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
131
|
+
version pull request before requesting its merge with GitHub's auto-merge
|
|
132
|
+
feature and the configured canonical method (`squash` for `direct`, `rebase`
|
|
133
|
+
for `staging-release`). GitHub performs the merge only after the branch's
|
|
134
|
+
required checks and reviews pass; the release runner exits after submitting
|
|
135
|
+
that request rather than waiting for every workflow to finish. This keeps a
|
|
136
|
+
healthy release from failing just because required checks outlast a bounded
|
|
137
|
+
runner-side wait. No checks, reviews, or branch rules are bypassed. The
|
|
138
|
+
request uses the exact head SHA returned by Code Foundry's path audit and is
|
|
139
|
+
refused if the branch changed during that audit.
|
|
140
|
+
|
|
141
|
+
Repositories using a valid `CODE_FOUNDRY_TOKEN` must allow auto-merge in their
|
|
142
|
+
GitHub settings when release checks may still be pending. GitHub rejects the
|
|
143
|
+
request if auto-merge is unavailable. If the PR is already eligible, the same
|
|
144
|
+
command merges it immediately under branch policy. A head change detected
|
|
145
|
+
between the path audit and enqueueing fails the release job. Conflicts remain
|
|
146
|
+
subject to GitHub's branch policy and keep the merge from completing until
|
|
147
|
+
resolved. GitHub's
|
|
148
|
+
automatic head-branch deletion setting removes branches after deferred merges;
|
|
149
|
+
the CLI's `--delete-branch` option also removes a branch when the merge completes
|
|
150
|
+
immediately. GitHub can keep auto-merge enabled if a later Release Please run
|
|
151
|
+
updates the branch. With the documented required `Validation / Gate`, each
|
|
152
|
+
synchronized head reruns the release-diff policy, and GitHub waits for that
|
|
153
|
+
head's required checks before merging.
|
|
140
154
|
|
|
141
155
|
## Operational checklist
|
|
142
156
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-foundry",
|
|
3
|
-
"version": "1.33.
|
|
3
|
+
"version": "1.33.3",
|
|
4
4
|
"description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
|
|
5
5
|
"homepage": "https://github.com/0xPlayerOne/code-foundry#readme",
|
|
6
6
|
"bugs": {
|
package/src/commands/release.mjs
CHANGED
|
@@ -783,7 +783,7 @@ export function validateReleasePullRequestDiffs(root) {
|
|
|
783
783
|
'--base',
|
|
784
784
|
'main',
|
|
785
785
|
'--json',
|
|
786
|
-
'number,title,headRefName',
|
|
786
|
+
'number,title,headRefName,headRefOid',
|
|
787
787
|
])
|
|
788
788
|
prs = Array.isArray(result) ? result : []
|
|
789
789
|
if (selectGeneratedReleasePrs(prs).length) break
|
|
@@ -792,6 +792,8 @@ export function validateReleasePullRequestDiffs(root) {
|
|
|
792
792
|
const generated = selectGeneratedReleasePrs(Array.isArray(prs) ? prs : [])
|
|
793
793
|
/** @type {Map<number, string[]>} */
|
|
794
794
|
const paths = new Map()
|
|
795
|
+
/** @type {string[]} */
|
|
796
|
+
const headErrors = []
|
|
795
797
|
for (const pr of generated) {
|
|
796
798
|
const number = Number(pr.number)
|
|
797
799
|
const result = spawnSync(
|
|
@@ -800,12 +802,36 @@ export function validateReleasePullRequestDiffs(root) {
|
|
|
800
802
|
{ cwd: resolve(root), encoding: 'utf8' }
|
|
801
803
|
)
|
|
802
804
|
paths.set(number, result.status === 0 ? result.stdout.split(/\r?\n/).filter(Boolean) : [])
|
|
805
|
+
|
|
806
|
+
const auditedHead = typeof pr.headRefOid === 'string' ? pr.headRefOid : ''
|
|
807
|
+
const currentPr = ghJson(root, [
|
|
808
|
+
'pr',
|
|
809
|
+
'view',
|
|
810
|
+
String(number),
|
|
811
|
+
'--repo',
|
|
812
|
+
repository,
|
|
813
|
+
'--json',
|
|
814
|
+
'headRefOid',
|
|
815
|
+
])
|
|
816
|
+
const currentHead =
|
|
817
|
+
currentPr && typeof currentPr === 'object' && !Array.isArray(currentPr)
|
|
818
|
+
? /** @type {{ headRefOid?: unknown }} */ (currentPr).headRefOid
|
|
819
|
+
: undefined
|
|
820
|
+
if (!auditedHead || currentHead !== auditedHead) {
|
|
821
|
+
headErrors.push(
|
|
822
|
+
`Generated release PR #${number} changed head while its path diff was being validated; rerun release validation before merging.`
|
|
823
|
+
)
|
|
824
|
+
}
|
|
803
825
|
}
|
|
804
826
|
const validation = validateReleasePullRequests(
|
|
805
827
|
Array.isArray(prs) ? prs : [],
|
|
806
828
|
paths,
|
|
807
829
|
approvedReleaseFiles(readReleaseConfig(root))
|
|
808
830
|
)
|
|
831
|
+
if (headErrors.length) {
|
|
832
|
+
validation.valid = false
|
|
833
|
+
validation.errors.push(...headErrors)
|
|
834
|
+
}
|
|
809
835
|
console.log(JSON.stringify(validation, null, 2))
|
|
810
836
|
if (!validation.valid) throw new Error(validation.errors.join(' '))
|
|
811
837
|
return validation
|
|
@@ -173,18 +173,18 @@ export function selectReleaseCredential(input) {
|
|
|
173
173
|
return { token: '', source: 'missing', autoMerge: false }
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
/** @param {Array<{number?: number, title?: string, headRefName?: string}>} prs */
|
|
176
|
+
/** @param {Array<{number?: number, title?: string, headRefName?: string, headRefOid?: string}>} prs */
|
|
177
177
|
export function selectGeneratedReleasePrs(prs) {
|
|
178
178
|
return prs.filter(
|
|
179
179
|
(pr) =>
|
|
180
180
|
String(pr.title ?? '').startsWith('chore(main): release ') &&
|
|
181
|
-
|
|
181
|
+
isReleasePleaseHead(pr.headRefName)
|
|
182
182
|
)
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
/**
|
|
186
186
|
* Validate all generated release PR diffs before any merge is attempted.
|
|
187
|
-
* @param {Array<{number?: number, title?: string, headRefName?: string}>} prs
|
|
187
|
+
* @param {Array<{number?: number, title?: string, headRefName?: string, headRefOid?: string}>} prs
|
|
188
188
|
* @param {Map<number, string[]>} changedPathsByPr
|
|
189
189
|
* @param {Set<string>} allowed
|
|
190
190
|
*/
|