Merge pull request #1753 from github/koesie10/copy-repo-list
Add copying of repository list for variant analyses
This commit is contained in:
@@ -944,6 +944,12 @@ async function activateWithInstalledDistribution(
|
||||
})
|
||||
);
|
||||
|
||||
ctx.subscriptions.push(
|
||||
commandRunner('codeQL.copyVariantAnalysisRepoList', async (variantAnalysisId: number) => {
|
||||
await variantAnalysisManager.copyRepoListToClipboard(variantAnalysisId);
|
||||
})
|
||||
);
|
||||
|
||||
ctx.subscriptions.push(
|
||||
commandRunner('codeQL.monitorVariantAnalysis', async (
|
||||
variantAnalysis: VariantAnalysis,
|
||||
|
||||
@@ -1256,11 +1256,15 @@ export class QueryHistoryManager extends DisposableObject {
|
||||
const { finalSingleItem, finalMultiSelect } = this.determineSelection(singleItem, multiSelect);
|
||||
|
||||
// Remote queries only
|
||||
if (!this.assertSingleQuery(finalMultiSelect) || !finalSingleItem || finalSingleItem.t !== 'remote') {
|
||||
if (!this.assertSingleQuery(finalMultiSelect) || !finalSingleItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
await commands.executeCommand('codeQL.copyRepoList', finalSingleItem.queryId);
|
||||
if (finalSingleItem.t === 'remote') {
|
||||
await commands.executeCommand('codeQL.copyRepoList', finalSingleItem.queryId);
|
||||
} else if (finalSingleItem.t === 'variant-analysis') {
|
||||
await commands.executeCommand('codeQL.copyVariantAnalysisRepoList', finalSingleItem.variantAnalysis.id);
|
||||
}
|
||||
}
|
||||
|
||||
async handleExportResults(): Promise<void> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import * as ghApiClient from './gh-api/gh-api-client';
|
||||
import { CancellationToken, commands, EventEmitter, ExtensionContext, Uri, window } from 'vscode';
|
||||
import { CancellationToken, commands, env, EventEmitter, ExtensionContext, Uri, window } from 'vscode';
|
||||
import { DisposableObject } from '../pure/disposable-object';
|
||||
import { Credentials } from '../authentication';
|
||||
import { VariantAnalysisMonitor } from './variant-analysis-monitor';
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
import PQueue from 'p-queue';
|
||||
import { createTimestampFile, showAndLogErrorMessage, showAndLogInformationMessage } from '../helpers';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import { cancelVariantAnalysis } from './gh-api/gh-actions-api-client';
|
||||
import { ProgressCallback, UserCancellationException } from '../commandRunner';
|
||||
import { CodeQLCliServer } from '../cli';
|
||||
@@ -367,6 +368,27 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
|
||||
await cancelVariantAnalysis(credentials, variantAnalysis);
|
||||
}
|
||||
|
||||
public async copyRepoListToClipboard(variantAnalysisId: number) {
|
||||
const variantAnalysis = this.variantAnalyses.get(variantAnalysisId);
|
||||
if (!variantAnalysis) {
|
||||
throw new Error(`No variant analysis with id: ${variantAnalysisId}`);
|
||||
}
|
||||
|
||||
const fullNames = variantAnalysis.scannedRepos?.filter(a => a.resultCount && a.resultCount > 0).map(a => a.repository.fullName);
|
||||
if (!fullNames || fullNames.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const text = [
|
||||
'"new-repo-list": [',
|
||||
...fullNames.slice(0, -1).map(repo => ` "${repo}",`),
|
||||
` "${fullNames[fullNames.length - 1]}"`,
|
||||
']'
|
||||
];
|
||||
|
||||
await env.clipboard.writeText(text.join(os.EOL));
|
||||
}
|
||||
|
||||
private getRepoStatesStoragePath(variantAnalysisId: number): string {
|
||||
return path.join(
|
||||
this.getVariantAnalysisStorageLocation(variantAnalysisId),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { assert, expect } from 'chai';
|
||||
import { CancellationTokenSource, commands, extensions, QuickPickItem, Uri, window } from 'vscode';
|
||||
import { CancellationTokenSource, commands, env, extensions, QuickPickItem, Uri, window } from 'vscode';
|
||||
import { CodeQLExtensionInterface } from '../../../extension';
|
||||
import { logger } from '../../../logging';
|
||||
import * as config from '../../../config';
|
||||
@@ -16,7 +16,10 @@ import { storagePath } from '../global.helper';
|
||||
import { VariantAnalysisResultsManager } from '../../../remote-queries/variant-analysis-results-manager';
|
||||
import { createMockVariantAnalysis } from '../../factories/remote-queries/shared/variant-analysis';
|
||||
import * as VariantAnalysisModule from '../../../remote-queries/shared/variant-analysis';
|
||||
import { createMockScannedRepos } from '../../factories/remote-queries/shared/scanned-repositories';
|
||||
import {
|
||||
createMockScannedRepo,
|
||||
createMockScannedRepos
|
||||
} from '../../factories/remote-queries/shared/scanned-repositories';
|
||||
import {
|
||||
VariantAnalysis,
|
||||
VariantAnalysisScannedRepository,
|
||||
@@ -252,7 +255,9 @@ describe('Variant Analysis Manager', async function() {
|
||||
});
|
||||
|
||||
describe('when credentials are invalid', async () => {
|
||||
beforeEach(async () => { sandbox.stub(Credentials, 'initialize').resolves(undefined); });
|
||||
beforeEach(async () => {
|
||||
sandbox.stub(Credentials, 'initialize').resolves(undefined);
|
||||
});
|
||||
|
||||
it('should return early if credentials are wrong', async () => {
|
||||
try {
|
||||
@@ -695,4 +700,121 @@ describe('Variant Analysis Manager', async function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('copyRepoListToClipboard', async () => {
|
||||
let variantAnalysis: VariantAnalysis;
|
||||
let variantAnalysisStorageLocation: string;
|
||||
|
||||
let writeTextStub: sinon.SinonStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
variantAnalysis = createMockVariantAnalysis({});
|
||||
|
||||
variantAnalysisStorageLocation = variantAnalysisManager.getVariantAnalysisStorageLocation(variantAnalysis.id);
|
||||
await createTimestampFile(variantAnalysisStorageLocation);
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
|
||||
|
||||
writeTextStub = sinon.stub();
|
||||
sinon.stub(env, 'clipboard').value({
|
||||
writeText: writeTextStub,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(variantAnalysisStorageLocation, { recursive: true });
|
||||
});
|
||||
|
||||
describe('when the variant analysis does not have any repositories', () => {
|
||||
beforeEach(async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis({
|
||||
...variantAnalysis,
|
||||
scannedRepos: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should not copy any text', async () => {
|
||||
await variantAnalysisManager.copyRepoListToClipboard(variantAnalysis.id);
|
||||
|
||||
expect(writeTextStub).not.to.have.been.called;
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the variant analysis does not have any repositories with results', () => {
|
||||
beforeEach(async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis({
|
||||
...variantAnalysis,
|
||||
scannedRepos: [
|
||||
{
|
||||
...createMockScannedRepo(),
|
||||
resultCount: 0,
|
||||
},
|
||||
{
|
||||
...createMockScannedRepo(),
|
||||
resultCount: undefined,
|
||||
}
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should not copy any text', async () => {
|
||||
await variantAnalysisManager.copyRepoListToClipboard(variantAnalysis.id);
|
||||
|
||||
expect(writeTextStub).not.to.have.been.called;
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the variant analysis has repositories with results', () => {
|
||||
const scannedRepos = [
|
||||
{
|
||||
...createMockScannedRepo(),
|
||||
resultCount: 100,
|
||||
},
|
||||
{
|
||||
...createMockScannedRepo(),
|
||||
resultCount: 0,
|
||||
},
|
||||
{
|
||||
...createMockScannedRepo(),
|
||||
resultCount: 200,
|
||||
},
|
||||
{
|
||||
...createMockScannedRepo(),
|
||||
resultCount: undefined,
|
||||
},
|
||||
{
|
||||
...createMockScannedRepo(),
|
||||
resultCount: 5,
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis({
|
||||
...variantAnalysis,
|
||||
scannedRepos,
|
||||
});
|
||||
});
|
||||
|
||||
it('should copy text', async () => {
|
||||
await variantAnalysisManager.copyRepoListToClipboard(variantAnalysis.id);
|
||||
|
||||
expect(writeTextStub).to.have.been.calledOnce;
|
||||
});
|
||||
|
||||
it('should be valid JSON when put in object', async () => {
|
||||
await variantAnalysisManager.copyRepoListToClipboard(variantAnalysis.id);
|
||||
|
||||
const text = writeTextStub.getCalls()[0].lastArg;
|
||||
|
||||
const parsed = JSON.parse('{' + text + '}');
|
||||
|
||||
expect(parsed).to.deep.eq({
|
||||
'new-repo-list': [
|
||||
scannedRepos[0].repository.fullName,
|
||||
scannedRepos[2].repository.fullName,
|
||||
scannedRepos[4].repository.fullName,
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user