Skip to content

Commit 4a98ab7

Browse files
authored
[spec-gen-sdk-runner] Move SpecGenSdkArtifactInfo to .github/shared (#38816)
- Prepares to enable `typescript-eslint` in `.github`
1 parent 90e9e68 commit 4a98ab7

17 files changed

+225
-143
lines changed

.github/shared/src/sdk-types.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,43 @@
1-
/* v8 ignore start */
1+
import * as z from "zod";
22

33
/**
4-
* @typedef {'azure-sdk-for-go' | 'azure-sdk-for-java' | 'azure-sdk-for-js' | 'azure-sdk-for-net' | 'azure-sdk-for-python'} SdkName
4+
* Represents supported SDK language identifiers.
5+
*
6+
* @readonly
7+
* @enum {"azure-sdk-for-go" | "azure-sdk-for-java" | "azure-sdk-for-js" | "azure-sdk-for-net" | "azure-sdk-for-python"}
8+
*/
9+
export const SdkName = Object.freeze({
10+
Go: "azure-sdk-for-go",
11+
Java: "azure-sdk-for-java",
12+
Js: "azure-sdk-for-js",
13+
Net: "azure-sdk-for-net",
14+
Python: "azure-sdk-for-python",
15+
});
16+
/** @type {import("zod").ZodType<SdkName>} */
17+
export const SdkNameSchema = z.enum(Object.values(SdkName));
18+
19+
/*
20+
* Data for the API view request.
21+
*/
22+
export const APIViewRequestDataSchema = z.object({ packageName: z.string(), filePath: z.string() });
23+
/**
24+
* @typedef {import("zod").infer<typeof APIViewRequestDataSchema>} APIViewRequestData
25+
*/
26+
27+
/**
28+
* Represents the result of the spec-gen-sdk generation process.
29+
*/
30+
export const SpecGenSdkArtifactInfoSchema = z.object({
31+
language: SdkNameSchema,
32+
result: z.string(),
33+
headSha: z.string(),
34+
prNumber: z.string().optional(),
35+
labelAction: z.boolean().optional(),
36+
isSpecGenSdkCheckRequired: z.boolean(),
37+
apiViewRequestData: z.array(APIViewRequestDataSchema),
38+
});
39+
/**
40+
* @typedef {import("zod").infer<typeof SpecGenSdkArtifactInfoSchema>} SpecGenSdkArtifactInfo
541
*/
642

743
/**

.github/shared/test/sdk-types.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { SdkName } from "../src/sdk-types.js";
2+
3+
/**
4+
* @typedef {import("../src/sdk-types.js").SpecGenSdkArtifactInfo} SpecGenSdkArtifactInfo
5+
*/
6+
7+
/**
8+
* Create a mock SpecGenSdkArtifactInfo, filling unspecified properties with defaults.
9+
*
10+
* @param {Partial<import("../src/sdk-types.js").SpecGenSdkArtifactInfo>} [overrides]
11+
* @returns {SpecGenSdkArtifactInfo}
12+
*/
13+
export function createMockSpecGenSdkArtifactInfo(overrides = {}) {
14+
/** @type {SpecGenSdkArtifactInfo} */
15+
const defaults = {
16+
apiViewRequestData: [],
17+
headSha: "abc123",
18+
isSpecGenSdkCheckRequired: true,
19+
language: SdkName.Go,
20+
result: "test result",
21+
};
22+
23+
return { ...defaults, ...overrides };
24+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { describe, expect, it } from "vitest";
2+
import { sdkLabels, SpecGenSdkArtifactInfoSchema } from "../src/sdk-types.js";
3+
import { createMockSpecGenSdkArtifactInfo } from "./sdk-types.js";
4+
5+
describe("sdk-types", () => {
6+
it("defines sdkLabels", () => {
7+
// Ensures constant "sdkLabels" is considered "covered" by codecov
8+
expect(sdkLabels).toBeDefined();
9+
});
10+
11+
it("parses SpecGetSdkArtifactInfo", () => {
12+
const artifactInfo = createMockSpecGenSdkArtifactInfo();
13+
14+
const json = JSON.stringify(artifactInfo);
15+
expect(json).toMatchInlineSnapshot(
16+
`"{"apiViewRequestData":[],"headSha":"abc123","isSpecGenSdkCheckRequired":true,"language":"azure-sdk-for-go","result":"test result"}"`,
17+
);
18+
19+
const parsed = SpecGenSdkArtifactInfoSchema.parse(JSON.parse(json));
20+
expect(parsed).toEqual(artifactInfo);
21+
});
22+
});

.github/workflows/src/sdk-breaking-change-labels.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { sdkLabels } from "../../shared/src/sdk-types.js";
1+
import { SpecGenSdkArtifactInfoSchema, sdkLabels } from "../../shared/src/sdk-types.js";
22
import { getAdoBuildInfoFromUrl, getAzurePipelineArtifact } from "./artifacts.js";
33
import { extractInputs } from "./context.js";
44
import { LabelAction } from "./label.js";
@@ -72,12 +72,14 @@ export async function getLabelAndActionImpl({ details_url, core, retryOptions =
7272
} else {
7373
core.info(`Artifact content: ${result.artifactData}`);
7474
// Parse the JSON data
75-
const specGenSdkArtifactInfo = JSON.parse(result.artifactData);
75+
const specGenSdkArtifactInfo = SpecGenSdkArtifactInfoSchema.parse(
76+
JSON.parse(result.artifactData),
77+
);
7678
const labelActionText = specGenSdkArtifactInfo.labelAction;
7779

7880
head_sha = specGenSdkArtifactInfo.headSha;
7981

80-
issue_number = parseInt(specGenSdkArtifactInfo.prNumber, 10);
82+
issue_number = parseInt(specGenSdkArtifactInfo.prNumber ?? "", 10);
8183
if (!issue_number) {
8284
core.warning(
8385
`No PR number found in the artifact '${artifactName}' with details_url:${details_url}.`,

.github/workflows/src/spec-gen-sdk-status.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CheckStatus, CommitStatusState, PER_PAGE_MAX } from "../../shared/src/github.js";
2+
import { SpecGenSdkArtifactInfoSchema } from "../../shared/src/sdk-types.js";
23
import { getAdoBuildInfoFromUrl, getAzurePipelineArtifact } from "./artifacts.js";
34
import { extractInputs } from "./context.js";
45
import { writeToActionsSummary } from "./github.js";
@@ -122,7 +123,7 @@ export async function setSpecGenSdkStatusImpl({
122123

123124
/**
124125
* @param {Object} params
125-
* @param {Array<any>} params.checkRuns
126+
* @param {import("./github.js").CheckRuns} params.checkRuns
126127
* @param {typeof import("@actions/core")} params.core
127128
* @returns {Promise<{state: CommitStatusState, description: string}>}
128129
*/
@@ -139,6 +140,9 @@ async function processResult({ checkRuns, core }) {
139140

140141
for (const checkRun of checkRuns) {
141142
core.info(`Processing check run: ${checkRun.name} (${checkRun.conclusion})`);
143+
if (checkRun.details_url === null) {
144+
throw new Error(`'details_url' is null in Check Run '${checkRun.name}'`);
145+
}
142146
const buildInfo = getAdoBuildInfoFromUrl(checkRun.details_url);
143147
const ado_project_url = buildInfo.projectUrl;
144148
const ado_build_id = buildInfo.buildId;
@@ -159,7 +163,8 @@ async function processResult({ checkRuns, core }) {
159163
`Artifact '${artifactName}' not found in the build with details_url:${checkRun.details_url}`,
160164
);
161165
}
162-
const artifactJsonObj = JSON.parse(result.artifactData);
166+
167+
const artifactJsonObj = SpecGenSdkArtifactInfoSchema.parse(JSON.parse(result.artifactData));
163168
const language = artifactJsonObj.language;
164169
const shortLanguageName = language.split("-").pop();
165170
const executionResult = artifactJsonObj.result;

.github/workflows/test/sdk-breaking-change-labels.test.js

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { beforeEach, describe, expect, it, vi } from "vitest";
22
import { sdkLabels } from "../../shared/src/sdk-types.js";
3+
import { createMockSpecGenSdkArtifactInfo } from "../../shared/test/sdk-types.js";
34
import { LabelAction } from "../src/label.js";
45
import {
56
getLabelAndActionImpl,
@@ -12,9 +13,11 @@ vi.mock("../src/context.js", () => ({
1213
extractInputs: vi.fn(),
1314
}));
1415

16+
/** @type {import('vitest').Mock<(url: string) => Promise<Partial<Response>>>} */
1517
const mockFetch = vi.fn();
18+
1619
// Mock global fetch
17-
global.fetch = mockFetch;
20+
global.fetch = /** @type {import('vitest').MockedFunction<typeof fetch>} */ (mockFetch);
1821

1922
const mockGithub = createMockGithub();
2023
const mockContext = createMockContext();
@@ -64,20 +67,22 @@ describe("sdk-breaking-change-labels", () => {
6467
const mockContentResponse = {
6568
ok: true,
6669
text: vi.fn().mockResolvedValue(
67-
JSON.stringify({
68-
labelAction: true,
69-
language,
70-
prNumber: "123",
71-
}),
70+
JSON.stringify(
71+
createMockSpecGenSdkArtifactInfo({
72+
labelAction: true,
73+
language,
74+
prNumber: "123",
75+
}),
76+
),
7277
),
7378
};
7479

7580
// Setup fetch to return different responses for each call
7681
mockFetch.mockImplementation((url) => {
7782
if (url.includes("artifacts?artifactName=")) {
78-
return mockArtifactResponse;
83+
return Promise.resolve(mockArtifactResponse);
7984
} else {
80-
return mockContentResponse;
85+
return Promise.resolve(mockContentResponse);
8186
}
8287
});
8388

@@ -90,6 +95,7 @@ describe("sdk-breaking-change-labels", () => {
9095

9196
// Verify result
9297
expect(result).toEqual({
98+
headSha: "abc123",
9399
labelName: sdkLabels[language].breakingChange,
94100
labelAction: LabelAction.Add,
95101
issueNumber: 123,
@@ -119,21 +125,21 @@ describe("sdk-breaking-change-labels", () => {
119125
const language = "azure-sdk-for-js";
120126
const mockContentResponse = {
121127
ok: true,
122-
text: vi.fn().mockResolvedValue(
123-
JSON.stringify({
124-
labelAction: false,
125-
language,
126-
prNumber: "123",
127-
}),
128-
),
128+
text: vi
129+
.fn()
130+
.mockResolvedValue(
131+
JSON.stringify(
132+
createMockSpecGenSdkArtifactInfo({ labelAction: false, language, prNumber: "123" }),
133+
),
134+
),
129135
};
130136

131137
// Setup fetch to return different responses for each call
132138
mockFetch.mockImplementation((url) => {
133139
if (url.includes("artifacts?artifactName=")) {
134-
return mockArtifactResponse;
140+
return Promise.resolve(mockArtifactResponse);
135141
} else {
136-
return mockContentResponse;
142+
return Promise.resolve(mockContentResponse);
137143
}
138144
});
139145

@@ -146,6 +152,7 @@ describe("sdk-breaking-change-labels", () => {
146152

147153
// Verify result has Remove action
148154
expect(result).toEqual({
155+
headSha: "abc123",
149156
labelName: sdkLabels[language].breakingChange,
150157
labelAction: LabelAction.Remove,
151158
issueNumber: 123,
@@ -176,20 +183,22 @@ describe("sdk-breaking-change-labels", () => {
176183
const mockContentResponse = {
177184
ok: true,
178185
text: vi.fn().mockResolvedValue(
179-
JSON.stringify({
180-
labelAction: false,
181-
language,
182-
prNumber: "123",
183-
}),
186+
JSON.stringify(
187+
createMockSpecGenSdkArtifactInfo({
188+
labelAction: false,
189+
language,
190+
prNumber: "123",
191+
}),
192+
),
184193
),
185194
};
186195

187196
// Setup fetch to return different responses for each call
188197
mockFetch.mockImplementation((url) => {
189198
if (url.includes("artifacts?artifactName=")) {
190-
return mockArtifactResponse;
199+
return Promise.resolve(mockArtifactResponse);
191200
} else {
192-
return mockContentResponse;
201+
return Promise.resolve(mockContentResponse);
193202
}
194203
});
195204

@@ -202,6 +211,7 @@ describe("sdk-breaking-change-labels", () => {
202211

203212
// Verify result has none action
204213
expect(result).toEqual({
214+
headSha: "abc123",
205215
labelName: sdkLabels[language].breakingChange,
206216
labelAction: LabelAction.None,
207217
issueNumber: 123,
@@ -343,11 +353,7 @@ describe("sdk-breaking-change-labels", () => {
343353
};
344354

345355
// Setup fetch to return different responses for each call
346-
mockFetch.mockImplementation((url) => {
347-
if (url.includes("artifacts?artifactName=")) {
348-
return mockArtifactResponse;
349-
}
350-
});
356+
mockFetch.mockResolvedValue(mockArtifactResponse);
351357

352358
// Call function and expect it to throw
353359
await expect(
@@ -374,11 +380,7 @@ describe("sdk-breaking-change-labels", () => {
374380
};
375381

376382
// Setup fetch to return different responses for each call
377-
mockFetch.mockImplementation((url) => {
378-
if (url.includes("artifacts?artifactName=")) {
379-
return mockArtifactResponse;
380-
}
381-
});
383+
mockFetch.mockResolvedValue(mockArtifactResponse);
382384

383385
// Call function and expect it to throw
384386
await expect(
@@ -419,9 +421,9 @@ describe("sdk-breaking-change-labels", () => {
419421
// Setup fetch to return different responses for each call
420422
mockFetch.mockImplementation((url) => {
421423
if (url.includes("artifacts?artifactName=")) {
422-
return mockArtifactResponse;
424+
return Promise.resolve(mockArtifactResponse);
423425
} else {
424-
return mockContentResponse;
426+
return Promise.resolve(mockContentResponse);
425427
}
426428
});
427429

0 commit comments

Comments
 (0)