@kinora/reporter 0.1.3 → 0.2.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/README.md +27 -1
- package/dist/index.d.mts +9 -0
- package/dist/index.mjs +38 -2
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -51,11 +51,37 @@ Create an API token in the kinora dashboard (Settings → Workspace). Self-hosti
|
|
|
51
51
|
| `project` | `{ slug: string, name?: string }` | required | Target project. `name` defaults to `slug`. |
|
|
52
52
|
| `url` | `string` | env `KINORA_URL`, then cloud | kinora server base URL. Set for self-host. |
|
|
53
53
|
| `token` | `string` | env `KINORA_TOKEN` | Project API token. Prefer the env var. |
|
|
54
|
-
| `git` | `{ sha?, branch?, repoUrl? }`
|
|
54
|
+
| `git` | `{ sha?, branch?, baseBranch?, repoUrl? }` | auto on GitHub Actions | Git metadata. `repoUrl` links a sha to its commit; `baseBranch` powers "regression vs base" in the PR comment. |
|
|
55
55
|
| `ci` | `{ provider?, runUrl?, runNumber? }` | auto on GitHub Actions | CI metadata for the run. |
|
|
56
|
+
| `prComment` | `boolean \| { label?, policy? }` | off | Post/update a summary comment on the GitHub PR (see below). |
|
|
56
57
|
|
|
57
58
|
On GitHub Actions, `git` and `ci` are filled from the standard `GITHUB_*` env vars (including the repo URL, so shas link to their commit in the dashboard). Pass them explicitly on other CI providers.
|
|
58
59
|
|
|
60
|
+
## GitHub PR comment
|
|
61
|
+
|
|
62
|
+
On a `pull_request` run, the reporter can post (and keep updating) a summary comment on the PR: pass/fail counts, tests newly failing vs the base branch, and a link to the run. It uses the job's ambient `GITHUB_TOKEN`, so no credentials are stored in kinora.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
reporter: [['@kinora/reporter', { project: { slug: 'web-app' }, prComment: true }]]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The workflow must grant write access to PRs:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
# in your workflow job:
|
|
72
|
+
permissions:
|
|
73
|
+
pull-requests: write # required for the PR comment
|
|
74
|
+
steps:
|
|
75
|
+
- run: npx playwright test
|
|
76
|
+
env:
|
|
77
|
+
KINORA_TOKEN: ${{ secrets.KINORA_TOKEN }}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- Same-repo PRs only: `GITHUB_TOKEN` is read-only on fork PRs, so the comment is skipped there.
|
|
81
|
+
- Shard your run with `merge-reports` (blob report) so one merged run posts one comment; per-shard runs are skipped.
|
|
82
|
+
- Matrix builds sharing a PR: set `prComment: { label: 'node20' }` so each leg keeps its own comment.
|
|
83
|
+
- `policy: 'on-failure'` skips the comment on green runs (default posts always).
|
|
84
|
+
|
|
59
85
|
## CI example (GitHub Actions)
|
|
60
86
|
|
|
61
87
|
```yaml
|
package/dist/index.d.mts
CHANGED
|
@@ -14,6 +14,14 @@ interface KinoraReporterOptions {
|
|
|
14
14
|
};
|
|
15
15
|
git?: GitMeta;
|
|
16
16
|
ci?: CiMeta;
|
|
17
|
+
/**
|
|
18
|
+
* Post/update a summary comment on the GitHub PR (uses the job's GITHUB_TOKEN; needs
|
|
19
|
+
* `permissions: pull-requests: write`). `label` distinguishes matrix legs sharing one PR.
|
|
20
|
+
*/
|
|
21
|
+
prComment?: boolean | {
|
|
22
|
+
label?: string;
|
|
23
|
+
policy?: 'always' | 'on-failure';
|
|
24
|
+
};
|
|
17
25
|
}
|
|
18
26
|
declare class KinoraReporter implements Reporter {
|
|
19
27
|
private readonly options;
|
|
@@ -22,6 +30,7 @@ declare class KinoraReporter implements Reporter {
|
|
|
22
30
|
constructor(options: KinoraReporterOptions);
|
|
23
31
|
onBegin(config: FullConfig, suite: Suite): void;
|
|
24
32
|
onEnd(result: FullResult): Promise<void>;
|
|
33
|
+
private maybePostPrComment;
|
|
25
34
|
}
|
|
26
35
|
//#endregion
|
|
27
36
|
export { KinoraReporterOptions, KinoraReporter as default };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { readFile } from "node:fs/promises";
|
|
2
3
|
import process from "node:process";
|
|
3
|
-
import { DEFAULT_KINORA_URL, IngestError, createIngestClient, effectiveAttachments, isTraceAttachment, makeTestKey } from "@kinora/core";
|
|
4
|
+
import { DEFAULT_KINORA_URL, IngestError, createIngestClient, effectiveAttachments, isTraceAttachment, makeTestKey, postPrComment, resolvePrContext } from "@kinora/core";
|
|
4
5
|
//#region src/index.ts
|
|
5
6
|
function identity(test) {
|
|
6
7
|
let file = "";
|
|
@@ -70,12 +71,14 @@ function countsOf(tests) {
|
|
|
70
71
|
function detectGit() {
|
|
71
72
|
const sha = process.env.GITHUB_SHA;
|
|
72
73
|
const branch = process.env.GITHUB_REF_NAME;
|
|
74
|
+
const baseBranch = process.env.GITHUB_BASE_REF || void 0;
|
|
73
75
|
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY } = process.env;
|
|
74
76
|
const repoUrl = GITHUB_SERVER_URL && GITHUB_REPOSITORY ? `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}` : void 0;
|
|
75
77
|
if (!sha && !branch && !repoUrl) return void 0;
|
|
76
78
|
return {
|
|
77
79
|
sha,
|
|
78
80
|
branch,
|
|
81
|
+
baseBranch,
|
|
79
82
|
repoUrl
|
|
80
83
|
};
|
|
81
84
|
}
|
|
@@ -125,7 +128,8 @@ var KinoraReporter = class {
|
|
|
125
128
|
try {
|
|
126
129
|
const client = createIngestClient({
|
|
127
130
|
baseUrl: url,
|
|
128
|
-
token
|
|
131
|
+
token,
|
|
132
|
+
regression: !!this.options.prComment
|
|
129
133
|
});
|
|
130
134
|
const res = await client.uploadRun(payload);
|
|
131
135
|
let traces = 0;
|
|
@@ -145,11 +149,43 @@ var KinoraReporter = class {
|
|
|
145
149
|
}
|
|
146
150
|
}
|
|
147
151
|
console.log(`[kinora] uploaded ${res.tests} tests + ${traces} traces (run ${res.runId})`);
|
|
152
|
+
await this.maybePostPrComment(payload, res);
|
|
148
153
|
} catch (err) {
|
|
149
154
|
if (err instanceof IngestError && err.status === 402) console.warn(`[kinora] ${err.message}`);
|
|
150
155
|
else console.error(`[kinora] upload failed:`, err instanceof Error ? err.message : err);
|
|
151
156
|
}
|
|
152
157
|
}
|
|
158
|
+
async maybePostPrComment(payload, res) {
|
|
159
|
+
if (!this.options.prComment) return;
|
|
160
|
+
const opt = this.options.prComment;
|
|
161
|
+
const label = typeof opt === "object" ? opt.label : void 0;
|
|
162
|
+
const policy = typeof opt === "object" ? opt.policy : void 0;
|
|
163
|
+
try {
|
|
164
|
+
const ctx = resolvePrContext(this.config?.shard ? {
|
|
165
|
+
...process.env,
|
|
166
|
+
__KINORA_IS_SHARD: "1"
|
|
167
|
+
} : process.env, (p) => {
|
|
168
|
+
try {
|
|
169
|
+
return readFileSync(p, "utf8");
|
|
170
|
+
} catch {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
if (!ctx) return;
|
|
175
|
+
const outcome = await postPrComment(ctx, {
|
|
176
|
+
projectSlug: payload.project.slug,
|
|
177
|
+
projectName: payload.project.name,
|
|
178
|
+
label,
|
|
179
|
+
runUrl: res.runUrl,
|
|
180
|
+
ciRunUrl: payload.run.ci?.runUrl,
|
|
181
|
+
counts: payload.run.counts,
|
|
182
|
+
regression: res.regression
|
|
183
|
+
}, policy ?? "always");
|
|
184
|
+
if (outcome !== "skipped") console.warn(`[kinora] PR comment ${outcome}`);
|
|
185
|
+
} catch (err) {
|
|
186
|
+
console.warn("[kinora] PR comment failed:", err instanceof Error ? err.message : err);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
153
189
|
};
|
|
154
190
|
//#endregion
|
|
155
191
|
export { KinoraReporter as default };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kinora/reporter",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"description": "Playwright reporter that uploads test results to a kinora server",
|
|
6
6
|
"author": "Joris Gallot",
|
|
7
7
|
"license": "MIT",
|
|
@@ -36,16 +36,19 @@
|
|
|
36
36
|
"@playwright/test": ">=1.40.0"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@kinora/core": "0.
|
|
39
|
+
"@kinora/core": "0.2.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@playwright/test": "^1.61.0",
|
|
43
43
|
"@types/node": "^26.0.0",
|
|
44
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
44
45
|
"tsdown": "^0.22.3",
|
|
45
|
-
"typescript": "~6.0.3"
|
|
46
|
+
"typescript": "~6.0.3",
|
|
47
|
+
"vitest": "^4.1.9"
|
|
46
48
|
},
|
|
47
49
|
"scripts": {
|
|
48
50
|
"build": "tsdown",
|
|
49
|
-
"typecheck": "tsc --noEmit"
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"test": "vitest run --coverage"
|
|
50
53
|
}
|
|
51
54
|
}
|