Merge pull request #1684 from github/mbg/add-resolve-environment

This commit is contained in:
Michael B. Gale 2023-06-15 17:50:42 +01:00 committed by GitHub
commit 0ac18158d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 453 additions and 5 deletions

View file

@ -306,7 +306,8 @@ type ActionName =
| "autobuild"
| "finish"
| "upload-sarif"
| "init-post";
| "init-post"
| "resolve-environment";
export type ActionStatus =
| "starting"
| "aborted"

View file

@ -118,6 +118,13 @@ export interface CodeQL {
queries: string[],
extraSearchPath: string | undefined
): Promise<ResolveQueriesOutput>;
/**
* Run 'codeql resolve build-environment'
*/
resolveBuildEnvironment(
workingDir: string | undefined,
language: Language
): Promise<ResolveBuildEnvironmentOutput>;
/**
* Run 'codeql pack download'.
@ -229,6 +236,14 @@ export interface ResolveQueriesOutput {
};
}
export interface ResolveBuildEnvironmentOutput {
configuration?: {
[language: string]: {
[key: string]: unknown;
};
};
}
export interface PackDownloadOutput {
packs: PackDownloadItem[];
}
@ -289,6 +304,11 @@ export const CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE = "2.12.1";
*/
export const CODEQL_VERSION_INIT_WITH_QLCONFIG = "2.12.4";
/**
* Versions 2.13.4+ of the CodeQL CLI support the `resolve build-environment` command.
*/
export const CODEQL_VERSION_RESOLVE_ENVIRONMENT = "2.13.4";
/**
* Set up CodeQL CLI access.
*
@ -402,6 +422,10 @@ export function setCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
"betterResolveLanguages"
),
resolveQueries: resolveFunction(partialCodeql, "resolveQueries"),
resolveBuildEnvironment: resolveFunction(
partialCodeql,
"resolveBuildEnvironment"
),
packDownload: resolveFunction(partialCodeql, "packDownload"),
databaseCleanup: resolveFunction(partialCodeql, "databaseCleanup"),
databaseBundle: resolveFunction(partialCodeql, "databaseBundle"),
@ -681,6 +705,29 @@ export async function getCodeQLForCmd(
throw new Error(`Unexpected output from codeql resolve queries: ${e}`);
}
},
async resolveBuildEnvironment(
workingDir: string | undefined,
language: Language
) {
const codeqlArgs = [
"resolve",
"build-environment",
`--language=${language}`,
...getExtraOptionsFromEnv(["resolve", "build-environment"]),
];
if (workingDir !== undefined) {
codeqlArgs.push("--working-dir", workingDir);
}
const output = await runTool(cmd, codeqlArgs);
try {
return JSON.parse(output);
} catch (e) {
throw new Error(
`Unexpected output from codeql resolve build-environment: ${e} in\n${output}`
);
}
},
async databaseRunQueries(
databasePath: string,
extraSearchPath: string | undefined,

View file

@ -0,0 +1,98 @@
import * as core from "@actions/core";
import {
createStatusReportBase,
getActionsStatus,
getOptionalInput,
getRequiredInput,
getTemporaryDirectory,
sendStatusReport,
} from "./actions-util";
import { getGitHubVersion } from "./api-client";
import { CommandInvocationError } from "./codeql";
import * as configUtils from "./config-utils";
import { Language, resolveAlias } from "./languages";
import { getActionsLogger } from "./logging";
import { runResolveBuildEnvironment } from "./resolve-environment";
import { checkForTimeout, checkGitHubVersionInRange, wrapError } from "./util";
const ACTION_NAME = "resolve-environment";
const ENVIRONMENT_OUTPUT_NAME = "environment";
async function run() {
const startedAt = new Date();
const logger = getActionsLogger();
const language: Language = resolveAlias(getRequiredInput("language"));
try {
if (
!(await sendStatusReport(
await createStatusReportBase(ACTION_NAME, "starting", startedAt)
))
) {
return;
}
const gitHubVersion = await getGitHubVersion();
checkGitHubVersionInRange(gitHubVersion, logger);
const config = await configUtils.getConfig(getTemporaryDirectory(), logger);
if (config === undefined) {
throw new Error(
"Config file could not be found at expected location. Has the 'init' action been called?"
);
}
const workingDirectory = getOptionalInput("working-directory");
const result = await runResolveBuildEnvironment(
config.codeQLCmd,
logger,
workingDirectory,
language
);
core.setOutput(ENVIRONMENT_OUTPUT_NAME, result);
} catch (unwrappedError) {
const error = wrapError(unwrappedError);
if (error instanceof CommandInvocationError) {
// If the CLI failed to run successfully for whatever reason,
// we just return an empty JSON object and proceed with the workflow.
core.setOutput(ENVIRONMENT_OUTPUT_NAME, {});
logger.warning(
`Failed to resolve a build environment suitable for automatically building your code. ${error.message}`
);
} else {
// For any other error types, something has more seriously gone wrong and we fail.
core.setFailed(
`Failed to resolve a build environment suitable for automatically building your code. ${error.message}`
);
await sendStatusReport(
await createStatusReportBase(
ACTION_NAME,
getActionsStatus(error),
startedAt,
error.message,
error.stack
)
);
}
return;
}
await sendStatusReport(
await createStatusReportBase(ACTION_NAME, "success", startedAt)
);
}
async function runWrapper() {
try {
await run();
} catch (error) {
core.setFailed(`${ACTION_NAME} action failed: ${wrapError(error).message}`);
}
await checkForTimeout();
}
void runWrapper();

View file

@ -0,0 +1,36 @@
import { CODEQL_VERSION_RESOLVE_ENVIRONMENT, getCodeQL } from "./codeql";
import { Language } from "./languages";
import { Logger } from "./logging";
import * as util from "./util";
export async function runResolveBuildEnvironment(
cmd: string,
logger: Logger,
workingDir: string | undefined,
language: Language
) {
logger.startGroup(`Attempting to resolve build environment for ${language}`);
const codeql = await getCodeQL(cmd);
let result = {};
// If the CodeQL version in use does not support the `resolve build-environment`
// command, just return an empty configuration. Otherwise invoke the CLI.
if (
!(await util.codeQlVersionAbove(codeql, CODEQL_VERSION_RESOLVE_ENVIRONMENT))
) {
logger.warning(
"Unsupported CodeQL CLI version for `resolve build-environment` command, " +
"returning an empty configuration."
);
} else {
if (workingDir !== undefined) {
logger.info(`Using ${workingDir} as the working directory.`);
}
result = await codeql.resolveBuildEnvironment(workingDir, language);
}
logger.endGroup();
return result;
}