Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 2 additions & 40 deletions extensions/ql-vscode/src/remote-queries/run-remote-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
getOnDiskWorkspaceFolders,
showAndLogErrorMessage,
showAndLogInformationMessage,
showInformationMessageWithAction,
tryGetQueryMetadata,
tmpDir
} from '../helpers';
Expand All @@ -22,7 +21,7 @@ import { OctokitResponse } from '@octokit/types/dist-types';
import { RemoteQuery } from './remote-query';
import { RemoteQuerySubmissionResult } from './remote-query-submission-result';
import { QueryMetadata } from '../pure/interface-types';
import { REPO_REGEX } from '../pure/helpers-pure';
import { getErrorMessage, REPO_REGEX } from '../pure/helpers-pure';

export interface QlPack {
name: string;
Expand Down Expand Up @@ -367,44 +366,7 @@ async function runRemoteQueriesApiRequest(
void showAndLogInformationMessage(`Successfully scheduled runs. [Click here to see the progress](https://github.com/${owner}/${repo}/actions/runs/${workflowRunId}).`);
return workflowRunId;
} catch (error) {
return await attemptRerun(error, credentials, ref, language, repositories, owner, repo, queryPackBase64, dryRun);
}
}

/** Attempts to rerun the query on only the valid repositories */
export async function attemptRerun(
error: any,
credentials: Credentials,
ref: string,
language: string,
repositories: string[],
owner: string,
repo: string,
queryPackBase64: string,
dryRun = false
) {
if (typeof error.message === 'string' && error.message.includes('Some repositories were invalid')) {
const invalidRepos = error?.response?.data?.invalid_repos || [];
void logger.log('Unable to run query on some of the specified repositories');
if (invalidRepos.length > 0) {
void logger.log(`Invalid repos: ${invalidRepos.join(', ')}`);
}

if (invalidRepos.length === repositories.length) {
// Every repo is invalid in some way
void showAndLogErrorMessage('Unable to run query on any of the specified repositories.');
return;
}

const popupMessage = 'Unable to run query on some of the specified repositories. [See logs for more details](command:codeQL.showLogs).';
const rerunQuery = await showInformationMessageWithAction(popupMessage, 'Rerun on the valid repositories only');
if (rerunQuery) {
const validRepositories = repositories.filter(r => !invalidRepos.includes(r));
void logger.log(`Rerunning query on set of valid repositories: ${JSON.stringify(validRepositories)}`);
return await runRemoteQueriesApiRequest(credentials, ref, language, validRepositories, owner, repo, queryPackBase64, dryRun);
}
} else {
void showAndLogErrorMessage(error);
void showAndLogErrorMessage(getErrorMessage(error));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,95 +104,4 @@ describe('run-remote-query', function() {
});

});

describe('attemptRerun', () => {
let sandbox: sinon.SinonSandbox;
let showAndLogErrorMessageSpy: sinon.SinonStub;
let showInformationMessageWithActionSpy: sinon.SinonStub;
let mockRequest: sinon.SinonStub;
let logSpy: sinon.SinonStub;
let mod: any;

const error = {
message: 'Unable to run query on the specified repositories. Some repositories were invalid.',
response: {
data: {
invalid_repos: ['abc/def', 'ghi/jkl']
}
}
};
const ref = 'main';
const language = 'javascript';
const credentials = getMockCredentials(0);
const query = 'select 1';
const owner = 'owner';
const repo = 'repo';

beforeEach(() => {
sandbox = sinon.createSandbox();
logSpy = sandbox.stub();
showAndLogErrorMessageSpy = sandbox.stub();
showInformationMessageWithActionSpy = sandbox.stub();
mod = proxyquire('../../remote-queries/run-remote-query', {
'../helpers': {
showAndLogErrorMessage: showAndLogErrorMessageSpy,
showInformationMessageWithAction: showInformationMessageWithActionSpy
},
'../logging': {
'logger': {
log: logSpy
}
},
});
});
afterEach(() => {
sandbox.restore();
});

it('should return and log error if it can\'t run on any repos', async () => {
const repositories = ['abc/def', 'ghi/jkl'];

// make the function call
await mod.attemptRerun(error, credentials, ref, language, repositories, query, owner, repo);

// check logging output
expect(logSpy.firstCall.args[0]).to.contain('Unable to run query');
expect(logSpy.secondCall.args[0]).to.contain('Invalid repos: abc/def, ghi/jkl');
expect(showAndLogErrorMessageSpy.firstCall.args[0]).to.contain('Unable to run query on any');
});

it('should list invalid repos and rerun on valid ones', async () => {
const repositories = ['foo/bar', 'abc/def', 'ghi/jkl', 'foo/baz'];

// fake return values
showInformationMessageWithActionSpy.resolves(true);

// make the function call
await mod.attemptRerun(error, credentials, ref, language, repositories, query, owner, repo);

// check logging output
expect(logSpy.firstCall.args[0]).to.contain('Unable to run query');
expect(logSpy.secondCall.args[0]).to.contain('Invalid repos: abc/def, ghi/jkl');

// check that the correct information message is displayed
expect(showInformationMessageWithActionSpy.firstCall.args[0]).to.contain('Unable to run query on some');
expect(showInformationMessageWithActionSpy.firstCall.args[1]).to.contain('Rerun');

// check that API request is made again, with only valid repos
expect(logSpy.lastCall.args[0]).to.contain('valid repositories: ["foo/bar","foo/baz"]');
// test a few values in the octokit request
expect(mockRequest.firstCall.args[1].data.language).to.eq('javascript');
expect(mockRequest.firstCall.args[1].data.repositories).to.deep.eq(['foo/bar', 'foo/baz']);

});

function getMockCredentials(response: any) {
mockRequest = sinon.stub().resolves(response);
return {
getOctokit: () => ({
request: mockRequest
})
};
}
});
});