code-foundry 1.44.6 → 1.44.7

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,99 @@ 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
+ const pulls = JSON.parse(gh([
273
+ 'api', `repos/${repo}/pulls`,
274
+ '-X', 'GET',
275
+ '-f', 'state=closed',
276
+ '-f', 'sort=updated',
277
+ '-f', 'direction=desc',
278
+ '-f', 'per_page=30',
279
+ ])).filter((pull) => pull.merged_at !== null).filter((pull) =>
280
+ pull.head.ref.startsWith('release-please--branches--')
281
+ );
282
+
283
+ // The newest existing tag supplies the tag prefix; the manifest
284
+ // supplies the version each merged pull request published.
285
+ const tags = JSON.parse(gh([
286
+ 'api', `repos/${repo}/tags`, '-X', 'GET', '-f', 'per_page=100',
287
+ ]));
288
+ const latestTag = tags[0]?.name ?? '';
289
+ const prefix = latestTag.replace(/v?\d+\.\d+\.\d+.*$/, '') || 'v';
290
+
291
+ let created = 0;
292
+ let lastTag = '';
293
+ let lastSha = '';
294
+ for (const pull of pulls) {
295
+ const version = /^chore\(main\): release ([^)]+)\)/.exec(pull.title)?.[1];
296
+ if (!version) continue;
297
+ const tag = `${prefix}v${version}`;
298
+ try {
299
+ gh(['api', `repos/${repo}/releases/tags/${tag}`, '--silent']);
300
+ console.log(`${tag}: release object already exists`);
301
+ continue;
302
+ } catch {
303
+ // No release object for this tag: create it below.
304
+ }
305
+ if (!tags.some((t) => t.name === tag)) {
306
+ gh(['api', `repos/${repo}/git/refs`, '-X', 'POST',
307
+ '-f', `ref=refs/tags/${tag}`, '-f', `sha=${pull.merge_commit_sha}`]);
308
+ console.log(`${tag}: tag created at ${pull.merge_commit_sha.slice(0, 10)}`);
309
+ }
310
+ const body = JSON.stringify({
311
+ tag_name: tag,
312
+ name: tag,
313
+ body: pull.body ?? '',
314
+ draft: config.packages?.['.']?.draft ?? config.draft ?? false,
315
+ prerelease: version.includes('-'),
316
+ });
317
+ gh(['api', `repos/${repo}/releases`, '-X', 'POST', '--input', '-'], { input: body });
318
+ console.log(`${tag}: release object created`);
319
+ created += 1;
320
+ lastTag = tag;
321
+ lastSha = pull.merge_commit_sha;
322
+ }
323
+ if (created === 0) {
324
+ throw new Error(
325
+ 'release-please failed and no merged version pull request was waiting for a release object; ' +
326
+ 'the failure needs human eyes'
327
+ );
328
+ }
329
+ fs.appendFileSync(
330
+ process.env.GITHUB_OUTPUT,
331
+ `fallback_created=true\ntag_name=${lastTag}\nsha=${lastSha}\n`,
332
+ );
333
+ NODE
237
334
  - name: Normalize Release Please outputs
238
335
  id: release
239
336
  if: steps.profile.outputs.release_type != 'none'
@@ -246,11 +343,17 @@ jobs:
246
343
  WORKFLOW_TAG_NAME: ${{ steps.release_workflow.outputs.tag_name }}
247
344
  WORKFLOW_SHA: ${{ steps.release_workflow.outputs.sha }}
248
345
  WORKFLOW_PRS_CREATED: ${{ steps.release_workflow.outputs.prs_created }}
346
+ FALLBACK_RELEASE_CREATED: ${{ steps.release_rest_fallback.outputs.fallback_created }}
347
+ FALLBACK_TAG_NAME: ${{ steps.release_rest_fallback.outputs.tag_name }}
348
+ FALLBACK_SHA: ${{ steps.release_rest_fallback.outputs.sha }}
349
+ FALLBACK_PRS_CREATED: '0'
249
350
  run: |
250
351
  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
352
+ # Exactly one of the three Release Please sources runs: the
353
+ # automation-token action, the workflow-token action, or the REST
354
+ # fallback that completes a rejected automation run. Selection by a
355
+ # non-empty release_created is deterministic. The stable release
356
+ # step id keeps the job outputs and downstream jobs reading
254
357
  # steps.release.outputs.* unchanged.
255
358
  if [ -n "$AUTOMATION_RELEASE_CREATED" ]; then
256
359
  {
@@ -259,6 +362,13 @@ jobs:
259
362
  echo "sha=$AUTOMATION_SHA"
260
363
  echo "prs_created=$AUTOMATION_PRS_CREATED"
261
364
  } >> "$GITHUB_OUTPUT"
365
+ elif [ -n "${FALLBACK_RELEASE_CREATED:-}" ]; then
366
+ {
367
+ echo "release_created=${FALLBACK_RELEASE_CREATED:-}"
368
+ echo "tag_name=${FALLBACK_TAG_NAME:-}"
369
+ echo "sha=${FALLBACK_SHA:-}"
370
+ echo "prs_created=${FALLBACK_PRS_CREATED:-}"
371
+ } >> "$GITHUB_OUTPUT"
262
372
  else
263
373
  {
264
374
  echo "release_created=$WORKFLOW_RELEASE_CREATED"
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.44.7](https://github.com/0xPlayerOne/code-foundry/compare/v1.44.6...v1.44.7) (2026-10-05)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **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))
9
+
3
10
  ## [1.44.6](https://github.com/0xPlayerOne/code-foundry/compare/v1.44.5...v1.44.6) (2026-10-05)
4
11
 
5
12
 
@@ -143,16 +150,9 @@
143
150
 
144
151
  * 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
152
 
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; 227 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.7",
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": {