Skip to content

Commit 1522d5f

Browse files
committed
chore: sync allure testops contract changes, simplify code
1 parent ed3f9dd commit 1522d5f

26 files changed

Lines changed: 1120 additions & 581 deletions

packages/ci/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,4 @@
88
- 📢 [Official announcements](https://github.com/orgs/allure-framework/discussions/categories/announcements) – be in touch with the latest updates
99
- 💬 [General Discussion ](https://github.com/orgs/allure-framework/discussions/categories/general-discussion) – engage in casual conversations, share insights and ideas with the community
1010

11-
---
12-
13-
TODO:
11+
---

packages/ci/src/detectors/github.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ import { join } from "node:path/posix";
22

33
import { type CiDescriptor, CiType } from "@allurereport/core-api";
44

5+
import { resolveGithubPullRequestNumber } from "../githubPullRequest.js";
56
import { getEnv } from "../utils.js";
67

7-
const pullRequestSuffixRe = /\/merge$/;
8-
98
const getBaseURL = () => getEnv("GITHUB_SERVER_URL");
109

1110
const getRunID = () => getEnv("GITHUB_RUN_ID");
@@ -62,13 +61,12 @@ export const github: CiDescriptor = {
6261
},
6362

6463
get pullRequestUrl(): string {
65-
const refName = getEnv("GITHUB_REF_NAME");
64+
const pullRequestNumber = resolveGithubPullRequestNumber();
6665

67-
if (!pullRequestSuffixRe.test(refName)) {
66+
if (!pullRequestNumber) {
6867
return "";
6968
}
7069

71-
const pullRequestNumber = refName.replace(pullRequestSuffixRe, "");
7270
const serverUrl = getEnv("GITHUB_SERVER_URL");
7371
const repo = getRepo();
7472
const pathname = join(repo, "pull", pullRequestNumber);
@@ -77,14 +75,12 @@ export const github: CiDescriptor = {
7775
},
7876

7977
get pullRequestName(): string {
80-
const refName = getEnv("GITHUB_REF_NAME");
78+
const pullRequestNumber = resolveGithubPullRequestNumber();
8179

82-
if (!pullRequestSuffixRe.test(refName)) {
80+
if (!pullRequestNumber) {
8381
return "";
8482
}
8583

86-
const pullRequestNumber = refName.replace(pullRequestSuffixRe, "");
87-
8884
return `Pull request #${pullRequestNumber}`;
8985
},
9086
};

packages/ci/src/gitHints/github.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { type CiDescriptor, type CiGitHints, GitProvider } from "@allurereport/core-api";
22

3+
import { resolveGithubPullRequestNumber } from "../githubPullRequest.js";
34
import { getEnv } from "../utils.js";
45

5-
const pullRequestSuffixRe = /\/merge$/;
6-
76
const stripRefsHeads = (ref: string): string => ref.replace(/^refs\/heads\//, "");
87

98
export const resolveGithubGitHints = (ci: CiDescriptor): CiGitHints => {
@@ -21,8 +20,7 @@ export const resolveGithubGitHints = (ci: CiDescriptor): CiGitHints => {
2120
const sourceBranch = headRef || stripRefsHeads(getEnv("GITHUB_REF")) || ci.jobRunBranch || undefined;
2221
const targetBranch = baseRef || undefined;
2322

24-
const refName = getEnv("GITHUB_REF_NAME");
25-
const pullRequestId = pullRequestSuffixRe.test(refName) ? refName.replace(pullRequestSuffixRe, "") : "";
23+
const pullRequestId = resolveGithubPullRequestNumber();
2624

2725
const pullRequest = pullRequestId
2826
? {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { readFileSync } from "node:fs";
2+
3+
import { getEnv } from "./utils.js";
4+
5+
const pullRequestSuffixRe = /\/merge$/;
6+
const pullRequestMergeRefRe = /^refs\/pull\/(\d+)\/merge$/;
7+
8+
export const parsePullRequestNumberFromEventJson = (content: string): string => {
9+
try {
10+
const event = JSON.parse(content) as { pull_request?: { number?: number } };
11+
const number = event?.pull_request?.number;
12+
13+
if (number === undefined || number === null) {
14+
return "";
15+
}
16+
17+
return String(number);
18+
} catch {
19+
return "";
20+
}
21+
};
22+
23+
const readPullRequestNumberFromEventPath = (): string => {
24+
const eventPath = getEnv("GITHUB_EVENT_PATH");
25+
26+
if (!eventPath) {
27+
return "";
28+
}
29+
30+
try {
31+
const content = readFileSync(eventPath, "utf-8");
32+
33+
return parsePullRequestNumberFromEventJson(content);
34+
} catch {
35+
return "";
36+
}
37+
};
38+
39+
export const resolveGithubPullRequestNumber = (): string => {
40+
const refName = getEnv("GITHUB_REF_NAME") || "";
41+
42+
if (pullRequestSuffixRe.test(refName)) {
43+
return refName.replace(pullRequestSuffixRe, "");
44+
}
45+
46+
const githubRef = getEnv("GITHUB_REF") || "";
47+
const mergeRefMatch = githubRef.match(pullRequestMergeRefRe);
48+
49+
if (mergeRefMatch) {
50+
return mergeRefMatch[1];
51+
}
52+
53+
const headRef = getEnv("GITHUB_HEAD_REF");
54+
const baseRef = getEnv("GITHUB_BASE_REF");
55+
56+
if (headRef && baseRef) {
57+
return readPullRequestNumberFromEventPath();
58+
}
59+
60+
return "";
61+
};

packages/ci/test/detectors/github.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { readFileSync } from "node:fs";
2+
13
import { type Mock, beforeEach, describe, expect, it, vi } from "vitest";
24

35
import { github } from "../../src/detectors/github.js";
@@ -7,6 +9,10 @@ vi.mock("../../src/utils.js", () => ({
79
getEnv: vi.fn(),
810
}));
911

12+
vi.mock("node:fs", () => ({
13+
readFileSync: vi.fn(),
14+
}));
15+
1016
beforeEach(() => {
1117
vi.clearAllMocks();
1218
});
@@ -271,6 +277,25 @@ describe("github", () => {
271277

272278
expect(github.pullRequestUrl).toBe("");
273279
});
280+
281+
it("should resolve pull request URL from GITHUB_EVENT_PATH for pull_request_target workflows", () => {
282+
(getEnv as Mock).mockImplementation((key: string) => {
283+
const env: Record<string, string> = {
284+
GITHUB_HEAD_REF: "feature/foo",
285+
GITHUB_BASE_REF: "main",
286+
GITHUB_REF: "refs/heads/main",
287+
GITHUB_REF_NAME: "main",
288+
GITHUB_EVENT_PATH: "/tmp/event.json",
289+
GITHUB_SERVER_URL: "https://github.com",
290+
GITHUB_REPOSITORY: "myorg/myrepo",
291+
};
292+
293+
return env[key] ?? "";
294+
});
295+
(readFileSync as Mock).mockReturnValue(JSON.stringify({ pull_request: { number: 123 } }));
296+
297+
expect(github.pullRequestUrl).toBe("https://github.com/myorg/myrepo/pull/123");
298+
});
274299
});
275300

276301
describe("pullRequestName", () => {
@@ -303,5 +328,22 @@ describe("github", () => {
303328

304329
expect(github.pullRequestName).toBe("");
305330
});
331+
332+
it("should resolve pull request name from GITHUB_EVENT_PATH for pull_request_target workflows", () => {
333+
(getEnv as Mock).mockImplementation((key: string) => {
334+
const env: Record<string, string> = {
335+
GITHUB_HEAD_REF: "feature/foo",
336+
GITHUB_BASE_REF: "main",
337+
GITHUB_REF: "refs/heads/main",
338+
GITHUB_REF_NAME: "main",
339+
GITHUB_EVENT_PATH: "/tmp/event.json",
340+
};
341+
342+
return env[key] ?? "";
343+
});
344+
(readFileSync as Mock).mockReturnValue(JSON.stringify({ pull_request: { number: 123 } }));
345+
346+
expect(github.pullRequestName).toBe("Pull request #123");
347+
});
306348
});
307349
});
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import { readFileSync } from "node:fs";
2+
3+
import { type Mock, beforeEach, describe, expect, it, vi } from "vitest";
4+
5+
import { parsePullRequestNumberFromEventJson, resolveGithubPullRequestNumber } from "../src/githubPullRequest.js";
6+
import { getEnv } from "../src/utils.js";
7+
8+
vi.mock("../src/utils.js", () => ({
9+
getEnv: vi.fn(),
10+
}));
11+
12+
vi.mock("node:fs", () => ({
13+
readFileSync: vi.fn(),
14+
}));
15+
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
});
19+
20+
describe("parsePullRequestNumberFromEventJson", () => {
21+
it("returns pull request number from event payload", () => {
22+
expect(
23+
parsePullRequestNumberFromEventJson(JSON.stringify({ pull_request: { number: 77, title: "Fix things" } })),
24+
).toBe("77");
25+
});
26+
27+
it("returns empty string for invalid JSON", () => {
28+
expect(parsePullRequestNumberFromEventJson("{not-json")).toBe("");
29+
});
30+
31+
it("returns empty string when pull_request is missing", () => {
32+
expect(parsePullRequestNumberFromEventJson(JSON.stringify({ action: "opened" }))).toBe("");
33+
});
34+
35+
it("returns empty string when pull_request.number is missing", () => {
36+
expect(parsePullRequestNumberFromEventJson(JSON.stringify({ pull_request: { title: "No number" } }))).toBe("");
37+
});
38+
});
39+
40+
describe("resolveGithubPullRequestNumber", () => {
41+
it("resolves pull request id from GITHUB_REF_NAME merge suffix", () => {
42+
(getEnv as Mock).mockImplementation((key: string) => {
43+
if (key === "GITHUB_REF_NAME") {
44+
return "42/merge";
45+
}
46+
47+
return "";
48+
});
49+
50+
expect(resolveGithubPullRequestNumber()).toBe("42");
51+
});
52+
53+
it("resolves pull request id from GITHUB_REF merge ref", () => {
54+
(getEnv as Mock).mockImplementation((key: string) => {
55+
const env: Record<string, string> = {
56+
GITHUB_REF: "refs/pull/99/merge",
57+
GITHUB_REF_NAME: "99",
58+
};
59+
60+
return env[key] ?? "";
61+
});
62+
63+
expect(resolveGithubPullRequestNumber()).toBe("99");
64+
});
65+
66+
it("resolves pull request id from GITHUB_EVENT_PATH for pull_request_target workflows", () => {
67+
(getEnv as Mock).mockImplementation((key: string) => {
68+
const env: Record<string, string> = {
69+
GITHUB_HEAD_REF: "feature/foo",
70+
GITHUB_BASE_REF: "main",
71+
GITHUB_REF: "refs/heads/main",
72+
GITHUB_REF_NAME: "main",
73+
GITHUB_EVENT_PATH: "/tmp/event.json",
74+
};
75+
76+
return env[key] ?? "";
77+
});
78+
(readFileSync as Mock).mockReturnValue(JSON.stringify({ pull_request: { number: 77 } }));
79+
80+
expect(resolveGithubPullRequestNumber()).toBe("77");
81+
expect(readFileSync).toHaveBeenCalledWith("/tmp/event.json", "utf-8");
82+
});
83+
84+
it("does not read event file when ref-based detection succeeds", () => {
85+
(getEnv as Mock).mockImplementation((key: string) => {
86+
const env: Record<string, string> = {
87+
GITHUB_HEAD_REF: "feature/foo",
88+
GITHUB_BASE_REF: "main",
89+
GITHUB_REF_NAME: "55/merge",
90+
GITHUB_EVENT_PATH: "/tmp/event.json",
91+
};
92+
93+
return env[key] ?? "";
94+
});
95+
96+
expect(resolveGithubPullRequestNumber()).toBe("55");
97+
expect(readFileSync).not.toHaveBeenCalled();
98+
});
99+
100+
it("returns empty string when event file is missing", () => {
101+
(getEnv as Mock).mockImplementation((key: string) => {
102+
const env: Record<string, string> = {
103+
GITHUB_HEAD_REF: "feature/foo",
104+
GITHUB_BASE_REF: "main",
105+
GITHUB_EVENT_PATH: "/tmp/missing-event.json",
106+
};
107+
108+
return env[key] ?? "";
109+
});
110+
(readFileSync as Mock).mockImplementation(() => {
111+
throw new Error("ENOENT");
112+
});
113+
114+
expect(resolveGithubPullRequestNumber()).toBe("");
115+
});
116+
117+
it("returns empty string when event JSON has no pull request number", () => {
118+
(getEnv as Mock).mockImplementation((key: string) => {
119+
const env: Record<string, string> = {
120+
GITHUB_HEAD_REF: "feature/foo",
121+
GITHUB_BASE_REF: "main",
122+
GITHUB_EVENT_PATH: "/tmp/event.json",
123+
};
124+
125+
return env[key] ?? "";
126+
});
127+
(readFileSync as Mock).mockReturnValue(JSON.stringify({ action: "push" }));
128+
129+
expect(resolveGithubPullRequestNumber()).toBe("");
130+
});
131+
132+
it("returns empty string when only one of head/base refs is set", () => {
133+
(getEnv as Mock).mockImplementation((key: string) => {
134+
if (key === "GITHUB_HEAD_REF") {
135+
return "feature/foo";
136+
}
137+
138+
if (key === "GITHUB_EVENT_PATH") {
139+
return "/tmp/event.json";
140+
}
141+
142+
return "";
143+
});
144+
(readFileSync as Mock).mockReturnValue(JSON.stringify({ pull_request: { number: 77 } }));
145+
146+
expect(resolveGithubPullRequestNumber()).toBe("");
147+
expect(readFileSync).not.toHaveBeenCalled();
148+
});
149+
});

0 commit comments

Comments
 (0)