code-foundry 1.48.7 → 1.50.0
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/CONTRIBUTING.md +8 -8
- package/.github/code-foundry.schema.json +10 -0
- package/.github/code-foundry.yml +2 -0
- package/.github/workflows/ci.yml +41 -5
- package/.github/workflows/draft-enforcement_self-ci.yml +12 -8
- package/.github/workflows/qualification-receipt.yml +201 -0
- package/.github/workflows/qualified-foundry-publish.yml +0 -12
- package/.github/workflows/release.yml +155 -107
- package/.github/workflows/release_self-ci.yml +0 -2
- package/.github/workflows/security.yml +3 -1
- package/.github/workflows/test.yml +90 -1
- package/.github/workflows/validation-billing.yml +160 -24
- package/.github/workflows/validation-no-codeql.yml +92 -16
- package/.github/workflows/validation.yml +97 -16
- package/.github/workflows/validation_self-ci.yml +7 -4
- package/CHANGELOG.md +50 -50
- package/docs/CONFIGURATION.md +11 -0
- package/docs/PUBLISHING.md +13 -5
- package/docs/WORKFLOWS.md +25 -12
- package/docs/qualified-publication.md +22 -14
- package/package.json +4 -1
- package/src/commands/qualified-publication.mjs +27 -0
- package/src/commands/sync.mjs +50 -4
- package/src/lib/github-doctor.mjs +23 -2
- package/src/lib/node-package-performance.mjs +57 -2
- package/src/lib/product-quality.mjs +11 -11
- package/src/lib/validation-policy.mjs +11 -11
- package/src/runtime-core.mjs +24 -0
|
@@ -43,6 +43,11 @@ on:
|
|
|
43
43
|
required: false
|
|
44
44
|
type: boolean
|
|
45
45
|
default: false
|
|
46
|
+
npm-publish-auth:
|
|
47
|
+
description: Select automatic token compatibility or force trusted OIDC publication.
|
|
48
|
+
required: false
|
|
49
|
+
type: string
|
|
50
|
+
default: auto
|
|
46
51
|
outputs:
|
|
47
52
|
release_created:
|
|
48
53
|
description: Whether Release Please created a release (possibly a draft).
|
|
@@ -63,6 +68,8 @@ on:
|
|
|
63
68
|
required: false
|
|
64
69
|
NPM_TOKEN:
|
|
65
70
|
required: false
|
|
71
|
+
NPM_READ_TOKEN:
|
|
72
|
+
required: false
|
|
66
73
|
|
|
67
74
|
permissions:
|
|
68
75
|
actions: write
|
|
@@ -271,11 +278,12 @@ jobs:
|
|
|
271
278
|
// Writes intermittently hit GitHub's secondary rate limiting from
|
|
272
279
|
// busy automation accounts (403 with the generic not-accessible
|
|
273
280
|
// message); back off and retry before giving up.
|
|
274
|
-
const gh = (args) => {
|
|
281
|
+
const gh = (args, options = {}) => {
|
|
275
282
|
for (const wait of [0, 10, 30]) {
|
|
276
283
|
try {
|
|
277
284
|
if (wait) sleep(wait);
|
|
278
285
|
return execFileSync('gh', args, {
|
|
286
|
+
...options,
|
|
279
287
|
encoding: 'utf8',
|
|
280
288
|
maxBuffer: 32 * 1024 * 1024,
|
|
281
289
|
});
|
|
@@ -316,6 +324,18 @@ jobs:
|
|
|
316
324
|
const latestTag = versionedTags[0] ?? '';
|
|
317
325
|
const prefix = latestTag.replace(/v?\d+\.\d+\.\d+.*$/, '') || 'v';
|
|
318
326
|
|
|
327
|
+
// Include drafts and every page before deciding an object is absent.
|
|
328
|
+
const releasePages = JSON.parse(gh([
|
|
329
|
+
'api', `repos/${repo}/releases`, '-X', 'GET', '-f', 'per_page=100',
|
|
330
|
+
'--paginate', '--slurp',
|
|
331
|
+
]));
|
|
332
|
+
if (!Array.isArray(releasePages) || releasePages.some((page) =>
|
|
333
|
+
!Array.isArray(page) || page.some((release) =>
|
|
334
|
+
!release || typeof release.tag_name !== 'string' || !release.tag_name))) {
|
|
335
|
+
throw new Error('Invalid existing release listing; refusing release creation');
|
|
336
|
+
}
|
|
337
|
+
const existingReleaseTags = new Set(releasePages.flat().map((release) => release.tag_name));
|
|
338
|
+
|
|
319
339
|
let ensured = 0;
|
|
320
340
|
let failures = 0;
|
|
321
341
|
let lastTag = '';
|
|
@@ -324,12 +344,7 @@ jobs:
|
|
|
324
344
|
const version = /^chore\(main\): release (\S+)/.exec(pull.title)?.[1];
|
|
325
345
|
if (!version) continue;
|
|
326
346
|
const tag = `${prefix}v${version}`;
|
|
327
|
-
|
|
328
|
-
// the list endpoint (which returns drafts) for the tag.
|
|
329
|
-
const releasesForCheck = JSON.parse(gh([
|
|
330
|
-
'api', `repos/${repo}/releases`, '-X', 'GET', '-f', 'per_page=100',
|
|
331
|
-
]));
|
|
332
|
-
if (releasesForCheck.some((release) => release.tag_name === tag)) {
|
|
347
|
+
if (existingReleaseTags.has(tag)) {
|
|
333
348
|
console.log(`${tag}: release object already exists`);
|
|
334
349
|
} else {
|
|
335
350
|
// No release object for this tag: create it. The tag may also
|
|
@@ -354,6 +369,7 @@ jobs:
|
|
|
354
369
|
prerelease: version.includes('-'),
|
|
355
370
|
});
|
|
356
371
|
gh(['api', `repos/${repo}/releases`, '-X', 'POST', '--input', '-'], { input: body });
|
|
372
|
+
existingReleaseTags.add(tag);
|
|
357
373
|
console.log(`${tag}: release object created`);
|
|
358
374
|
} catch (error) {
|
|
359
375
|
failures += 1;
|
|
@@ -514,96 +530,106 @@ jobs:
|
|
|
514
530
|
fi
|
|
515
531
|
|
|
516
532
|
for pr in "${release_prs[@]}"; do
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
(.
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
.
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
533
|
+
# A lock-sync/synchronize transition can move the PR while Actions is
|
|
534
|
+
# being read. Re-evaluate the whole tuple and its owner; never carry
|
|
535
|
+
# eligibility across heads or retry a stable failed qualification.
|
|
536
|
+
for state_attempt in 1 2 3; do
|
|
537
|
+
pr_state=$(gh pr view "$pr" --repo "$GITHUB_REPOSITORY" \
|
|
538
|
+
--json isDraft,headRefOid,headRefName \
|
|
539
|
+
--jq '[.isDraft, .headRefOid, .headRefName] | @tsv')
|
|
540
|
+
read -r PR_DRAFT PR_HEAD PR_BRANCH <<< "$pr_state"
|
|
541
|
+
if [[ ! "$PR_DRAFT" =~ ^(true|false)$ || ! "$PR_HEAD" =~ ^[a-f0-9]{40}$ ]]; then
|
|
542
|
+
echo 'Unable to verify generated release PR state.' >&2
|
|
543
|
+
exit 1
|
|
544
|
+
fi
|
|
545
|
+
case "$PR_BRANCH" in
|
|
546
|
+
release-please--branches--main|release-please--branches--main--*) ;;
|
|
547
|
+
*) echo 'Release PR head left the generated namespace; refusing readiness mutation.' >&2; exit 1 ;;
|
|
548
|
+
esac
|
|
549
|
+
if [ "$AUTO_MERGE" = true ]; then
|
|
550
|
+
if [ "$PR_DRAFT" = false ]; then
|
|
551
|
+
# A ready head already receives synchronize validation. Preserve
|
|
552
|
+
# its live/completed owner instead of cancelling and reallocating
|
|
553
|
+
# CI every time another queued main release run prepares it.
|
|
554
|
+
runs=$(GH_TOKEN="$VALIDATION_TOKEN" gh api \
|
|
555
|
+
"repos/$GITHUB_REPOSITORY/actions/runs" --method GET \
|
|
556
|
+
-f event=pull_request -f head_sha="$PR_HEAD" -f per_page=100)
|
|
557
|
+
validation=$(jq -er --arg head "$PR_HEAD" --arg branch "$PR_BRANCH" \
|
|
558
|
+
--arg repo "$GITHUB_REPOSITORY" '
|
|
559
|
+
def active: .status == "queued" or .status == "in_progress" or
|
|
560
|
+
.status == "waiting" or .status == "pending" or .status == "requested";
|
|
561
|
+
def valid_run:
|
|
562
|
+
type == "object" and
|
|
563
|
+
(.id | type == "number" and . > 0 and floor == .) and
|
|
564
|
+
(.run_attempt | type == "number" and . >= 1 and floor == .) and
|
|
565
|
+
(.head_sha | type == "string" and test("^[a-f0-9]{40}$")) and
|
|
566
|
+
(.head_branch | type == "string" and length > 0) and
|
|
567
|
+
(.event | type == "string" and length > 0) and
|
|
568
|
+
(.repository | type == "object") and
|
|
569
|
+
(.repository.full_name | type == "string" and length > 0) and
|
|
570
|
+
(.path | type == "string" and length > 0) and
|
|
571
|
+
((active and has("conclusion") and .conclusion == null) or
|
|
572
|
+
(.status == "completed" and
|
|
573
|
+
(.conclusion == "success" or .conclusion == "failure" or
|
|
574
|
+
.conclusion == "timed_out" or .conclusion == "action_required" or
|
|
575
|
+
.conclusion == "cancelled" or .conclusion == "skipped" or
|
|
576
|
+
.conclusion == "neutral")));
|
|
577
|
+
if (.workflow_runs | type) != "array" or
|
|
578
|
+
(.total_count | type) != "number" then
|
|
579
|
+
error("Invalid validation owner response")
|
|
580
|
+
elif .total_count != (.workflow_runs | length) then
|
|
581
|
+
error("Incomplete validation owner response")
|
|
582
|
+
elif any(.workflow_runs[]; valid_run | not) then
|
|
583
|
+
error("Invalid validation run identity or state")
|
|
584
|
+
else
|
|
585
|
+
[.workflow_runs[] | (.path | split("@")[0]) as $workflow | select(
|
|
586
|
+
.head_sha == $head and .head_branch == $branch and
|
|
587
|
+
.event == "pull_request" and .repository.full_name == $repo and
|
|
588
|
+
($workflow == ".github/workflows/validation.yml" or
|
|
589
|
+
$workflow == ".github/workflows/validation_self-ci.yml")
|
|
590
|
+
)] | sort_by(.id) | last |
|
|
591
|
+
if . == null then "missing"
|
|
592
|
+
elif active or (.status == "completed" and .conclusion == "success") then "owned"
|
|
593
|
+
elif .status == "completed" and
|
|
594
|
+
(.conclusion == "failure" or .conclusion == "timed_out" or
|
|
595
|
+
.conclusion == "action_required") then "failed"
|
|
596
|
+
elif .status == "completed" and
|
|
597
|
+
(.conclusion == "cancelled" or .conclusion == "skipped" or
|
|
598
|
+
.conclusion == "neutral") then "missing"
|
|
599
|
+
else error("Unconfirmed validation owner state") end
|
|
600
|
+
end' <<< "$runs")
|
|
601
|
+
fresh_state=$(gh pr view "$pr" --repo "$GITHUB_REPOSITORY" \
|
|
602
|
+
--json isDraft,headRefOid,headRefName \
|
|
603
|
+
--jq '[.isDraft, .headRefOid, .headRefName] | @tsv')
|
|
604
|
+
if [ "$fresh_state" != "$pr_state" ]; then
|
|
605
|
+
if [ "$state_attempt" -eq 3 ]; then
|
|
606
|
+
echo 'Release PR state did not stabilize during validation lookup; refusing readiness mutation.' >&2
|
|
607
|
+
exit 1
|
|
608
|
+
fi
|
|
609
|
+
echo "Release PR #$pr changed during validation lookup; reading its complete state and owner again."
|
|
610
|
+
continue
|
|
611
|
+
fi
|
|
612
|
+
if [ "$validation" = owned ]; then
|
|
613
|
+
echo "Release PR #$pr already has current-head validation; preserving readiness."
|
|
614
|
+
break
|
|
615
|
+
fi
|
|
616
|
+
if [ "$validation" = failed ]; then
|
|
617
|
+
echo "Current-head validation failed for release PR #$pr; resolve or explicitly retry it before release." >&2
|
|
618
|
+
exit 1
|
|
619
|
+
fi
|
|
620
|
+
# A missing, cancelled or skipped owner still needs the existing
|
|
621
|
+
# explicit ready_for_review transition with the validated token.
|
|
622
|
+
gh pr ready --undo "$pr" --repo "$GITHUB_REPOSITORY"
|
|
591
623
|
fi
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
624
|
+
gh pr ready "$pr" --repo "$GITHUB_REPOSITORY"
|
|
625
|
+
else
|
|
626
|
+
if [ "$PR_DRAFT" = false ]; then
|
|
627
|
+
gh pr ready --undo "$pr" --repo "$GITHUB_REPOSITORY"
|
|
595
628
|
fi
|
|
596
|
-
|
|
597
|
-
# explicit ready_for_review transition with the validated token.
|
|
598
|
-
gh pr ready --undo "$pr" --repo "$GITHUB_REPOSITORY"
|
|
629
|
+
echo "::notice title=Manual release merge required::Release Please created or updated a version pull request. No valid automation token is available (absent or rejected by GitHub), so release PRs are left in draft and need manual readiness before validation and merge workflows trigger."
|
|
599
630
|
fi
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
if [ "$PR_DRAFT" = false ]; then
|
|
603
|
-
gh pr ready --undo "$pr" --repo "$GITHUB_REPOSITORY"
|
|
604
|
-
fi
|
|
605
|
-
echo "::notice title=Manual release merge required::Release Please created or updated a version pull request. No valid automation token is available (absent or rejected by GitHub), so release PRs are left in draft and need manual readiness before validation and merge workflows trigger."
|
|
606
|
-
fi
|
|
631
|
+
break
|
|
632
|
+
done
|
|
607
633
|
done
|
|
608
634
|
- name: Leave release pull request for manual merge
|
|
609
635
|
if: steps.release.outputs.prs_created == 'true' && steps.credentials.outputs.auto_merge != 'true'
|
|
@@ -824,24 +850,30 @@ jobs:
|
|
|
824
850
|
contents: read
|
|
825
851
|
id-token: write
|
|
826
852
|
env:
|
|
827
|
-
|
|
853
|
+
NPM_PUBLISH_AUTH: ${{ inputs['npm-publish-auth'] }}
|
|
854
|
+
HAS_NPM_TOKEN: ${{ secrets.NPM_TOKEN != '' }}
|
|
855
|
+
HAS_NPM_READ_TOKEN: ${{ secrets.NPM_READ_TOKEN != '' }}
|
|
828
856
|
steps:
|
|
829
857
|
- name: Checkout release
|
|
830
858
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
831
859
|
with:
|
|
832
860
|
persist-credentials: false
|
|
833
861
|
ref: ${{ needs.release.outputs.tag_name }}
|
|
834
|
-
- name:
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
862
|
+
- name: Validate npm publication authentication
|
|
863
|
+
run: |
|
|
864
|
+
set -euo pipefail
|
|
865
|
+
case "$NPM_PUBLISH_AUTH" in
|
|
866
|
+
auto|oidc|token) ;;
|
|
867
|
+
*) echo "Unsupported npm-publish-auth: $NPM_PUBLISH_AUTH" >&2; exit 1 ;;
|
|
868
|
+
esac
|
|
869
|
+
if [ "$NPM_PUBLISH_AUTH" = token ] && [ "$HAS_NPM_TOKEN" != true ]; then
|
|
870
|
+
echo 'npm-publish-auth token requires the NPM_TOKEN secret.' >&2
|
|
871
|
+
exit 1
|
|
872
|
+
fi
|
|
873
|
+
- name: Setup Node
|
|
841
874
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
|
842
875
|
with:
|
|
843
876
|
node-version: 24
|
|
844
|
-
registry-url: https://registry.npmjs.org
|
|
845
877
|
- name: Setup Bun (lockfile managers)
|
|
846
878
|
# The install step below dispatches on lockfile: bun, pnpm, yarn, or
|
|
847
879
|
# npm. Stock runners only provide Node, so provision Bun (oven-sh)
|
|
@@ -855,8 +887,18 @@ jobs:
|
|
|
855
887
|
- name: Install dependencies
|
|
856
888
|
# npm publish runs prepublishOnly (usually a build), which needs
|
|
857
889
|
# devDependencies present. Install with the project's own manager.
|
|
890
|
+
env:
|
|
891
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_READ_TOKEN || (inputs['npm-publish-auth'] != 'oidc' && secrets.NPM_TOKEN) || '' }}
|
|
858
892
|
run: |
|
|
859
893
|
set -euo pipefail
|
|
894
|
+
npmrc=''
|
|
895
|
+
if [ -n "${NODE_AUTH_TOKEN:-}" ]; then
|
|
896
|
+
npmrc="$(mktemp)"
|
|
897
|
+
chmod 600 "$npmrc"
|
|
898
|
+
printf '//registry.npmjs.org/:_authToken=%s\n' "$NODE_AUTH_TOKEN" > "$npmrc"
|
|
899
|
+
export NPM_CONFIG_USERCONFIG="$npmrc"
|
|
900
|
+
fi
|
|
901
|
+
trap '[ -z "$npmrc" ] || rm -f "$npmrc"' EXIT
|
|
860
902
|
if [ -f bun.lock ] || [ -f bun.lockb ]; then bun install --frozen-lockfile
|
|
861
903
|
elif [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile
|
|
862
904
|
elif [ -f yarn.lock ]; then yarn install --immutable
|
|
@@ -864,10 +906,16 @@ jobs:
|
|
|
864
906
|
elif [ -f package.json ]; then npm install --no-audit --fund=false --package-lock=false
|
|
865
907
|
fi
|
|
866
908
|
- name: Publish npm with token
|
|
867
|
-
if: env.
|
|
909
|
+
if: inputs['npm-publish-auth'] == 'token' || (inputs['npm-publish-auth'] == 'auto' && env.HAS_NPM_TOKEN == 'true')
|
|
868
910
|
env:
|
|
869
|
-
NODE_AUTH_TOKEN: ${{
|
|
870
|
-
run:
|
|
911
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
912
|
+
run: |
|
|
913
|
+
set -euo pipefail
|
|
914
|
+
npmrc="$(mktemp)"
|
|
915
|
+
chmod 600 "$npmrc"
|
|
916
|
+
printf '//registry.npmjs.org/:_authToken=%s\n' "$NODE_AUTH_TOKEN" > "$npmrc"
|
|
917
|
+
trap 'rm -f "$npmrc"' EXIT
|
|
918
|
+
NPM_CONFIG_USERCONFIG="$npmrc" npm publish --provenance --access public
|
|
871
919
|
- name: Publish npm with trusted publishing
|
|
872
|
-
if: env.
|
|
920
|
+
if: inputs['npm-publish-auth'] == 'oidc' || (inputs['npm-publish-auth'] == 'auto' && env.HAS_NPM_TOKEN != 'true')
|
|
873
921
|
run: npm publish --provenance --access public
|
|
@@ -256,5 +256,3 @@ jobs:
|
|
|
256
256
|
tag: ${{ needs.release.outputs.tag_name || needs.recovery.outputs.tag }}
|
|
257
257
|
asset: ${{ needs.qualification.outputs.filename }}
|
|
258
258
|
billing-pause-bypass: ${{ github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true }}
|
|
259
|
-
secrets:
|
|
260
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@@ -140,7 +140,9 @@ jobs:
|
|
|
140
140
|
dependency-audit:
|
|
141
141
|
name: Dependency Audit (${{ matrix.entry.display }})
|
|
142
142
|
needs: profile
|
|
143
|
-
|
|
143
|
+
# Avoid expanding an empty matrix; skip only the explicitly empty result.
|
|
144
|
+
# Missing or malformed output still fails closed during matrix expansion.
|
|
145
|
+
if: vars.CI_BILLING_PAUSED != 'true' && needs.profile.result == 'success' && needs.profile.outputs.audit_matrix != '[]'
|
|
144
146
|
strategy:
|
|
145
147
|
fail-fast: false
|
|
146
148
|
max-parallel: 8
|
|
@@ -38,6 +38,11 @@ on:
|
|
|
38
38
|
required: false
|
|
39
39
|
type: string
|
|
40
40
|
default: task-result
|
|
41
|
+
integration-total-shards:
|
|
42
|
+
description: Integration partitions (1 or 2); sharded scripts must honor INTEGRATION_SHARD_INDEX and INTEGRATION_TOTAL_SHARDS.
|
|
43
|
+
required: false
|
|
44
|
+
type: string
|
|
45
|
+
default: '1'
|
|
41
46
|
e2e-shard-list:
|
|
42
47
|
description: Comma-separated E2E shard indices, for example "1,2". A single index runs one unsharded job.
|
|
43
48
|
required: false
|
|
@@ -255,10 +260,14 @@ jobs:
|
|
|
255
260
|
|
|
256
261
|
integration:
|
|
257
262
|
name: Integration
|
|
258
|
-
if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true
|
|
263
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true && inputs.integration-total-shards != '2'
|
|
259
264
|
runs-on: ${{ inputs.runner }}
|
|
260
265
|
timeout-minutes: 30
|
|
261
266
|
steps:
|
|
267
|
+
- name: Validate integration shard count
|
|
268
|
+
env:
|
|
269
|
+
SHARDS: ${{ inputs.integration-total-shards }}
|
|
270
|
+
run: test "$SHARDS" = 1
|
|
262
271
|
- name: Checkout
|
|
263
272
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
264
273
|
with:
|
|
@@ -326,6 +335,86 @@ jobs:
|
|
|
326
335
|
- name: Save Vite+ task cache
|
|
327
336
|
uses: ./.github/actions/vite-plus-cache-save
|
|
328
337
|
|
|
338
|
+
integration-sharded:
|
|
339
|
+
name: Integration shard
|
|
340
|
+
if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true && inputs.integration-total-shards == '2'
|
|
341
|
+
runs-on: ${{ inputs.runner }}
|
|
342
|
+
timeout-minutes: 30
|
|
343
|
+
strategy:
|
|
344
|
+
fail-fast: false
|
|
345
|
+
matrix:
|
|
346
|
+
shard: [1, 2]
|
|
347
|
+
steps:
|
|
348
|
+
- name: Checkout
|
|
349
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
350
|
+
with:
|
|
351
|
+
persist-credentials: false
|
|
352
|
+
fetch-depth: 2
|
|
353
|
+
- name: Runtime
|
|
354
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
355
|
+
with:
|
|
356
|
+
persist-credentials: false
|
|
357
|
+
repository: ${{ inputs.runtime-repository }}
|
|
358
|
+
ref: ${{ inputs.runtime-ref }}
|
|
359
|
+
path: .github/.code-foundry
|
|
360
|
+
sparse-checkout: |
|
|
361
|
+
.github/actions
|
|
362
|
+
src/lib
|
|
363
|
+
src/runtime-core.mjs
|
|
364
|
+
src/runtime.mjs
|
|
365
|
+
- name: Install runtime
|
|
366
|
+
run: |
|
|
367
|
+
mkdir -p .github/actions
|
|
368
|
+
mv .github/.code-foundry "$RUNNER_TEMP/code-foundry"
|
|
369
|
+
cp -R "$RUNNER_TEMP/code-foundry/.github/actions/." .github/actions/
|
|
370
|
+
- name: Detect
|
|
371
|
+
id: applicability
|
|
372
|
+
env:
|
|
373
|
+
EVENT_NAME: ${{ github.event_name }}
|
|
374
|
+
BASE_REF: ${{ github.event.pull_request.base.ref }}
|
|
375
|
+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
376
|
+
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
|
377
|
+
BEFORE_SHA: ${{ github.event.before }}
|
|
378
|
+
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci task_profile integration >> "$GITHUB_OUTPUT"
|
|
379
|
+
- name: Setup
|
|
380
|
+
if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
|
|
381
|
+
uses: ./.github/actions/setup
|
|
382
|
+
with:
|
|
383
|
+
install: true
|
|
384
|
+
install-javascript: ${{ steps.applicability.outputs.javascript == 'true' }}
|
|
385
|
+
install-python: ${{ steps.applicability.outputs.python == 'true' }}
|
|
386
|
+
install-rust: ${{ steps.applicability.outputs.rust == 'true' }}
|
|
387
|
+
cache-build: ${{ steps.applicability.outputs.rust == 'true' }}
|
|
388
|
+
cache-environment: false
|
|
389
|
+
cache-save: ${{ github.event_name == 'push' }}
|
|
390
|
+
task: integration
|
|
391
|
+
task-javascript: ${{ steps.applicability.outputs.javascript }}
|
|
392
|
+
task-python: ${{ steps.applicability.outputs.python }}
|
|
393
|
+
task-rust: ${{ steps.applicability.outputs.rust }}
|
|
394
|
+
- name: Integration
|
|
395
|
+
id: execute
|
|
396
|
+
if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false'
|
|
397
|
+
env:
|
|
398
|
+
INTEGRATION_SHARD_INDEX: ${{ matrix.shard }}
|
|
399
|
+
INTEGRATION_TOTAL_SHARDS: ${{ inputs.integration-total-shards }}
|
|
400
|
+
run: node "$RUNNER_TEMP/code-foundry/src/runtime.mjs" ci integration
|
|
401
|
+
- name: Retain task receipt
|
|
402
|
+
if: >-
|
|
403
|
+
always() &&
|
|
404
|
+
(steps.execute.outcome == 'success' || steps.execute.outcome == 'failure' ||
|
|
405
|
+
steps.applicability.outputs.applicable == 'false' || steps.applicability.outputs.affected == 'false') &&
|
|
406
|
+
hashFiles('.code-foundry/results/integration.json') != ''
|
|
407
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
408
|
+
with:
|
|
409
|
+
name: ${{ inputs.artifact-prefix }}-${{ github.run_id }}-${{ github.run_attempt }}-integration-s${{ matrix.shard }}
|
|
410
|
+
path: .code-foundry/results/integration.json
|
|
411
|
+
include-hidden-files: true
|
|
412
|
+
if-no-files-found: error
|
|
413
|
+
retention-days: 14
|
|
414
|
+
|
|
415
|
+
- name: Save Vite+ task cache
|
|
416
|
+
uses: ./.github/actions/vite-plus-cache-save
|
|
417
|
+
|
|
329
418
|
e2e:
|
|
330
419
|
name: E2E
|
|
331
420
|
if: vars.CI_BILLING_PAUSED != 'true' && inputs.unit-only != true
|