Skip to content

Commit 3c678ca

Browse files
committed
First pass at workflow dispatch
See also: hackathon work from https://github.com/github/vscode-codeql/pull/701/files
1 parent 3dc0ce9 commit 3c678ca

5 files changed

Lines changed: 116 additions & 15 deletions

File tree

extensions/ql-vscode/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/ql-vscode/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@
245245
"command": "codeQL.runQuery",
246246
"title": "CodeQL: Run Query"
247247
},
248+
{
249+
"command": "codeQL.runRemoteQuery",
250+
"title": "CodeQL: Run Remote Query"
251+
},
248252
{
249253
"command": "codeQL.runQueries",
250254
"title": "CodeQL: Run Queries in Selected Files"
@@ -663,6 +667,10 @@
663667
"command": "codeQL.runQuery",
664668
"when": "resourceLangId == ql && resourceExtname == .ql"
665669
},
670+
{
671+
"command": "codeQL.runRemoteQuery",
672+
"when": "editorLangId == ql && resourceExtname == .ql"
673+
},
666674
{
667675
"command": "codeQL.runQueries",
668676
"when": "false"
@@ -805,6 +813,10 @@
805813
"command": "codeQL.runQuery",
806814
"when": "editorLangId == ql && resourceExtname == .ql"
807815
},
816+
{
817+
"command": "codeQL.runRemoteQuery",
818+
"when": "editorLangId == ql && resourceExtname == .ql"
819+
},
808820
{
809821
"command": "codeQL.viewAst",
810822
"when": "resourceScheme == codeql-zip-archive"

extensions/ql-vscode/src/authentication.ts

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ const GITHUB_AUTH_PROVIDER_ID = 'github';
77
// https://docs.github.com/apps/building-oauth-apps/understanding-scopes-for-oauth-apps
88
const SCOPES = ['repo'];
99

10+
interface OctokitAndToken {
11+
octokit: Octokit.Octokit;
12+
token: string;
13+
}
14+
1015
/**
1116
* Handles authentication to GitHub, using the VS Code [authentication API](https://code.visualstudio.com/api/references/vscode-api#authentication).
1217
*/
1318
export class Credentials {
14-
private octokit: Octokit.Octokit | undefined;
19+
private octokitAndToken: OctokitAndToken | undefined;
1520

1621
// Explicitly make the constructor private, so that we can't accidentally call the constructor from outside the class
1722
// without also initializing the class.
@@ -21,39 +26,56 @@ export class Credentials {
2126
static async initialize(context: vscode.ExtensionContext): Promise<Credentials> {
2227
const c = new Credentials();
2328
c.registerListeners(context);
24-
c.octokit = await c.createOctokit(false);
29+
c.octokitAndToken = await c.createOctokit(false);
2530
return c;
2631
}
2732

28-
private async createOctokit(createIfNone: boolean): Promise<Octokit.Octokit | undefined> {
33+
private async createOctokit(createIfNone: boolean): Promise<OctokitAndToken | undefined> {
2934
const session = await vscode.authentication.getSession(GITHUB_AUTH_PROVIDER_ID, SCOPES, { createIfNone });
3035

31-
return session
32-
? new Octokit.Octokit({
33-
auth: session.accessToken
34-
}) : undefined;
36+
if (session) {
37+
return {
38+
octokit: new Octokit.Octokit({
39+
auth: session.accessToken
40+
}),
41+
token: session.accessToken
42+
};
43+
} else {
44+
return undefined;
45+
}
3546
}
3647

3748
registerListeners(context: vscode.ExtensionContext): void {
3849
// Sessions are changed when a user logs in or logs out.
3950
context.subscriptions.push(vscode.authentication.onDidChangeSessions(async e => {
4051
if (e.provider.id === GITHUB_AUTH_PROVIDER_ID) {
41-
this.octokit = await this.createOctokit(false);
52+
this.octokitAndToken = await this.createOctokit(false);
4253
}
4354
}));
4455
}
4556

4657
async getOctokit(): Promise<Octokit.Octokit> {
47-
if (this.octokit) {
48-
return this.octokit;
58+
if (this.octokitAndToken) {
59+
return this.octokitAndToken.octokit;
4960
}
5061

51-
this.octokit = await this.createOctokit(true);
62+
this.octokitAndToken = await this.createOctokit(true);
5263
// octokit shouldn't be undefined, since we've set "createIfNone: true".
5364
// The following block is mainly here to prevent a compiler error.
54-
if (!this.octokit) {
65+
if (!this.octokitAndToken) {
66+
throw new Error('Did not initialize Octokit.');
67+
}
68+
return this.octokitAndToken.octokit;
69+
}
70+
71+
async getToken(): Promise<string> {
72+
if (this.octokitAndToken) {
73+
return this.octokitAndToken.token;
74+
}
75+
this.octokitAndToken = await this.createOctokit(true);
76+
if (!this.octokitAndToken) {
5577
throw new Error('Did not initialize Octokit.');
5678
}
57-
return this.octokit;
79+
return this.octokitAndToken.token;
5880
}
5981
}

extensions/ql-vscode/src/extension.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import {
7171
import { CodeQlStatusBarHandler } from './status-bar';
7272

7373
import { Credentials } from './authentication';
74+
import runRemoteQuery from './run-remote-query';
7475

7576
/**
7677
* extension.ts
@@ -642,6 +643,13 @@ async function activateWithInstalledDistribution(
642643
}
643644
)
644645
);
646+
ctx.subscriptions.push(
647+
commandRunner('codeQL.runRemoteQuery', async (
648+
uri: Uri | undefined
649+
) => {
650+
await runRemoteQuery(credentials, uri || window.activeTextEditor?.document.uri);
651+
})
652+
);
645653
ctx.subscriptions.push(
646654
commandRunner(
647655
'codeQL.openReferencedFile',
@@ -716,7 +724,7 @@ async function activateWithInstalledDistribution(
716724

717725
/**
718726
* Credentials for authenticating to GitHub.
719-
* Currently unused, but will be useful in the future when making API calls.
727+
* These are used when making API calls.
720728
*/
721729
const credentials = await Credentials.initialize(ctx);
722730

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { Uri } from 'vscode';
2+
import * as yaml from 'js-yaml';
3+
import * as fs from 'fs-extra';
4+
import { showAndLogErrorMessage, showAndLogInformationMessage } from './helpers';
5+
import { Credentials } from './authentication';
6+
7+
interface Config {
8+
repositories: string[];
9+
ref?: string;
10+
language: string;
11+
}
12+
13+
export default async function runRemoteQuery(credentials: Credentials, uri?: Uri) {
14+
if (!uri || !uri.fsPath.endsWith('.ql')) {
15+
return;
16+
}
17+
18+
const octokit = await credentials.getOctokit();
19+
const token = await credentials.getToken();
20+
21+
const queryFile = uri.fsPath;
22+
const query = await fs.readFile(queryFile, 'utf8');
23+
24+
const repositoriesFile = queryFile.substring(0, queryFile.length - '.ql'.length) + '.repositories';
25+
if (!(await fs.pathExists(repositoriesFile))) {
26+
void showAndLogErrorMessage(`Missing file: '${repositoriesFile}' to specify the repositories to run against.`);
27+
return;
28+
}
29+
30+
const config = yaml.safeLoad(await fs.readFile(repositoriesFile, 'utf8')) as Config;
31+
32+
const ref = config.ref || 'main';
33+
const language = config.language;
34+
const repositories = JSON.stringify(config.repositories);
35+
36+
// Test "controller" repository and workflow.
37+
const owner = 'dsp-testing';
38+
const repo = 'qc-controller';
39+
const workflow_id = 'codeql-query.yml';
40+
41+
try {
42+
await octokit.rest.actions.createWorkflowDispatch({
43+
owner: owner,
44+
repo: repo,
45+
workflow_id: workflow_id,
46+
ref: ref,
47+
inputs: {
48+
language,
49+
repositories,
50+
query,
51+
token
52+
}
53+
});
54+
void showAndLogInformationMessage(`Successfully scheduled runs. [Click here to see the progress](https://github.com/${owner}/${repo}/actions).`);
55+
56+
} catch (error) {
57+
void showAndLogErrorMessage(error);
58+
}
59+
}

0 commit comments

Comments
 (0)