@kinora/reporter 0.15.0 → 0.16.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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { AttachmentKind, CiMeta, GitMeta } from "@kinora/core";
1
+ import { AttachmentKind, CiMeta, GitMeta, PrCommentOption, PrStatusOption } from "@kinora/core";
2
2
  import { FullConfig, FullResult, Reporter, Suite } from "@playwright/test/reporter";
3
3
  export interface KinoraReporterOptions {
4
4
  /** kinora server base URL. Defaults to env KINORA_URL, then the hosted cloud. Set for self-host. */
@@ -17,10 +17,14 @@ export interface KinoraReporterOptions {
17
17
  * `permissions: pull-requests: write`) or the GitLab MR (needs a GITLAB_TOKEN CI variable with
18
18
  * the `api` scope). `label` distinguishes matrix legs sharing one PR.
19
19
  */
20
- prComment?: boolean | {
21
- label?: string;
22
- policy?: 'always' | 'on-failure';
23
- };
20
+ prComment?: PrCommentOption;
21
+ /**
22
+ * Set a `kinora / <project>` commit status on the GitHub PR (needs `permissions: statuses: write`)
23
+ * or the GitLab MR pipeline (GITLAB_TOKEN with the Developer role): red only for tests newly
24
+ * failing vs the base branch, so branch protection or "Pipelines must succeed" can require it.
25
+ * `label` distinguishes matrix legs, defaulting to the `prComment` one.
26
+ */
27
+ prStatus?: PrStatusOption;
24
28
  /**
25
29
  * Which attachment kinds to upload. Defaults to `['trace', 'snapshot']` (`snapshot` = the images
26
30
  * of a failed screenshot assertion, shown as a comparison). Add `'video'` / `'screenshot'`
@@ -43,6 +47,6 @@ export default class KinoraReporter implements Reporter {
43
47
  onBegin(config: FullConfig, suite: Suite): void;
44
48
  onEnd(result: FullResult): Promise<void>;
45
49
  private shard;
46
- private prCommentLabel;
47
- private maybePostPrComment;
50
+ private prOptions;
51
+ private maybePostToPr;
48
52
  }
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readFileSync, statSync } from "node:fs";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import process from "node:process";
4
- import { DEFAULT_KINORA_URL, DEFAULT_UPLOAD_ATTACHMENTS, IngestError, a11yFromScans, artifactsToUpload, createIngestClient, describeRetry, detectCiEnv, effectiveAttachments, flakyTestsOf, makeTestKey, parseAxeScan, postPrComment, resolvePrContext, resolveShardGroup, shardFromEnv, uploadArtifacts } from "@kinora/core";
4
+ import { DEFAULT_KINORA_URL, DEFAULT_UPLOAD_ATTACHMENTS, IngestError, a11yFromScans, artifactsToUpload, createIngestClient, describeRetry, detectCiEnv, effectiveAttachments, flakyTestsOf, makeTestKey, parseAxeScan, postToPr, prLegLabel, resolvePrContext, resolvePrReportOptions, resolveShardGroup, shardFromEnv, uploadArtifacts } from "@kinora/core";
5
5
  // src/index.ts
6
6
  function identity(test) {
7
7
  let file = "";
@@ -107,7 +107,7 @@ var KinoraReporter = class {
107
107
  const shard = this.shard();
108
108
  const group = shard && this.options.groupKey !== false ? resolveShardGroup(process.env, {
109
109
  groupKey: this.options.groupKey,
110
- leg: this.prCommentLabel()
110
+ leg: prLegLabel(this.prOptions())
111
111
  }) : void 0;
112
112
  const baseUrls = [...new Set((this.config?.projects ?? []).flatMap((p) => p.use.baseURL ? [p.use.baseURL] : []))];
113
113
  const payload = {
@@ -137,7 +137,7 @@ var KinoraReporter = class {
137
137
  const client = createIngestClient({
138
138
  baseUrl: url,
139
139
  token,
140
- regression: !!this.options.prComment,
140
+ regression: !!(this.options.prComment || this.options.prStatus),
141
141
  onRetry: (info) => console.warn(`[kinora] ${describeRetry(info)}`)
142
142
  });
143
143
  const res = await client.uploadRun(payload);
@@ -147,7 +147,7 @@ var KinoraReporter = class {
147
147
  });
148
148
  console.log(`[kinora] uploaded ${res.tests} tests + ${artifacts} artifacts (run ${res.runId}${res.shardProgress ? `, ${res.shardProgress.landed} of ${res.shardProgress.total} shards` : ""})`);
149
149
  if (res.incident) console.warn(`[kinora] environment incident, not counted: ${res.incident.reason}`);
150
- await this.maybePostPrComment(payload, res);
150
+ await this.maybePostToPr(payload, res);
151
151
  } catch (err) {
152
152
  if (err instanceof IngestError && err.status === 402) console.warn(`[kinora] ${err.message}`);
153
153
  else console.error(`[kinora] upload failed:`, err instanceof Error ? err.message : err);
@@ -156,49 +156,44 @@ var KinoraReporter = class {
156
156
  shard() {
157
157
  return this.config?.shard ?? shardFromEnv(process.env);
158
158
  }
159
- prCommentLabel() {
160
- const opt = this.options.prComment;
161
- return typeof opt === "object" ? opt.label : void 0;
159
+ prOptions() {
160
+ return resolvePrReportOptions(this.options.prComment, this.options.prStatus);
162
161
  }
163
- async maybePostPrComment(payload, res) {
164
- if (!this.options.prComment) return;
165
- const opt = this.options.prComment;
166
- const label = this.prCommentLabel();
167
- const policy = typeof opt === "object" ? opt.policy : void 0;
162
+ async maybePostToPr(payload, res) {
163
+ const opts = this.prOptions();
164
+ if (!opts.comment && !opts.status) return;
168
165
  const grouped = !!payload.run.groupKey;
169
166
  if (grouped && !res.shardProgress) return;
170
- try {
171
- const env = this.shard() && !grouped ? {
172
- ...process.env,
173
- __KINORA_IS_SHARD: "1"
174
- } : process.env;
175
- const ctx = resolvePrContext(env, (p) => {
176
- try {
177
- return readFileSync(p, "utf8");
178
- } catch {
179
- return;
180
- }
181
- });
182
- if (!ctx) return;
183
- const outcome = await postPrComment(ctx, {
184
- projectSlug: payload.project.slug,
185
- projectName: payload.project.name,
186
- label,
187
- runUrl: res.runUrl,
188
- ciRunUrl: payload.run.ci?.runUrl,
189
- counts: res.counts ?? payload.run.counts,
190
- regression: res.regression,
191
- flaky: res.flaky ?? flakyTestsOf(payload.tests),
192
- ...res.shardProgress && { shards: {
193
- runId: res.runId,
194
- ...res.shardProgress
195
- } },
196
- ...res.incident && { incident: res.incident }
197
- }, policy ?? "always");
198
- if (outcome !== "skipped") console.warn(`[kinora] PR comment ${outcome}`);
199
- } catch (err) {
200
- console.warn("[kinora] PR comment failed:", err instanceof Error ? err.message : err);
201
- }
167
+ const env = this.shard() && !grouped ? {
168
+ ...process.env,
169
+ __KINORA_IS_SHARD: "1"
170
+ } : process.env;
171
+ const ctx = resolvePrContext(env, (p) => {
172
+ try {
173
+ return readFileSync(p, "utf8");
174
+ } catch {
175
+ return;
176
+ }
177
+ });
178
+ if (!ctx) return;
179
+ await postToPr(ctx, opts, {
180
+ projectSlug: payload.project.slug,
181
+ projectName: payload.project.name,
182
+ runUrl: res.runUrl,
183
+ ciRunUrl: payload.run.ci?.runUrl,
184
+ counts: res.counts ?? payload.run.counts,
185
+ regression: res.regression,
186
+ flaky: res.flaky ?? flakyTestsOf(payload.tests),
187
+ baseBranch: payload.run.git?.baseBranch,
188
+ ...res.shardProgress && { shards: {
189
+ runId: res.runId,
190
+ ...res.shardProgress
191
+ } },
192
+ ...res.incident && { incident: res.incident }
193
+ }, {
194
+ info: (m) => console.warn(`[kinora] ${m}`),
195
+ warn: (m) => console.warn(`[kinora] ${m}`)
196
+ });
202
197
  }
203
198
  };
204
199
  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.15.0",
4
+ "version": "0.16.0",
5
5
  "description": "Playwright reporter that uploads test results to a kinora server",
6
6
  "author": "Joris Gallot",
7
7
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@kinora/core": "0.17.0"
48
+ "@kinora/core": "0.18.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@axe-core/playwright": "^4.14.0",