Merge pull request #1889 from github/shati-nora/add-remote-repositories

Create "Add database" button in DB panel
This commit is contained in:
Nora
2022-12-20 17:31:12 +01:00
committed by GitHub
7 changed files with 150 additions and 13 deletions

View File

@@ -60,6 +60,7 @@
"onCommand:codeQLDatabases.chooseDatabase",
"onCommand:codeQLDatabases.setCurrentDatabase",
"onCommand:codeQLDatabasesExperimental.openConfigFile",
"onCommand:codeQLDatabasesExperimental.addNewDatabase",
"onCommand:codeQLDatabasesExperimental.addNewList",
"onCommand:codeQLDatabasesExperimental.setSelectedItem",
"onCommand:codeQL.quickQuery",
@@ -362,6 +363,11 @@
"title": "Open Database Configuration File",
"icon": "$(edit)"
},
{
"command": "codeQLDatabasesExperimental.addNewDatabase",
"title": "Add new database",
"icon": "$(add)"
},
{
"command": "codeQLDatabasesExperimental.addNewList",
"title": "Add new list",
@@ -758,6 +764,11 @@
"when": "view == codeQLDatabasesExperimental",
"group": "navigation"
},
{
"command": "codeQLDatabasesExperimental.addNewDatabase",
"when": "view == codeQLDatabasesExperimental && codeQLDatabasesExperimental.configError == false",
"group": "navigation"
},
{
"command": "codeQLDatabasesExperimental.addNewList",
"when": "view == codeQLDatabasesExperimental && codeQLDatabasesExperimental.configError == false",
@@ -981,6 +992,10 @@
"command": "codeQLDatabasesExperimental.openConfigFile",
"when": "false"
},
{
"command": "codeQLDatabasesExperimental.addNewDatabase",
"when": "false"
},
{
"command": "codeQLDatabasesExperimental.addNewList",
"when": "false"

View File

@@ -5,7 +5,7 @@ import { OWNER_REGEX, REPO_REGEX } from "../pure/helpers-pure";
* @param identifier The GitHub NWO
* @returns
*/
export function validGitHubNwo(identifier: string): boolean {
export function isValidGitHubNwo(identifier: string): boolean {
return validGitHubNwoOrOwner(identifier, "nwo");
}
@@ -14,7 +14,7 @@ export function validGitHubNwo(identifier: string): boolean {
* @param identifier The GitHub owner
* @returns
*/
export function validGitHubOwner(identifier: string): boolean {
export function isValidGitHubOwner(identifier: string): boolean {
return validGitHubNwoOrOwner(identifier, "owner");
}
@@ -28,7 +28,7 @@ function validGitHubNwoOrOwner(
}
/**
* Extracts an NOW from a GitHub URL.
* Extracts an NWO from a GitHub URL.
* @param githubUrl The GitHub repository URL
* @return The corresponding NWO, or undefined if the URL is not valid
*/

View File

@@ -24,7 +24,7 @@ import { Credentials } from "./authentication";
import { getErrorMessage } from "./pure/helpers-pure";
import {
getNwoFromGitHubUrl,
validGitHubNwo,
isValidGitHubNwo,
} from "./common/github-url-identifier-helper";
/**
@@ -101,7 +101,7 @@ export async function promptImportGithubDatabase(
}
const nwo = getNwoFromGitHubUrl(githubRepo) || githubRepo;
if (!validGitHubNwo(nwo)) {
if (!isValidGitHubNwo(nwo)) {
throw new Error(`Invalid GitHub repository: ${githubRepo}`);
}

View File

@@ -94,6 +94,28 @@ export class DbConfigStore extends DisposableObject {
await this.writeConfig(config);
}
public async addRemoteRepo(repoNwo: string): Promise<void> {
if (!this.config) {
throw Error("Cannot add remote repo if config is not loaded");
}
const config: DbConfig = cloneDbConfig(this.config);
config.databases.remote.repositories.push(repoNwo);
await this.writeConfig(config);
}
public async addRemoteOwner(owner: string): Promise<void> {
if (!this.config) {
throw Error("Cannot add remote owner if config is not loaded");
}
const config: DbConfig = cloneDbConfig(this.config);
config.databases.remote.owners.push(owner);
await this.writeConfig(config);
}
public async addRemoteList(listName: string): Promise<void> {
if (!this.config) {
throw Error("Cannot add remote list if config is not loaded");

View File

@@ -75,6 +75,14 @@ export class DbManager {
await this.dbConfigStore.updateExpandedState(newExpandedItems);
}
public async addNewRemoteRepo(nwo: string): Promise<void> {
await this.dbConfigStore.addRemoteRepo(nwo);
}
public async addNewRemoteOwner(owner: string): Promise<void> {
await this.dbConfigStore.addRemoteOwner(owner);
}
public async addNewList(kind: DbItemKind, listName: string): Promise<void> {
if (remoteDbKinds.includes(kind)) {
if (listName === "") {

View File

@@ -1,11 +1,27 @@
import { TreeView, TreeViewExpansionEvent, window, workspace } from "vscode";
import { commandRunner } from "../../commandRunner";
import {
QuickPickItem,
TreeView,
TreeViewExpansionEvent,
window,
workspace,
} from "vscode";
import { commandRunner, UserCancellationException } from "../../commandRunner";
import {
getNwoFromGitHubUrl,
isValidGitHubNwo,
getOwnerFromGitHubUrl,
isValidGitHubOwner,
} from "../../common/github-url-identifier-helper";
import { DisposableObject } from "../../pure/disposable-object";
import { DbItem, DbItemKind } from "../db-item";
import { DbManager } from "../db-manager";
import { DbTreeDataProvider } from "./db-tree-data-provider";
import { DbTreeViewItem } from "./db-tree-view-item";
interface RemoteDatabaseQuickPickItem extends QuickPickItem {
kind: string;
}
export class DbPanel extends DisposableObject {
private readonly dataProvider: DbTreeDataProvider;
private readonly treeView: TreeView<DbTreeViewItem>;
@@ -40,6 +56,11 @@ export class DbPanel extends DisposableObject {
this.openConfigFile(),
),
);
this.push(
commandRunner("codeQLDatabasesExperimental.addNewDatabase", () =>
this.addNewRemoteDatabase(),
),
);
this.push(
commandRunner("codeQLDatabasesExperimental.addNewList", () =>
this.addNewRemoteList(),
@@ -59,6 +80,77 @@ export class DbPanel extends DisposableObject {
await window.showTextDocument(document);
}
private async addNewRemoteDatabase(): Promise<void> {
const quickPickItems = [
{
label: "$(repo) From a GitHub repository",
detail: "Add a remote repository from GitHub",
alwaysShow: true,
kind: "repo",
},
{
label: "$(organization) All repositories of a GitHub org or owner",
detail:
"Add a remote list of repositories from a GitHub organization/owner",
alwaysShow: true,
kind: "owner",
},
];
const databaseKind =
await window.showQuickPick<RemoteDatabaseQuickPickItem>(quickPickItems, {
title: "Add a remote repository",
placeHolder: "Select an option",
ignoreFocusOut: true,
});
if (!databaseKind) {
// We don't need to display a warning pop-up in this case, since the user just escaped out of the operation.
// We set 'true' to make this a silent exception.
throw new UserCancellationException("No repository selected", true);
}
if (databaseKind.kind === "repo") {
await this.addNewRemoteRepo();
} else if (databaseKind.kind === "owner") {
await this.addNewRemoteOwner();
}
}
private async addNewRemoteRepo(): Promise<void> {
const repoName = await window.showInputBox({
title: "Add a remote repository",
prompt: "Insert a GitHub repository URL or name with owner",
placeHolder: "github.com/<owner>/<repo> or <owner>/<repo>",
});
if (!repoName) {
return;
}
const nwo = getNwoFromGitHubUrl(repoName) || repoName;
if (!isValidGitHubNwo(nwo)) {
throw new Error(`Invalid GitHub repository: ${repoName}`);
}
await this.dbManager.addNewRemoteRepo(nwo);
}
private async addNewRemoteOwner(): Promise<void> {
const ownerName = await window.showInputBox({
title: "Add all repositories of a GitHub org or owner",
prompt: "Insert a GitHub organization or owner name",
placeHolder: "github.com/<owner> or <owner>",
});
if (!ownerName) {
return;
}
const owner = getOwnerFromGitHubUrl(ownerName) || ownerName;
if (!isValidGitHubOwner(owner)) {
throw new Error(`Invalid user or organization: ${owner}`);
}
await this.dbManager.addNewRemoteOwner(owner);
}
private async addNewRemoteList(): Promise<void> {
const listName = await window.showInputBox({
prompt: "Enter a name for the new list",

View File

@@ -1,23 +1,23 @@
import {
getNwoFromGitHubUrl,
getOwnerFromGitHubUrl,
validGitHubNwo,
validGitHubOwner,
isValidGitHubNwo,
isValidGitHubOwner,
} from "../../../src/common/github-url-identifier-helper";
describe("github url identifier helper", () => {
describe("valid GitHub Nwo Or Owner method", () => {
it("should return true for valid owner", () => {
expect(validGitHubOwner("github")).toBe(true);
expect(isValidGitHubOwner("github")).toBe(true);
});
it("should return true for valid NWO", () => {
expect(validGitHubNwo("github/codeql")).toBe(true);
expect(isValidGitHubNwo("github/codeql")).toBe(true);
});
it("should return false for invalid owner", () => {
expect(validGitHubOwner("github/codeql")).toBe(false);
expect(isValidGitHubOwner("github/codeql")).toBe(false);
});
it("should return false for invalid NWO", () => {
expect(validGitHubNwo("githubl")).toBe(false);
expect(isValidGitHubNwo("githubl")).toBe(false);
});
});