Skip to content

Commit f8fa863

Browse files
committed
Use Octokit REST for listing CodeQL databases
This switches the request to the GitHub API for listing CodeQL databases from a custom request to the Octokit REST API. This allows us to be more type-safe without introducing our own types. The update to `@octokit/openapi-types` was necessary to have access to the `commit_oid` field.
1 parent 6fc567b commit f8fa863

File tree

4 files changed

+44
-24
lines changed

4 files changed

+44
-24
lines changed

extensions/ql-vscode/package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/ql-vscode/src/databases/database-fetcher.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -562,10 +562,10 @@ export async function convertGithubNwoToDatabaseUrl(
562562
try {
563563
const [owner, repo] = nwo.split("/");
564564

565-
const response = await octokit.request(
566-
"GET /repos/:owner/:repo/code-scanning/codeql/databases",
567-
{ owner, repo },
568-
);
565+
const response = await octokit.rest.codeScanning.listCodeqlDatabases({
566+
owner,
567+
repo,
568+
});
569569

570570
const languages = response.data.map((db: any) => db.language);
571571

@@ -584,12 +584,12 @@ export async function convertGithubNwoToDatabaseUrl(
584584
}
585585

586586
return {
587-
databaseUrl: `https://api.github.com/repos/${owner}/${repo}/code-scanning/codeql/databases/${language}`,
587+
databaseUrl: databaseForLanguage.url,
588588
owner,
589589
name: repo,
590590
databaseId: databaseForLanguage.id,
591591
databaseCreatedAt: databaseForLanguage.created_at,
592-
commitOid: databaseForLanguage.commit_oid,
592+
commitOid: databaseForLanguage.commit_oid ?? null,
593593
};
594594
} catch (e) {
595595
void extLogger.log(`Error: ${getErrorMessage(e)}`);

extensions/ql-vscode/test/vscode-tests/no-workspace/databases/database-fetcher.test.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import {
88
findDirWithFile,
99
} from "../../../../src/databases/database-fetcher";
1010
import * as Octokit from "@octokit/rest";
11-
import { mockedQuickPickItem } from "../../utils/mocking.helpers";
11+
import {
12+
mockedObject,
13+
mockedOctokitFunction,
14+
mockedQuickPickItem,
15+
} from "../../utils/mocking.helpers";
1216

1317
// These tests make API calls and may need extra time to complete.
1418
jest.setTimeout(10000);
@@ -18,10 +22,17 @@ describe("database-fetcher", () => {
1822
let quickPickSpy: jest.SpiedFunction<typeof window.showQuickPick>;
1923

2024
const progressSpy = jest.fn();
21-
const mockRequest = jest.fn();
22-
const octokit: Octokit.Octokit = {
23-
request: mockRequest,
24-
} as unknown as Octokit.Octokit;
25+
const mockListCodeqlDatabases = mockedOctokitFunction<
26+
"codeScanning",
27+
"listCodeqlDatabases"
28+
>();
29+
const octokit = mockedObject<Octokit.Octokit>({
30+
rest: {
31+
codeScanning: {
32+
listCodeqlDatabases: mockListCodeqlDatabases,
33+
},
34+
},
35+
});
2536

2637
// We can't make the real octokit request (since we need credentials), so we mock the response.
2738
const successfullMockApiResponse = {
@@ -72,7 +83,7 @@ describe("database-fetcher", () => {
7283
});
7384

7485
it("should convert a GitHub nwo to a database url", async () => {
75-
mockRequest.mockResolvedValue(successfullMockApiResponse);
86+
mockListCodeqlDatabases.mockResolvedValue(successfullMockApiResponse);
7687
quickPickSpy.mockResolvedValue(
7788
mockedQuickPickItem({
7889
label: "JavaScript",
@@ -93,7 +104,7 @@ describe("database-fetcher", () => {
93104
const { databaseUrl, name, owner } = result;
94105

95106
expect(databaseUrl).toBe(
96-
"https://api.github.com/repos/github/codeql/code-scanning/codeql/databases/javascript",
107+
"https://api.github.com/repositories/143040428/code-scanning/codeql/databases/javascript",
97108
);
98109
expect(name).toBe("codeql");
99110
expect(owner).toBe("github");
@@ -128,7 +139,7 @@ describe("database-fetcher", () => {
128139
},
129140
status: 404,
130141
};
131-
mockRequest.mockResolvedValue(mockApiResponse);
142+
mockListCodeqlDatabases.mockResolvedValue(mockApiResponse);
132143
const githubRepo = "foo/bar-not-real";
133144
await expect(
134145
convertGithubNwoToDatabaseUrl(githubRepo, octokit, progressSpy),
@@ -142,7 +153,7 @@ describe("database-fetcher", () => {
142153
data: [],
143154
};
144155

145-
mockRequest.mockResolvedValue(mockApiResponse);
156+
mockListCodeqlDatabases.mockResolvedValue(mockApiResponse);
146157
const githubRepo = "foo/bar-with-no-dbs";
147158
await expect(
148159
convertGithubNwoToDatabaseUrl(githubRepo, octokit, progressSpy),
@@ -153,7 +164,7 @@ describe("database-fetcher", () => {
153164
describe("when language is already provided", () => {
154165
describe("when language is valid", () => {
155166
it("should not prompt the user", async () => {
156-
mockRequest.mockResolvedValue(successfullMockApiResponse);
167+
mockListCodeqlDatabases.mockResolvedValue(successfullMockApiResponse);
157168
const githubRepo = "github/codeql";
158169
await convertGithubNwoToDatabaseUrl(
159170
githubRepo,
@@ -167,7 +178,7 @@ describe("database-fetcher", () => {
167178

168179
describe("when language is invalid", () => {
169180
it("should prompt for language", async () => {
170-
mockRequest.mockResolvedValue(successfullMockApiResponse);
181+
mockListCodeqlDatabases.mockResolvedValue(successfullMockApiResponse);
171182
const githubRepo = "github/codeql";
172183
await convertGithubNwoToDatabaseUrl(
173184
githubRepo,
@@ -182,7 +193,7 @@ describe("database-fetcher", () => {
182193

183194
describe("when language is not provided", () => {
184195
it("should prompt for language", async () => {
185-
mockRequest.mockResolvedValue(successfullMockApiResponse);
196+
mockListCodeqlDatabases.mockResolvedValue(successfullMockApiResponse);
186197
const githubRepo = "github/codeql";
187198
await convertGithubNwoToDatabaseUrl(githubRepo, octokit, progressSpy);
188199
expect(quickPickSpy).toHaveBeenCalled();

extensions/ql-vscode/test/vscode-tests/utils/mocking.helpers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { QuickPickItem, window, Uri } from "vscode";
22
import { DatabaseItem } from "../../../src/databases/local-databases";
3+
import * as Octokit from "@octokit/rest";
34

45
export type DeepPartial<T> = T extends object
56
? {
@@ -57,6 +58,14 @@ export function mockedObject<T extends object>(
5758
});
5859
}
5960

61+
export function mockedOctokitFunction<
62+
Namespace extends keyof Octokit.Octokit["rest"],
63+
Name extends keyof Octokit.Octokit["rest"][Namespace],
64+
>(): Octokit.Octokit["rest"][Namespace][Name] & jest.Mock {
65+
const fn = jest.fn();
66+
return fn as unknown as Octokit.Octokit["rest"][Namespace][Name] & jest.Mock;
67+
}
68+
6069
export function mockDatabaseItem(
6170
props: DeepPartial<DatabaseItem> = {},
6271
): DatabaseItem {

0 commit comments

Comments
 (0)