Merge pull request #1989 from github/robertbrignull/credentials_in_app

Add credentials to App
This commit is contained in:
Robert 2023-01-25 15:15:30 +00:00 коммит произвёл GitHub
Родитель 64e73c6426 9e25d19924
Коммит ad6cbe60fd
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
34 изменённых файлов: 284 добавлений и 265 удалений

Просмотреть файл

@ -1,6 +1,7 @@
import * as vscode from "vscode";
import * as Octokit from "@octokit/rest";
import { retry } from "@octokit/plugin-retry";
import { Credentials } from "./common/authentication";
const GITHUB_AUTH_PROVIDER_ID = "github";
@ -13,41 +14,12 @@ const SCOPES = ["repo", "gist", "read:packages"];
/**
* Handles authentication to GitHub, using the VS Code [authentication API](https://code.visualstudio.com/api/references/vscode-api#authentication).
*/
export class Credentials {
export class VSCodeCredentials implements Credentials {
/**
* A specific octokit to return, otherwise a new authenticated octokit will be created when needed.
*/
private octokit: Octokit.Octokit | undefined;
// Explicitly make the constructor private, so that we can't accidentally call the constructor from outside the class
// without also initializing the class.
private constructor(octokit?: Octokit.Octokit) {
this.octokit = octokit;
}
/**
* Initializes a Credentials instance. This will generate octokit instances
* authenticated as the user. If there is not already an authenticated GitHub
* session available then the user will be prompted to log in.
*
* @returns An instance of credentials.
*/
static async initialize(): Promise<Credentials> {
return new Credentials();
}
/**
* Initializes an instance of credentials with an octokit instance using
* a specific known token. This method is meant to be used in
* non-interactive environments such as tests.
*
* @param overrideToken The GitHub token to use for authentication.
* @returns An instance of credentials.
*/
static async initializeWithToken(overrideToken: string) {
return new Credentials(new Octokit.Octokit({ auth: overrideToken, retry }));
}
/**
* Creates or returns an instance of Octokit.
*

Просмотреть файл

@ -27,7 +27,7 @@ import { Logger, ProgressReporter } from "./common";
import { CompilationMessage } from "./pure/legacy-messages";
import { sarifParser } from "./sarif-parser";
import { dbSchemeToLanguage, walkDirectory } from "./helpers";
import { Credentials } from "./authentication";
import { App } from "./common/app";
/**
* The version of the SARIF format that we are using.
@ -197,6 +197,7 @@ export class CodeQLCliServer implements Disposable {
public quiet = false;
constructor(
private readonly app: App,
private distributionProvider: DistributionProvider,
private cliConfig: CliConfig,
private logger: Logger,
@ -618,9 +619,7 @@ export class CodeQLCliServer implements Disposable {
addFormat = true,
progressReporter?: ProgressReporter,
): Promise<OutputType> {
const credentials = await Credentials.initialize();
const accessToken = await credentials.getExistingAccessToken();
const accessToken = await this.app.credentials.getExistingAccessToken();
const extraArgs = accessToken ? ["--github-auth-stdin"] : [];
@ -633,7 +632,7 @@ export class CodeQLCliServer implements Disposable {
async (line) => {
if (line.startsWith("Enter value for --github-auth-stdin")) {
try {
return await credentials.getAccessToken();
return await this.app.credentials.getAccessToken();
} catch (e) {
// If the user cancels the authentication prompt, we still need to give a value to the CLI.
// By giving a potentially invalid value, the user will just get a 401/403 when they try to access a

Просмотреть файл

@ -1,3 +1,4 @@
import { Credentials } from "./authentication";
import { Disposable } from "../pure/disposable-object";
import { AppEventEmitter } from "./events";
import { Logger } from "./logging";
@ -13,6 +14,7 @@ export interface App {
readonly globalStoragePath: string;
readonly workspaceStoragePath?: string;
readonly workspaceState: Memento;
readonly credentials: Credentials;
}
export enum AppMode {

Просмотреть файл

@ -0,0 +1,34 @@
import * as Octokit from "@octokit/rest";
/**
* An interface providing methods for obtaining access tokens
* or an octokit instance for making HTTP requests.
*/
export interface Credentials {
/**
* Returns an authenticated instance of Octokit.
* May prompt the user to log in and grant permission to use their
* token, if they have not already done so.
*
* @returns An instance of Octokit.
*/
getOctokit(): Promise<Octokit.Octokit>;
/**
* Returns an OAuth access token.
* May prompt the user to log in and grant permission to use their
* token, if they have not already done so.
*
* @returns An OAuth access token.
*/
getAccessToken(): Promise<string>;
/**
* Returns an OAuth access token if one is available.
* If a token is not available this will return undefined and
* will not prompt the user to log in.
*
* @returns An OAuth access token, or undefined.
*/
getExistingAccessToken(): Promise<string | undefined>;
}

Просмотреть файл

@ -1,4 +1,5 @@
import * as vscode from "vscode";
import { VSCodeCredentials } from "../../authentication";
import { Disposable } from "../../pure/disposable-object";
import { App, AppMode } from "../app";
import { AppEventEmitter } from "../events";
@ -7,9 +8,13 @@ import { Memento } from "../memento";
import { VSCodeAppEventEmitter } from "./events";
export class ExtensionApp implements App {
public readonly credentials: VSCodeCredentials;
public constructor(
public readonly extensionContext: vscode.ExtensionContext,
) {}
) {
this.credentials = new VSCodeCredentials();
}
public get extensionPath(): string {
return this.extensionContext.extensionPath;

Просмотреть файл

@ -20,12 +20,12 @@ import { DatabaseManager, DatabaseItem } from "./databases";
import { showAndLogInformationMessage, tmpDir } from "./helpers";
import { reportStreamProgress, ProgressCallback } from "./commandRunner";
import { extLogger } from "./common";
import { Credentials } from "./authentication";
import { getErrorMessage } from "./pure/helpers-pure";
import {
getNwoFromGitHubUrl,
isValidGitHubNwo,
} from "./common/github-url-identifier-helper";
import { Credentials } from "./common/authentication";
/**
* Prompts a user to fetch a database from a remote location. Database is assumed to be an archive file.

Просмотреть файл

@ -35,9 +35,10 @@ import {
promptImportInternetDatabase,
} from "./databaseFetcher";
import { asyncFilter, getErrorMessage } from "./pure/helpers-pure";
import { Credentials } from "./authentication";
import { QueryRunner } from "./queryRunner";
import { isCanary } from "./config";
import { App } from "./common/app";
import { Credentials } from "./common/authentication";
type ThemableIconPath = { light: string; dark: string } | string;
@ -220,11 +221,11 @@ export class DatabaseUI extends DisposableObject {
private treeDataProvider: DatabaseTreeDataProvider;
public constructor(
private app: App,
private databaseManager: DatabaseManager,
private readonly queryServer: QueryRunner | undefined,
private readonly storagePath: string,
readonly extensionPath: string,
private readonly getCredentials: () => Promise<Credentials>,
) {
super();
@ -297,9 +298,7 @@ export class DatabaseUI extends DisposableObject {
commandRunnerWithProgress(
"codeQLDatabases.chooseDatabaseGithub",
async (progress: ProgressCallback, token: CancellationToken) => {
const credentials = isCanary()
? await this.getCredentials()
: undefined;
const credentials = isCanary() ? this.app.credentials : undefined;
await this.handleChooseDatabaseGithub(credentials, progress, token);
},
{

Просмотреть файл

@ -102,7 +102,6 @@ import {
} from "./commandRunner";
import { CodeQlStatusBarHandler } from "./status-bar";
import { Credentials } from "./authentication";
import { RemoteQueriesManager } from "./remote-queries/remote-queries-manager";
import { RemoteQueryResult } from "./remote-queries/remote-query-result";
import { URLSearchParams } from "url";
@ -546,6 +545,8 @@ async function activateWithInstalledDistribution(
// of activation.
errorStubs.forEach((stub) => stub.dispose());
const app = new ExtensionApp(ctx);
void extLogger.log("Initializing configuration listener...");
const qlConfigurationListener =
await QueryServerConfigListener.createQueryServerConfigListener(
@ -555,6 +556,7 @@ async function activateWithInstalledDistribution(
void extLogger.log("Initializing CodeQL cli server...");
const cliServer = new CodeQLCliServer(
app,
distributionManager,
new CliConfigListener(),
extLogger,
@ -587,11 +589,11 @@ async function activateWithInstalledDistribution(
ctx.subscriptions.push(dbm);
void extLogger.log("Initializing database panel.");
const databaseUI = new DatabaseUI(
app,
dbm,
qs,
getContextStoragePath(ctx),
ctx.extensionPath,
() => Credentials.initialize(),
);
databaseUI.init();
ctx.subscriptions.push(databaseUI);
@ -623,8 +625,6 @@ async function activateWithInstalledDistribution(
void extLogger.log("Initializing variant analysis manager.");
const app = new ExtensionApp(ctx);
const dbModule = await DbModule.initialize(app);
const variantAnalysisStorageDir = join(
@ -633,12 +633,14 @@ async function activateWithInstalledDistribution(
);
await ensureDir(variantAnalysisStorageDir);
const variantAnalysisResultsManager = new VariantAnalysisResultsManager(
app.credentials,
cliServer,
extLogger,
);
const variantAnalysisManager = new VariantAnalysisManager(
ctx,
app,
cliServer,
variantAnalysisStorageDir,
variantAnalysisResultsManager,
@ -656,6 +658,7 @@ async function activateWithInstalledDistribution(
void extLogger.log("Initializing remote queries manager.");
const rqm = new RemoteQueriesManager(
ctx,
app,
cliServer,
queryStorageDir,
extLogger,
@ -664,6 +667,7 @@ async function activateWithInstalledDistribution(
void extLogger.log("Initializing query history.");
const qhm = new QueryHistoryManager(
app,
qs,
dbm,
localQueryResultsView,
@ -1224,7 +1228,7 @@ async function activateWithInstalledDistribution(
commandRunner(
"codeQL.exportRemoteQueryResults",
async (queryId: string) => {
await exportRemoteQueryResults(qhm, rqm, queryId);
await exportRemoteQueryResults(qhm, rqm, queryId, app.credentials);
},
),
);
@ -1242,6 +1246,7 @@ async function activateWithInstalledDistribution(
variantAnalysisManager,
variantAnalysisId,
filterSort,
app.credentials,
progress,
token,
);
@ -1342,9 +1347,7 @@ async function activateWithInstalledDistribution(
commandRunnerWithProgress(
"codeQL.chooseDatabaseGithub",
async (progress: ProgressCallback, token: CancellationToken) => {
const credentials = isCanary()
? await Credentials.initialize()
: undefined;
const credentials = isCanary() ? app.credentials : undefined;
await databaseUI.handleChooseDatabaseGithub(
credentials,
progress,
@ -1398,8 +1401,7 @@ async function activateWithInstalledDistribution(
* Credentials for authenticating to GitHub.
* These are used when making API calls.
*/
const credentials = await Credentials.initialize();
const octokit = await credentials.getOctokit();
const octokit = await app.credentials.getOctokit();
const userInfo = await octokit.users.getAuthenticated();
void showAndLogInformationMessage(
`Authenticated to GitHub as user: ${userInfo.data.login}`,

Просмотреть файл

@ -56,7 +56,6 @@ import {
import { pathExists } from "fs-extra";
import { CliVersionConstraint } from "../cli";
import { HistoryItemLabelProvider } from "./history-item-label-provider";
import { Credentials } from "../authentication";
import { cancelRemoteQuery } from "../remote-queries/gh-api/gh-actions-api-client";
import { RemoteQueriesManager } from "../remote-queries/remote-queries-manager";
import { RemoteQueryHistoryItem } from "../remote-queries/remote-query-history-item";
@ -70,6 +69,7 @@ import { QueryRunner } from "../queryRunner";
import { VariantAnalysisManager } from "../remote-queries/variant-analysis-manager";
import { VariantAnalysisHistoryItem } from "./variant-analysis-history-item";
import { getTotalResultCount } from "../remote-queries/shared/variant-analysis";
import { App } from "../common/app";
/**
* query-history.ts
@ -362,6 +362,7 @@ export class QueryHistoryManager extends DisposableObject {
readonly onDidCompleteQuery = this._onDidCompleteQuery.event;
constructor(
private readonly app: App,
private readonly qs: QueryRunner,
private readonly dbm: DatabaseManager,
private readonly localQueriesResultsView: ResultsView,
@ -604,10 +605,6 @@ export class QueryHistoryManager extends DisposableObject {
this._onDidCompleteQuery.fire(info);
}
private getCredentials() {
return Credentials.initialize();
}
/**
* Register and create the history scrubber.
*/
@ -1314,8 +1311,7 @@ export class QueryHistoryManager extends DisposableObject {
void showAndLogInformationMessage(
"Cancelling variant analysis. This may take a while.",
);
const credentials = await this.getCredentials();
await cancelRemoteQuery(credentials, item.remoteQuery);
await cancelRemoteQuery(this.app.credentials, item.remoteQuery);
} else if (item.t === "variant-analysis") {
await commands.executeCommand(
"codeQL.cancelVariantAnalysis",

Просмотреть файл

@ -3,7 +3,6 @@ import { EOL } from "os";
import { extname } from "path";
import { CancellationToken } from "vscode";
import { Credentials } from "../authentication";
import { Logger } from "../common";
import { downloadArtifactFromLink } from "./gh-api/gh-actions-api-client";
import { AnalysisSummary } from "./shared/remote-query-result";
@ -19,6 +18,7 @@ import { CodeQLCliServer } from "../cli";
import { extractRawResults } from "./bqrs-processing";
import { asyncFilter, getErrorMessage } from "../pure/helpers-pure";
import { createDownloadPath } from "./download-link";
import { App } from "../common/app";
export class AnalysesResultsManager {
// Store for the results of various analyses for each remote query.
@ -26,6 +26,7 @@ export class AnalysesResultsManager {
private readonly analysesResults: Map<string, AnalysisResults[]>;
constructor(
private readonly app: App,
private readonly cliServer: CodeQLCliServer,
readonly storagePath: string,
private readonly logger: Logger,
@ -42,17 +43,11 @@ export class AnalysesResultsManager {
return;
}
const credentials = await Credentials.initialize();
void this.logger.log(
`Downloading and processing results for ${analysisSummary.nwo}`,
);
await this.downloadSingleAnalysisResults(
analysisSummary,
credentials,
publishResults,
);
await this.downloadSingleAnalysisResults(analysisSummary, publishResults);
}
/**
@ -76,8 +71,6 @@ export class AnalysesResultsManager {
(x) => !this.isAnalysisInMemory(x),
);
const credentials = await Credentials.initialize();
void this.logger.log("Downloading and processing analyses results");
const batchSize = 3;
@ -94,11 +87,7 @@ export class AnalysesResultsManager {
const batch = analysesToDownload.slice(i, i + batchSize);
const batchTasks = batch.map((analysis) =>
this.downloadSingleAnalysisResults(
analysis,
credentials,
publishResults,
),
this.downloadSingleAnalysisResults(analysis, publishResults),
);
const nwos = batch.map((a) => a.nwo).join(", ");
@ -138,7 +127,6 @@ export class AnalysesResultsManager {
private async downloadSingleAnalysisResults(
analysis: AnalysisSummary,
credentials: Credentials,
publishResults: (analysesResults: AnalysisResults[]) => Promise<void>,
): Promise<void> {
const analysisResults: AnalysisResults = {
@ -159,7 +147,7 @@ export class AnalysesResultsManager {
let artifactPath;
try {
artifactPath = await downloadArtifactFromLink(
credentials,
this.app.credentials,
this.storagePath,
analysis.downloadLink,
);

Просмотреть файл

@ -9,7 +9,6 @@ import {
window,
workspace,
} from "vscode";
import { Credentials } from "../authentication";
import { ProgressCallback, UserCancellationException } from "../commandRunner";
import { showInformationMessageWithAction } from "../helpers";
import { extLogger } from "../common";
@ -37,6 +36,7 @@ import {
filterAndSortRepositoriesWithResults,
RepositoriesFilterSortStateWithIds,
} from "../pure/variant-analysis-filter-sort";
import { Credentials } from "../common/authentication";
/**
* Exports the results of the currently-selected remote query or variant analysis.
@ -74,6 +74,7 @@ export async function exportRemoteQueryResults(
queryHistoryManager: QueryHistoryManager,
remoteQueriesManager: RemoteQueriesManager,
queryId: string,
credentials: Credentials,
): Promise<void> {
const queryHistoryItem = queryHistoryManager.getRemoteQueryById(queryId);
if (!queryHistoryItem) {
@ -109,6 +110,7 @@ export async function exportRemoteQueryResults(
query,
analysesResults,
exportFormat,
credentials,
);
}
@ -117,6 +119,7 @@ export async function exportRemoteQueryAnalysisResults(
query: RemoteQuery,
analysesResults: AnalysisResults[],
exportFormat: "gist" | "local",
credentials: Credentials,
) {
const description = buildGistDescription(query, analysesResults);
const markdownFiles = generateMarkdown(query, analysesResults, exportFormat);
@ -126,6 +129,7 @@ export async function exportRemoteQueryAnalysisResults(
description,
markdownFiles,
exportFormat,
credentials,
);
}
@ -139,6 +143,7 @@ export async function exportVariantAnalysisResults(
variantAnalysisManager: VariantAnalysisManager,
variantAnalysisId: number,
filterSort: RepositoriesFilterSortStateWithIds | undefined,
credentials: Credentials,
progress: ProgressCallback,
token: CancellationToken,
): Promise<void> {
@ -238,6 +243,7 @@ export async function exportVariantAnalysisResults(
getAnalysesResults(),
repositories?.length ?? 0,
exportFormat,
credentials,
progress,
token,
);
@ -251,6 +257,7 @@ export async function exportVariantAnalysisAnalysisResults(
>,
expectedAnalysesResultsCount: number,
exportFormat: "gist" | "local",
credentials: Credentials,
progress: ProgressCallback,
token: CancellationToken,
) {
@ -280,6 +287,7 @@ export async function exportVariantAnalysisAnalysisResults(
description,
markdownFiles,
exportFormat,
credentials,
progress,
token,
);
@ -323,6 +331,7 @@ export async function exportResults(
description: string,
markdownFiles: MarkdownFile[],
exportFormat: "gist" | "local",
credentials: Credentials,
progress?: ProgressCallback,
token?: CancellationToken,
) {
@ -331,7 +340,13 @@ export async function exportResults(
}
if (exportFormat === "gist") {
await exportToGist(description, markdownFiles, progress, token);
await exportToGist(
description,
markdownFiles,
credentials,
progress,
token,
);
} else if (exportFormat === "local") {
await exportToLocalMarkdown(
exportedResultsPath,
@ -345,6 +360,7 @@ export async function exportResults(
export async function exportToGist(
description: string,
markdownFiles: MarkdownFile[],
credentials: Credentials,
progress?: ProgressCallback,
token?: CancellationToken,
) {
@ -354,8 +370,6 @@ export async function exportToGist(
message: "Creating Gist",
});
const credentials = await Credentials.initialize();
if (token?.isCancellationRequested) {
throw new UserCancellationException("Cancelled");
}

Просмотреть файл

@ -5,7 +5,7 @@ import {
showAndLogWarningMessage,
tmpDir,
} from "../../helpers";
import { Credentials } from "../../authentication";
import { Credentials } from "../../common/authentication";
import { extLogger } from "../../common";
import { RemoteQueryWorkflowResult } from "../remote-query-workflow-result";
import { DownloadLink, createDownloadPath } from "../download-link";

Просмотреть файл

@ -1,5 +1,5 @@
import { Credentials } from "../../authentication";
import { OctokitResponse } from "@octokit/types/dist-types";
import { Credentials } from "../../common/authentication";
import { RemoteQueriesSubmission } from "../shared/remote-queries";
import { VariantAnalysisSubmission } from "../shared/variant-analysis";
import {

Просмотреть файл

@ -1,5 +1,5 @@
import { EOL } from "os";
import { Credentials } from "../authentication";
import { Credentials } from "../common/authentication";
import { RepositorySelection } from "./repository-selection";
import { Repository } from "./shared/repository";
import { RemoteQueriesResponse } from "./gh-api/remote-queries";

Просмотреть файл

@ -11,7 +11,6 @@ import { join } from "path";
import { writeFile, readFile, remove, pathExists } from "fs-extra";
import { EOL } from "os";
import { Credentials } from "../authentication";
import { CodeQLCliServer } from "../cli";
import { ProgressCallback } from "../commandRunner";
import {
@ -42,6 +41,7 @@ import { QueryStatus } from "../query-status";
import { DisposableObject } from "../pure/disposable-object";
import { AnalysisResults } from "./shared/analysis-result";
import { runRemoteQueriesApiRequest } from "./remote-queries-api";
import { App } from "../common/app";
const autoDownloadMaxSize = 300 * 1024;
const autoDownloadMaxCount = 100;
@ -82,12 +82,14 @@ export class RemoteQueriesManager extends DisposableObject {
constructor(
ctx: ExtensionContext,
private readonly app: App,
private readonly cliServer: CodeQLCliServer,
private readonly storagePath: string,
logger: Logger,
) {
super();
this.analysesResultsManager = new AnalysesResultsManager(
app,
cliServer,
storagePath,
logger,
@ -159,8 +161,6 @@ export class RemoteQueriesManager extends DisposableObject {
progress: ProgressCallback,
token: CancellationToken,
): Promise<void> {
const credentials = await Credentials.initialize();
const {
actionBranch,
base64Pack,
@ -172,14 +172,14 @@ export class RemoteQueriesManager extends DisposableObject {
language,
} = await prepareRemoteQueryRun(
this.cliServer,
credentials,
this.app.credentials,
uri,
progress,
token,
);
const apiResponse = await runRemoteQueriesApiRequest(
credentials,
this.app.credentials,
actionBranch,
language,
repoSelection,
@ -217,10 +217,9 @@ export class RemoteQueriesManager extends DisposableObject {
remoteQuery: RemoteQuery,
cancellationToken: CancellationToken,
): Promise<void> {
const credentials = await Credentials.initialize();
const queryWorkflowResult = await this.remoteQueriesMonitor.monitorQuery(
remoteQuery,
this.app.credentials,
cancellationToken,
);
@ -230,7 +229,6 @@ export class RemoteQueriesManager extends DisposableObject {
await this.downloadAvailableResults(
queryId,
remoteQuery,
credentials,
executionEndTime,
);
} else if (queryWorkflowResult.status === "CompletedUnsuccessfully") {
@ -244,7 +242,6 @@ export class RemoteQueriesManager extends DisposableObject {
await this.downloadAvailableResults(
queryId,
remoteQuery,
credentials,
executionEndTime,
);
void showAndLogInformationMessage("Variant analysis was cancelled");
@ -267,7 +264,6 @@ export class RemoteQueriesManager extends DisposableObject {
await this.downloadAvailableResults(
queryId,
remoteQuery,
credentials,
executionEndTime,
);
void showAndLogInformationMessage("Variant analysis was cancelled");
@ -444,15 +440,14 @@ export class RemoteQueriesManager extends DisposableObject {
private async downloadAvailableResults(
queryId: string,
remoteQuery: RemoteQuery,
credentials: Credentials,
executionEndTime: number,
): Promise<void> {
const resultIndex = await getRemoteQueryIndex(credentials, remoteQuery);
const resultIndex = await getRemoteQueryIndex(
this.app.credentials,
remoteQuery,
);
if (resultIndex) {
const metadata = await this.getRepositoriesMetadata(
resultIndex,
credentials,
);
const metadata = await this.getRepositoriesMetadata(resultIndex);
const queryResult = this.mapQueryResult(
executionEndTime,
resultIndex,
@ -494,12 +489,9 @@ export class RemoteQueriesManager extends DisposableObject {
}
}
private async getRepositoriesMetadata(
resultIndex: RemoteQueryResultIndex,
credentials: Credentials,
) {
private async getRepositoriesMetadata(resultIndex: RemoteQueryResultIndex) {
const nwos = resultIndex.successes.map((s) => s.nwo);
return await getRepositoriesMetadata(credentials, nwos);
return await getRepositoriesMetadata(this.app.credentials, nwos);
}
// Pulled from the analysis results manager, so that we can get access to

Просмотреть файл

@ -1,6 +1,6 @@
import * as vscode from "vscode";
import { Credentials } from "../authentication";
import { Logger } from "../common";
import { Credentials } from "../common/authentication";
import { sleep } from "../pure/time";
import {
getWorkflowStatus,
@ -20,10 +20,9 @@ export class RemoteQueriesMonitor {
public async monitorQuery(
remoteQuery: RemoteQuery,
credentials: Credentials,
cancellationToken: vscode.CancellationToken,
): Promise<RemoteQueryWorkflowResult> {
const credentials = await Credentials.initialize();
let attemptCount = 0;
while (attemptCount <= RemoteQueriesMonitor.maxAttemptCount) {

Просмотреть файл

@ -10,7 +10,7 @@ import {
tryGetQueryMetadata,
tmpDir,
} from "../helpers";
import { Credentials } from "../authentication";
import { Credentials } from "../common/authentication";
import * as cli from "../cli";
import { extLogger } from "../common";
import {

Просмотреть файл

@ -16,7 +16,6 @@ import {
workspace,
} from "vscode";
import { DisposableObject } from "../pure/disposable-object";
import { Credentials } from "../authentication";
import { VariantAnalysisMonitor } from "./variant-analysis-monitor";
import {
getActionsWorkflowRunUrl,
@ -62,6 +61,7 @@ import {
import { URLSearchParams } from "url";
import { DbManager } from "../databases/db-manager";
import { isVariantAnalysisReposPanelEnabled } from "../config";
import { App } from "../common/app";
export class VariantAnalysisManager
extends DisposableObject
@ -100,6 +100,7 @@ export class VariantAnalysisManager
constructor(
private readonly ctx: ExtensionContext,
private readonly app: App,
private readonly cliServer: CodeQLCliServer,
private readonly storagePath: string,
private readonly variantAnalysisResultsManager: VariantAnalysisResultsManager,
@ -126,8 +127,6 @@ export class VariantAnalysisManager
progress: ProgressCallback,
token: CancellationToken,
): Promise<void> {
const credentials = await Credentials.initialize();
const {
actionBranch,
base64Pack,
@ -139,7 +138,7 @@ export class VariantAnalysisManager
language,
} = await prepareRemoteQueryRun(
this.cliServer,
credentials,
this.app.credentials,
uri,
progress,
token,
@ -175,7 +174,7 @@ export class VariantAnalysisManager
};
const variantAnalysisResponse = await submitVariantAnalysis(
credentials,
this.app.credentials,
variantAnalysisSubmission,
);
@ -456,6 +455,7 @@ export class VariantAnalysisManager
): Promise<void> {
await this.variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
this.app.credentials,
cancellationToken,
);
}
@ -480,8 +480,6 @@ export class VariantAnalysisManager
await this.onRepoStateUpdated(variantAnalysis.id, repoState);
const credentials = await Credentials.initialize();
if (cancellationToken && cancellationToken.isCancellationRequested) {
repoState.downloadStatus =
VariantAnalysisScannedRepositoryDownloadStatus.Failed;
@ -492,7 +490,7 @@ export class VariantAnalysisManager
let repoTask: VariantAnalysisRepositoryTask;
try {
const repoTaskResponse = await getVariantAnalysisRepo(
credentials,
this.app.credentials,
variantAnalysis.controllerRepo.id,
variantAnalysis.id,
scannedRepo.repository.id,
@ -517,7 +515,6 @@ export class VariantAnalysisManager
try {
await this.variantAnalysisResultsManager.download(
credentials,
variantAnalysis.id,
repoTask,
this.getVariantAnalysisStorageLocation(variantAnalysis.id),
@ -578,12 +575,10 @@ export class VariantAnalysisManager
);
}
const credentials = await Credentials.initialize();
void showAndLogInformationMessage(
"Cancelling variant analysis. This may take a while.",
);
await cancelVariantAnalysis(credentials, variantAnalysis);
await cancelVariantAnalysis(this.app.credentials, variantAnalysis);
}
public async openVariantAnalysisLogs(variantAnalysisId: number) {

Просмотреть файл

@ -1,5 +1,4 @@
import { CancellationToken, commands, EventEmitter } from "vscode";
import { Credentials } from "../authentication";
import { getVariantAnalysis } from "./gh-api/gh-api-client";
import {
@ -14,6 +13,7 @@ import { DisposableObject } from "../pure/disposable-object";
import { sleep } from "../pure/time";
import { getErrorMessage } from "../pure/helpers-pure";
import { showAndLogWarningMessage } from "../helpers";
import { Credentials } from "../common/authentication";
export class VariantAnalysisMonitor extends DisposableObject {
// With a sleep of 5 seconds, the maximum number of attempts takes
@ -36,10 +36,9 @@ export class VariantAnalysisMonitor extends DisposableObject {
public async monitorVariantAnalysis(
variantAnalysis: VariantAnalysis,
credentials: Credentials,
cancellationToken: CancellationToken,
): Promise<void> {
const credentials = await Credentials.initialize();
let attemptCount = 0;
const scannedReposDownloaded: number[] = [];

Просмотреть файл

@ -8,7 +8,7 @@ import {
import { EOL } from "os";
import { join } from "path";
import { Credentials } from "../authentication";
import { Credentials } from "../common/authentication";
import { Logger } from "../common";
import { AnalysisAlert, AnalysisRawResults } from "./shared/analysis-result";
import { sarifParser } from "../sarif-parser";
@ -63,6 +63,7 @@ export class VariantAnalysisResultsManager extends DisposableObject {
readonly onResultLoaded = this._onResultLoaded.event;
constructor(
private readonly credentials: Credentials,
private readonly cliServer: CodeQLCliServer,
private readonly logger: Logger,
) {
@ -71,7 +72,6 @@ export class VariantAnalysisResultsManager extends DisposableObject {
}
public async download(
credentials: Credentials,
variantAnalysisId: number,
repoTask: VariantAnalysisRepositoryTask,
variantAnalysisStoragePath: string,
@ -86,7 +86,7 @@ export class VariantAnalysisResultsManager extends DisposableObject {
);
const result = await getVariantAnalysisRepoResult(
credentials,
this.credentials,
repoTask.artifactUrl,
);

Просмотреть файл

@ -4,6 +4,8 @@ import { Memento } from "../../src/common/memento";
import { Disposable } from "../../src/pure/disposable-object";
import { createMockLogger } from "./loggerMock";
import { createMockMemento } from "../mock-memento";
import { testCredentialsWithStub } from "../factories/authentication";
import { Credentials } from "../../src/common/authentication";
export function createMockApp({
extensionPath = "/mock/extension/path",
@ -12,6 +14,7 @@ export function createMockApp({
createEventEmitter = <T>() => new MockAppEventEmitter<T>(),
executeCommand = jest.fn(() => Promise.resolve()),
workspaceState = createMockMemento(),
credentials = testCredentialsWithStub(),
}: {
extensionPath?: string;
workspaceStoragePath?: string;
@ -19,6 +22,7 @@ export function createMockApp({
createEventEmitter?: <T>() => AppEventEmitter<T>;
executeCommand?: () => Promise<void>;
workspaceState?: Memento;
credentials?: Credentials;
}): App {
return {
mode: AppMode.Test,
@ -30,6 +34,7 @@ export function createMockApp({
workspaceState,
createEventEmitter,
executeCommand,
credentials,
};
}

Просмотреть файл

@ -0,0 +1,42 @@
import { retry } from "@octokit/plugin-retry";
import * as Octokit from "@octokit/rest";
import { RequestInterface } from "@octokit/types/dist-types/RequestInterface";
import { Credentials } from "../../src/common/authentication";
function makeTestOctokit(octokit: Octokit.Octokit): Credentials {
return {
getOctokit: async () => octokit,
getAccessToken: async () => {
throw new Error("getAccessToken not supported by test credentials");
},
getExistingAccessToken: async () => {
throw new Error(
"getExistingAccessToken not supported by test credentials",
);
},
};
}
/**
* Get a Credentials instance that calls a stub function instead
* of making real HTTP requests.
*/
export function testCredentialsWithStub(
requestSpy?: jest.SpyInstance<RequestInterface<object>>,
): Credentials {
const request =
requestSpy ??
jest.fn(async () => {
throw new Error("Tried to make HTTP request but no stub was provided");
});
return makeTestOctokit({ request } as any);
}
/**
* Get a Credentials instance that returns a real octokit instance,
* optionally authenticated with a given token.
*/
export function testCredentialsWithRealOctokit(token?: string): Credentials {
return makeTestOctokit(new Octokit.Octokit({ auth: token, retry }));
}

Просмотреть файл

@ -1,6 +1,3 @@
import { Octokit as Octokit_Octokit } from "@octokit/rest";
import { retry } from "@octokit/plugin-retry";
import { faker } from "@faker-js/faker";
import {
@ -10,17 +7,13 @@ import {
getVariantAnalysisRepoResult,
submitVariantAnalysis,
} from "../../../../src/remote-queries/gh-api/gh-api-client";
import { Credentials } from "../../../../src/authentication";
import { createMockSubmission } from "../../../factories/remote-queries/shared/variant-analysis-submission";
import { MockGitHubApiServer } from "../../../../src/mocks/mock-gh-api-server";
import { response } from "../../../../src/mocks/scenarios/problem-query-success/0-getRepo.json";
import { response as variantAnalysisJson_response } from "../../../../src/mocks/scenarios/problem-query-success/1-submitVariantAnalysis.json";
import { response as variantAnalysisRepoJson_response } from "../../../../src/mocks/scenarios/problem-query-success/9-getVariantAnalysisRepo.json";
const mockCredentials = {
getOctokit: () => Promise.resolve(new Octokit_Octokit({ retry })),
} as unknown as Credentials;
import { testCredentialsWithRealOctokit } from "../../../factories/authentication";
const mockServer = new MockGitHubApiServer();
beforeAll(() => mockServer.startServer());
@ -36,7 +29,7 @@ describe("submitVariantAnalysis", () => {
await mockServer.loadScenario("problem-query-success");
const result = await submitVariantAnalysis(
mockCredentials,
testCredentialsWithRealOctokit(),
createMockSubmission(),
);
@ -50,7 +43,7 @@ describe("getVariantAnalysis", () => {
await mockServer.loadScenario("problem-query-success");
const result = await getVariantAnalysis(
mockCredentials,
testCredentialsWithRealOctokit(),
controllerRepoId,
variantAnalysisId,
);
@ -65,7 +58,7 @@ describe("getVariantAnalysisRepo", () => {
await mockServer.loadScenario("problem-query-success");
const result = await getVariantAnalysisRepo(
mockCredentials,
testCredentialsWithRealOctokit(),
controllerRepoId,
variantAnalysisId,
repoTaskId,
@ -81,7 +74,7 @@ describe("getVariantAnalysisRepoResult", () => {
await mockServer.loadScenario("problem-query-success");
const result = await getVariantAnalysisRepoResult(
mockCredentials,
testCredentialsWithRealOctokit(),
`https://objects-origin.githubusercontent.com/codeql-query-console/codeql-variant-analysis-repo-tasks/${variantAnalysisId}/${repoTaskId}/${faker.datatype.uuid()}`,
);
@ -98,7 +91,7 @@ describe("getRepositoryFromNwo", () => {
await mockServer.loadScenario("problem-query-success");
const result = await getRepositoryFromNwo(
mockCredentials,
testCredentialsWithRealOctokit(),
"github",
"mrva-demo-controller-repo",
);

Просмотреть файл

@ -25,11 +25,12 @@ import { OutputChannelLogger } from "../../../../src/common";
import { RemoteQueriesSubmission } from "../../../../src/remote-queries/shared/remote-queries";
import { readBundledPack } from "../../utils/bundled-pack-helpers";
import { RemoteQueriesManager } from "../../../../src/remote-queries/remote-queries-manager";
import { Credentials } from "../../../../src/authentication";
import {
fixWorkspaceReferences,
restoreWorkspaceReferences,
} from "../global.helper";
import { createMockApp } from "../../../__mocks__/appMock";
import { App } from "../../../../src/common/app";
// up to 3 minutes per test
jest.setTimeout(3 * 60 * 1000);
@ -50,6 +51,7 @@ describe("Remote queries", () => {
>;
let ctx: ExtensionContext;
let logger: any;
let app: App;
let remoteQueriesManager: RemoteQueriesManager;
let originalDeps: Record<string, string> | undefined;
@ -74,8 +76,10 @@ describe("Remote queries", () => {
ctx = createMockExtensionContext();
logger = new OutputChannelLogger("test-logger");
app = createMockApp({});
remoteQueriesManager = new RemoteQueriesManager(
ctx,
app,
cli,
"fake-storage-dir",
logger,
@ -104,14 +108,6 @@ describe("Remote queries", () => {
"vscode-codeql": ["github/vscode-codeql"],
});
const mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: undefined,
}),
} as unknown as Credentials;
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
// Only new version support `${workspace}` in qlpack.yml
originalDeps = await fixWorkspaceReferences(
qlpackFileWithWorkspaceRefs,

Просмотреть файл

@ -19,7 +19,6 @@ import {
} from "../../../../src/config";
import * as ghApiClient from "../../../../src/remote-queries/gh-api/gh-api-client";
import * as ghActionsApiClient from "../../../../src/remote-queries/gh-api/gh-actions-api-client";
import { Credentials } from "../../../../src/authentication";
import * as fs from "fs-extra";
import { join } from "path";
@ -58,12 +57,15 @@ import {
SortKey,
} from "../../../../src/pure/variant-analysis-filter-sort";
import { DbManager } from "../../../../src/databases/db-manager";
import { App } from "../../../../src/common/app";
import { createMockApp } from "../../../__mocks__/appMock";
// up to 3 minutes per test
jest.setTimeout(3 * 60 * 1000);
describe("Variant Analysis Manager", () => {
let cli: CodeQLCliServer;
let app: App;
let cancellationTokenSource: CancellationTokenSource;
let variantAnalysisManager: VariantAnalysisManager;
let variantAnalysisResultsManager: VariantAnalysisResultsManager;
@ -91,12 +93,15 @@ describe("Variant Analysis Manager", () => {
)!
.activate();
cli = extension.cliServer;
app = createMockApp({});
variantAnalysisResultsManager = new VariantAnalysisResultsManager(
app.credentials,
cli,
extLogger,
);
variantAnalysisManager = new VariantAnalysisManager(
extension.ctx,
app,
cli,
storagePath,
variantAnalysisResultsManager,
@ -127,14 +132,6 @@ describe("Variant Analysis Manager", () => {
}
beforeEach(async () => {
const mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: jest.fn(),
}),
} as unknown as Credentials;
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
// Should not have asked for a language
showQuickPickSpy = jest
.spyOn(window, "showQuickPick")
@ -349,14 +346,6 @@ describe("Variant Analysis Manager", () => {
let repoStatesPath: string;
beforeEach(async () => {
const mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: jest.fn(),
}),
} as unknown as Credentials;
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
const sourceFilePath = join(
__dirname,
"../data/variant-analysis-results.zip",
@ -612,16 +601,6 @@ describe("Variant Analysis Manager", () => {
});
describe("enqueueDownload", () => {
beforeEach(async () => {
const mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: jest.fn(),
}),
} as unknown as Credentials;
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
});
it("should pop download tasks off the queue", async () => {
const getResultsSpy = jest
.spyOn(variantAnalysisManager, "autoDownloadVariantAnalysisResult")
@ -782,8 +761,6 @@ describe("Variant Analysis Manager", () => {
let variantAnalysisStorageLocation: string;
let mockCredentials: Credentials;
beforeEach(async () => {
variantAnalysis = createMockVariantAnalysis({});
@ -797,14 +774,6 @@ describe("Variant Analysis Manager", () => {
);
await createTimestampFile(variantAnalysisStorageLocation);
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: jest.fn(),
}),
} as unknown as Credentials;
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
});
afterEach(() => {
@ -842,7 +811,7 @@ describe("Variant Analysis Manager", () => {
await variantAnalysisManager.cancelVariantAnalysis(variantAnalysis.id);
expect(mockCancelVariantAnalysis).toBeCalledWith(
mockCredentials,
app.credentials,
variantAnalysis,
);
});

Просмотреть файл

@ -23,9 +23,9 @@ import {
processScannedRepository,
processUpdatedVariantAnalysis,
} from "../../../../src/remote-queries/variant-analysis-processor";
import { Credentials } from "../../../../src/authentication";
import { createMockVariantAnalysis } from "../../../factories/remote-queries/shared/variant-analysis";
import { VariantAnalysisManager } from "../../../../src/remote-queries/variant-analysis-manager";
import { testCredentialsWithStub } from "../../../factories/authentication";
jest.setTimeout(60_000);
@ -74,14 +74,6 @@ describe("Variant Analysis Monitor", () => {
.mockRejectedValue(new Error("Not mocked"));
limitNumberOfAttemptsToMonitor();
const mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: jest.fn(),
}),
} as unknown as Credentials;
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
});
it("should return early if variant analysis is cancelled", async () => {
@ -89,6 +81,7 @@ describe("Variant Analysis Monitor", () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);
@ -100,6 +93,7 @@ describe("Variant Analysis Monitor", () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);
@ -117,6 +111,7 @@ describe("Variant Analysis Monitor", () => {
it("should mark as failed and stop monitoring", async () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);
@ -166,6 +161,7 @@ describe("Variant Analysis Monitor", () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);
@ -184,6 +180,7 @@ describe("Variant Analysis Monitor", () => {
it("should download all available results", async () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);
@ -216,6 +213,7 @@ describe("Variant Analysis Monitor", () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);
@ -225,6 +223,7 @@ describe("Variant Analysis Monitor", () => {
it("should not try to download any repos", async () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);
@ -283,6 +282,7 @@ describe("Variant Analysis Monitor", () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);
@ -301,6 +301,7 @@ describe("Variant Analysis Monitor", () => {
it("should not try to download any repos", async () => {
await variantAnalysisMonitor.monitorVariantAnalysis(
variantAnalysis,
testCredentialsWithStub(),
cancellationTokenSource.token,
);

Просмотреть файл

@ -1,7 +1,6 @@
import { extensions } from "vscode";
import { CodeQLExtensionInterface } from "../../../../src/extension";
import { extLogger } from "../../../../src/common";
import { Credentials } from "../../../../src/authentication";
import * as fs from "fs-extra";
import { join, resolve } from "path";
@ -15,6 +14,8 @@ import {
VariantAnalysisRepositoryTask,
VariantAnalysisScannedRepositoryResult,
} from "../../../../src/remote-queries/shared/variant-analysis";
import { testCredentialsWithStub } from "../../../factories/authentication";
import { Credentials } from "../../../../src/common/authentication";
jest.setTimeout(10_000);
@ -34,12 +35,6 @@ describe(VariantAnalysisResultsManager.name, () => {
});
describe("download", () => {
const mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: jest.fn(),
}),
} as unknown as Credentials;
let dummyRepoTask: VariantAnalysisRepositoryTask;
let variantAnalysisStoragePath: string;
let repoTaskStorageDirectory: string;
@ -49,6 +44,7 @@ describe(VariantAnalysisResultsManager.name, () => {
jest.spyOn(extLogger, "log").mockResolvedValue(undefined);
variantAnalysisResultsManager = new VariantAnalysisResultsManager(
testCredentialsWithStub(),
cli,
extLogger,
);
@ -90,7 +86,6 @@ describe(VariantAnalysisResultsManager.name, () => {
await expect(
variantAnalysisResultsManager.download(
mockCredentials,
variantAnalysisId,
dummyRepoTask,
variantAnalysisStoragePath,
@ -127,7 +122,6 @@ describe(VariantAnalysisResultsManager.name, () => {
it("should call the API to download the results", async () => {
await variantAnalysisResultsManager.download(
mockCredentials,
variantAnalysisId,
dummyRepoTask,
variantAnalysisStoragePath,
@ -138,7 +132,6 @@ describe(VariantAnalysisResultsManager.name, () => {
it("should save the results zip file to disk", async () => {
await variantAnalysisResultsManager.download(
mockCredentials,
variantAnalysisId,
dummyRepoTask,
variantAnalysisStoragePath,
@ -151,7 +144,6 @@ describe(VariantAnalysisResultsManager.name, () => {
it("should unzip the results in a `results/` folder", async () => {
await variantAnalysisResultsManager.download(
mockCredentials,
variantAnalysisId,
dummyRepoTask,
variantAnalysisStoragePath,
@ -165,7 +157,6 @@ describe(VariantAnalysisResultsManager.name, () => {
describe("isVariantAnalysisRepoDownloaded", () => {
it("should return true once results are downloaded", async () => {
await variantAnalysisResultsManager.download(
mockCredentials,
variantAnalysisId,
dummyRepoTask,
variantAnalysisStoragePath,
@ -194,6 +185,7 @@ describe(VariantAnalysisResultsManager.name, () => {
beforeEach(() => {
variantAnalysisResultsManager = new VariantAnalysisResultsManager(
testCredentialsWithStub(),
cli,
extLogger,
);

Просмотреть файл

@ -9,11 +9,8 @@ import {
window,
workspace,
} from "vscode";
import { Octokit } from "@octokit/rest";
import { retry } from "@octokit/plugin-retry";
import { CodeQLExtensionInterface } from "../../../../src/extension";
import { Credentials } from "../../../../src/authentication";
import { MockGitHubApiServer } from "../../../../src/mocks/mock-gh-api-server";
jest.setTimeout(30_000);
@ -93,11 +90,6 @@ describe("Variant Analysis Submission Integration", () => {
},
});
const mockCredentials = {
getOctokit: () => Promise.resolve(new Octokit({ retry })),
} as unknown as Credentials;
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
quickPickSpy = jest
.spyOn(window, "showQuickPick")
.mockResolvedValue(undefined);

Просмотреть файл

@ -11,7 +11,7 @@ import { Uri } from "vscode";
import { DatabaseUI } from "../../../src/databases-ui";
import { testDisposeHandler } from "../test-dispose-handler";
import { Credentials } from "../../../src/authentication";
import { createMockApp } from "../../__mocks__/appMock";
describe("databases-ui", () => {
describe("fixDbUri", () => {
@ -82,7 +82,9 @@ describe("databases-ui", () => {
"codeql-database.yml",
);
const app = createMockApp({});
const databaseUI = new DatabaseUI(
app,
{
databaseItems: [{ databaseUri: Uri.file(db1) }],
onDidChangeDatabaseItem: () => {
@ -95,7 +97,6 @@ describe("databases-ui", () => {
{} as any,
storageDir,
storageDir,
() => Promise.resolve({} as Credentials),
);
await databaseUI.handleRemoveOrphanedDatabases();

Просмотреть файл

@ -42,10 +42,12 @@ import { VariantAnalysisHistoryItem } from "../../../../src/query-history/varian
import { QueryStatus } from "../../../../src/query-status";
import { VariantAnalysisStatus } from "../../../../src/remote-queries/shared/variant-analysis";
import * as ghActionsApiClient from "../../../../src/remote-queries/gh-api/gh-actions-api-client";
import { Credentials } from "../../../../src/authentication";
import { QuickPickItem, TextEditor } from "vscode";
import { WebviewReveal } from "../../../../src/interface-utils";
import * as helpers from "../../../../src/helpers";
import { testCredentialsWithStub } from "../../../factories/authentication";
import { Credentials } from "../../../../src/common/authentication";
import { createMockApp } from "../../../__mocks__/appMock";
describe("query-history", () => {
const mockExtensionLocation = join(tmpDir.name, "mock-extension-location");
@ -873,23 +875,13 @@ describe("query-history", () => {
});
describe("handleCancel", () => {
let mockCredentials: Credentials;
let mockCancelRemoteQuery: jest.SpiedFunction<
typeof ghActionsApiClient.cancelRemoteQuery
>;
const getOctokitStub = jest.fn();
const mockCredentials = testCredentialsWithStub(getOctokitStub);
beforeEach(async () => {
mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: getOctokitStub,
}),
} as unknown as Credentials;
jest
.spyOn(Credentials, "initialize")
.mockResolvedValue(mockCredentials);
mockCancelRemoteQuery = jest
.spyOn(ghActionsApiClient, "cancelRemoteQuery")
.mockResolvedValue();
@ -897,7 +889,10 @@ describe("query-history", () => {
describe("if the item is in progress", () => {
it("should cancel a single local query", async () => {
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
// cancelling the selected item
const inProgress1 = localQueryHistory[4];
@ -908,7 +903,10 @@ describe("query-history", () => {
});
it("should cancel multiple local queries", async () => {
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
// cancelling the selected item
const inProgress1 = localQueryHistory[4];
@ -926,7 +924,10 @@ describe("query-history", () => {
});
it("should cancel a single remote query", async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
queryHistoryManager = await createMockQueryHistory(
allHistory,
mockCredentials,
);
// cancelling the selected item
const inProgress1 = remoteQueryHistory[2];
@ -939,7 +940,10 @@ describe("query-history", () => {
});
it("should cancel multiple remote queries", async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
queryHistoryManager = await createMockQueryHistory(
allHistory,
mockCredentials,
);
// cancelling the selected item
const inProgress1 = remoteQueryHistory[2];
@ -960,7 +964,10 @@ describe("query-history", () => {
});
it("should cancel a single variant analysis", async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
queryHistoryManager = await createMockQueryHistory(
allHistory,
mockCredentials,
);
// cancelling the selected item
const inProgress1 = variantAnalysisHistory[1];
@ -973,7 +980,10 @@ describe("query-history", () => {
});
it("should cancel multiple variant analyses", async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
queryHistoryManager = await createMockQueryHistory(
allHistory,
mockCredentials,
);
// cancelling the selected item
const inProgress1 = variantAnalysisHistory[1];
@ -996,7 +1006,10 @@ describe("query-history", () => {
describe("if the item is not in progress", () => {
it("should not cancel a single local query", async () => {
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
// cancelling the selected item
const completed = localQueryHistory[0];
@ -1007,7 +1020,10 @@ describe("query-history", () => {
});
it("should not cancel multiple local queries", async () => {
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
// cancelling the selected item
const completed = localQueryHistory[0];
@ -1025,7 +1041,10 @@ describe("query-history", () => {
});
it("should not cancel a single remote query", async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
queryHistoryManager = await createMockQueryHistory(
allHistory,
mockCredentials,
);
// cancelling the selected item
const completed = remoteQueryHistory[0];
@ -1038,7 +1057,10 @@ describe("query-history", () => {
});
it("should not cancel multiple remote queries", async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
queryHistoryManager = await createMockQueryHistory(
allHistory,
mockCredentials,
);
// cancelling the selected item
const completed = remoteQueryHistory[0];
@ -1059,7 +1081,10 @@ describe("query-history", () => {
});
it("should not cancel a single variant analysis", async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
queryHistoryManager = await createMockQueryHistory(
allHistory,
mockCredentials,
);
// cancelling the selected item
const completedVariantAnalysis = variantAnalysisHistory[0];
@ -1074,7 +1099,10 @@ describe("query-history", () => {
});
it("should not cancel multiple variant analyses", async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
queryHistoryManager = await createMockQueryHistory(
allHistory,
mockCredentials,
);
// cancelling the selected item
const completedVariantAnalysis = variantAnalysisHistory[0];
@ -1984,8 +2012,12 @@ describe("query-history", () => {
});
});
async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) {
async function createMockQueryHistory(
allHistory: QueryHistoryInfo[],
credentials?: Credentials,
) {
const qhm = new QueryHistoryManager(
createMockApp({ credentials }),
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,

Просмотреть файл

@ -21,7 +21,6 @@ import { QueryHistoryConfig } from "../../../../src/config";
import { DatabaseManager } from "../../../../src/databases";
import { tmpDir, walkDirectory } from "../../../../src/helpers";
import { QueryHistoryManager } from "../../../../src/query-history/query-history";
import { Credentials } from "../../../../src/authentication";
import { AnalysesResultsManager } from "../../../../src/remote-queries/analyses-results-manager";
import { RemoteQueryResult } from "../../../../src/remote-queries/shared/remote-query-result";
import { DisposableBucket } from "../../disposable-bucket";
@ -32,6 +31,9 @@ import { ResultsView } from "../../../../src/interface";
import { EvalLogViewer } from "../../../../src/eval-log-viewer";
import { QueryRunner } from "../../../../src/queryRunner";
import { VariantAnalysisManager } from "../../../../src/remote-queries/variant-analysis-manager";
import { App } from "../../../../src/common/app";
import { createMockApp } from "../../../__mocks__/appMock";
import { testCredentialsWithStub } from "../../../factories/authentication";
// set a higher timeout since recursive delete may take a while, expecially on Windows.
jest.setTimeout(120000);
@ -47,6 +49,8 @@ describe("Remote queries and query history manager", () => {
/** noop */
};
const mockOctokit = jest.fn();
let app: App;
let qhm: QueryHistoryManager;
const localQueriesResultsViewStub = {
showResults: jest.fn(),
@ -107,7 +111,9 @@ describe("Remote queries and query history manager", () => {
),
);
app = createMockApp({ credentials: testCredentialsWithStub(mockOctokit) });
qhm = new QueryHistoryManager(
app,
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,
@ -256,19 +262,11 @@ describe("Remote queries and query history manager", () => {
});
describe("AnalysisResultsManager", () => {
let mockCredentials: any;
let mockOctokit: any;
let mockLogger: any;
let mockCliServer: any;
let arm: AnalysesResultsManager;
beforeEach(() => {
mockOctokit = {
request: jest.fn(),
};
mockCredentials = {
getOctokit: () => mockOctokit,
};
mockLogger = {
log: jest.fn(),
};
@ -276,9 +274,9 @@ describe("Remote queries and query history manager", () => {
bqrsInfo: jest.fn(),
bqrsDecode: jest.fn(),
};
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
arm = new AnalysesResultsManager(
app,
mockCliServer,
join(STORAGE_DIR, "queries"),
mockLogger,
@ -292,7 +290,7 @@ describe("Remote queries and query history manager", () => {
await arm.downloadAnalysisResults(analysisSummary, publisher);
// Should not have made the request since the analysis result is already on disk
expect(mockOctokit.request).not.toBeCalled();
expect(mockOctokit).not.toBeCalled();
// result should have been published twice
expect(publisher).toHaveBeenCalledTimes(2);

Просмотреть файл

@ -21,6 +21,8 @@ import { ResultsView } from "../../../../src/interface";
import { EvalLogViewer } from "../../../../src/eval-log-viewer";
import { QueryRunner } from "../../../../src/queryRunner";
import { VariantAnalysisManager } from "../../../../src/remote-queries/variant-analysis-manager";
import { App } from "../../../../src/common/app";
import { createMockApp } from "../../../__mocks__/appMock";
// set a higher timeout since recursive delete may take a while, expecially on Windows.
jest.setTimeout(120000);
@ -36,6 +38,7 @@ describe("Variant Analyses and QueryHistoryManager", () => {
/** noop */
};
let app: App;
let qhm: QueryHistoryManager;
let rawQueryHistory: any;
let disposables: DisposableBucket;
@ -77,7 +80,10 @@ describe("Variant Analyses and QueryHistoryManager", () => {
join(STORAGE_DIR, "workspace-query-history.json"),
).queries;
app = createMockApp({});
qhm = new QueryHistoryManager(
app,
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,

Просмотреть файл

@ -1,17 +1,14 @@
import { join } from "path";
import { readFile } from "fs-extra";
import { Credentials } from "../../../../src/authentication";
import * as markdownGenerator from "../../../../src/remote-queries/remote-queries-markdown-generation";
import * as ghApiClient from "../../../../src/remote-queries/gh-api/gh-api-client";
import { exportRemoteQueryAnalysisResults } from "../../../../src/remote-queries/export-results";
import { testCredentialsWithStub } from "../../../factories/authentication";
describe("export results", () => {
describe("exportRemoteQueryAnalysisResults", () => {
const mockCredentials = {} as unknown as Credentials;
beforeEach(() => {
jest.spyOn(markdownGenerator, "generateMarkdown").mockReturnValue([]);
jest.spyOn(Credentials, "initialize").mockResolvedValue(mockCredentials);
});
it("should call the GitHub Actions API with the correct gist title", async function () {
@ -43,6 +40,7 @@ describe("export results", () => {
query,
analysesResults,
"gist",
testCredentialsWithStub(),
);
expect(mockCreateGist).toHaveBeenCalledTimes(1);

Просмотреть файл

@ -1,4 +1,3 @@
import { Credentials } from "../../../../../src/authentication";
import {
cancelRemoteQuery,
cancelVariantAnalysis,
@ -7,17 +6,16 @@ import {
import { RemoteQuery } from "../../../../../src/remote-queries/remote-query";
import { createMockVariantAnalysis } from "../../../../factories/remote-queries/shared/variant-analysis";
import { VariantAnalysis } from "../../../../../src/remote-queries/shared/variant-analysis";
import {
testCredentialsWithStub,
testCredentialsWithRealOctokit,
} from "../../../../factories/authentication";
jest.setTimeout(10000);
describe("gh-actions-api-client mock responses", () => {
const mockRequest = jest.fn();
const mockCredentials = {
getOctokit: () =>
Promise.resolve({
request: mockRequest,
}),
} as unknown as Credentials;
const mockCredentials = testCredentialsWithStub(mockRequest);
describe("cancelRemoteQuery", () => {
it("should cancel a remote query", async () => {
@ -95,7 +93,7 @@ describe("gh-actions-api-client real responses", () => {
return;
}
const credentials = await Credentials.initializeWithToken(
const credentials = testCredentialsWithRealOctokit(
process.env.VSCODE_CODEQL_GITHUB_TOKEN!,
);
const stargazers = await getRepositoriesMetadata(