Skip to content

Commit e9b4a58

Browse files
Fix artifacts parsing for @opentelemetry/exporter-trace-otlp-http version <0.29.0 (#36)
1 parent b8144c1 commit e9b4a58

15 files changed

+239
-344
lines changed

CHANGELOG.md

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.13.2] - 2025-01-04
11+
12+
### Fixed
13+
14+
- Fix artifacts parsing for `@opentelemetry/exporter-trace-otlp-http` version `<0.29.0`
15+
16+
### Changed
17+
18+
- Refactor artifacts handling
19+
1020
## [1.13.1] - 2024-12-31
1121

1222
### Fixed
@@ -113,7 +123,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
113123
- Support for `https` endpoints (proto over http).
114124
- Update to node 20.x
115125

116-
[unreleased]: https://github.com/corentinmusard/otel-cicd-action/compare/v1.13.1...HEAD
126+
[unreleased]: https://github.com/corentinmusard/otel-cicd-action/compare/v1.13.2...HEAD
127+
[1.13.2]: https://github.com/corentinmusard/otel-cicd-action/compare/v1.13.1...v1.13.2
117128
[1.13.1]: https://github.com/corentinmusard/otel-cicd-action/compare/v1.13.0...v1.13.1
118129
[1.13.0]: https://github.com/corentinmusard/otel-cicd-action/compare/v1.12.1...v1.13.0
119130
[1.12.1]: https://github.com/corentinmusard/otel-cicd-action/compare/v1.12.0...v1.12.1

dist/index.js

+81-122
Large diffs are not rendered by default.

dist/index.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/__assets__/run.rec

+2-2
Large diffs are not rendered by default.

src/github/__assets__/getPRLabels.rec

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
/repos/{owner}/{repo}/issues/{issue_number}/labels
1+
https://api.github.com/repos/corentinmusard/otel-cicd-action/issues/18/labels
22
https://api.github.com/repos/corentinmusard/otel-cicd-action/issues/18/labels
33
200
44
W3siaWQiOjY1NzA0MjU5NzUsIm5vZGVfaWQiOiJMQV9rd0RPTFRpOGtzOEFBQUFCaDZDLWR3IiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9jb3JlbnRpbm11c2FyZC9vdGVsLWNpY2QtYWN0aW9uL2xhYmVscy9lbmhhbmNlbWVudCIsIm5hbWUiOiJlbmhhbmNlbWVudCIsImNvbG9yIjoiYTJlZWVmIiwiZGVmYXVsdCI6dHJ1ZSwiZGVzY3JpcHRpb24iOiJOZXcgZmVhdHVyZSBvciByZXF1ZXN0In0seyJpZCI6NzA3NDExMDQ1OSwibm9kZV9pZCI6IkxBX2t3RE9MVGk4a3M4QUFBQUJwYVpiLXciLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2NvcmVudGlubXVzYXJkL290ZWwtY2ljZC1hY3Rpb24vbGFiZWxzL3Rlc3QiLCJuYW1lIjoidGVzdCIsImNvbG9yIjoiOTM4MkY5IiwiZGVmYXVsdCI6ZmFsc2UsImRlc2NyaXB0aW9uIjoiIn1d
5-
/repos/{owner}/{repo}/issues/{issue_number}/labels
5+
https://api.github.com/repos/corentinmusard/otel-cicd-action/issues/19/labels
66
https://api.github.com/repos/corentinmusard/otel-cicd-action/issues/19/labels
77
200
88
W10=
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
/repos/{owner}/{repo}/issues/{issue_number}/labels
1+
https://api.github.com/repos/corentinmusard/otel-cicd-action/issues/18/labels
22
https://api.github.com/repos/corentinmusard/otel-cicd-action/issues/18/labels
33
200
44
W3siaWQiOjY1NzA0MjU5NzUsIm5vZGVfaWQiOiJMQV9rd0RPTFRpOGtzOEFBQUFCaDZDLWR3IiwidXJsIjoiaHR0cHM6Ly9hcGkuZ2l0aHViLmNvbS9yZXBvcy9jb3JlbnRpbm11c2FyZC9vdGVsLWNpY2QtYWN0aW9uL2xhYmVscy9lbmhhbmNlbWVudCIsIm5hbWUiOiJlbmhhbmNlbWVudCIsImNvbG9yIjoiYTJlZWVmIiwiZGVmYXVsdCI6dHJ1ZSwiZGVzY3JpcHRpb24iOiJOZXcgZmVhdHVyZSBvciByZXF1ZXN0In0seyJpZCI6NzA3NDExMDQ1OSwibm9kZV9pZCI6IkxBX2t3RE9MVGk4a3M4QUFBQUJwYVpiLXciLCJ1cmwiOiJodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL2NvcmVudGlubXVzYXJkL290ZWwtY2ljZC1hY3Rpb24vbGFiZWxzL3Rlc3QiLCJuYW1lIjoidGVzdCIsImNvbG9yIjoiOTM4MkY5IiwiZGVmYXVsdCI6ZmFsc2UsImRlc2NyaXB0aW9uIjoiIn1d
5-
/repos/{owner}/{repo}/issues/{issue_number}/labels
5+
https://api.github.com/repos/corentinmusard/otel-cicd-action/issues/19/labels
66
https://api.github.com/repos/corentinmusard/otel-cicd-action/issues/19/labels
77
200
88
W10=

src/github/__assets__/getWorkflowRunJobs.rec

+1-1
Large diffs are not rendered by default.

src/github/github.test.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-meth
88
import fetchMock from "jest-fetch-mock";
99
import { mock, mockDeep } from "jest-mock-extended";
1010
import type { Octokit } from "./github";
11-
import { type WorkflowArtifactDownload, listWorkflowRunArtifacts } from "./github";
11+
import { listWorkflowRunArtifacts } from "./github";
1212

1313
const __filename = url.fileURLToPath(import.meta.url);
1414
const __dirname = path.dirname(__filename);
@@ -22,7 +22,7 @@ type DownloadArtifactResponse = RestEndpointMethodTypes["actions"]["downloadArti
2222
describe("listWorkflowRunArtifacts", () => {
2323
let mockContext: Context;
2424
let mockOctokit: Octokit = mockDeep<Octokit>();
25-
let subject: WorkflowArtifactDownload;
25+
let artifactPath: string;
2626

2727
beforeAll(async () => {
2828
mockContext = mockDeep<Context>();
@@ -47,29 +47,29 @@ describe("listWorkflowRunArtifacts", () => {
4747
fetchMock.mockResponseOnce(() => Promise.resolve({ body: zipFile as unknown as string }));
4848

4949
const lookup = await listWorkflowRunArtifacts(mockContext, mockOctokit, 1);
50-
const response = lookup("lint-and-test", "run tests");
50+
const response = lookup.get("lint-and-test")?.get("run tests");
5151
if (!response) {
5252
fail("Lookup Failed: Did not parse zip file correctly");
5353
}
54-
subject = response;
54+
artifactPath = response;
5555
});
5656

5757
afterAll(() => {
58-
if (subject?.path) {
59-
fs.unlinkSync(subject.path);
58+
if (artifactPath) {
59+
fs.unlinkSync(artifactPath);
6060
}
6161
});
6262

6363
it("test WorkflowArtifactDownload return to be defined", () => {
64-
expect(subject).toBeDefined();
64+
expect(artifactPath).toBeDefined();
6565
});
6666

6767
it("test WorkflowArtifactDownload path exists", () => {
68-
expect(subject.path).toEqual("{lint-and-test}{run tests}.log");
69-
expect(fs.existsSync(subject.path)).toBeTruthy();
68+
expect(artifactPath).toEqual("{lint-and-test}{run tests}.log");
69+
expect(fs.existsSync(artifactPath)).toBeTruthy();
7070
});
7171
it("test WorkflowArtifactDownload has data", () => {
72-
const data = fs.readFileSync(subject.path, { encoding: "utf8", flag: "r" });
72+
const data = fs.readFileSync(artifactPath, { encoding: "utf8", flag: "r" });
7373
// expect(data.length).toBeGreaterThan(0);
7474
const lines = data.split("\n");
7575
expect(lines.length).toBeGreaterThan(1);

src/github/github.ts

+47-98
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,21 @@ import * as artifact from "@actions/artifact";
44
import * as core from "@actions/core";
55
import type { Context } from "@actions/github/lib/context";
66
import type { GitHub } from "@actions/github/lib/utils";
7-
import type { components } from "@octokit/openapi-types";
87
import JSZip from "jszip";
98

109
type Octokit = InstanceType<typeof GitHub>;
11-
type WorkflowRunJob = components["schemas"]["job"];
1210

13-
type WorkflowArtifactMap = {
14-
[job: string]: {
15-
[step: string]: WorkflowArtifactDownload;
16-
};
17-
};
18-
19-
type WorkflowArtifactDownload = {
20-
jobName: string;
21-
stepName: string;
22-
path: string;
23-
};
24-
25-
type WorkflowArtifactLookup = (jobName: string, stepName: string) => WorkflowArtifactDownload | undefined;
11+
type JobName = string;
12+
type StepName = string;
13+
type ArtifactPath = string;
2614

27-
async function listWorkflowRunArtifacts(
28-
context: Context,
29-
octokit: Octokit,
30-
runId: number,
31-
): Promise<WorkflowArtifactLookup> {
32-
let artifactsLookup: WorkflowArtifactMap = {};
15+
type StepArtifactMap = Map<StepName, ArtifactPath>;
16+
type JobArtifactMap = Map<JobName, StepArtifactMap>;
3317

34-
if (runId === context.runId) {
35-
artifactsLookup = await getSelfArtifactMap();
36-
} else {
37-
artifactsLookup = await getWorkflowRunArtifactMap(context, octokit, runId);
38-
}
39-
return (jobName: string, stepName: string) => {
40-
try {
41-
return artifactsLookup[jobName][stepName];
42-
} catch (_e) {
43-
return undefined;
44-
}
45-
};
18+
async function listWorkflowRunArtifacts(context: Context, octokit: Octokit, runId: number) {
19+
return runId === context.runId
20+
? await getSelfArtifactMap()
21+
: await getWorkflowRunArtifactMap(context, octokit, runId);
4622
}
4723

4824
const artifactNameRegex = /\{(?<jobName>.*)\}\{(?<stepName>.*)\}/;
@@ -54,15 +30,14 @@ async function getWorkflowRunArtifactMap(context: Context, octokit: Octokit, run
5430
per_page: 100,
5531
});
5632

57-
const artifactsLookup: WorkflowArtifactMap = await artifacts.reduce(async (resultP, artifact) => {
58-
const result = await resultP;
33+
return await artifacts.reduce(async (resultP: Promise<JobArtifactMap>, artifact) => {
34+
const next = await resultP;
5935
const match = artifact.name.match(artifactNameRegex);
60-
const next: WorkflowArtifactMap = { ...result };
6136
if (match?.groups?.["jobName"] && match?.groups?.["stepName"]) {
6237
const { jobName, stepName } = match.groups;
6338
core.debug(`Found Artifact for Job<${jobName}> Step<${stepName}>`);
64-
if (!(jobName in next)) {
65-
next[jobName] = {};
39+
if (!next.has(jobName)) {
40+
next.set(jobName, new Map());
6641
}
6742

6843
const downloadResponse = await octokit.rest.actions.downloadArtifact({
@@ -77,11 +52,7 @@ async function getWorkflowRunArtifactMap(context: Context, octokit: Octokit, run
7752
// useful for testing because the artifact url expires after 1 minute
7853
if (fs.existsSync(`${artifact.name}.log`)) {
7954
core.debug(`Artifact ${artifact.name} already exists, skipping download`);
80-
next[jobName][stepName] = {
81-
jobName,
82-
stepName,
83-
path: filename,
84-
};
55+
next.get(jobName)?.set(stepName, filename);
8556
return next;
8657
}
8758

@@ -93,86 +64,54 @@ async function getWorkflowRunArtifactMap(context: Context, octokit: Octokit, run
9364
zip.files[Object.keys(zip.files)[0]].nodeStream().pipe(writeStream);
9465
await new Promise((fulfill) => writeStream.on("finish", fulfill));
9566
core.debug(`Downloaded Artifact ${writeStream.path.toString()}`);
96-
next[jobName][stepName] = {
97-
jobName,
98-
stepName,
99-
path: writeStream.path.toString(),
100-
};
67+
next.get(jobName)?.set(stepName, writeStream.path.toString());
10168
} finally {
10269
writeStream.close();
10370
}
10471
}
10572

10673
return next;
107-
}, Promise.resolve({}));
108-
return artifactsLookup;
74+
}, Promise.resolve(new Map()));
10975
}
11076

11177
async function getSelfArtifactMap() {
11278
const client = artifact.create();
11379
const responses = await client.downloadAllArtifacts();
114-
const artifactsMap: WorkflowArtifactMap = responses.reduce((result, { artifactName, downloadPath }) => {
115-
const next: WorkflowArtifactMap = { ...result };
80+
81+
return responses.reduce((result: JobArtifactMap, { artifactName, downloadPath }) => {
82+
const next = result;
11683
const match = artifactName.match(artifactNameRegex);
11784
if (match?.groups?.["jobName"] && match?.groups?.["stepName"]) {
11885
const { jobName, stepName } = match.groups;
11986
core.debug(`Found Artifact for Job<${jobName}> Step<${stepName}>`);
120-
if (!(jobName in next)) {
121-
next[jobName] = {};
87+
if (!next.has(jobName)) {
88+
next.set(jobName, new Map());
12289
}
90+
12391
const artifactDirFiles = fs.readdirSync(downloadPath);
124-
if (artifactDirFiles && artifactDirFiles.length > 0) {
125-
next[jobName][stepName] = {
126-
jobName,
127-
stepName,
128-
path: path.join(downloadPath, artifactDirFiles[0]),
129-
};
92+
if (artifactDirFiles.length > 0) {
93+
next.get(jobName)?.set(stepName, path.join(downloadPath, artifactDirFiles[0]));
13094
}
13195
}
13296
return next;
133-
}, {});
134-
135-
return artifactsMap;
97+
}, new Map());
13698
}
13799

138-
async function listJobsForWorkflowRun(context: Context, octokit: Octokit, runId: number) {
139-
return await octokit.paginate(octokit.rest.actions.listJobsForWorkflowRun, {
100+
async function getWorkflowRun(context: Context, octokit: Octokit, runId: number) {
101+
const res = await octokit.rest.actions.getWorkflowRun({
140102
...context.repo,
141103
run_id: runId,
142-
filter: "latest", // risk of missing a run if re-run happens between Action trigger and this query
143-
per_page: 100,
144104
});
105+
return res.data;
145106
}
146107

147-
type WorkflowRunJobs = {
148-
workflowRun: components["schemas"]["workflow-run"];
149-
jobs: WorkflowRunJob[];
150-
workflowRunArtifacts: WorkflowArtifactLookup;
151-
};
152-
153-
async function getWorkflowRunJobs(context: Context, octokit: Octokit, runId: number) {
154-
const getWorkflowRunResponse = await octokit.rest.actions.getWorkflowRun({
108+
async function listJobsForWorkflowRun(context: Context, octokit: Octokit, runId: number) {
109+
return await octokit.paginate(octokit.rest.actions.listJobsForWorkflowRun, {
155110
...context.repo,
156111
run_id: runId,
112+
filter: "latest", // risk of missing a run if re-run happens between Action trigger and this query
113+
per_page: 100,
157114
});
158-
159-
const workflowRunArtifacts = await listWorkflowRunArtifacts(context, octokit, runId);
160-
const jobs = await listJobsForWorkflowRun(context, octokit, runId);
161-
162-
const workflowRunJobs: WorkflowRunJobs = {
163-
workflowRun: getWorkflowRunResponse.data,
164-
jobs,
165-
workflowRunArtifacts,
166-
};
167-
return workflowRunJobs;
168-
}
169-
170-
async function getPRLabels(context: Context, octokit: Octokit, prNumber: number) {
171-
const labelResponse = await octokit.rest.issues.listLabelsOnIssue({
172-
...context.repo,
173-
issue_number: prNumber,
174-
});
175-
return labelResponse.data.map((l) => l.name);
176115
}
177116

178117
async function getPRsLabels(context: Context, octokit: Octokit, prNumbers: number[]) {
@@ -184,14 +123,24 @@ async function getPRsLabels(context: Context, octokit: Octokit, prNumbers: numbe
184123
return labels;
185124
}
186125

126+
async function getPRLabels(context: Context, octokit: Octokit, prNumber: number) {
127+
return await octokit.paginate(
128+
octokit.rest.issues.listLabelsOnIssue,
129+
{
130+
...context.repo,
131+
issue_number: prNumber,
132+
},
133+
(response) => response.data.map((issue) => issue.name),
134+
);
135+
}
136+
187137
export {
188-
getWorkflowRunJobs,
138+
getWorkflowRun,
189139
listWorkflowRunArtifacts,
140+
listJobsForWorkflowRun,
190141
getPRLabels,
191142
getPRsLabels,
192143
type Octokit,
193-
type WorkflowArtifactDownload,
194-
type WorkflowArtifactLookup,
195-
type WorkflowRunJob,
196-
type WorkflowRunJobs,
144+
type StepArtifactMap,
145+
type JobArtifactMap,
197146
};

src/github/github2.test.ts

+1-19
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,11 @@
11
import { Context } from "@actions/github/lib/context";
22
import { replayOctokit } from "../replay";
3-
import { type Octokit, getPRLabels, getPRsLabels, getWorkflowRunJobs } from "./github";
3+
import { type Octokit, getPRLabels, getPRsLabels } from "./github";
44

55
const token = process.env["GH_TOKEN"] ?? "";
66
const owner = "corentinmusard";
77
const repo = "otel-cicd-action";
88

9-
describe("getWorkflowRunJobs", () => {
10-
let octokit: Octokit;
11-
12-
beforeAll(async () => {
13-
process.env["GITHUB_REPOSITORY"] = "biomejs/biome";
14-
octokit = await replayOctokit("getWorkflowRunJobs", token);
15-
});
16-
17-
it("should return the workflow run jobs", async () => {
18-
const context = new Context();
19-
context.runId = 2; // different than 12541749172
20-
21-
const workflowRunJobs = await getWorkflowRunJobs(context, octokit, 12541749172);
22-
expect(workflowRunJobs.jobs).toHaveLength(8);
23-
expect(workflowRunJobs.workflowRun.id).toBe(12541749172);
24-
}, 10000);
25-
});
26-
279
describe("getPRLabels", () => {
2810
let octokit: Octokit;
2911

0 commit comments

Comments
 (0)