Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions extensions/ql-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,19 @@
"Never download a GitHub databases when a workspace is opened."
],
"description": "Ask to download a GitHub database when a workspace is opened."
},
"codeQL.githubDatabase.update": {
"type": "string",
"default": "ask",
"enum": [
"ask",
"never"
],
"enumDescriptions": [
"Ask to download an updated GitHub database when a new version is available.",
"Never download an updated GitHub database when a new version is available."
],
"description": "Ask to download an updated GitHub database when a new version is available."
}
}
},
Expand Down
22 changes: 22 additions & 0 deletions extensions/ql-vscode/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -788,13 +788,23 @@ const GITHUB_DATABASE_DOWNLOAD = new Setting(
const GitHubDatabaseDownloadValues = ["ask", "never"] as const;
type GitHubDatabaseDownload = (typeof GitHubDatabaseDownloadValues)[number];

const GITHUB_DATABASE_UPDATE = new Setting("update", GITHUB_DATABASE_SETTING);

const GitHubDatabaseUpdateValues = ["ask", "never"] as const;
type GitHubDatabaseUpdate = (typeof GitHubDatabaseUpdateValues)[number];

export interface GitHubDatabaseConfig {
enable: boolean;
download: GitHubDatabaseDownload;
update: GitHubDatabaseUpdate;
setDownload(
value: GitHubDatabaseDownload,
target?: ConfigurationTarget,
): Promise<void>;
setUpdate(
value: GitHubDatabaseUpdate,
target?: ConfigurationTarget,
): Promise<void>;
}

export class GitHubDatabaseConfigListener
Expand All @@ -817,10 +827,22 @@ export class GitHubDatabaseConfigListener
return GitHubDatabaseDownloadValues.includes(value) ? value : "ask";
}

public get update(): GitHubDatabaseUpdate {
const value = GITHUB_DATABASE_UPDATE.getValue<GitHubDatabaseUpdate>();
return GitHubDatabaseUpdateValues.includes(value) ? value : "ask";
}

public async setDownload(
value: GitHubDatabaseDownload,
target: ConfigurationTarget = ConfigurationTarget.Workspace,
): Promise<void> {
await GITHUB_DATABASE_DOWNLOAD.updateValue(value, target);
}

public async setUpdate(
value: GitHubDatabaseUpdate,
target: ConfigurationTarget = ConfigurationTarget.Workspace,
): Promise<void> {
await GITHUB_DATABASE_UPDATE.updateValue(value, target);
}
}
17 changes: 13 additions & 4 deletions extensions/ql-vscode/src/databases/github-database-download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export async function downloadDatabaseFromGitHub(
*
* @param languages The languages to join. These should be language identifiers, such as `csharp`.
*/
function joinLanguages(languages: string[]): string {
export function joinLanguages(languages: string[]): string {
const languageDisplayNames = languages
.map((language) => getLanguageDisplayName(language))
.sort();
Expand All @@ -130,8 +130,17 @@ function joinLanguages(languages: string[]): string {
return result;
}

async function promptForDatabases(
type PromptForDatabasesOptions = {
title?: string;
placeHolder?: string;
};

export async function promptForDatabases(
databases: CodeqlDatabase[],
{
title = "Select databases to download",
placeHolder = "Databases found in this repository",
}: PromptForDatabasesOptions = {},
): Promise<CodeqlDatabase[]> {
if (databases.length === 1) {
return databases;
Expand All @@ -152,8 +161,8 @@ async function promptForDatabases(
.sort((a, b) => a.label.localeCompare(b.label));

const selectedItems = await window.showQuickPick(items, {
title: "Select databases to download",
placeHolder: "Databases found in this repository",
title,
placeHolder,
ignoreFocusOut: true,
canPickMany: true,
});
Expand Down
94 changes: 80 additions & 14 deletions extensions/ql-vscode/src/databases/github-database-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,26 @@ import { DisposableObject } from "../common/disposable-object";
import { App } from "../common/app";
import { findGitHubRepositoryForWorkspace } from "./github-repository-finder";
import { redactableError } from "../common/errors";
import { asError, getErrorMessage } from "../common/helpers-pure";
import { asError, assertNever, getErrorMessage } from "../common/helpers-pure";
import {
askForGitHubDatabaseDownload,
downloadDatabaseFromGitHub,
} from "./github-database-download";
import { GitHubDatabaseConfig, GitHubDatabaseConfigListener } from "../config";
import { DatabaseManager } from "./local-databases";
import { CodeQLCliServer } from "../codeql-cli/cli";
import { listDatabases, ListDatabasesResult } from "./github-database-api";
import {
CodeqlDatabase,
listDatabases,
ListDatabasesResult,
} from "./github-database-api";
import {
askForGitHubDatabaseUpdate,
DatabaseUpdate,
downloadDatabaseUpdateFromGitHub,
isNewerDatabaseAvailable,
} from "./github-database-updates";
import { Octokit } from "@octokit/rest";

export class GithubDatabaseModule extends DisposableObject {
private readonly config: GitHubDatabaseConfig;
Expand Down Expand Up @@ -79,16 +90,6 @@ export class GithubDatabaseModule extends DisposableObject {

const githubRepository = githubRepositoryResult.value;

const hasExistingDatabase = this.databaseManager.databaseItems.some(
(db) =>
db.origin?.type === "github" &&
db.origin.repository ===
`${githubRepository.owner}/${githubRepository.name}`,
);
if (hasExistingDatabase) {
return;
}

let result: ListDatabasesResult | undefined;
try {
result = await listDatabases(
Expand Down Expand Up @@ -130,6 +131,45 @@ export class GithubDatabaseModule extends DisposableObject {
return;
}

const updateStatus = isNewerDatabaseAvailable(
databases,
githubRepository.owner,
githubRepository.name,
this.databaseManager,
);

switch (updateStatus.type) {
case "upToDate":
return;
case "updateAvailable":
await this.updateGitHubDatabase(
octokit,
githubRepository.owner,
githubRepository.name,
updateStatus.databaseUpdates,
);
break;
case "noDatabase":
await this.downloadGitHubDatabase(
octokit,
githubRepository.owner,
githubRepository.name,
databases,
promptedForCredentials,
);
break;
default:
assertNever(updateStatus);
}
}

private async downloadGitHubDatabase(
octokit: Octokit,
owner: string,
repo: string,
databases: CodeqlDatabase[],
promptedForCredentials: boolean,
) {
// If the user already had an access token, first ask if they even want to download the DB.
if (!promptedForCredentials) {
if (!(await askForGitHubDatabaseDownload(databases, this.config))) {
Expand All @@ -139,13 +179,39 @@ export class GithubDatabaseModule extends DisposableObject {

await downloadDatabaseFromGitHub(
octokit,
githubRepository.owner,
githubRepository.name,
owner,
repo,
databases,
this.databaseManager,
this.databaseStoragePath,
this.cliServer,
this.app.commands,
);
}

private async updateGitHubDatabase(
octokit: Octokit,
owner: string,
repo: string,
databaseUpdates: DatabaseUpdate[],
): Promise<void> {
if (this.config.update === "never") {
return;
}

if (!(await askForGitHubDatabaseUpdate(databaseUpdates, this.config))) {
return;
}

await downloadDatabaseUpdateFromGitHub(
octokit,
owner,
repo,
databaseUpdates,
this.databaseManager,
this.databaseStoragePath,
this.cliServer,
this.app.commands,
);
}
}
Loading