donobu 5.37.0 → 5.37.1
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/cli/donobu-cli.js +34 -0
- package/dist/codegen/CodeGenerator.js +10 -6
- package/dist/envVars.d.ts +20 -0
- package/dist/envVars.js +40 -0
- package/dist/esm/cli/donobu-cli.js +34 -0
- package/dist/esm/codegen/CodeGenerator.js +10 -6
- package/dist/esm/envVars.d.ts +20 -0
- package/dist/esm/envVars.js +40 -0
- package/dist/esm/reporter/renderPullRequestBody.d.ts +16 -0
- package/dist/esm/reporter/renderPullRequestBody.js +89 -0
- package/dist/reporter/renderPullRequestBody.d.ts +16 -0
- package/dist/reporter/renderPullRequestBody.js +89 -0
- package/package.json +1 -1
package/dist/cli/donobu-cli.js
CHANGED
|
@@ -68,6 +68,7 @@ const merge_1 = require("../reporter/merge");
|
|
|
68
68
|
const model_1 = require("../reporter/model");
|
|
69
69
|
const render_1 = require("../reporter/render");
|
|
70
70
|
const renderMarkdown_1 = require("../reporter/renderMarkdown");
|
|
71
|
+
const renderPullRequestBody_1 = require("../reporter/renderPullRequestBody");
|
|
71
72
|
const renderSlack_1 = require("../reporter/renderSlack");
|
|
72
73
|
const slack_1 = require("../reporter/slack");
|
|
73
74
|
const Logger_1 = require("../utils/Logger");
|
|
@@ -1404,6 +1405,7 @@ async function attemptAutoHealRun(params) {
|
|
|
1404
1405
|
}
|
|
1405
1406
|
if (mergedReport) {
|
|
1406
1407
|
await regenerateDonobuReports(mergedReport);
|
|
1408
|
+
await writeAutoHealPullRequestBody(mergedReport, params.playwrightOutputDir);
|
|
1407
1409
|
}
|
|
1408
1410
|
}
|
|
1409
1411
|
}
|
|
@@ -1412,6 +1414,38 @@ async function attemptAutoHealRun(params) {
|
|
|
1412
1414
|
}
|
|
1413
1415
|
return { attempted: true, exitCode: healExitCode };
|
|
1414
1416
|
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Filename of the auto-heal PR body artifact. Lands in the Playwright output
|
|
1419
|
+
* directory alongside the merged JSON / HTML / Markdown reports so the
|
|
1420
|
+
* generated GitHub Actions workflow can find it at a stable, well-known path
|
|
1421
|
+
* when preparing the self-healing pull request body.
|
|
1422
|
+
*/
|
|
1423
|
+
const AUTO_HEAL_PR_BODY_FILENAME = 'auto-heal-pr-body.md';
|
|
1424
|
+
/**
|
|
1425
|
+
* Emit a PR-shaped markdown body when auto-heal applied fixes. The generated
|
|
1426
|
+
* GitHub Actions workflow points peter-evans/create-pull-request at this file
|
|
1427
|
+
* via `body-path:`, so all PR-body composition (heading, healed list,
|
|
1428
|
+
* reviewer checklist, workflow-run footer) lives here rather than in
|
|
1429
|
+
* customer-facing YAML. Skipped when no tests were healed; peter-evans is
|
|
1430
|
+
* gated by `hashFiles()` in that case so it won't try to read a missing file.
|
|
1431
|
+
* Failures are logged but never surfaced — a missing PR body should not block
|
|
1432
|
+
* the heal run from exiting cleanly.
|
|
1433
|
+
*/
|
|
1434
|
+
async function writeAutoHealPullRequestBody(mergedReport, playwrightOutputDir) {
|
|
1435
|
+
try {
|
|
1436
|
+
const body = (0, renderPullRequestBody_1.renderPullRequestBody)(mergedReport);
|
|
1437
|
+
if (!body) {
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
await fs_1.promises.mkdir(playwrightOutputDir, { recursive: true });
|
|
1441
|
+
const outputFile = path.join(playwrightOutputDir, AUTO_HEAL_PR_BODY_FILENAME);
|
|
1442
|
+
await fs_1.promises.writeFile(outputFile, body, 'utf8');
|
|
1443
|
+
Logger_1.appLogger.info(`Donobu auto-heal PR body written to: ${outputFile}`);
|
|
1444
|
+
}
|
|
1445
|
+
catch (error) {
|
|
1446
|
+
Logger_1.appLogger.warn('Failed to write Donobu auto-heal PR body.', error);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1415
1449
|
/**
|
|
1416
1450
|
* Copy attachment files that live in a temporary directory (e.g. the auto-heal
|
|
1417
1451
|
* staging area) into the persistent output directory and rewrite the paths in
|
|
@@ -429,17 +429,21 @@ on:
|
|
|
429
429
|
const pullRequestCreationSection = options.disablePullRequestCreation
|
|
430
430
|
? ''
|
|
431
431
|
: `
|
|
432
|
-
#
|
|
432
|
+
# Open a self-healing PR with whatever auto-heal changed. Donobu writes
|
|
433
|
+
# the PR body to test-results/auto-heal-pr-body.md when it heals tests;
|
|
434
|
+
# the hashFiles() guard skips PR creation when no body is present.
|
|
433
435
|
- name: Create Pull Request for Test Fixes (if any)
|
|
434
|
-
if: \${{ github.event_name != 'pull_request' }}
|
|
436
|
+
if: \${{ github.event_name != 'pull_request' && hashFiles('test-results/auto-heal-pr-body.md') }}
|
|
435
437
|
uses: peter-evans/create-pull-request@v8
|
|
436
438
|
with:
|
|
437
439
|
token: \${{ secrets.GITHUB_TOKEN }}
|
|
438
|
-
commit-message: "
|
|
439
|
-
title: "
|
|
440
|
-
body:
|
|
440
|
+
commit-message: "Donobu auto-heal: fix failing tests"
|
|
441
|
+
title: "Donobu auto-heal: Test fixes for \${{ github.ref_name }}"
|
|
442
|
+
body-path: test-results/auto-heal-pr-body.md
|
|
441
443
|
branch: fix-playwright-tests-for-\${{ github.ref_name }}
|
|
442
|
-
base: \${{ github.ref_name }}
|
|
444
|
+
base: \${{ github.ref_name }}
|
|
445
|
+
labels: donobu, auto-heal
|
|
446
|
+
delete-branch: true`;
|
|
443
447
|
return `name: Run Playwright Tests
|
|
444
448
|
${triggerSection}
|
|
445
449
|
|
package/dist/envVars.d.ts
CHANGED
|
@@ -42,6 +42,16 @@ export declare const env: Env<{
|
|
|
42
42
|
DONOBU_REPORT_URL: z.ZodOptional<z.ZodString>;
|
|
43
43
|
DONOBU_SLACK_WEBHOOK_URL: z.ZodOptional<z.ZodString>;
|
|
44
44
|
GITHUB_STEP_SUMMARY: z.ZodOptional<z.ZodString>;
|
|
45
|
+
GITHUB_RUN_ID: z.ZodOptional<z.ZodString>;
|
|
46
|
+
GITHUB_RUN_NUMBER: z.ZodOptional<z.ZodString>;
|
|
47
|
+
GITHUB_SERVER_URL: z.ZodOptional<z.ZodString>;
|
|
48
|
+
GITHUB_REPOSITORY: z.ZodOptional<z.ZodString>;
|
|
49
|
+
GITHUB_ACTOR: z.ZodOptional<z.ZodString>;
|
|
50
|
+
GITHUB_REF_NAME: z.ZodOptional<z.ZodString>;
|
|
51
|
+
CI_PIPELINE_URL: z.ZodOptional<z.ZodString>;
|
|
52
|
+
CI_PIPELINE_IID: z.ZodOptional<z.ZodString>;
|
|
53
|
+
GITLAB_USER_LOGIN: z.ZodOptional<z.ZodString>;
|
|
54
|
+
CI_COMMIT_REF_NAME: z.ZodOptional<z.ZodString>;
|
|
45
55
|
PLAYWRIGHT_JSON_OUTPUT_DIR: z.ZodOptional<z.ZodString>;
|
|
46
56
|
DONOBU_PAGE_AI_CLEAR_CACHE: z.ZodOptional<z.ZodEnum<{
|
|
47
57
|
0: "0";
|
|
@@ -92,6 +102,16 @@ export declare const env: Env<{
|
|
|
92
102
|
DONOBU_REPORT_URL?: string | undefined;
|
|
93
103
|
DONOBU_SLACK_WEBHOOK_URL?: string | undefined;
|
|
94
104
|
GITHUB_STEP_SUMMARY?: string | undefined;
|
|
105
|
+
GITHUB_RUN_ID?: string | undefined;
|
|
106
|
+
GITHUB_RUN_NUMBER?: string | undefined;
|
|
107
|
+
GITHUB_SERVER_URL?: string | undefined;
|
|
108
|
+
GITHUB_REPOSITORY?: string | undefined;
|
|
109
|
+
GITHUB_ACTOR?: string | undefined;
|
|
110
|
+
GITHUB_REF_NAME?: string | undefined;
|
|
111
|
+
CI_PIPELINE_URL?: string | undefined;
|
|
112
|
+
CI_PIPELINE_IID?: string | undefined;
|
|
113
|
+
GITLAB_USER_LOGIN?: string | undefined;
|
|
114
|
+
CI_COMMIT_REF_NAME?: string | undefined;
|
|
95
115
|
PLAYWRIGHT_JSON_OUTPUT_DIR?: string | undefined;
|
|
96
116
|
DONOBU_PAGE_AI_CLEAR_CACHE?: "0" | "1" | "true" | "false" | undefined;
|
|
97
117
|
GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
|
package/dist/envVars.js
CHANGED
|
@@ -79,6 +79,46 @@ network call.`),
|
|
|
79
79
|
.describe(`Set by the GitHub Actions runner to the path of a per-step Markdown file. Anything
|
|
80
80
|
written here is concatenated into the workflow run's job summary. The Donobu Markdown reporter writes
|
|
81
81
|
to this automatically when running inside a GHA step so no separate workflow step is needed.`),
|
|
82
|
+
GITHUB_RUN_ID: v4_1.z
|
|
83
|
+
.string()
|
|
84
|
+
.optional()
|
|
85
|
+
.describe(`Set by the GitHub Actions runner. Used by the auto-heal PR body footer to link back to the workflow run that produced the heal.`),
|
|
86
|
+
GITHUB_RUN_NUMBER: v4_1.z
|
|
87
|
+
.string()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as a human-friendly run number.`),
|
|
90
|
+
GITHUB_SERVER_URL: v4_1.z
|
|
91
|
+
.string()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe(`Set by the GitHub Actions runner (e.g. https://github.com). Combined with GITHUB_REPOSITORY and GITHUB_RUN_ID to build the auto-heal PR body footer link.`),
|
|
94
|
+
GITHUB_REPOSITORY: v4_1.z
|
|
95
|
+
.string()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe(`Set by the GitHub Actions runner (owner/repo). Used by the auto-heal PR body footer link.`),
|
|
98
|
+
GITHUB_ACTOR: v4_1.z
|
|
99
|
+
.string()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as the user who triggered the run.`),
|
|
102
|
+
GITHUB_REF_NAME: v4_1.z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as the source branch.`),
|
|
106
|
+
CI_PIPELINE_URL: v4_1.z
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe(`Set by the GitLab CI runner. Used by the auto-heal MR body footer to link back to the pipeline that produced the heal.`),
|
|
110
|
+
CI_PIPELINE_IID: v4_1.z
|
|
111
|
+
.string()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe(`Set by the GitLab CI runner — the per-project pipeline number GitLab shows in its UI. Embedded in the auto-heal MR body footer.`),
|
|
114
|
+
GITLAB_USER_LOGIN: v4_1.z
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe(`Set by the GitLab CI runner. Embedded in the auto-heal MR body footer as the user who triggered the pipeline.`),
|
|
118
|
+
CI_COMMIT_REF_NAME: v4_1.z
|
|
119
|
+
.string()
|
|
120
|
+
.optional()
|
|
121
|
+
.describe(`Set by the GitLab CI runner. Embedded in the auto-heal MR body footer as the source branch.`),
|
|
82
122
|
PLAYWRIGHT_JSON_OUTPUT_DIR: v4_1.z.string().optional()
|
|
83
123
|
.describe(`Directory where the Playwright JSON reporter writes its output (and where the Donobu
|
|
84
124
|
reporters merge their per-reporter state into a shared sidecar so the auto-heal orchestrator can
|
|
@@ -68,6 +68,7 @@ const merge_1 = require("../reporter/merge");
|
|
|
68
68
|
const model_1 = require("../reporter/model");
|
|
69
69
|
const render_1 = require("../reporter/render");
|
|
70
70
|
const renderMarkdown_1 = require("../reporter/renderMarkdown");
|
|
71
|
+
const renderPullRequestBody_1 = require("../reporter/renderPullRequestBody");
|
|
71
72
|
const renderSlack_1 = require("../reporter/renderSlack");
|
|
72
73
|
const slack_1 = require("../reporter/slack");
|
|
73
74
|
const Logger_1 = require("../utils/Logger");
|
|
@@ -1404,6 +1405,7 @@ async function attemptAutoHealRun(params) {
|
|
|
1404
1405
|
}
|
|
1405
1406
|
if (mergedReport) {
|
|
1406
1407
|
await regenerateDonobuReports(mergedReport);
|
|
1408
|
+
await writeAutoHealPullRequestBody(mergedReport, params.playwrightOutputDir);
|
|
1407
1409
|
}
|
|
1408
1410
|
}
|
|
1409
1411
|
}
|
|
@@ -1412,6 +1414,38 @@ async function attemptAutoHealRun(params) {
|
|
|
1412
1414
|
}
|
|
1413
1415
|
return { attempted: true, exitCode: healExitCode };
|
|
1414
1416
|
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Filename of the auto-heal PR body artifact. Lands in the Playwright output
|
|
1419
|
+
* directory alongside the merged JSON / HTML / Markdown reports so the
|
|
1420
|
+
* generated GitHub Actions workflow can find it at a stable, well-known path
|
|
1421
|
+
* when preparing the self-healing pull request body.
|
|
1422
|
+
*/
|
|
1423
|
+
const AUTO_HEAL_PR_BODY_FILENAME = 'auto-heal-pr-body.md';
|
|
1424
|
+
/**
|
|
1425
|
+
* Emit a PR-shaped markdown body when auto-heal applied fixes. The generated
|
|
1426
|
+
* GitHub Actions workflow points peter-evans/create-pull-request at this file
|
|
1427
|
+
* via `body-path:`, so all PR-body composition (heading, healed list,
|
|
1428
|
+
* reviewer checklist, workflow-run footer) lives here rather than in
|
|
1429
|
+
* customer-facing YAML. Skipped when no tests were healed; peter-evans is
|
|
1430
|
+
* gated by `hashFiles()` in that case so it won't try to read a missing file.
|
|
1431
|
+
* Failures are logged but never surfaced — a missing PR body should not block
|
|
1432
|
+
* the heal run from exiting cleanly.
|
|
1433
|
+
*/
|
|
1434
|
+
async function writeAutoHealPullRequestBody(mergedReport, playwrightOutputDir) {
|
|
1435
|
+
try {
|
|
1436
|
+
const body = (0, renderPullRequestBody_1.renderPullRequestBody)(mergedReport);
|
|
1437
|
+
if (!body) {
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
await fs_1.promises.mkdir(playwrightOutputDir, { recursive: true });
|
|
1441
|
+
const outputFile = path.join(playwrightOutputDir, AUTO_HEAL_PR_BODY_FILENAME);
|
|
1442
|
+
await fs_1.promises.writeFile(outputFile, body, 'utf8');
|
|
1443
|
+
Logger_1.appLogger.info(`Donobu auto-heal PR body written to: ${outputFile}`);
|
|
1444
|
+
}
|
|
1445
|
+
catch (error) {
|
|
1446
|
+
Logger_1.appLogger.warn('Failed to write Donobu auto-heal PR body.', error);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1415
1449
|
/**
|
|
1416
1450
|
* Copy attachment files that live in a temporary directory (e.g. the auto-heal
|
|
1417
1451
|
* staging area) into the persistent output directory and rewrite the paths in
|
|
@@ -429,17 +429,21 @@ on:
|
|
|
429
429
|
const pullRequestCreationSection = options.disablePullRequestCreation
|
|
430
430
|
? ''
|
|
431
431
|
: `
|
|
432
|
-
#
|
|
432
|
+
# Open a self-healing PR with whatever auto-heal changed. Donobu writes
|
|
433
|
+
# the PR body to test-results/auto-heal-pr-body.md when it heals tests;
|
|
434
|
+
# the hashFiles() guard skips PR creation when no body is present.
|
|
433
435
|
- name: Create Pull Request for Test Fixes (if any)
|
|
434
|
-
if: \${{ github.event_name != 'pull_request' }}
|
|
436
|
+
if: \${{ github.event_name != 'pull_request' && hashFiles('test-results/auto-heal-pr-body.md') }}
|
|
435
437
|
uses: peter-evans/create-pull-request@v8
|
|
436
438
|
with:
|
|
437
439
|
token: \${{ secrets.GITHUB_TOKEN }}
|
|
438
|
-
commit-message: "
|
|
439
|
-
title: "
|
|
440
|
-
body:
|
|
440
|
+
commit-message: "Donobu auto-heal: fix failing tests"
|
|
441
|
+
title: "Donobu auto-heal: Test fixes for \${{ github.ref_name }}"
|
|
442
|
+
body-path: test-results/auto-heal-pr-body.md
|
|
441
443
|
branch: fix-playwright-tests-for-\${{ github.ref_name }}
|
|
442
|
-
base: \${{ github.ref_name }}
|
|
444
|
+
base: \${{ github.ref_name }}
|
|
445
|
+
labels: donobu, auto-heal
|
|
446
|
+
delete-branch: true`;
|
|
443
447
|
return `name: Run Playwright Tests
|
|
444
448
|
${triggerSection}
|
|
445
449
|
|
package/dist/esm/envVars.d.ts
CHANGED
|
@@ -42,6 +42,16 @@ export declare const env: Env<{
|
|
|
42
42
|
DONOBU_REPORT_URL: z.ZodOptional<z.ZodString>;
|
|
43
43
|
DONOBU_SLACK_WEBHOOK_URL: z.ZodOptional<z.ZodString>;
|
|
44
44
|
GITHUB_STEP_SUMMARY: z.ZodOptional<z.ZodString>;
|
|
45
|
+
GITHUB_RUN_ID: z.ZodOptional<z.ZodString>;
|
|
46
|
+
GITHUB_RUN_NUMBER: z.ZodOptional<z.ZodString>;
|
|
47
|
+
GITHUB_SERVER_URL: z.ZodOptional<z.ZodString>;
|
|
48
|
+
GITHUB_REPOSITORY: z.ZodOptional<z.ZodString>;
|
|
49
|
+
GITHUB_ACTOR: z.ZodOptional<z.ZodString>;
|
|
50
|
+
GITHUB_REF_NAME: z.ZodOptional<z.ZodString>;
|
|
51
|
+
CI_PIPELINE_URL: z.ZodOptional<z.ZodString>;
|
|
52
|
+
CI_PIPELINE_IID: z.ZodOptional<z.ZodString>;
|
|
53
|
+
GITLAB_USER_LOGIN: z.ZodOptional<z.ZodString>;
|
|
54
|
+
CI_COMMIT_REF_NAME: z.ZodOptional<z.ZodString>;
|
|
45
55
|
PLAYWRIGHT_JSON_OUTPUT_DIR: z.ZodOptional<z.ZodString>;
|
|
46
56
|
DONOBU_PAGE_AI_CLEAR_CACHE: z.ZodOptional<z.ZodEnum<{
|
|
47
57
|
0: "0";
|
|
@@ -92,6 +102,16 @@ export declare const env: Env<{
|
|
|
92
102
|
DONOBU_REPORT_URL?: string | undefined;
|
|
93
103
|
DONOBU_SLACK_WEBHOOK_URL?: string | undefined;
|
|
94
104
|
GITHUB_STEP_SUMMARY?: string | undefined;
|
|
105
|
+
GITHUB_RUN_ID?: string | undefined;
|
|
106
|
+
GITHUB_RUN_NUMBER?: string | undefined;
|
|
107
|
+
GITHUB_SERVER_URL?: string | undefined;
|
|
108
|
+
GITHUB_REPOSITORY?: string | undefined;
|
|
109
|
+
GITHUB_ACTOR?: string | undefined;
|
|
110
|
+
GITHUB_REF_NAME?: string | undefined;
|
|
111
|
+
CI_PIPELINE_URL?: string | undefined;
|
|
112
|
+
CI_PIPELINE_IID?: string | undefined;
|
|
113
|
+
GITLAB_USER_LOGIN?: string | undefined;
|
|
114
|
+
CI_COMMIT_REF_NAME?: string | undefined;
|
|
95
115
|
PLAYWRIGHT_JSON_OUTPUT_DIR?: string | undefined;
|
|
96
116
|
DONOBU_PAGE_AI_CLEAR_CACHE?: "0" | "1" | "true" | "false" | undefined;
|
|
97
117
|
GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
|
package/dist/esm/envVars.js
CHANGED
|
@@ -79,6 +79,46 @@ network call.`),
|
|
|
79
79
|
.describe(`Set by the GitHub Actions runner to the path of a per-step Markdown file. Anything
|
|
80
80
|
written here is concatenated into the workflow run's job summary. The Donobu Markdown reporter writes
|
|
81
81
|
to this automatically when running inside a GHA step so no separate workflow step is needed.`),
|
|
82
|
+
GITHUB_RUN_ID: v4_1.z
|
|
83
|
+
.string()
|
|
84
|
+
.optional()
|
|
85
|
+
.describe(`Set by the GitHub Actions runner. Used by the auto-heal PR body footer to link back to the workflow run that produced the heal.`),
|
|
86
|
+
GITHUB_RUN_NUMBER: v4_1.z
|
|
87
|
+
.string()
|
|
88
|
+
.optional()
|
|
89
|
+
.describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as a human-friendly run number.`),
|
|
90
|
+
GITHUB_SERVER_URL: v4_1.z
|
|
91
|
+
.string()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe(`Set by the GitHub Actions runner (e.g. https://github.com). Combined with GITHUB_REPOSITORY and GITHUB_RUN_ID to build the auto-heal PR body footer link.`),
|
|
94
|
+
GITHUB_REPOSITORY: v4_1.z
|
|
95
|
+
.string()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe(`Set by the GitHub Actions runner (owner/repo). Used by the auto-heal PR body footer link.`),
|
|
98
|
+
GITHUB_ACTOR: v4_1.z
|
|
99
|
+
.string()
|
|
100
|
+
.optional()
|
|
101
|
+
.describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as the user who triggered the run.`),
|
|
102
|
+
GITHUB_REF_NAME: v4_1.z
|
|
103
|
+
.string()
|
|
104
|
+
.optional()
|
|
105
|
+
.describe(`Set by the GitHub Actions runner. Embedded in the auto-heal PR body footer as the source branch.`),
|
|
106
|
+
CI_PIPELINE_URL: v4_1.z
|
|
107
|
+
.string()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe(`Set by the GitLab CI runner. Used by the auto-heal MR body footer to link back to the pipeline that produced the heal.`),
|
|
110
|
+
CI_PIPELINE_IID: v4_1.z
|
|
111
|
+
.string()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe(`Set by the GitLab CI runner — the per-project pipeline number GitLab shows in its UI. Embedded in the auto-heal MR body footer.`),
|
|
114
|
+
GITLAB_USER_LOGIN: v4_1.z
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe(`Set by the GitLab CI runner. Embedded in the auto-heal MR body footer as the user who triggered the pipeline.`),
|
|
118
|
+
CI_COMMIT_REF_NAME: v4_1.z
|
|
119
|
+
.string()
|
|
120
|
+
.optional()
|
|
121
|
+
.describe(`Set by the GitLab CI runner. Embedded in the auto-heal MR body footer as the source branch.`),
|
|
82
122
|
PLAYWRIGHT_JSON_OUTPUT_DIR: v4_1.z.string().optional()
|
|
83
123
|
.describe(`Directory where the Playwright JSON reporter writes its output (and where the Donobu
|
|
84
124
|
reporters merge their per-reporter state into a shared sidecar so the auto-heal orchestrator can
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DonobuReport } from './model';
|
|
2
|
+
type FooterEnv = {
|
|
3
|
+
readonly GITHUB_RUN_ID?: string;
|
|
4
|
+
readonly GITHUB_RUN_NUMBER?: string;
|
|
5
|
+
readonly GITHUB_SERVER_URL?: string;
|
|
6
|
+
readonly GITHUB_REPOSITORY?: string;
|
|
7
|
+
readonly GITHUB_ACTOR?: string;
|
|
8
|
+
readonly GITHUB_REF_NAME?: string;
|
|
9
|
+
readonly CI_PIPELINE_URL?: string;
|
|
10
|
+
readonly CI_PIPELINE_IID?: string;
|
|
11
|
+
readonly GITLAB_USER_LOGIN?: string;
|
|
12
|
+
readonly CI_COMMIT_REF_NAME?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function renderPullRequestBody(report: DonobuReport, envData?: FooterEnv): string;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=renderPullRequestBody.d.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderPullRequestBody = renderPullRequestBody;
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Donobu auto-heal pull request body renderer.
|
|
6
|
+
*
|
|
7
|
+
* Turns the merged auto-heal `DonobuReport` into the markdown body of the
|
|
8
|
+
* PR/MR opened by the surrounding CI job. Pure: callers pass the env subset
|
|
9
|
+
* the footer needs as a plain object, defaulting to the central `env.pick`
|
|
10
|
+
* view of the relevant CI vars when running in production.
|
|
11
|
+
*
|
|
12
|
+
* Returns an empty string when nothing was healed — the CLI uses that to
|
|
13
|
+
* decide whether to write the file at all.
|
|
14
|
+
*/
|
|
15
|
+
const envVars_1 = require("../envVars");
|
|
16
|
+
function parseHealedKey(rawKey) {
|
|
17
|
+
// Composite key shape from buildTestKey(): `file::projectName::title`.
|
|
18
|
+
// Titles can themselves contain `::`, so we only split off the first two
|
|
19
|
+
// segments and treat the remainder as the title.
|
|
20
|
+
const firstSep = rawKey.indexOf('::');
|
|
21
|
+
if (firstSep < 0) {
|
|
22
|
+
return { file: 'unknown-file', projectName: 'default', title: rawKey };
|
|
23
|
+
}
|
|
24
|
+
const file = rawKey.slice(0, firstSep);
|
|
25
|
+
const rest = rawKey.slice(firstSep + 2);
|
|
26
|
+
const secondSep = rest.indexOf('::');
|
|
27
|
+
if (secondSep < 0) {
|
|
28
|
+
return { file, projectName: 'default', title: rest };
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
file,
|
|
32
|
+
projectName: rest.slice(0, secondSep),
|
|
33
|
+
title: rest.slice(secondSep + 2),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function renderPullRequestBody(report, envData = envVars_1.env.pick('GITHUB_RUN_ID', 'GITHUB_RUN_NUMBER', 'GITHUB_SERVER_URL', 'GITHUB_REPOSITORY', 'GITHUB_ACTOR', 'GITHUB_REF_NAME', 'CI_PIPELINE_URL', 'CI_PIPELINE_IID', 'GITLAB_USER_LOGIN', 'CI_COMMIT_REF_NAME').data) {
|
|
37
|
+
const healedKeys = report.metadata?.donobuHealedTests ?? [];
|
|
38
|
+
if (healedKeys.length === 0) {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
const parsed = healedKeys.map(parseHealedKey);
|
|
42
|
+
const noun = parsed.length === 1 ? 'test' : 'tests';
|
|
43
|
+
let body = `🩹 **Donobu auto-heal applied fixes to ${parsed.length} failing ${noun}** in this branch.\n\n`;
|
|
44
|
+
body += `The auto-heal rerun applied a treatment plan to the failing ${noun}.\n\n`;
|
|
45
|
+
body += `## Healed ${noun}\n\n`;
|
|
46
|
+
for (const entry of parsed) {
|
|
47
|
+
const projectSuffix = entry.projectName && entry.projectName !== 'default'
|
|
48
|
+
? ` _(project: \`${entry.projectName}\`)_`
|
|
49
|
+
: '';
|
|
50
|
+
body += `- ❤️🩹 \`${entry.file}\` — ${entry.title}${projectSuffix}\n`;
|
|
51
|
+
}
|
|
52
|
+
const footer = buildCiFooter(envData);
|
|
53
|
+
if (footer) {
|
|
54
|
+
body += `\n---\n\n${footer}\n`;
|
|
55
|
+
}
|
|
56
|
+
return body;
|
|
57
|
+
}
|
|
58
|
+
function buildCiFooter(e) {
|
|
59
|
+
if (e.GITHUB_RUN_ID && e.GITHUB_SERVER_URL && e.GITHUB_REPOSITORY) {
|
|
60
|
+
const url = `${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`;
|
|
61
|
+
const label = e.GITHUB_RUN_NUMBER
|
|
62
|
+
? `workflow run #${e.GITHUB_RUN_NUMBER}`
|
|
63
|
+
: 'workflow run';
|
|
64
|
+
return assembleFooter(label, url, e.GITHUB_ACTOR, e.GITHUB_REF_NAME);
|
|
65
|
+
}
|
|
66
|
+
else if (e.CI_PIPELINE_URL) {
|
|
67
|
+
// `CI_PIPELINE_IID` is the per-project pipeline number GitLab shows in
|
|
68
|
+
// its UI ("#42") — far more useful in a footer than the global numeric
|
|
69
|
+
// `CI_PIPELINE_ID` reviewers don't recognize.
|
|
70
|
+
const label = e.CI_PIPELINE_IID
|
|
71
|
+
? `pipeline #${e.CI_PIPELINE_IID}`
|
|
72
|
+
: 'pipeline';
|
|
73
|
+
return assembleFooter(label, e.CI_PIPELINE_URL, e.GITLAB_USER_LOGIN, e.CI_COMMIT_REF_NAME);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function assembleFooter(label, url, actor, refName) {
|
|
80
|
+
let footer = `🤖 Generated by Donobu auto-heal · [${label}](${url})`;
|
|
81
|
+
if (actor) {
|
|
82
|
+
footer += ` · triggered by @${actor}`;
|
|
83
|
+
}
|
|
84
|
+
if (refName) {
|
|
85
|
+
footer += ` · on \`${refName}\``;
|
|
86
|
+
}
|
|
87
|
+
return footer;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=renderPullRequestBody.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DonobuReport } from './model';
|
|
2
|
+
type FooterEnv = {
|
|
3
|
+
readonly GITHUB_RUN_ID?: string;
|
|
4
|
+
readonly GITHUB_RUN_NUMBER?: string;
|
|
5
|
+
readonly GITHUB_SERVER_URL?: string;
|
|
6
|
+
readonly GITHUB_REPOSITORY?: string;
|
|
7
|
+
readonly GITHUB_ACTOR?: string;
|
|
8
|
+
readonly GITHUB_REF_NAME?: string;
|
|
9
|
+
readonly CI_PIPELINE_URL?: string;
|
|
10
|
+
readonly CI_PIPELINE_IID?: string;
|
|
11
|
+
readonly GITLAB_USER_LOGIN?: string;
|
|
12
|
+
readonly CI_COMMIT_REF_NAME?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function renderPullRequestBody(report: DonobuReport, envData?: FooterEnv): string;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=renderPullRequestBody.d.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderPullRequestBody = renderPullRequestBody;
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Donobu auto-heal pull request body renderer.
|
|
6
|
+
*
|
|
7
|
+
* Turns the merged auto-heal `DonobuReport` into the markdown body of the
|
|
8
|
+
* PR/MR opened by the surrounding CI job. Pure: callers pass the env subset
|
|
9
|
+
* the footer needs as a plain object, defaulting to the central `env.pick`
|
|
10
|
+
* view of the relevant CI vars when running in production.
|
|
11
|
+
*
|
|
12
|
+
* Returns an empty string when nothing was healed — the CLI uses that to
|
|
13
|
+
* decide whether to write the file at all.
|
|
14
|
+
*/
|
|
15
|
+
const envVars_1 = require("../envVars");
|
|
16
|
+
function parseHealedKey(rawKey) {
|
|
17
|
+
// Composite key shape from buildTestKey(): `file::projectName::title`.
|
|
18
|
+
// Titles can themselves contain `::`, so we only split off the first two
|
|
19
|
+
// segments and treat the remainder as the title.
|
|
20
|
+
const firstSep = rawKey.indexOf('::');
|
|
21
|
+
if (firstSep < 0) {
|
|
22
|
+
return { file: 'unknown-file', projectName: 'default', title: rawKey };
|
|
23
|
+
}
|
|
24
|
+
const file = rawKey.slice(0, firstSep);
|
|
25
|
+
const rest = rawKey.slice(firstSep + 2);
|
|
26
|
+
const secondSep = rest.indexOf('::');
|
|
27
|
+
if (secondSep < 0) {
|
|
28
|
+
return { file, projectName: 'default', title: rest };
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
file,
|
|
32
|
+
projectName: rest.slice(0, secondSep),
|
|
33
|
+
title: rest.slice(secondSep + 2),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function renderPullRequestBody(report, envData = envVars_1.env.pick('GITHUB_RUN_ID', 'GITHUB_RUN_NUMBER', 'GITHUB_SERVER_URL', 'GITHUB_REPOSITORY', 'GITHUB_ACTOR', 'GITHUB_REF_NAME', 'CI_PIPELINE_URL', 'CI_PIPELINE_IID', 'GITLAB_USER_LOGIN', 'CI_COMMIT_REF_NAME').data) {
|
|
37
|
+
const healedKeys = report.metadata?.donobuHealedTests ?? [];
|
|
38
|
+
if (healedKeys.length === 0) {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
const parsed = healedKeys.map(parseHealedKey);
|
|
42
|
+
const noun = parsed.length === 1 ? 'test' : 'tests';
|
|
43
|
+
let body = `🩹 **Donobu auto-heal applied fixes to ${parsed.length} failing ${noun}** in this branch.\n\n`;
|
|
44
|
+
body += `The auto-heal rerun applied a treatment plan to the failing ${noun}.\n\n`;
|
|
45
|
+
body += `## Healed ${noun}\n\n`;
|
|
46
|
+
for (const entry of parsed) {
|
|
47
|
+
const projectSuffix = entry.projectName && entry.projectName !== 'default'
|
|
48
|
+
? ` _(project: \`${entry.projectName}\`)_`
|
|
49
|
+
: '';
|
|
50
|
+
body += `- ❤️🩹 \`${entry.file}\` — ${entry.title}${projectSuffix}\n`;
|
|
51
|
+
}
|
|
52
|
+
const footer = buildCiFooter(envData);
|
|
53
|
+
if (footer) {
|
|
54
|
+
body += `\n---\n\n${footer}\n`;
|
|
55
|
+
}
|
|
56
|
+
return body;
|
|
57
|
+
}
|
|
58
|
+
function buildCiFooter(e) {
|
|
59
|
+
if (e.GITHUB_RUN_ID && e.GITHUB_SERVER_URL && e.GITHUB_REPOSITORY) {
|
|
60
|
+
const url = `${e.GITHUB_SERVER_URL}/${e.GITHUB_REPOSITORY}/actions/runs/${e.GITHUB_RUN_ID}`;
|
|
61
|
+
const label = e.GITHUB_RUN_NUMBER
|
|
62
|
+
? `workflow run #${e.GITHUB_RUN_NUMBER}`
|
|
63
|
+
: 'workflow run';
|
|
64
|
+
return assembleFooter(label, url, e.GITHUB_ACTOR, e.GITHUB_REF_NAME);
|
|
65
|
+
}
|
|
66
|
+
else if (e.CI_PIPELINE_URL) {
|
|
67
|
+
// `CI_PIPELINE_IID` is the per-project pipeline number GitLab shows in
|
|
68
|
+
// its UI ("#42") — far more useful in a footer than the global numeric
|
|
69
|
+
// `CI_PIPELINE_ID` reviewers don't recognize.
|
|
70
|
+
const label = e.CI_PIPELINE_IID
|
|
71
|
+
? `pipeline #${e.CI_PIPELINE_IID}`
|
|
72
|
+
: 'pipeline';
|
|
73
|
+
return assembleFooter(label, e.CI_PIPELINE_URL, e.GITLAB_USER_LOGIN, e.CI_COMMIT_REF_NAME);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function assembleFooter(label, url, actor, refName) {
|
|
80
|
+
let footer = `🤖 Generated by Donobu auto-heal · [${label}](${url})`;
|
|
81
|
+
if (actor) {
|
|
82
|
+
footer += ` · triggered by @${actor}`;
|
|
83
|
+
}
|
|
84
|
+
if (refName) {
|
|
85
|
+
footer += ` · on \`${refName}\``;
|
|
86
|
+
}
|
|
87
|
+
return footer;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=renderPullRequestBody.js.map
|