@allurereport/ci 3.21.0 → 3.22.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.
@@ -143,6 +143,12 @@ export const amazon = {
143
143
  return getProjectName(buildArn);
144
144
  }
145
145
  },
146
+ get pipelineRunName() {
147
+ return getPipelineName();
148
+ },
149
+ get pipelineRunUrl() {
150
+ return getPipelineName() ? this.jobUrl : undefined;
151
+ },
146
152
  get jobRunUid() {
147
153
  const pipelineName = getPipelineName();
148
154
  if (pipelineName) {
@@ -153,6 +159,10 @@ export const amazon = {
153
159
  }
154
160
  },
155
161
  get jobRunUrl() {
162
+ const buildUrl = getEnv("CODEBUILD_BUILD_URL");
163
+ if (buildUrl) {
164
+ return buildUrl;
165
+ }
156
166
  const pipelineName = getPipelineName();
157
167
  if (pipelineName) {
158
168
  const buildArn = getEnv("CODEBUILD_BUILD_ARN");
@@ -197,6 +207,10 @@ export const amazon = {
197
207
  get pullRequestName() {
198
208
  return "";
199
209
  },
210
+ get commitSha() {
211
+ const version = getEnv("CODEBUILD_RESOLVED_SOURCE_VERSION") || getEnv("CODEBUILD_SOURCE_VERSION");
212
+ return GIT_SHA_REGEXP.test(version) ? version : undefined;
213
+ },
200
214
  get provider() {
201
215
  return getRepository()?.provider;
202
216
  },
@@ -80,6 +80,12 @@ export const azure = {
80
80
  }
81
81
  return getEnv("BUILD_DEFINITIONNAME");
82
82
  },
83
+ get pipelineRunName() {
84
+ return this.jobName || this.jobRunName || this.jobRunUid;
85
+ },
86
+ get pipelineRunUrl() {
87
+ return this.jobRunUid ? this.jobRunUrl : undefined;
88
+ },
83
89
  get jobRunUid() {
84
90
  if (isClassicRelease()) {
85
91
  return getEnv("RELEASE_RELEASEID");
@@ -119,6 +125,15 @@ export const azure = {
119
125
  get pullRequestName() {
120
126
  return "";
121
127
  },
128
+ get commitSha() {
129
+ return getEnv("SYSTEM_PULLREQUEST_SOURCECOMMITID") || getEnv("BUILD_SOURCEVERSION") || undefined;
130
+ },
131
+ get commitUrl() {
132
+ const repositoryUrl = getRepositoryUrl();
133
+ if (getEnv("BUILD_REPOSITORY_PROVIDER") !== "TfsGit" || !repositoryUrl || !this.commitSha)
134
+ return undefined;
135
+ return `${getBrowserRepositoryUrl(repositoryUrl)}/commit/${encodeURIComponent(this.commitSha)}`;
136
+ },
122
137
  get provider() {
123
138
  return getRepositoryFromUrl()?.provider ?? mapAzureRepositoryProvider(getEnv("BUILD_REPOSITORY_PROVIDER"));
124
139
  },
@@ -40,6 +40,12 @@ export const bitbucket = {
40
40
  get jobName() {
41
41
  return getEnv("BITBUCKET_REPO_FULL_NAME");
42
42
  },
43
+ get pipelineRunName() {
44
+ return getEnv("BITBUCKET_BUILD_NUMBER") || this.jobRunUid;
45
+ },
46
+ get pipelineRunUrl() {
47
+ return this.jobRunUid ? this.jobRunUrl : undefined;
48
+ },
43
49
  get jobRunUid() {
44
50
  return getEnv("BITBUCKET_PIPELINE_UUID");
45
51
  },
@@ -66,6 +72,9 @@ export const bitbucket = {
66
72
  get pullRequestName() {
67
73
  return "";
68
74
  },
75
+ get commitSha() {
76
+ return getEnv("BITBUCKET_COMMIT") || undefined;
77
+ },
69
78
  get provider() {
70
79
  return GitProvider.Bitbucket;
71
80
  },
@@ -50,6 +50,13 @@ export const circle = {
50
50
  const reponame = getEnv("CIRCLE_PROJECT_REPONAME");
51
51
  return `${username}/${reponame}`;
52
52
  },
53
+ get pipelineRunName() {
54
+ return getEnv("CIRCLE_WORKFLOW_ID");
55
+ },
56
+ get pipelineRunUrl() {
57
+ const id = getEnv("CIRCLE_WORKFLOW_ID");
58
+ return id ? `https://app.circleci.com/pipelines/workflows/${encodeURIComponent(id)}` : undefined;
59
+ },
53
60
  get jobRunUid() {
54
61
  return getEnv("CIRCLE_WORKFLOW_JOB_ID");
55
62
  },
@@ -68,6 +75,9 @@ export const circle = {
68
75
  get pullRequestName() {
69
76
  return "";
70
77
  },
78
+ get commitSha() {
79
+ return getEnv("CIRCLE_SHA1") || undefined;
80
+ },
71
81
  get provider() {
72
82
  return getRepository()?.provider;
73
83
  },
@@ -66,6 +66,12 @@ export const drone = {
66
66
  get jobName() {
67
67
  return getEnv("DRONE_REPO");
68
68
  },
69
+ get pipelineRunName() {
70
+ return getEnv("DRONE_REPO") || getJobRunUID();
71
+ },
72
+ get pipelineRunUrl() {
73
+ return getJobRunURL() || undefined;
74
+ },
69
75
  get jobRunUid() {
70
76
  return getJobRunUID();
71
77
  },
@@ -101,6 +107,9 @@ export const drone = {
101
107
  get pullRequestName() {
102
108
  return getEnv("DRONE_PULL_REQUEST_TITLE");
103
109
  },
110
+ get commitSha() {
111
+ return getEnv("DRONE_COMMIT_SHA") || undefined;
112
+ },
104
113
  get provider() {
105
114
  return getRepository()?.provider;
106
115
  },
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path/posix";
2
2
  import { CiType, GitProvider } from "@allurereport/core-api";
3
- import { resolveGithubPullRequestContext, resolveGithubPullRequestNumber } from "../helpers/github.js";
3
+ import { resolveGithubCommitSha, resolveGithubPullRequestContext, resolveGithubPullRequestNumber, } from "../helpers/github.js";
4
4
  import { stripRefsHeads } from "../helpers/gitProvider.js";
5
5
  import { getEnv } from "../utils.js";
6
6
  const getBaseURL = () => getEnv("GITHUB_SERVER_URL");
@@ -55,6 +55,12 @@ export const github = {
55
55
  get jobName() {
56
56
  return `${getRepo()} - ${getWorkflow()}`;
57
57
  },
58
+ get pipelineRunName() {
59
+ return getWorkflow() || getRunID();
60
+ },
61
+ get pipelineRunUrl() {
62
+ return getRunID() ? this.jobRunUrl : undefined;
63
+ },
58
64
  get jobRunUid() {
59
65
  return getRunID();
60
66
  },
@@ -86,6 +92,9 @@ export const github = {
86
92
  }
87
93
  return `Pull request #${pullRequestNumber}`;
88
94
  },
95
+ get commitSha() {
96
+ return resolveGithubCommitSha();
97
+ },
89
98
  get provider() {
90
99
  return GitProvider.Github;
91
100
  },
@@ -34,6 +34,12 @@ export const gitlab = {
34
34
  get ciJobName() {
35
35
  return getEnv("CI_JOB_NAME");
36
36
  },
37
+ get pipelineRunName() {
38
+ return getEnv("CI_PIPELINE_NAME") || getEnv("CI_PIPELINE_ID");
39
+ },
40
+ get pipelineRunUrl() {
41
+ return getEnv("CI_PIPELINE_URL") || undefined;
42
+ },
37
43
  get jobRunUid() {
38
44
  return getEnv("CI_PIPELINE_ID");
39
45
  },
@@ -57,6 +63,9 @@ export const gitlab = {
57
63
  get pullRequestName() {
58
64
  return getEnv("CI_MERGE_REQUEST_TITLE");
59
65
  },
66
+ get commitSha() {
67
+ return getEnv("CI_MERGE_REQUEST_SOURCE_BRANCH_SHA") || getEnv("CI_COMMIT_SHA") || undefined;
68
+ },
60
69
  get provider() {
61
70
  return GitProvider.Gitlab;
62
71
  },
@@ -64,6 +64,9 @@ export const jenkins = {
64
64
  get pullRequestName() {
65
65
  return getEnv("CHANGE_TITLE");
66
66
  },
67
+ get commitSha() {
68
+ return getEnv("GIT_COMMIT") || undefined;
69
+ },
67
70
  get provider() {
68
71
  return getRepository()?.provider;
69
72
  },
@@ -59,6 +59,10 @@ export const local = {
59
59
  get pullRequestName() {
60
60
  return "";
61
61
  },
62
+ get commitSha() {
63
+ const output = spawnSync("git", ["rev-parse", "HEAD"]);
64
+ return !output.error && output.status === 0 ? output.stdout.toString().trim() || undefined : undefined;
65
+ },
62
66
  get provider() {
63
67
  return getRepository()?.provider;
64
68
  },
@@ -2,8 +2,10 @@ export type GithubPullRequestContext = {
2
2
  number: string;
3
3
  headRef?: string;
4
4
  baseRef?: string;
5
+ headSha?: string;
5
6
  };
6
7
  export declare const parsePullRequestContextFromEventJson: (content: string) => GithubPullRequestContext | undefined;
7
8
  export declare const parsePullRequestNumberFromEventJson: (content: string) => string;
8
9
  export declare const resolveGithubPullRequestContext: () => GithubPullRequestContext | undefined;
10
+ export declare const resolveGithubCommitSha: () => string | undefined;
9
11
  export declare const resolveGithubPullRequestNumber: () => string;
@@ -21,11 +21,11 @@ const contextFromPullRequestFields = (pullRequest, fallbackNumber) => {
21
21
  number,
22
22
  headRef: nonBlank(pullRequest?.head?.ref),
23
23
  baseRef: nonBlank(pullRequest?.base?.ref),
24
+ headSha: nonBlank(pullRequest?.head?.sha),
24
25
  };
25
26
  };
26
- export const parsePullRequestContextFromEventJson = (content) => {
27
+ const pullRequestContextFromEvent = (event) => {
27
28
  try {
28
- const event = JSON.parse(content);
29
29
  const fromPullRequest = contextFromPullRequestFields(event.pull_request, event.number);
30
30
  if (fromPullRequest) {
31
31
  return fromPullRequest;
@@ -40,17 +40,25 @@ export const parsePullRequestContextFromEventJson = (content) => {
40
40
  return undefined;
41
41
  }
42
42
  };
43
+ export const parsePullRequestContextFromEventJson = (content) => {
44
+ try {
45
+ return pullRequestContextFromEvent(JSON.parse(content));
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ };
43
51
  export const parsePullRequestNumberFromEventJson = (content) => {
44
52
  return parsePullRequestContextFromEventJson(content)?.number ?? "";
45
53
  };
46
- const readPullRequestContextFromEventPath = () => {
54
+ const readGithubEventFromPath = () => {
47
55
  const eventPath = getEnv("GITHUB_EVENT_PATH");
48
56
  if (!eventPath) {
49
57
  return undefined;
50
58
  }
51
59
  try {
52
60
  const content = readFileSync(eventPath, "utf-8");
53
- return parsePullRequestContextFromEventJson(content);
61
+ return JSON.parse(content);
54
62
  }
55
63
  catch {
56
64
  return undefined;
@@ -75,7 +83,15 @@ export const resolveGithubPullRequestContext = () => {
75
83
  baseRef: nonBlank(getEnv("GITHUB_BASE_REF")),
76
84
  };
77
85
  }
78
- return readPullRequestContextFromEventPath();
86
+ const event = readGithubEventFromPath();
87
+ return event ? pullRequestContextFromEvent(event) : undefined;
88
+ };
89
+ export const resolveGithubCommitSha = () => {
90
+ const event = readGithubEventFromPath();
91
+ return (nonBlank(event?.workflow_run?.head_sha) ||
92
+ (event ? pullRequestContextFromEvent(event)?.headSha : undefined) ||
93
+ getEnv("GITHUB_SHA") ||
94
+ undefined);
79
95
  };
80
96
  export const resolveGithubPullRequestNumber = () => {
81
97
  return resolveGithubPullRequestContext()?.number ?? "";
@@ -0,0 +1,10 @@
1
+ import { type CiDescriptor } from "@allurereport/core-api";
2
+ import type { PluginSummary } from "@allurereport/plugin-api";
3
+ export type ContextLink = {
4
+ label: string;
5
+ href: string;
6
+ };
7
+ type ReportCiContext = Pick<PluginSummary, "commitSha" | "commitHref" | "ciRunName" | "ciRunHref">;
8
+ export declare const createReportCiContext: (ci: CiDescriptor | undefined) => ReportCiContext;
9
+ export declare const reportCiContextLinks: (report: ReportCiContext) => ContextLink[];
10
+ export {};
@@ -0,0 +1,94 @@
1
+ import { GitProvider } from "@allurereport/core-api";
2
+ const browserUrl = (value) => {
3
+ if (!value) {
4
+ return undefined;
5
+ }
6
+ try {
7
+ const url = new URL(value);
8
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
9
+ return undefined;
10
+ }
11
+ if (url.username || url.password) {
12
+ url.username = "";
13
+ url.password = "";
14
+ return url.toString();
15
+ }
16
+ return value;
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ };
22
+ const trimTrailingSlashes = (value) => {
23
+ if (!value) {
24
+ return undefined;
25
+ }
26
+ let end = value.length;
27
+ while (end > 0 && value[end - 1] === "/") {
28
+ end--;
29
+ }
30
+ return value.slice(0, end);
31
+ };
32
+ const commitUrl = (ci, sha) => {
33
+ const explicit = browserUrl(ci.commitUrl);
34
+ if (explicit) {
35
+ return explicit;
36
+ }
37
+ const repositoryUrl = trimTrailingSlashes(browserUrl(ci.repository?.url))?.replace(/\.git$/i, "");
38
+ const pullRequestUrl = trimTrailingSlashes(browserUrl(ci.pullRequest?.url));
39
+ switch (ci.provider) {
40
+ case GitProvider.Github:
41
+ if (!pullRequestUrl && !repositoryUrl)
42
+ return undefined;
43
+ if (pullRequestUrl) {
44
+ return `${pullRequestUrl}/commits/${encodeURIComponent(sha)}`;
45
+ }
46
+ else {
47
+ return `${repositoryUrl}/commit/${encodeURIComponent(sha)}`;
48
+ }
49
+ case GitProvider.Gitlab:
50
+ if (!pullRequestUrl && !repositoryUrl)
51
+ return undefined;
52
+ if (pullRequestUrl) {
53
+ return `${pullRequestUrl}/diffs?commit_id=${encodeURIComponent(sha)}`;
54
+ }
55
+ else {
56
+ return `${repositoryUrl}/-/commit/${encodeURIComponent(sha)}`;
57
+ }
58
+ case GitProvider.Bitbucket:
59
+ return repositoryUrl ? `${repositoryUrl}/commits/${encodeURIComponent(sha)}` : undefined;
60
+ default:
61
+ return undefined;
62
+ }
63
+ };
64
+ export const createReportCiContext = (ci) => {
65
+ if (!ci) {
66
+ return { commitSha: undefined, commitHref: undefined, ciRunName: undefined, ciRunHref: undefined };
67
+ }
68
+ const sha = ci.commitSha;
69
+ const pipelineHref = browserUrl(ci.pipelineRunUrl);
70
+ const runHref = pipelineHref || browserUrl(ci.jobRunUrl);
71
+ return {
72
+ commitSha: sha,
73
+ commitHref: sha ? commitUrl(ci, sha) : undefined,
74
+ ciRunHref: runHref,
75
+ ciRunName: runHref
76
+ ? pipelineHref
77
+ ? ci.pipelineRunName || "Pipeline"
78
+ : ci.jobRunName || ci.jobRunUid || ci.type
79
+ : undefined,
80
+ };
81
+ };
82
+ export const reportCiContextLinks = (report) => {
83
+ const links = [];
84
+ const sha = report.commitSha;
85
+ const shaUrl = browserUrl(report.commitHref);
86
+ const runUrl = browserUrl(report.ciRunHref);
87
+ if (sha && shaUrl) {
88
+ links.push({ label: sha.slice(0, 8), href: shaUrl });
89
+ }
90
+ if (runUrl) {
91
+ links.push({ label: report.ciRunName || "CI run", href: runUrl });
92
+ }
93
+ return links;
94
+ };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from "./reportContext.js";
2
2
  export * from "./reportMarkdown.js";
3
3
  export { applyAllureCiEnv } from "./ciEnv.js";
4
4
  export { detect } from "./detect.js";
5
+ export { createReportCiContext } from "./helpers/reportCiContext.js";
5
6
  export { isLocalCiDescriptor } from "./detectors/local.js";
6
7
  export { restoreGitlabHistory, upsertGitlabJobNote } from "./helpers/gitlab/index.js";
7
8
  export type { GitlabCiDescriptor } from "./detectors/gitlab.js";
package/dist/index.js CHANGED
@@ -2,5 +2,6 @@ export * from "./reportContext.js";
2
2
  export * from "./reportMarkdown.js";
3
3
  export { applyAllureCiEnv } from "./ciEnv.js";
4
4
  export { detect } from "./detect.js";
5
+ export { createReportCiContext } from "./helpers/reportCiContext.js";
5
6
  export { isLocalCiDescriptor } from "./detectors/local.js";
6
7
  export { restoreGitlabHistory, upsertGitlabJobNote } from "./helpers/gitlab/index.js";
@@ -1,3 +1,4 @@
1
+ import { reportCiContextLinks } from "./helpers/reportCiContext.js";
1
2
  const STATUS_ORDER = ["passed", "failed", "broken", "skipped", "unknown"];
2
3
  const STATUS_LABELS = {
3
4
  passed: "Passed tests",
@@ -144,6 +145,7 @@ const toReportLink = (report) => {
144
145
  label: reportLabel(report),
145
146
  href,
146
147
  kind: reportLinkKind(report),
148
+ context: reportCiContextLinks(report),
147
149
  }
148
150
  : undefined;
149
151
  };
@@ -158,7 +160,21 @@ const renderReportLinks = (reports) => {
158
160
  const links = sortLinks(reports.map(toReportLink).filter((item) => item !== undefined));
159
161
  const reportLinks = links.filter(({ kind }) => kind === "report");
160
162
  const testOpsLinks = links.filter(({ kind }) => kind === "testops");
161
- return [renderLinks("Reports", reportLinks), renderLinks("Allure TestOps", testOpsLinks)].filter((line) => line !== undefined);
163
+ const context = reportLinks[0]?.context ?? [];
164
+ const hasSharedContext = reportLinks.every(({ context: current }) => current.length === context.length &&
165
+ current.every((item, index) => item.label === context[index].label && item.href === context[index].href));
166
+ if (hasSharedContext) {
167
+ return [
168
+ renderLinks("Reports", reportLinks),
169
+ renderLinks("Context", context),
170
+ renderLinks("Allure TestOps", testOpsLinks),
171
+ ].filter((line) => line !== undefined);
172
+ }
173
+ const reportItems = reportLinks.map(({ label, href, context }) => {
174
+ const links = [{ label: "Report", href }, ...context];
175
+ return `* ${escapeHtml(label)} - ${links.map((item) => link(item.label, item.href)).join(", ")}`;
176
+ });
177
+ return [["**Reports:**", ...reportItems].join("\n"), renderLinks("Allure TestOps", testOpsLinks)].filter((line) => line !== undefined);
162
178
  };
163
179
  const pluginSummaryToStatusStats = (report) => ({
164
180
  failed: report.stats.failed ?? 0,
package/dist/utils.js CHANGED
@@ -5,7 +5,7 @@ export const parseURLPath = (urlString) => {
5
5
  const { pathname } = new URL(urlString);
6
6
  return pathname.replace(/^\/+/, "");
7
7
  }
8
- catch (error) {
8
+ catch {
9
9
  return "";
10
10
  }
11
11
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/ci",
3
- "version": "3.21.0",
3
+ "version": "3.22.0",
4
4
  "description": "Utilities set to get useful report data from different CI",
5
5
  "keywords": [
6
6
  "allure",
@@ -27,27 +27,29 @@
27
27
  "scripts": {
28
28
  "build": "run clean && tsc --project ./tsconfig.json",
29
29
  "clean": "rimraf ./dist",
30
- "test": "rimraf ./out && vitest run",
30
+ "test": "rimraf out && vp test run",
31
31
  "test:unit": "yarn test",
32
- "lint": "oxlint --import-plugin src test features stories",
33
- "lint:fix": "oxlint --import-plugin --fix src test features stories"
32
+ "lint": "vp lint --import-plugin src test features stories",
33
+ "lint:fix": "vp lint --import-plugin --fix src test features stories"
34
34
  },
35
35
  "dependencies": {
36
- "@allurereport/core-api": "3.21.0",
37
- "@allurereport/plugin-api": "3.21.0",
36
+ "@allurereport/core-api": "3.22.0",
37
+ "@allurereport/plugin-api": "3.22.0",
38
38
  "axios": "^1.20.0",
39
39
  "glob": "^13.0.6"
40
40
  },
41
41
  "devDependencies": {
42
- "@allurereport/test-config": "3.21.0",
42
+ "@allurereport/common-config": "3.22.0",
43
43
  "@types/node": "^20",
44
- "@vitest/coverage-istanbul": "^4.1.0",
45
- "@vitest/runner": "^2.1.8",
46
- "@vitest/snapshot": "^5.0.1",
44
+ "@vitest/coverage-istanbul": "5.0.4",
45
+ "@vitest/runner": "^2",
46
+ "@vitest/snapshot": "5.0.4",
47
47
  "allure-js-commons": "^3",
48
48
  "allure-vitest": "^3",
49
49
  "rimraf": "^6",
50
50
  "typescript": "^5",
51
- "vitest": "^4.1.0"
51
+ "vite": "@voidzero-dev/vite-plus-core@1.2.0",
52
+ "vite-plus": "1.2.0",
53
+ "vitest": "5.0.4"
52
54
  }
53
55
  }
@@ -1,9 +0,0 @@
1
- export { amazon } from "./amazon.js";
2
- export { azure } from "./azure.js";
3
- export { bitbucket } from "./bitbucket.js";
4
- export { circle } from "./circle.js";
5
- export { drone } from "./drone.js";
6
- export { github } from "./github.js";
7
- export { gitlab } from "./gitlab.js";
8
- export { jenkins } from "./jenkins.js";
9
- export { local } from "./local.js";
@@ -1,9 +0,0 @@
1
- export { amazon } from "./amazon.js";
2
- export { azure } from "./azure.js";
3
- export { bitbucket } from "./bitbucket.js";
4
- export { circle } from "./circle.js";
5
- export { drone } from "./drone.js";
6
- export { github } from "./github.js";
7
- export { gitlab } from "./gitlab.js";
8
- export { jenkins } from "./jenkins.js";
9
- export { local } from "./local.js";