Allow the codeql-action to be run locally (#117)
* Allow the codeql-action to be run locally This change allows the codeql-action to be run locally through [act](https://github.com/nektos/act). In order to run the action locally, you need to do two things: 1. Add the `CODEQL_LOCAL_RUN: true` environment variable. The only way I could figure out how to do this was to add it directly in the workflow file in an `env` block. It _should_ be possible to add it through a `.env` file and pass it to `act`, but I couldn't get it working. 2. Run this command `act -j codeql -s GITHUB_TOKEN=<MY_PAT>` Setting the `CODEQL_LOCAL_RUN` env var will fill in missing env vars that the action needs, but isn't set by `act`. It will also avoid making api calls to github that would fail locally. This is a refactoring discussed in https://github.com/github/dsp-codeql/issues/36
This commit is contained in:
parent
631929a68f
commit
42235cc048
25 changed files with 195 additions and 20 deletions
|
|
@ -2,7 +2,12 @@ import * as core from "@actions/core";
|
|||
import * as github from "@actions/github";
|
||||
import consoleLogLevel from "console-log-level";
|
||||
|
||||
export const getApiClient = function() {
|
||||
import { isLocalRun } from "./util";
|
||||
|
||||
export const getApiClient = function(allowLocalRun = false) {
|
||||
if (isLocalRun() && !allowLocalRun) {
|
||||
throw new Error('Invalid API call in local run');
|
||||
}
|
||||
return new github.GitHub(
|
||||
core.getInput('token'),
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ async function run() {
|
|||
const startedAt = new Date();
|
||||
let language;
|
||||
try {
|
||||
util.prepareLocalRunEnvironment();
|
||||
if (util.should_abort('autobuild', true) ||
|
||||
!await util.sendStatusReport(await util.createStatusReportBase('autobuild', 'starting', startedAt), true)) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ async function getLanguagesInRepo(): Promise<string[]> {
|
|||
let repo = repo_nwo[1];
|
||||
|
||||
core.debug(`GitHub repo ${owner} ${repo}`);
|
||||
const response = await api.getApiClient().request("GET /repos/:owner/:repo/languages", ({
|
||||
const response = await api.getApiClient(true).request("GET /repos/:owner/:repo/languages", ({
|
||||
owner,
|
||||
repo
|
||||
}));
|
||||
|
|
@ -636,7 +636,7 @@ async function getRemoteConfig(configFile: string): Promise<UserConfig> {
|
|||
throw new Error(getConfigFileRepoFormatInvalidMessage(configFile));
|
||||
}
|
||||
|
||||
const response = await api.getApiClient().repos.getContents({
|
||||
const response = await api.getApiClient(true).repos.getContents({
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ async function run() {
|
|||
let queriesStats: QueriesStatusReport | undefined = undefined;
|
||||
let uploadStats: upload_lib.UploadStatusReport | undefined = undefined;
|
||||
try {
|
||||
util.prepareLocalRunEnvironment();
|
||||
if (util.should_abort('finish', true) ||
|
||||
!await util.sendStatusReport(await util.createStatusReportBase('finish', 'starting', startedAt), true)) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ async function run() {
|
|||
let codeql: CodeQL;
|
||||
|
||||
try {
|
||||
util.prepareLocalRunEnvironment();
|
||||
if (util.should_abort('init', false) ||
|
||||
!await util.sendStatusReport(await util.createStatusReportBase('init', 'starting', startedAt), true)) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -218,9 +218,12 @@ async function uploadFiles(sarifFiles: string[]): Promise<UploadStatusReport> {
|
|||
const numResultInSarif = countResultsInSarif(sarifPayload);
|
||||
core.debug("Number of results in upload: " + numResultInSarif);
|
||||
|
||||
// Make the upload
|
||||
await uploadPayload(payload);
|
||||
|
||||
if (!util.isLocalRun()) {
|
||||
// Make the upload
|
||||
await uploadPayload(payload);
|
||||
} else {
|
||||
core.debug("Not uploading because this is a local run.");
|
||||
}
|
||||
core.endGroup();
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -67,3 +67,52 @@ test('getRef() throws on the empty string', t => {
|
|||
process.env["GITHUB_REF"] = "";
|
||||
t.throws(util.getRef);
|
||||
});
|
||||
|
||||
test('isLocalRun() runs correctly', t => {
|
||||
const origLocalRun = process.env.CODEQL_LOCAL_RUN;
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = '';
|
||||
t.assert(!util.isLocalRun());
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = 'false';
|
||||
t.assert(!util.isLocalRun());
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = '0';
|
||||
t.assert(!util.isLocalRun());
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = 'true';
|
||||
t.assert(util.isLocalRun());
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = 'hucairz';
|
||||
t.assert(util.isLocalRun());
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = origLocalRun;
|
||||
});
|
||||
|
||||
test('prepareEnvironment() when a local run', t => {
|
||||
const origLocalRun = process.env.CODEQL_LOCAL_RUN;
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = 'false';
|
||||
process.env.GITHUB_JOB = 'YYY';
|
||||
|
||||
util.prepareLocalRunEnvironment();
|
||||
|
||||
// unchanged
|
||||
t.deepEqual(process.env.GITHUB_JOB, 'YYY');
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = 'true';
|
||||
|
||||
util.prepareLocalRunEnvironment();
|
||||
|
||||
// unchanged
|
||||
t.deepEqual(process.env.GITHUB_JOB, 'YYY');
|
||||
|
||||
process.env.GITHUB_JOB = '';
|
||||
|
||||
util.prepareLocalRunEnvironment();
|
||||
|
||||
// updated
|
||||
t.deepEqual(process.env.GITHUB_JOB, 'UNKNOWN-JOB');
|
||||
|
||||
process.env.CODEQL_LOCAL_RUN = origLocalRun;
|
||||
});
|
||||
|
|
|
|||
29
src/util.ts
29
src/util.ts
|
|
@ -64,6 +64,26 @@ export function getRequiredEnvParam(paramName: string): string {
|
|||
return value;
|
||||
}
|
||||
|
||||
export function isLocalRun(): boolean {
|
||||
return !!process.env.CODEQL_LOCAL_RUN
|
||||
&& process.env.CODEQL_LOCAL_RUN !== 'false'
|
||||
&& process.env.CODEQL_LOCAL_RUN !== '0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures all required environment variables are set in the context of a local run.
|
||||
*/
|
||||
export function prepareLocalRunEnvironment() {
|
||||
if (!isLocalRun()) {
|
||||
return;
|
||||
}
|
||||
|
||||
core.debug('Action is running locally.');
|
||||
if (!process.env.GITHUB_JOB) {
|
||||
core.exportVariable('GITHUB_JOB', 'UNKNOWN-JOB');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SHA of the commit that is currently checked out.
|
||||
*/
|
||||
|
|
@ -95,6 +115,9 @@ export async function getCommitOid(): Promise<string> {
|
|||
* Get the path of the currently executing workflow.
|
||||
*/
|
||||
async function getWorkflowPath(): Promise<string> {
|
||||
if (isLocalRun()) {
|
||||
return 'LOCAL';
|
||||
}
|
||||
const repo_nwo = getRequiredEnvParam('GITHUB_REPOSITORY').split("/");
|
||||
const owner = repo_nwo[0];
|
||||
const repo = repo_nwo[1];
|
||||
|
|
@ -273,8 +296,12 @@ export async function sendStatusReport<S extends StatusReportBase>(
|
|||
return true;
|
||||
}
|
||||
|
||||
const statusReportJSON = JSON.stringify(statusReport);
|
||||
if (isLocalRun()) {
|
||||
core.debug("Not sending status report because this is a local run");
|
||||
return true;
|
||||
}
|
||||
|
||||
const statusReportJSON = JSON.stringify(statusReport);
|
||||
core.debug('Sending status report: ' + statusReportJSON);
|
||||
|
||||
const nwo = getRequiredEnvParam("GITHUB_REPOSITORY");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue