Skip to content

Commit f332e61

Browse files
committed
Implement addNewDatabase
1 parent 6350ac7 commit f332e61

4 files changed

Lines changed: 138 additions & 2 deletions

File tree

extensions/ql-vscode/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"onCommand:codeQLDatabases.chooseDatabase",
6161
"onCommand:codeQLDatabases.setCurrentDatabase",
6262
"onCommand:codeQLDatabasesExperimental.openConfigFile",
63+
"onCommand:codeQLDatabasesExperimental.addNewDatabase",
6364
"onCommand:codeQLDatabasesExperimental.addNewList",
6465
"onCommand:codeQLDatabasesExperimental.setSelectedItem",
6566
"onCommand:codeQL.quickQuery",
@@ -362,6 +363,11 @@
362363
"title": "Open Database Configuration File",
363364
"icon": "$(edit)"
364365
},
366+
{
367+
"command": "codeQLDatabasesExperimental.addNewDatabase",
368+
"title": "Add new database",
369+
"icon": "$(add)"
370+
},
365371
{
366372
"command": "codeQLDatabasesExperimental.addNewList",
367373
"title": "Add new list",
@@ -759,6 +765,11 @@
759765
"when": "view == codeQLDatabasesExperimental",
760766
"group": "navigation"
761767
},
768+
{
769+
"command": "codeQLDatabasesExperimental.addNewDatabase",
770+
"when": "view == codeQLDatabasesExperimental && codeQLDatabasesExperimental.configError == false",
771+
"group": "navigation"
772+
},
762773
{
763774
"command": "codeQLDatabasesExperimental.addNewList",
764775
"when": "view == codeQLDatabasesExperimental && codeQLDatabasesExperimental.configError == false",
@@ -982,6 +993,10 @@
982993
"command": "codeQLDatabasesExperimental.openConfigFile",
983994
"when": "false"
984995
},
996+
{
997+
"command": "codeQLDatabasesExperimental.addNewDatabase",
998+
"when": "false"
999+
},
9851000
{
9861001
"command": "codeQLDatabasesExperimental.addNewList",
9871002
"when": "false"

extensions/ql-vscode/src/databases/config/db-config-store.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,28 @@ export class DbConfigStore extends DisposableObject {
9494
await this.writeConfig(config);
9595
}
9696

97+
public async addRemoteRepo(repoNwo: string): Promise<void> {
98+
if (!this.config) {
99+
throw Error("Cannot add remote repo if config is not loaded");
100+
}
101+
102+
const config: DbConfig = cloneDbConfig(this.config);
103+
config.databases.remote.repositories.push(repoNwo);
104+
105+
await this.writeConfig(config);
106+
}
107+
108+
public async addRemoteOwner(owner: string): Promise<void> {
109+
if (!this.config) {
110+
throw Error("Cannot add remote owner if config is not loaded");
111+
}
112+
113+
const config: DbConfig = cloneDbConfig(this.config);
114+
config.databases.remote.owners.push(owner);
115+
116+
await this.writeConfig(config);
117+
}
118+
97119
public async addRemoteList(listName: string): Promise<void> {
98120
if (!this.config) {
99121
throw Error("Cannot add remote list if config is not loaded");

extensions/ql-vscode/src/databases/db-manager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ export class DbManager {
7575
await this.dbConfigStore.updateExpandedState(newExpandedItems);
7676
}
7777

78+
public async addNewRemoteRepo(nwo: string): Promise<void> {
79+
await this.dbConfigStore.addRemoteRepo(nwo);
80+
}
81+
82+
public async addNewRemoteOwner(owner: string): Promise<void> {
83+
await this.dbConfigStore.addRemoteOwner(owner);
84+
}
85+
7886
public async addNewRemoteList(listName: string): Promise<void> {
7987
if (listName === "") {
8088
throw Error("List name cannot be empty");

extensions/ql-vscode/src/databases/ui/db-panel.ts

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
1-
import { TreeViewExpansionEvent, window, workspace } from "vscode";
2-
import { commandRunner } from "../../commandRunner";
1+
import {
2+
QuickPickItem,
3+
TreeViewExpansionEvent,
4+
window,
5+
workspace,
6+
} from "vscode";
7+
import { commandRunner, UserCancellationException } from "../../commandRunner";
8+
import {
9+
getNwoFromGitHubUrl,
10+
validGitHubNwo,
11+
getOwnerFromGitHubUrl,
12+
validGitHubOwner,
13+
} from "../../common/github-url-identifier-helper";
314
import { showAndLogErrorMessage } from "../../helpers";
415
import { DisposableObject } from "../../pure/disposable-object";
516
import { DbManager } from "../db-manager";
617
import { DbTreeDataProvider } from "./db-tree-data-provider";
718
import { DbTreeViewItem } from "./db-tree-view-item";
819

20+
interface RemoteDatabaseQuickPickItem extends QuickPickItem {
21+
kind: string;
22+
}
23+
924
export class DbPanel extends DisposableObject {
1025
private readonly dataProvider: DbTreeDataProvider;
1126

@@ -39,6 +54,11 @@ export class DbPanel extends DisposableObject {
3954
this.openConfigFile(),
4055
),
4156
);
57+
this.push(
58+
commandRunner("codeQLDatabasesExperimental.addNewDatabase", () =>
59+
this.addNewRemoteDatabase(),
60+
),
61+
);
4262
this.push(
4363
commandRunner("codeQLDatabasesExperimental.addNewList", () =>
4464
this.addNewRemoteList(),
@@ -58,6 +78,77 @@ export class DbPanel extends DisposableObject {
5878
await window.showTextDocument(document);
5979
}
6080

81+
private async addNewRemoteDatabase(): Promise<void> {
82+
const quickPickItems = [
83+
{
84+
label: "$(repo) From a GitHub repository",
85+
detail: "Add a remote repository from GitHub",
86+
alwaysShow: true,
87+
kind: "repo",
88+
},
89+
{
90+
label: "$(organization) All repositories of a GitHub org or owner",
91+
detail:
92+
"Add a remote list of repositories from a GitHub organization/owner",
93+
alwaysShow: true,
94+
kind: "owner",
95+
},
96+
];
97+
const databaseKind =
98+
await window.showQuickPick<RemoteDatabaseQuickPickItem>(quickPickItems, {
99+
title: "Add a remote repository",
100+
placeHolder: "Select an option",
101+
ignoreFocusOut: true,
102+
});
103+
if (!databaseKind) {
104+
// We don't need to display a warning pop-up in this case, since the user just escaped out of the operation.
105+
// We set 'true' to make this a silent exception.
106+
throw new UserCancellationException("No repository selected", true);
107+
}
108+
if (databaseKind.kind === "repo") {
109+
await this.addNewRemoteRepo();
110+
} else if (databaseKind.kind === "owner") {
111+
await this.addNewRemoteOwner();
112+
}
113+
}
114+
115+
private async addNewRemoteRepo(): Promise<void> {
116+
const repoName = await window.showInputBox({
117+
title: "Add a remote repository",
118+
prompt: "Insert a GitHub repository URL or name with owner",
119+
placeHolder: "github.com/<owner>/<repo> or <owner>/<repo>",
120+
});
121+
if (!repoName) {
122+
return;
123+
}
124+
125+
const nwo = getNwoFromGitHubUrl(repoName) || repoName;
126+
if (!validGitHubNwo(nwo)) {
127+
throw new Error(`Invalid GitHub repository: ${repoName}`);
128+
}
129+
130+
await this.dbManager.addNewRemoteRepo(nwo);
131+
}
132+
133+
private async addNewRemoteOwner(): Promise<void> {
134+
const ownerName = await window.showInputBox({
135+
title: "Add all repositories of a GitHub org or owner",
136+
prompt: "Insert a GitHub organization or owner name",
137+
placeHolder: "github.com/<owner> or <owner>",
138+
});
139+
140+
if (!ownerName) {
141+
return;
142+
}
143+
144+
const owner = getOwnerFromGitHubUrl(ownerName) || ownerName;
145+
if (!validGitHubOwner(owner)) {
146+
throw new Error(`Invalid user or organization: ${owner}`);
147+
}
148+
149+
await this.dbManager.addNewRemoteOwner(owner);
150+
}
151+
61152
private async addNewRemoteList(): Promise<void> {
62153
const listName = await window.showInputBox({
63154
prompt: "Enter a name for the new list",

0 commit comments

Comments
 (0)