Skip to content

Commit 3fb2c71

Browse files
Merge branch 'main' into fix-lgtm-download-message
2 parents b40f648 + fbadc15 commit 3fb2c71

File tree

6 files changed

+90
-28
lines changed

6 files changed

+90
-28
lines changed

extensions/ql-vscode/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
## [UNRELEASED]
44

5+
56
- Remove line about selecting a language from the dropdown when downloading database from LGTM. This makes the download progress visible when the popup is not expanded. [#894](https://github.com/github/vscode-codeql/issues/894)
67

8+
- Fixed a bug where copying the version information fails when a CodeQL CLI cannot be found. [#958](https://github.com/github/vscode-codeql/pull/958)
9+
710
## 1.5.5 - 08 September 2021
811

912
- Fix bug where a query is sometimes run before the file is saved. [#947](https://github.com/github/vscode-codeql/pull/947)

extensions/ql-vscode/package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@
241241
"scope": "application",
242242
"description": "Specifies whether or not to write telemetry events to the extension log."
243243
},
244-
"codeQL.remoteRepositoryLists": {
244+
"codeQL.remoteQueries.repositoryLists": {
245245
"type": [
246246
"object",
247247
null
@@ -256,6 +256,13 @@
256256
},
257257
"default": null,
258258
"markdownDescription": "[For internal use only] Lists of GitHub repositories that you want to query remotely. This should be a JSON object where each key is a user-specified name for this repository list, and the value is an array of GitHub repositories (of the form `<owner>/<repo>`)."
259+
},
260+
"codeQL.remoteQueries.controllerRepo": {
261+
"type": "string",
262+
"default": "",
263+
"pattern": "^$|^(?:[a-zA-Z0-9]+-)*[a-zA-Z0-9]+/[a-zA-Z0-9-_]+$",
264+
"patternErrorMessage": "Please enter a valid GitHub repository",
265+
"markdownDescription": "[For internal use only] The name of the GitHub repository where you can view the progress and results of the \"Run Remote query\" command. The repository should be of the form `<owner>/<repo>`)."
259266
}
260267
}
261268
},

extensions/ql-vscode/src/config.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,15 +298,34 @@ export function isCanary() {
298298
*/
299299
export const NO_CACHE_AST_VIEWER = new Setting('disableCache', AST_VIEWER_SETTING);
300300

301+
// Settings for remote queries
302+
const REMOTE_QUERIES_SETTING = new Setting('remoteQueries', ROOT_SETTING);
303+
301304
/**
302305
* Lists of GitHub repositories that you want to query remotely via the "Run Remote query" command.
303306
* Note: This command is only available for internal users.
304307
*
305308
* This setting should be a JSON object where each key is a user-specified name (string),
306309
* and the value is an array of GitHub repositories (of the form `<owner>/<repo>`).
307310
*/
308-
const REMOTE_REPO_LISTS = new Setting('remoteRepositoryLists', ROOT_SETTING);
311+
const REMOTE_REPO_LISTS = new Setting('repositoryLists', REMOTE_QUERIES_SETTING);
309312

310313
export function getRemoteRepositoryLists(): Record<string, string[]> | undefined {
311314
return REMOTE_REPO_LISTS.getValue<Record<string, string[]>>() || undefined;
312315
}
316+
317+
/**
318+
* The name of the "controller" repository that you want to use with the "Run Remote query" command.
319+
* Note: This command is only available for internal users.
320+
*
321+
* This setting should be a GitHub repository of the form `<owner>/<repo>`.
322+
*/
323+
const REMOTE_CONTROLLER_REPO = new Setting('controllerRepo', REMOTE_QUERIES_SETTING);
324+
325+
export function getRemoteControllerRepo(): string | undefined {
326+
return REMOTE_CONTROLLER_REPO.getValue<string>() || undefined;
327+
}
328+
329+
export async function setRemoteControllerRepo(repo: string | undefined) {
330+
await REMOTE_CONTROLLER_REPO.updateValue(repo, ConfigurationTarget.Global);
331+
}

extensions/ql-vscode/src/extension.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,11 +792,19 @@ async function activateWithInstalledDistribution(
792792

793793
ctx.subscriptions.push(
794794
commandRunner('codeQL.copyVersion', async () => {
795-
const text = `CodeQL extension version: ${extension?.packageJSON.version} \nCodeQL CLI version: ${await cliServer.getVersion()} \nPlatform: ${os.platform()} ${os.arch()}`;
795+
const text = `CodeQL extension version: ${extension?.packageJSON.version} \nCodeQL CLI version: ${await getCliVersion()} \nPlatform: ${os.platform()} ${os.arch()}`;
796796
await env.clipboard.writeText(text);
797797
void helpers.showAndLogInformationMessage(text);
798798
}));
799799

800+
const getCliVersion = async () => {
801+
try {
802+
return await cliServer.getVersion();
803+
} catch {
804+
return '<missing>';
805+
}
806+
};
807+
800808
// The "authenticateToGitHub" command is internal-only.
801809
ctx.subscriptions.push(
802810
commandRunner('codeQL.authenticateToGitHub', async () => {

extensions/ql-vscode/src/run-remote-query.ts

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@ import { findLanguage, showAndLogErrorMessage, showAndLogInformationMessage, sho
55
import { Credentials } from './authentication';
66
import * as cli from './cli';
77
import { logger } from './logging';
8-
import { getRemoteRepositoryLists } from './config';
8+
import { getRemoteControllerRepo, getRemoteRepositoryLists, setRemoteControllerRepo } from './config';
99
interface Config {
1010
repositories: string[];
1111
ref?: string;
1212
language?: string;
1313
}
1414

15-
// Test "controller" repository and workflow.
16-
const OWNER = 'dsp-testing';
17-
const REPO = 'qc-controller';
18-
1915
interface RepoListQuickPickItem extends QuickPickItem {
2016
repoList: string[];
2117
}
2218

19+
/**
20+
* This regex matches strings of the form `owner/repo` where:
21+
* - `owner` is made up of alphanumeric characters or single hyphens, starting and ending in an alphanumeric character
22+
* - `repo` is made up of alphanumeric characters, hyphens, or underscores
23+
*/
24+
const REPO_REGEX = /^(?:[a-zA-Z0-9]+-)*[a-zA-Z0-9]+\/[a-zA-Z0-9-_]+$/;
25+
2326
/**
2427
* Gets the repositories to run the query against.
2528
*/
@@ -35,7 +38,7 @@ export async function getRepositories(): Promise<string[] | undefined> {
3538
const quickpick = await window.showQuickPick<RepoListQuickPickItem>(
3639
quickPickItems,
3740
{
38-
placeHolder: 'Select a repository list. You can define repository lists in the `codeQL.remoteRepositoryLists` setting.',
41+
placeHolder: 'Select a repository list. You can define repository lists in the `codeQL.remoteQueries.repositoryLists` setting.',
3942
ignoreFocusOut: true,
4043
});
4144
if (quickpick?.repoList.length) {
@@ -47,22 +50,16 @@ export async function getRepositories(): Promise<string[] | undefined> {
4750
}
4851
} else {
4952
void logger.log('No repository lists defined. Displaying text input box.');
50-
/**
51-
* This regex matches strings of the form `owner/repo` where:
52-
* - `owner` is made up of alphanumeric characters or single hyphens, starting and ending in an alphanumeric character
53-
* - `repo` is made up of alphanumeric characters, hyphens, or underscores
54-
*/
55-
const repoRegex = /^(?:[a-zA-Z0-9]+-)*[a-zA-Z0-9]+\/[a-zA-Z0-9-_]+$/;
5653
const remoteRepo = await window.showInputBox({
5754
title: 'Enter a GitHub repository in the format <owner>/<repo> (e.g. github/codeql)',
5855
placeHolder: '<owner>/<repo>',
59-
prompt: 'Tip: you can save frequently used repositories in the `codeql.remoteRepositoryLists` setting',
56+
prompt: 'Tip: you can save frequently used repositories in the `codeQL.remoteQueries.repositoryLists` setting',
6057
ignoreFocusOut: true,
6158
});
6259
if (!remoteRepo) {
6360
void showAndLogErrorMessage('No repositories entered.');
6461
return;
65-
} else if (!repoRegex.test(remoteRepo)) { // Check if user entered invalid input
62+
} else if (!REPO_REGEX.test(remoteRepo)) { // Check if user entered invalid input
6663
void showAndLogErrorMessage('Invalid repository format. Must be in the format <owner>/<repo> (e.g. github/codeql)');
6764
return;
6865
}
@@ -85,7 +82,7 @@ export async function runRemoteQuery(cliServer: cli.CodeQLCliServer, credentials
8582
let repositories: string[] | undefined;
8683

8784
// If the user has an explicit `.repositories` file, use that.
88-
// Otherwise, prompt user to select repositories from the `codeQL.remoteRepositoryLists` setting.
85+
// Otherwise, prompt user to select repositories from the `codeQL.remoteQueries.repositoryLists` setting.
8986
if (await fs.pathExists(repositoriesFile)) {
9087
void logger.log(`Found '${repositoriesFile}'. Using information from that file to run ${queryFile}.`);
9188

@@ -107,18 +104,44 @@ export async function runRemoteQuery(cliServer: cli.CodeQLCliServer, credentials
107104
return; // No error message needed, since `getRepositories` already displays one.
108105
}
109106

110-
await runRemoteQueriesApiRequest(credentials, ref, language, repositories, query);
107+
// Get the controller repo from the config, if it exists.
108+
// If it doesn't exist, prompt the user to enter it, and save that value to the config.
109+
let controllerRepo: string | undefined;
110+
controllerRepo = getRemoteControllerRepo();
111+
if (!controllerRepo || !REPO_REGEX.test(controllerRepo)) {
112+
void logger.log(controllerRepo ? 'Invalid controller repository name.' : 'No controller repository defined.');
113+
controllerRepo = await window.showInputBox({
114+
title: 'Controller repository in which to display progress and results of remote queries',
115+
placeHolder: '<owner>/<repo>',
116+
prompt: 'Enter the name of a GitHub repository in the format <owner>/<repo>',
117+
ignoreFocusOut: true,
118+
});
119+
if (!controllerRepo) {
120+
void showAndLogErrorMessage('No controller repository entered.');
121+
return;
122+
} else if (!REPO_REGEX.test(controllerRepo)) { // Check if user entered invalid input
123+
void showAndLogErrorMessage('Invalid repository format. Must be a valid GitHub repository in the format <owner>/<repo>.');
124+
return;
125+
}
126+
void logger.log(`Setting the controller repository as: ${controllerRepo}`);
127+
await setRemoteControllerRepo(controllerRepo);
128+
}
129+
130+
void logger.log(`Using controller repository: ${controllerRepo}`);
131+
const [owner, repo] = controllerRepo.split('/');
132+
133+
await runRemoteQueriesApiRequest(credentials, ref, language, repositories, query, owner, repo);
111134
}
112135

113-
async function runRemoteQueriesApiRequest(credentials: Credentials, ref: string, language: string, repositories: string[], query: string) {
136+
async function runRemoteQueriesApiRequest(credentials: Credentials, ref: string, language: string, repositories: string[], query: string, owner: string, repo: string) {
114137
const octokit = await credentials.getOctokit();
115138

116139
try {
117140
await octokit.request(
118141
'POST /repos/:owner/:repo/code-scanning/codeql/queries',
119142
{
120-
owner: OWNER,
121-
repo: REPO,
143+
owner,
144+
repo,
122145
data: {
123146
ref: ref,
124147
language: language,
@@ -127,15 +150,15 @@ async function runRemoteQueriesApiRequest(credentials: Credentials, ref: string,
127150
}
128151
}
129152
);
130-
void showAndLogInformationMessage(`Successfully scheduled runs. [Click here to see the progress](https://github.com/${OWNER}/${REPO}/actions).`);
153+
void showAndLogInformationMessage(`Successfully scheduled runs. [Click here to see the progress](https://github.com/${owner}/${repo}/actions).`);
131154

132155
} catch (error) {
133-
await attemptRerun(error, credentials, ref, language, repositories, query);
156+
await attemptRerun(error, credentials, ref, language, repositories, query, owner, repo);
134157
}
135158
}
136159

137160
/** Attempts to rerun the query on only the valid repositories */
138-
export async function attemptRerun(error: any, credentials: Credentials, ref: string, language: string, repositories: string[], query: string) {
161+
export async function attemptRerun(error: any, credentials: Credentials, ref: string, language: string, repositories: string[], query: string, owner: string, repo: string) {
139162
if (typeof error.message === 'string' && error.message.includes('Some repositories were invalid')) {
140163
const invalidRepos = error?.response?.data?.invalid_repos || [];
141164
const reposWithoutDbUploads = error?.response?.data?.repos_without_db_uploads || [];
@@ -158,7 +181,7 @@ export async function attemptRerun(error: any, credentials: Credentials, ref: st
158181
if (rerunQuery) {
159182
const validRepositories = repositories.filter(r => !invalidRepos.includes(r) && !reposWithoutDbUploads.includes(r));
160183
void logger.log(`Rerunning query on set of valid repositories: ${JSON.stringify(validRepositories)}`);
161-
await runRemoteQueriesApiRequest(credentials, ref, language, validRepositories, query);
184+
await runRemoteQueriesApiRequest(credentials, ref, language, validRepositories, query, owner, repo);
162185
}
163186

164187
} else {

extensions/ql-vscode/src/vscode-tests/no-workspace/run-remote-query.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ describe('run-remote-query', function() {
126126
const language = 'javascript';
127127
const credentials = getMockCredentials(0);
128128
const query = 'select 1';
129+
const owner = 'owner';
130+
const repo = 'repo';
129131

130132
beforeEach(() => {
131133
sandbox = sinon.createSandbox();
@@ -152,7 +154,7 @@ describe('run-remote-query', function() {
152154
const repositories = ['abc/def', 'ghi/jkl', 'mno/pqr', 'stu/vwx'];
153155

154156
// make the function call
155-
await mod.attemptRerun(error, credentials, ref, language, repositories, query);
157+
await mod.attemptRerun(error, credentials, ref, language, repositories, query, owner, repo);
156158

157159
// check logging output
158160
expect(logSpy.firstCall.args[0]).to.contain('Unable to run query');
@@ -168,7 +170,7 @@ describe('run-remote-query', function() {
168170
showInformationMessageWithActionSpy.resolves(true);
169171

170172
// make the function call
171-
await mod.attemptRerun(error, credentials, ref, language, repositories, query);
173+
await mod.attemptRerun(error, credentials, ref, language, repositories, query, owner, repo);
172174

173175
// check logging output
174176
expect(logSpy.firstCall.args[0]).to.contain('Unable to run query');

0 commit comments

Comments
 (0)