@clearlydev/nx-archweave 0.2.0 → 0.2.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/dist/bin/review-verdict.js +36 -20
- package/dist/generators/add-review/generator.js +251 -182
- package/dist/generators/doctor/generator.js +254 -184
- package/dist/generators/init/generator.js +251 -182
- package/package.json +1 -1
|
@@ -293,9 +293,9 @@ var ROUND_MARKER = "<!-- archweave-review-round -->";
|
|
|
293
293
|
|
|
294
294
|
// ../template-engine/dist/review/action-pins.js
|
|
295
295
|
var ACTION_PINS = {
|
|
296
|
-
"actions/checkout": "actions/checkout@
|
|
297
|
-
"actions/setup-node": "actions/setup-node@
|
|
298
|
-
"pnpm/action-setup": "pnpm/action-setup@
|
|
296
|
+
"actions/checkout": "actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1",
|
|
297
|
+
"actions/setup-node": "actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0",
|
|
298
|
+
"pnpm/action-setup": "pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0",
|
|
299
299
|
"oven-sh/setup-bun": "oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0",
|
|
300
300
|
"anthropics/claude-code-action": "anthropics/claude-code-action@6b6870e649b5ff408753befeaee5fc7989d4e6a9 # v1.0.258",
|
|
301
301
|
"google-github-actions/run-gemini-cli": "google-github-actions/run-gemini-cli@f77273f4c914e4bf38440cf36a0369cb64a37489 # v0.1.22",
|
|
@@ -320,13 +320,14 @@ function renderConcurrencyBlock() {
|
|
|
320
320
|
" cancel-in-progress: false"
|
|
321
321
|
].join("\n");
|
|
322
322
|
}
|
|
323
|
-
|
|
324
|
-
|
|
323
|
+
var REVIEW_GATE_CONDITION = "steps.secret-gate.outputs.enabled == 'true' && steps.round-gate.outputs.allowed == 'true'";
|
|
324
|
+
function renderReviewPermissions(idToken) {
|
|
325
|
+
return ["permissions:", " contents: read", " pull-requests: write", ...idToken ? [" id-token: write"] : []].join("\n");
|
|
325
326
|
}
|
|
326
327
|
function renderCheckoutStep(gateCondition, extraWith = []) {
|
|
327
328
|
return [
|
|
328
329
|
"- name: Checkout repository",
|
|
329
|
-
` if: ${gateCondition}
|
|
330
|
+
...gateCondition === void 0 ? [] : [` if: ${gateCondition}`],
|
|
330
331
|
` uses: ${pinnedUses("actions/checkout")}`,
|
|
331
332
|
" with:",
|
|
332
333
|
...extraWith.map((line) => ` ${line}`),
|
|
@@ -368,10 +369,46 @@ function renderRoundGateStep(maxRounds) {
|
|
|
368
369
|
" fi"
|
|
369
370
|
].join("\n");
|
|
370
371
|
}
|
|
372
|
+
var JUDGE_CONDITION = "steps.ai-review-result.outputs.run == 'true'";
|
|
373
|
+
function renderAiReviewResultStep() {
|
|
374
|
+
return [
|
|
375
|
+
"- name: Check the AI review result",
|
|
376
|
+
" id: ai-review-result",
|
|
377
|
+
" env:",
|
|
378
|
+
" AI_REVIEW_RESULT: ${{ needs.ai-review.result }}",
|
|
379
|
+
" REVIEW_ENABLED: ${{ needs.ai-review.outputs.enabled }}",
|
|
380
|
+
" REVIEW_ALLOWED: ${{ needs.ai-review.outputs.allowed }}",
|
|
381
|
+
" LAST_COMMENT_ID: ${{ needs.ai-review.outputs.last-comment-id }}",
|
|
382
|
+
" run: |",
|
|
383
|
+
' if [ "$AI_REVIEW_RESULT" != success ]; then',
|
|
384
|
+
` echo "::error title=AI review did not succeed::The AI review job ended with '$AI_REVIEW_RESULT'."`,
|
|
385
|
+
" exit 1",
|
|
386
|
+
" fi",
|
|
387
|
+
' case "$REVIEW_ENABLED/$REVIEW_ALLOWED" in',
|
|
388
|
+
" false/* | true/false)",
|
|
389
|
+
' echo "The AI review did not run (no secret, or the round limit) - nothing to judge."',
|
|
390
|
+
' echo "run=false" >> "$GITHUB_OUTPUT"',
|
|
391
|
+
" exit 0",
|
|
392
|
+
" ;;",
|
|
393
|
+
" true/true)",
|
|
394
|
+
' case "$LAST_COMMENT_ID" in',
|
|
395
|
+
" '' | *[!0-9]*) ;;",
|
|
396
|
+
" *)",
|
|
397
|
+
' echo "run=true" >> "$GITHUB_OUTPUT"',
|
|
398
|
+
" exit 0",
|
|
399
|
+
" ;;",
|
|
400
|
+
" esac",
|
|
401
|
+
" ;;",
|
|
402
|
+
" esac",
|
|
403
|
+
` echo "::error title=Review verdict not computed::The AI review job's results did not reach this job, so no verdict can be computed. Re-run all jobs."`,
|
|
404
|
+
" exit 1"
|
|
405
|
+
].join("\n");
|
|
406
|
+
}
|
|
371
407
|
function renderVerdictGateStep(maxRounds, locale) {
|
|
372
408
|
return [
|
|
373
409
|
"- name: Compute review verdict",
|
|
374
|
-
"
|
|
410
|
+
" id: verdict",
|
|
411
|
+
` if: ${JUDGE_CONDITION}`,
|
|
375
412
|
" env:",
|
|
376
413
|
" GH_TOKEN: ${{ github.token }}",
|
|
377
414
|
" GITHUB_REPOSITORY: ${{ github.repository }}",
|
|
@@ -379,7 +416,8 @@ function renderVerdictGateStep(maxRounds, locale) {
|
|
|
379
416
|
` ARCHWEAVE_MAX_ROUNDS: '${maxRounds}'`,
|
|
380
417
|
` ARCHWEAVE_LOCALE: '${locale}'`,
|
|
381
418
|
" ARCHWEAVE_HEAD_SHA: ${{ github.event.pull_request.head.sha }}",
|
|
382
|
-
" ARCHWEAVE_ROUND_AFTER_ID: ${{
|
|
419
|
+
" ARCHWEAVE_ROUND_AFTER_ID: ${{ needs.ai-review.outputs.last-comment-id }}",
|
|
420
|
+
" ARCHWEAVE_VERDICT_OUTPUT: 'github-output'",
|
|
383
421
|
" run: |",
|
|
384
422
|
" if [ -x node_modules/.bin/archweave-review-verdict ]; then",
|
|
385
423
|
" node_modules/.bin/archweave-review-verdict",
|
|
@@ -388,16 +426,46 @@ function renderVerdictGateStep(maxRounds, locale) {
|
|
|
388
426
|
" fi"
|
|
389
427
|
].join("\n");
|
|
390
428
|
}
|
|
429
|
+
function renderBlockStep() {
|
|
430
|
+
return [
|
|
431
|
+
"- name: Fail on a blocking verdict",
|
|
432
|
+
" if: steps.verdict.outputs.blocked == 'true'",
|
|
433
|
+
" run: |",
|
|
434
|
+
' echo "The review verdict is BLOCK - see the verdict comment on this pull request."',
|
|
435
|
+
" exit 1"
|
|
436
|
+
].join("\n");
|
|
437
|
+
}
|
|
438
|
+
function renderVerdictCommentStep() {
|
|
439
|
+
return [
|
|
440
|
+
"- name: Post review verdict",
|
|
441
|
+
" env:",
|
|
442
|
+
" GH_TOKEN: ${{ github.token }}",
|
|
443
|
+
" REPOSITORY: ${{ github.repository }}",
|
|
444
|
+
" PR_NUMBER: ${{ github.event.pull_request.number }}",
|
|
445
|
+
" VERDICT_BODY: ${{ needs.review.outputs.comment-body }}",
|
|
446
|
+
" PREVIOUS_ID: ${{ needs.review.outputs.previous-comment-id }}",
|
|
447
|
+
" run: |",
|
|
448
|
+
` payload=$(jq -n --arg body "$VERDICT_BODY" '{body: $body}')`,
|
|
449
|
+
' case "$PREVIOUS_ID" in',
|
|
450
|
+
" ''|*[!0-9]*) PREVIOUS_ID= ;;",
|
|
451
|
+
" esac",
|
|
452
|
+
` if [ -n "$PREVIOUS_ID" ] && printf '%s' "$payload" | gh api -X PATCH "repos/$REPOSITORY/issues/comments/$PREVIOUS_ID" --input - > /dev/null; then`,
|
|
453
|
+
" exit 0",
|
|
454
|
+
" fi",
|
|
455
|
+
` printf '%s' "$payload" | gh api -X POST "repos/$REPOSITORY/issues/$PR_NUMBER/comments" --input - > /dev/null \\`,
|
|
456
|
+
' || echo "Could not post the verdict comment (continuing)."'
|
|
457
|
+
].join("\n");
|
|
458
|
+
}
|
|
391
459
|
var SETUP_NODE_VERSION = "22";
|
|
392
460
|
var FALLBACK_PNPM_VERSION = "10";
|
|
393
461
|
var INSTALL_LINES = {
|
|
394
|
-
pnpm: [" pnpm install --frozen-lockfile"],
|
|
395
|
-
npm: [" npm ci"],
|
|
462
|
+
pnpm: [" pnpm install --frozen-lockfile --ignore-scripts"],
|
|
463
|
+
npm: [" npm ci --ignore-scripts"],
|
|
396
464
|
yarn: [
|
|
397
465
|
" corepack enable yarn",
|
|
398
|
-
' if [ "$(yarn --version | cut -d. -f1)" -ge 2 ]; then yarn install --immutable; else yarn install --frozen-lockfile; fi'
|
|
466
|
+
' if [ "$(yarn --version | cut -d. -f1)" -ge 2 ]; then YARN_ENABLE_SCRIPTS=false yarn install --immutable --mode=skip-build; else yarn install --frozen-lockfile --ignore-scripts; fi'
|
|
399
467
|
],
|
|
400
|
-
bun: [" bun install --frozen-lockfile"]
|
|
468
|
+
bun: [" bun install --frozen-lockfile --ignore-scripts"]
|
|
401
469
|
};
|
|
402
470
|
function renderPnpmVersionStep(gate) {
|
|
403
471
|
return [
|
|
@@ -413,7 +481,7 @@ function renderPnpmVersionStep(gate) {
|
|
|
413
481
|
].join("\n");
|
|
414
482
|
}
|
|
415
483
|
function renderWorkspaceSetupSteps(packageManager) {
|
|
416
|
-
const gate =
|
|
484
|
+
const gate = ` if: ${JUDGE_CONDITION}`;
|
|
417
485
|
const steps = [];
|
|
418
486
|
if (packageManager === "pnpm") {
|
|
419
487
|
steps.push(renderPnpmVersionStep(gate));
|
|
@@ -448,6 +516,60 @@ function renderWorkspaceSetupSteps(packageManager) {
|
|
|
448
516
|
].join("\n"));
|
|
449
517
|
return steps.join("\n\n");
|
|
450
518
|
}
|
|
519
|
+
function renderReviewWorkflow(input, parts) {
|
|
520
|
+
const aiReviewSteps = [renderSecretGateStep(parts.secretName), renderRoundGateStep(input.maxRounds), ...parts.reviewSteps];
|
|
521
|
+
const reviewSteps = [
|
|
522
|
+
renderAiReviewResultStep(),
|
|
523
|
+
renderCheckoutStep(JUDGE_CONDITION),
|
|
524
|
+
renderWorkspaceSetupSteps(input.packageManager),
|
|
525
|
+
renderVerdictGateStep(input.maxRounds, input.locale),
|
|
526
|
+
renderBlockStep()
|
|
527
|
+
];
|
|
528
|
+
return [
|
|
529
|
+
`name: ${parts.name}`,
|
|
530
|
+
"",
|
|
531
|
+
renderTriggerBlock(),
|
|
532
|
+
"",
|
|
533
|
+
renderConcurrencyBlock(),
|
|
534
|
+
"",
|
|
535
|
+
"permissions: {}",
|
|
536
|
+
"",
|
|
537
|
+
"jobs:",
|
|
538
|
+
" ai-review:",
|
|
539
|
+
" runs-on: ubuntu-latest",
|
|
540
|
+
indentBlock(renderReviewPermissions(parts.idToken), 4),
|
|
541
|
+
" outputs:",
|
|
542
|
+
" enabled: ${{ steps.secret-gate.outputs.enabled }}",
|
|
543
|
+
" allowed: ${{ steps.round-gate.outputs.allowed }}",
|
|
544
|
+
" last-comment-id: ${{ steps.round-gate.outputs.last-comment-id }}",
|
|
545
|
+
" steps:",
|
|
546
|
+
indentBlock(aiReviewSteps.join("\n\n"), 6),
|
|
547
|
+
"",
|
|
548
|
+
" review:",
|
|
549
|
+
" needs: ai-review",
|
|
550
|
+
" if: always()",
|
|
551
|
+
" runs-on: ubuntu-latest",
|
|
552
|
+
" permissions:",
|
|
553
|
+
" contents: read",
|
|
554
|
+
" pull-requests: read",
|
|
555
|
+
" outputs:",
|
|
556
|
+
" comment-body: ${{ steps.verdict.outputs.comment-body }}",
|
|
557
|
+
" previous-comment-id: ${{ steps.verdict.outputs.previous-comment-id }}",
|
|
558
|
+
" steps:",
|
|
559
|
+
indentBlock(reviewSteps.join("\n\n"), 6),
|
|
560
|
+
"",
|
|
561
|
+
" review-comment:",
|
|
562
|
+
" needs: review",
|
|
563
|
+
// Runs after a BLOCK failed the review job, too: the comment explains the red check.
|
|
564
|
+
" if: ${{ !cancelled() && needs.review.outputs.comment-body != '' }}",
|
|
565
|
+
" runs-on: ubuntu-latest",
|
|
566
|
+
" permissions:",
|
|
567
|
+
" pull-requests: write",
|
|
568
|
+
" steps:",
|
|
569
|
+
indentBlock(renderVerdictCommentStep(), 6),
|
|
570
|
+
""
|
|
571
|
+
].join("\n");
|
|
572
|
+
}
|
|
451
573
|
|
|
452
574
|
// ../template-engine/dist/review/claude/claude-provider.js
|
|
453
575
|
var SECRET_NAME = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
@@ -480,40 +602,26 @@ function composePrompt(input) {
|
|
|
480
602
|
return sections.join("\n\n---\n\n");
|
|
481
603
|
}
|
|
482
604
|
function buildWorkflowYaml(input) {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
"",
|
|
504
|
-
renderTriggerBlock(),
|
|
505
|
-
"",
|
|
506
|
-
renderConcurrencyBlock(),
|
|
507
|
-
"",
|
|
508
|
-
renderPermissionsBlock(),
|
|
509
|
-
"",
|
|
510
|
-
"jobs:",
|
|
511
|
-
" review:",
|
|
512
|
-
" runs-on: ubuntu-latest",
|
|
513
|
-
" steps:",
|
|
514
|
-
indentBlock(steps.join("\n\n"), 6),
|
|
515
|
-
""
|
|
516
|
-
].join("\n");
|
|
605
|
+
return renderReviewWorkflow(input, {
|
|
606
|
+
name: "Claude Code Review",
|
|
607
|
+
secretName: SECRET_NAME,
|
|
608
|
+
// The Claude GitHub App signs in with the workflow's OIDC token (claude-code-action's FAQ).
|
|
609
|
+
idToken: true,
|
|
610
|
+
reviewSteps: [
|
|
611
|
+
renderCheckoutStep(REVIEW_GATE_CONDITION),
|
|
612
|
+
[
|
|
613
|
+
"- name: Run Claude review",
|
|
614
|
+
` if: ${REVIEW_GATE_CONDITION}`,
|
|
615
|
+
` uses: ${pinnedUses("anthropics/claude-code-action")}`,
|
|
616
|
+
" with:",
|
|
617
|
+
` claude_code_oauth_token: \${{ secrets.${SECRET_NAME} }}`,
|
|
618
|
+
" prompt: |",
|
|
619
|
+
indentBlock(composePrompt(input), 6),
|
|
620
|
+
" claude_args: |",
|
|
621
|
+
` --allowedTools "${ALLOWED_TOOLS}"`
|
|
622
|
+
].join("\n")
|
|
623
|
+
]
|
|
624
|
+
});
|
|
517
625
|
}
|
|
518
626
|
var claudeProvider = {
|
|
519
627
|
id: "claude",
|
|
@@ -553,49 +661,39 @@ function composePrompt2(input) {
|
|
|
553
661
|
return sections.join("\n\n---\n\n");
|
|
554
662
|
}
|
|
555
663
|
function buildWorkflowYaml2(input) {
|
|
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
|
-
renderPermissionsBlock(),
|
|
591
|
-
"",
|
|
592
|
-
"jobs:",
|
|
593
|
-
" review:",
|
|
594
|
-
" runs-on: ubuntu-latest",
|
|
595
|
-
" steps:",
|
|
596
|
-
indentBlock(steps.join("\n\n"), 6),
|
|
597
|
-
""
|
|
598
|
-
].join("\n");
|
|
664
|
+
return renderReviewWorkflow(input, {
|
|
665
|
+
name: "Cursor Code Review",
|
|
666
|
+
secretName: SECRET_NAME2,
|
|
667
|
+
// An API key: the Cursor CLI needs no OIDC token.
|
|
668
|
+
idToken: false,
|
|
669
|
+
reviewSteps: [
|
|
670
|
+
renderCheckoutStep(REVIEW_GATE_CONDITION),
|
|
671
|
+
[
|
|
672
|
+
"- name: Install cursor-agent CLI",
|
|
673
|
+
` if: ${REVIEW_GATE_CONDITION}`,
|
|
674
|
+
" run: |",
|
|
675
|
+
// HTTPS only, TLS 1.2 or newer. Cursor publishes no pinned version or checksum for
|
|
676
|
+
// this installer; docs/pr-review.md states what that leaves open.
|
|
677
|
+
" curl --proto '=https' --tlsv1.2 -fsS https://cursor.com/install | bash",
|
|
678
|
+
// The docs name ~/.cursor/bin; the installer currently links `agent` into ~/.local/bin.
|
|
679
|
+
// Both go on the PATH, so the next step finds it wherever the installer puts it.
|
|
680
|
+
' echo "$HOME/.local/bin" >> "$GITHUB_PATH"',
|
|
681
|
+
' echo "$HOME/.cursor/bin" >> "$GITHUB_PATH"'
|
|
682
|
+
].join("\n"),
|
|
683
|
+
[
|
|
684
|
+
"- name: Run Cursor review",
|
|
685
|
+
` if: ${REVIEW_GATE_CONDITION}`,
|
|
686
|
+
" env:",
|
|
687
|
+
` CURSOR_API_KEY: \${{ secrets.${SECRET_NAME2} }}`,
|
|
688
|
+
" GH_TOKEN: ${{ github.token }}",
|
|
689
|
+
" run: |",
|
|
690
|
+
` agent -p "$(cat <<'${PROMPT_HEREDOC_DELIMITER}'`,
|
|
691
|
+
indentBlock(composePrompt2(input), 4),
|
|
692
|
+
` ${PROMPT_HEREDOC_DELIMITER}`,
|
|
693
|
+
' )"'
|
|
694
|
+
].join("\n")
|
|
695
|
+
]
|
|
696
|
+
});
|
|
599
697
|
}
|
|
600
698
|
var cursorProvider = {
|
|
601
699
|
id: "cursor",
|
|
@@ -634,40 +732,26 @@ function composePrompt3(input) {
|
|
|
634
732
|
return sections.join("\n\n---\n\n");
|
|
635
733
|
}
|
|
636
734
|
function buildWorkflowYaml3(input) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
"",
|
|
658
|
-
renderTriggerBlock(),
|
|
659
|
-
"",
|
|
660
|
-
renderConcurrencyBlock(),
|
|
661
|
-
"",
|
|
662
|
-
renderPermissionsBlock(),
|
|
663
|
-
"",
|
|
664
|
-
"jobs:",
|
|
665
|
-
" review:",
|
|
666
|
-
" runs-on: ubuntu-latest",
|
|
667
|
-
" steps:",
|
|
668
|
-
indentBlock(steps.join("\n\n"), 6),
|
|
669
|
-
""
|
|
670
|
-
].join("\n");
|
|
735
|
+
return renderReviewWorkflow(input, {
|
|
736
|
+
name: "Gemini Code Review",
|
|
737
|
+
secretName: SECRET_NAME3,
|
|
738
|
+
// An API key: run-gemini-cli uses OIDC only for Google Cloud workload identity federation.
|
|
739
|
+
idToken: false,
|
|
740
|
+
reviewSteps: [
|
|
741
|
+
renderCheckoutStep(REVIEW_GATE_CONDITION),
|
|
742
|
+
[
|
|
743
|
+
"- name: Run Gemini review",
|
|
744
|
+
` if: ${REVIEW_GATE_CONDITION}`,
|
|
745
|
+
` uses: ${pinnedUses("google-github-actions/run-gemini-cli")}`,
|
|
746
|
+
" env:",
|
|
747
|
+
" GITHUB_TOKEN: ${{ github.token }}",
|
|
748
|
+
" with:",
|
|
749
|
+
` gemini_api_key: \${{ secrets.${SECRET_NAME3} }}`,
|
|
750
|
+
" prompt: |",
|
|
751
|
+
indentBlock(composePrompt3(input), 6)
|
|
752
|
+
].join("\n")
|
|
753
|
+
]
|
|
754
|
+
});
|
|
671
755
|
}
|
|
672
756
|
var geminiProvider = {
|
|
673
757
|
id: "gemini",
|
|
@@ -706,64 +790,49 @@ function composePrompt4(input) {
|
|
|
706
790
|
return sections.join("\n\n---\n\n");
|
|
707
791
|
}
|
|
708
792
|
function buildWorkflowYaml4(input) {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
[
|
|
715
|
-
"
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
"
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
"
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
"name: GPT Code Review",
|
|
753
|
-
"",
|
|
754
|
-
renderTriggerBlock(),
|
|
755
|
-
"",
|
|
756
|
-
renderConcurrencyBlock(),
|
|
757
|
-
"",
|
|
758
|
-
renderPermissionsBlock(),
|
|
759
|
-
"",
|
|
760
|
-
"jobs:",
|
|
761
|
-
" review:",
|
|
762
|
-
" runs-on: ubuntu-latest",
|
|
763
|
-
" steps:",
|
|
764
|
-
indentBlock(steps.join("\n\n"), 6),
|
|
765
|
-
""
|
|
766
|
-
].join("\n");
|
|
793
|
+
return renderReviewWorkflow(input, {
|
|
794
|
+
name: "GPT Code Review",
|
|
795
|
+
secretName: SECRET_NAME4,
|
|
796
|
+
// An API key: codex-action needs no OIDC token.
|
|
797
|
+
idToken: false,
|
|
798
|
+
reviewSteps: [
|
|
799
|
+
renderCheckoutStep(REVIEW_GATE_CONDITION, ["ref: refs/pull/${{ github.event.pull_request.number }}/merge"]),
|
|
800
|
+
[
|
|
801
|
+
"- name: Fetch base and head refs for the PR",
|
|
802
|
+
` if: ${REVIEW_GATE_CONDITION}`,
|
|
803
|
+
" env:",
|
|
804
|
+
" PR_BASE_REF: ${{ github.event.pull_request.base.ref }}",
|
|
805
|
+
" PR_NUMBER: ${{ github.event.pull_request.number }}",
|
|
806
|
+
" run: |",
|
|
807
|
+
" # Explicit destinations: the sandboxed review step has no network, so both sides",
|
|
808
|
+
" # of the diff must survive as stable local refs (FETCH_HEAD alone is ambiguous).",
|
|
809
|
+
" git fetch --no-tags origin \\",
|
|
810
|
+
' "+refs/heads/$PR_BASE_REF:refs/remotes/origin/pr-base" \\',
|
|
811
|
+
' "+refs/pull/$PR_NUMBER/head:refs/remotes/origin/pr-head"'
|
|
812
|
+
].join("\n"),
|
|
813
|
+
[
|
|
814
|
+
"- name: Run Codex review",
|
|
815
|
+
" id: codex-review",
|
|
816
|
+
` if: ${REVIEW_GATE_CONDITION}`,
|
|
817
|
+
` uses: ${pinnedUses("openai/codex-action")}`,
|
|
818
|
+
" with:",
|
|
819
|
+
` openai-api-key: \${{ secrets.${SECRET_NAME4} }}`,
|
|
820
|
+
' permission-profile: ":read-only"',
|
|
821
|
+
" prompt: |",
|
|
822
|
+
indentBlock(composePrompt4(input), 6)
|
|
823
|
+
].join("\n"),
|
|
824
|
+
[
|
|
825
|
+
"- name: Post review comment",
|
|
826
|
+
` if: ${REVIEW_GATE_CONDITION}`,
|
|
827
|
+
" env:",
|
|
828
|
+
" GH_TOKEN: ${{ github.token }}",
|
|
829
|
+
" PR_NUMBER: ${{ github.event.pull_request.number }}",
|
|
830
|
+
" REVIEW_BODY: ${{ steps.codex-review.outputs.final-message }}",
|
|
831
|
+
" run: |",
|
|
832
|
+
' printf %s "$REVIEW_BODY" | gh pr comment "$PR_NUMBER" --body-file -'
|
|
833
|
+
].join("\n")
|
|
834
|
+
]
|
|
835
|
+
});
|
|
767
836
|
}
|
|
768
837
|
var gptProvider = {
|
|
769
838
|
id: "gpt",
|
|
@@ -1038,13 +1107,14 @@ function buildReviewConfigConsistencyCheck(root, mainWorkflowPath, mainExists, c
|
|
|
1038
1107
|
evidence: [mainWorkflowPath, CONFIG_PATH]
|
|
1039
1108
|
});
|
|
1040
1109
|
}
|
|
1110
|
+
const earlierVersion = !/^ {2}review-comment:$/m.test(workflowContent);
|
|
1041
1111
|
return createDoctorCheck({
|
|
1042
1112
|
id: "review-config-consistency",
|
|
1043
1113
|
label: "Review config/workflow consistency",
|
|
1044
1114
|
status: "warning",
|
|
1045
|
-
message: `${mainWorkflowPath} differs from what ${CONFIG_PATH}'s review options would generate`,
|
|
1115
|
+
message: earlierVersion ? `${mainWorkflowPath} was generated by an earlier nx-archweave version: it installs dependencies in the job that holds the provider secret` : `${mainWorkflowPath} differs from what ${CONFIG_PATH}'s review options would generate`,
|
|
1046
1116
|
evidence: [mainWorkflowPath, CONFIG_PATH],
|
|
1047
|
-
suggestedAction: `Re-run the add-review generator with --onConflict=overwrite to re-sync ${mainWorkflowPath} with ${CONFIG_PATH}, or update ${CONFIG_PATH} to match the installed file.`
|
|
1117
|
+
suggestedAction: earlierVersion ? `Re-run add-review --onConflict=overwrite to regenerate ${mainWorkflowPath}: the verdict then runs in a job without the secret, an OIDC token or install scripts. Edits you made to the file are replaced; the report shows the difference first.` : `Re-run the add-review generator with --onConflict=overwrite to re-sync ${mainWorkflowPath} with ${CONFIG_PATH}, or update ${CONFIG_PATH} to match the installed file.`
|
|
1048
1118
|
});
|
|
1049
1119
|
}
|
|
1050
1120
|
|