Merge pull request #2108 from github/henrymercer/build-mode-input

Add experimental `build-mode` input
This commit is contained in:
Henry Mercer 2024-02-02 10:46:37 +00:00 committed by GitHub
commit 81eb6b2bf4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 224 additions and 55 deletions

View file

@ -23,6 +23,7 @@ import {
import { isTracedLanguage, Language } from "./languages";
import { Logger } from "./logging";
import * as setupCodeql from "./setup-codeql";
import { ToolsFeature, isSupportedToolsFeature } from "./tools-features";
import * as util from "./util";
import { wrapError } from "./util";
@ -90,6 +91,10 @@ export interface CodeQL {
* Print version information about CodeQL.
*/
printVersion(): Promise<void>;
/**
* Returns whether the CodeQL executable supports the specified feature.
*/
supportsFeature(feature: ToolsFeature): Promise<boolean>;
/**
* Run 'codeql database init --db-cluster'.
*/
@ -452,17 +457,17 @@ function resolveFunction<T>(
export function setCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
cachedCodeQL = {
getPath: resolveFunction(partialCodeql, "getPath", () => "/tmp/dummy-path"),
getVersion: resolveFunction(
partialCodeql,
"getVersion",
() =>
new Promise((resolve) =>
resolve({
version: "1.0.0",
}),
),
),
getVersion: resolveFunction(partialCodeql, "getVersion", async () => ({
version: "1.0.0",
})),
printVersion: resolveFunction(partialCodeql, "printVersion"),
supportsFeature: resolveFunction(
partialCodeql,
"supportsFeature",
async (feature) =>
!!partialCodeql.getVersion &&
isSupportedToolsFeature(await partialCodeql.getVersion(), feature),
),
databaseInitCluster: resolveFunction(partialCodeql, "databaseInitCluster"),
runAutobuild: resolveFunction(partialCodeql, "runAutobuild"),
extractScannedLanguage: resolveFunction(
@ -561,6 +566,9 @@ export async function getCodeQLForCmd(
async printVersion() {
await runTool(cmd, ["version", "--format=json"]);
},
async supportsFeature(feature: ToolsFeature) {
return isSupportedToolsFeature(await this.getVersion(), feature);
},
async databaseInitCluster(
config: Config,
sourceRoot: string,
@ -589,6 +597,12 @@ export async function getCodeQLForCmd(
extraArgs.push("--external-repository-token-stdin");
}
if (
config.buildMode !== undefined &&
(await this.supportsFeature(ToolsFeature.BuildModeOption))
) {
extraArgs.push(`--build-mode=${config.buildMode}`);
}
if (
qlconfigFile !== undefined &&
(await util.codeQlVersionAbove(this, CODEQL_VERSION_INIT_WITH_QLCONFIG))

View file

@ -45,6 +45,7 @@ function createTestInitConfigInputs(
configFile: undefined,
dbLocation: undefined,
configInput: undefined,
buildModeInput: undefined,
trapCachingEnabled: false,
debugMode: false,
debugArtifactName: "",
@ -322,6 +323,7 @@ test("load non-empty input", async (t) => {
// And the config we expect it to parse to
const expectedConfig: configUtils.Config = {
languages: [Language.javascript],
buildMode: "none",
originalUserInput: {
name: "my config",
"disable-default-queries": true,
@ -347,6 +349,7 @@ test("load non-empty input", async (t) => {
const actualConfig = await configUtils.initConfig(
createTestInitConfigInputs({
languagesInput,
buildModeInput: "none",
configFile: configFilePath,
debugArtifactName: "my-artifact",
debugDatabaseName: "my-db",

View file

@ -80,6 +80,10 @@ export interface Config {
* Set of languages to run analysis for.
*/
languages: Language[];
/**
* Build mode, if set. Currently only a single build mode is supported per job.
*/
buildMode: string | undefined;
/**
* A unaltered copy of the original user input.
* Mainly intended to be used for status reporting.
@ -399,6 +403,7 @@ export interface InitConfigInputs {
configFile: string | undefined;
dbLocation: string | undefined;
configInput: string | undefined;
buildModeInput: string | undefined;
trapCachingEnabled: boolean;
debugMode: boolean;
debugArtifactName: string;
@ -428,6 +433,7 @@ export async function getDefaultConfig({
languagesInput,
queriesInput,
packsInput,
buildModeInput,
dbLocation,
trapCachingEnabled,
debugMode,
@ -460,6 +466,7 @@ export async function getDefaultConfig({
return {
languages,
buildMode: buildModeInput,
originalUserInput: {},
tempDir,
codeQLCmd: codeql.getPath(),
@ -500,6 +507,7 @@ async function loadConfig({
languagesInput,
queriesInput,
packsInput,
buildModeInput,
configFile,
dbLocation,
trapCachingEnabled,
@ -546,6 +554,7 @@ async function loadConfig({
return {
languages,
buildMode: buildModeInput,
originalUserInput: parsedYAML,
tempDir,
codeQLCmd: codeql.getPath(),

View file

@ -38,7 +38,7 @@ import {
getActionsStatus,
sendStatusReport,
} from "./status-report";
import { ToolsFeature, isSupportedToolsFeature } from "./tools-features";
import { ToolsFeature } from "./tools-features";
import { getTotalCacheSize } from "./trap-caching";
import {
checkDiskUsage,
@ -269,6 +269,7 @@ async function run() {
languagesInput: getOptionalInput("languages"),
queriesInput: getOptionalInput("queries"),
packsInput: getOptionalInput("packs"),
buildModeInput: getOptionalInput("build-mode"),
configFile: getOptionalInput("config-file"),
dbLocation: getOptionalInput("db-location"),
configInput: getOptionalInput("config"),
@ -327,9 +328,6 @@ async function run() {
}
try {
// Query CLI for supported features
const versionInfo = await codeql.getVersion();
// Forward Go flags
const goFlags = process.env["GOFLAGS"];
if (goFlags) {
@ -353,10 +351,9 @@ async function run() {
// typically dynamically linked, this provides a suitable entry point for the CodeQL tracer.
if (
fileOutput.includes("statically linked") &&
!isSupportedToolsFeature(
versionInfo,
!(await codeql.supportsFeature(
ToolsFeature.IndirectTracingSupportsStaticBinaries,
)
))
) {
try {
logger.debug(`Applying static binary workaround for Go`);

View file

@ -90,7 +90,7 @@ export async function runInit(
} catch (e) {
throw processError(e);
}
return await getCombinedTracerConfig(await codeql.getVersion(), config);
return await getCombinedTracerConfig(codeql, config);
}
export function printPathFiltersWarning(

View file

@ -230,11 +230,11 @@ export function mockCodeQLVersion(
version: string,
features?: { [name: string]: boolean },
) {
return {
return codeql.setCodeQL({
async getVersion() {
return makeVersionInfo(version, features);
},
} as codeql.CodeQL;
});
}
/**
@ -304,6 +304,7 @@ export function createTestConfig(overrides: Partial<Config>): Config {
{},
{
languages: [],
buildMode: undefined,
originalUserInput: {},
tempDir: "",
codeQLCmd: "",

View file

@ -1,6 +1,7 @@
import { VersionInfo } from "./codeql";
import type { VersionInfo } from "./codeql";
export enum ToolsFeature {
BuildModeOption = "buildModeOption",
IndirectTracingSupportsStaticBinaries = "indirectTracingSupportsStaticBinaries",
SetsCodeqlRunnerEnvVar = "setsCodeqlRunnerEnvVar",
}

View file

@ -5,7 +5,11 @@ import test from "ava";
import * as configUtils from "./config-utils";
import { Language } from "./languages";
import { createTestConfig, makeVersionInfo, setupTests } from "./testing-utils";
import {
createTestConfig,
mockCodeQLVersion,
setupTests,
} from "./testing-utils";
import { getCombinedTracerConfig } from "./tracer-config";
import * as util from "./util";
@ -25,7 +29,7 @@ test("getCombinedTracerConfig - return undefined when no languages are traced la
// No traced languages
config.languages = [Language.javascript, Language.python];
t.deepEqual(
await getCombinedTracerConfig(makeVersionInfo("1.0.0"), config),
await getCombinedTracerConfig(mockCodeQLVersion("1.0.0"), config),
undefined,
);
});
@ -61,7 +65,7 @@ test("getCombinedTracerConfig - with start-tracing.json environment file", async
fs.writeFileSync(startTracingJson, JSON.stringify(startTracingEnv));
const result = await getCombinedTracerConfig(
makeVersionInfo("1.0.0"),
mockCodeQLVersion("1.0.0"),
config,
);
t.notDeepEqual(result, undefined);
@ -121,7 +125,7 @@ test("getCombinedTracerConfig - with SetsCodeqlRunnerEnvVar feature enabled in C
fs.writeFileSync(startTracingJson, JSON.stringify(startTracingEnv));
const result = await getCombinedTracerConfig(
makeVersionInfo("1.0.0", { setsCodeqlRunnerEnvVar: true }),
mockCodeQLVersion("1.0.0", { setsCodeqlRunnerEnvVar: true }),
config,
);
t.notDeepEqual(result, undefined);

View file

@ -1,10 +1,10 @@
import * as fs from "fs";
import * as path from "path";
import { VersionInfo } from "./codeql";
import { CodeQL } from "./codeql";
import * as configUtils from "./config-utils";
import { isTracedLanguage } from "./languages";
import { ToolsFeature, isSupportedToolsFeature } from "./tools-features";
import { ToolsFeature } from "./tools-features";
export type TracerConfig = {
env: { [key: string]: string };
@ -61,7 +61,7 @@ export async function getTracerConfigForCluster(
}
export async function getCombinedTracerConfig(
versionInfo: VersionInfo,
codeql: CodeQL,
config: configUtils.Config,
): Promise<TracerConfig | undefined> {
// Abort if there are no traced languages as there's nothing to do
@ -74,9 +74,7 @@ export async function getCombinedTracerConfig(
// If the CLI doesn't yet support setting the CODEQL_RUNNER environment variable to
// the runner executable path, we set it here in the Action.
if (
!isSupportedToolsFeature(versionInfo, ToolsFeature.SetsCodeqlRunnerEnvVar)
) {
if (!(await codeql.supportsFeature(ToolsFeature.SetsCodeqlRunnerEnvVar))) {
// On MacOS when System Integrity Protection is enabled, it's necessary to prefix
// the build command with the runner executable for indirect tracing, so we expose
// it here via the CODEQL_RUNNER environment variable.