code-foundry 1.44.6 → 1.44.8

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.
@@ -220,6 +220,10 @@ jobs:
220
220
  fi
221
221
  - name: Release Please (automation token)
222
222
  id: release_automation
223
+ # The REST fallback below completes the run when the action's own
224
+ # release-creation call is rejected, so this step must not fail the
225
+ # job before the fallback gets its turn.
226
+ continue-on-error: true
223
227
  if: steps.profile.outputs.release_type != 'none' && steps.credentials.outputs.token_source == 'configured'
224
228
  uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
225
229
  with:
@@ -234,6 +238,100 @@ jobs:
234
238
  token: ${{ github.token }}
235
239
  config-file: ${{ inputs.config-file }}
236
240
  release-type: ${{ steps.profile.outputs.legacy_release_type }}
241
+ - name: Create missing release objects over REST
242
+ id: release_rest_fallback
243
+ # release-please's own release-creation call is occasionally rejected
244
+ # with 403 even though the same credential creates release objects and
245
+ # refs through the plain REST API from the same runner (observed with
246
+ # fine-grained automation tokens; the identical curl call succeeds
247
+ # seconds earlier). When the action failed but merged version pull
248
+ # requests are waiting for their release objects, create them here
249
+ # through the REST API with the validated credential.
250
+ if: >-
251
+ always() &&
252
+ steps.profile.outputs.release_type != 'none' &&
253
+ steps.credentials.outputs.token_source == 'configured' &&
254
+ steps.release_automation.outcome == 'failure'
255
+ env:
256
+ GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN }}
257
+ REPOSITORY: ${{ github.repository }}
258
+ CONFIG_FILE: ${{ inputs.config-file }}
259
+ run: |
260
+ set -euo pipefail
261
+ node <<'NODE'
262
+ const { execFileSync } = require('node:child_process');
263
+ const fs = require('node:fs');
264
+
265
+ const gh = (args) => execFileSync('gh', args, { encoding: 'utf8' });
266
+
267
+ const repo = process.env.REPOSITORY;
268
+ const config = JSON.parse(fs.readFileSync(process.env.CONFIG_FILE, 'utf8'));
269
+ const manifest = JSON.parse(fs.readFileSync('.release-please-manifest.json', 'utf8'));
270
+
271
+ // Newest merged release-please version pull requests first.
272
+ // The head filter keeps the query on the version-PR branch
273
+ // regardless of how many unrelated pull requests merged since.
274
+ const pulls = JSON.parse(gh([
275
+ 'api', `repos/${repo}/pulls`,
276
+ '-X', 'GET',
277
+ '-f', 'state=closed',
278
+ '-f', `head=${repo.split('/')[0]}:release-please--branches--main`,
279
+ '-f', 'sort=updated',
280
+ '-f', 'direction=desc',
281
+ '-f', 'per_page=100',
282
+ ])).filter((pull) => pull.merged_at !== null);
283
+
284
+ // The newest existing tag supplies the tag prefix; the manifest
285
+ // supplies the version each merged pull request published.
286
+ const tags = JSON.parse(gh([
287
+ 'api', `repos/${repo}/tags`, '-X', 'GET', '-f', 'per_page=100',
288
+ ]));
289
+ const latestTag = tags[0]?.name ?? '';
290
+ const prefix = latestTag.replace(/v?\d+\.\d+\.\d+.*$/, '') || 'v';
291
+
292
+ let created = 0;
293
+ let lastTag = '';
294
+ let lastSha = '';
295
+ for (const pull of pulls) {
296
+ const version = /^chore\(main\): release ([^)]+)\)/.exec(pull.title)?.[1];
297
+ if (!version) continue;
298
+ const tag = `${prefix}v${version}`;
299
+ try {
300
+ gh(['api', `repos/${repo}/releases/tags/${tag}`, '--silent']);
301
+ console.log(`${tag}: release object already exists`);
302
+ continue;
303
+ } catch {
304
+ // No release object for this tag: create it below.
305
+ }
306
+ if (!tags.some((t) => t.name === tag)) {
307
+ gh(['api', `repos/${repo}/git/refs`, '-X', 'POST',
308
+ '-f', `ref=refs/tags/${tag}`, '-f', `sha=${pull.merge_commit_sha}`]);
309
+ console.log(`${tag}: tag created at ${pull.merge_commit_sha.slice(0, 10)}`);
310
+ }
311
+ const body = JSON.stringify({
312
+ tag_name: tag,
313
+ name: tag,
314
+ body: pull.body ?? '',
315
+ draft: config.packages?.['.']?.draft ?? config.draft ?? false,
316
+ prerelease: version.includes('-'),
317
+ });
318
+ gh(['api', `repos/${repo}/releases`, '-X', 'POST', '--input', '-'], { input: body });
319
+ console.log(`${tag}: release object created`);
320
+ created += 1;
321
+ lastTag = tag;
322
+ lastSha = pull.merge_commit_sha;
323
+ }
324
+ if (created === 0) {
325
+ throw new Error(
326
+ 'release-please failed and no merged version pull request was waiting for a release object; ' +
327
+ 'the failure needs human eyes'
328
+ );
329
+ }
330
+ fs.appendFileSync(
331
+ process.env.GITHUB_OUTPUT,
332
+ `fallback_created=true\ntag_name=${lastTag}\nsha=${lastSha}\n`,
333
+ );
334
+ NODE
237
335
  - name: Normalize Release Please outputs
238
336
  id: release
239
337
  if: steps.profile.outputs.release_type != 'none'
@@ -246,11 +344,17 @@ jobs:
246
344
  WORKFLOW_TAG_NAME: ${{ steps.release_workflow.outputs.tag_name }}
247
345
  WORKFLOW_SHA: ${{ steps.release_workflow.outputs.sha }}
248
346
  WORKFLOW_PRS_CREATED: ${{ steps.release_workflow.outputs.prs_created }}
347
+ FALLBACK_RELEASE_CREATED: ${{ steps.release_rest_fallback.outputs.fallback_created }}
348
+ FALLBACK_TAG_NAME: ${{ steps.release_rest_fallback.outputs.tag_name }}
349
+ FALLBACK_SHA: ${{ steps.release_rest_fallback.outputs.sha }}
350
+ FALLBACK_PRS_CREATED: '0'
249
351
  run: |
250
352
  set -euo pipefail
251
- # Exactly one of the two Release Please steps runs, so selecting the
252
- # source by a non-empty release_created is deterministic. The stable
253
- # release step id keeps the job outputs and downstream jobs reading
353
+ # Exactly one of the three Release Please sources runs: the
354
+ # automation-token action, the workflow-token action, or the REST
355
+ # fallback that completes a rejected automation run. Selection by a
356
+ # non-empty release_created is deterministic. The stable release
357
+ # step id keeps the job outputs and downstream jobs reading
254
358
  # steps.release.outputs.* unchanged.
255
359
  if [ -n "$AUTOMATION_RELEASE_CREATED" ]; then
256
360
  {
@@ -259,6 +363,13 @@ jobs:
259
363
  echo "sha=$AUTOMATION_SHA"
260
364
  echo "prs_created=$AUTOMATION_PRS_CREATED"
261
365
  } >> "$GITHUB_OUTPUT"
366
+ elif [ -n "${FALLBACK_RELEASE_CREATED:-}" ]; then
367
+ {
368
+ echo "release_created=${FALLBACK_RELEASE_CREATED:-}"
369
+ echo "tag_name=${FALLBACK_TAG_NAME:-}"
370
+ echo "sha=${FALLBACK_SHA:-}"
371
+ echo "prs_created=${FALLBACK_PRS_CREATED:-}"
372
+ } >> "$GITHUB_OUTPUT"
262
373
  else
263
374
  {
264
375
  echo "release_created=$WORKFLOW_RELEASE_CREATED"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.44.8](https://github.com/0xPlayerOne/code-foundry/compare/v1.44.7...v1.44.8) (2026-10-06)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **release:** query the version-PR branch directly in the REST fallback ([#722](https://github.com/0xPlayerOne/code-foundry/issues/722)) ([b38f394](https://github.com/0xPlayerOne/code-foundry/commit/b38f394c0ca6438117fdd2f45bd106b0b145a0f9))
9
+
10
+ ## [1.44.7](https://github.com/0xPlayerOne/code-foundry/compare/v1.44.6...v1.44.7) (2026-10-05)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **release:** complete rejected release-please runs over REST ([#720](https://github.com/0xPlayerOne/code-foundry/issues/720)) ([14e88b5](https://github.com/0xPlayerOne/code-foundry/commit/14e88b5561803fc8d5d3a77b67b99e1be90bc4af))
16
+
3
17
  ## [1.44.6](https://github.com/0xPlayerOne/code-foundry/compare/v1.44.5...v1.44.6) (2026-10-05)
4
18
 
5
19
 
@@ -136,23 +150,9 @@
136
150
 
137
151
  * normalize blank runs when stripping legacy managed markers ([#678](https://github.com/0xPlayerOne/code-foundry/issues/678)) ([acd5afc](https://github.com/0xPlayerOne/code-foundry/commit/acd5afce12b3de3b3574259639e89067e1ab3cb0))
138
152
 
139
- ## [1.38.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.37.3...v1.38.0) (2026-09-30)
140
-
141
-
142
- ### Features
143
-
144
- * fold the Turbo impact check into the delivery candidate job ([#676](https://github.com/0xPlayerOne/code-foundry/issues/676)) ([fd99d29](https://github.com/0xPlayerOne/code-foundry/commit/fd99d29ae7e10ef9346b8059dcad0ed4df6df109))
145
-
146
- ## [1.37.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.37.2...v1.37.3) (2026-09-30)
147
-
148
-
149
- ### Bug Fixes
150
-
151
- * perf-budget-best-of-n ([#674](https://github.com/0xPlayerOne/code-foundry/issues/674)) ([c377ede](https://github.com/0xPlayerOne/code-foundry/commit/c377ede617d89fb0606413ab7b5d478330c49e93))
152
-
153
153
  <!-- code-foundry: packaged changelog -->
154
154
 
155
155
  ---
156
156
 
157
- This packaged changelog lists the 20 most recent releases; 226 older releases are omitted to keep the package small.
157
+ This packaged changelog lists the 20 most recent releases; 228 older releases are omitted to keep the package small.
158
158
  See the [full changelog](https://github.com/0xPlayerOne/code-foundry/blob/main/CHANGELOG.md) for the complete history.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.44.6",
3
+ "version": "1.44.8",
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": {