Introduce a rollback mechanism for Java buildless

This commit is contained in:
Henry Mercer 2024-02-12 22:47:05 +00:00
parent 77be28fbdb
commit 4e5f9c0873
9 changed files with 139 additions and 22 deletions

30
lib/config-utils.js generated
View file

@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapEnvironment = exports.generateRegistries = exports.getConfig = exports.getPathToParsedConfigFile = exports.initConfig = exports.validatePackSpecification = exports.parsePacksSpecification = exports.parsePacksFromInput = exports.calculateAugmentation = exports.getDefaultConfig = exports.getRawLanguages = exports.getLanguageAliases = exports.getLanguages = exports.getLanguagesInRepo = exports.getUnknownLanguagesError = exports.getNoLanguagesError = exports.getConfigFileDirectoryGivenMessage = exports.getConfigFileFormatInvalidMessage = exports.getConfigFileRepoFormatInvalidMessage = exports.getConfigFileDoesNotExistErrorMessage = exports.getConfigFileOutsideWorkspaceErrorMessage = exports.getPacksStrInvalid = exports.defaultAugmentationProperties = exports.BuildMode = void 0;
exports.parseBuildModeInput = exports.wrapEnvironment = exports.generateRegistries = exports.getConfig = exports.getPathToParsedConfigFile = exports.initConfig = exports.validatePackSpecification = exports.parsePacksSpecification = exports.parsePacksFromInput = exports.calculateAugmentation = exports.getDefaultConfig = exports.getRawLanguages = exports.getLanguageAliases = exports.getLanguages = exports.getLanguagesInRepo = exports.getUnknownLanguagesError = exports.getNoLanguagesError = exports.getConfigFileDirectoryGivenMessage = exports.getConfigFileFormatInvalidMessage = exports.getConfigFileRepoFormatInvalidMessage = exports.getConfigFileDoesNotExistErrorMessage = exports.getConfigFileOutsideWorkspaceErrorMessage = exports.getPacksStrInvalid = exports.defaultAugmentationProperties = exports.BuildMode = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const perf_hooks_1 = require("perf_hooks");
@ -31,6 +31,7 @@ const yaml = __importStar(require("js-yaml"));
const semver = __importStar(require("semver"));
const api = __importStar(require("./api-client"));
const codeql_1 = require("./codeql");
const feature_flags_1 = require("./feature-flags");
const languages_1 = require("./languages");
const trap_caching_1 = require("./trap-caching");
const util_1 = require("./util");
@ -218,13 +219,14 @@ exports.getRawLanguages = getRawLanguages;
/**
* Get the default config for when the user has not supplied one.
*/
async function getDefaultConfig({ languagesInput, queriesInput, packsInput, buildModeInput, dbLocation, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeql, githubVersion, logger, }) {
async function getDefaultConfig({ languagesInput, queriesInput, packsInput, buildModeInput, dbLocation, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeql, githubVersion, features, logger, }) {
const languages = await getLanguages(codeql, languagesInput, repository, logger);
const buildMode = await parseBuildModeInput(buildModeInput, languages, features, logger);
const augmentationProperties = calculateAugmentation(packsInput, queriesInput, languages);
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(trapCachingEnabled, codeql, languages, logger);
return {
languages,
buildMode: validateBuildModeInput(buildModeInput),
buildMode,
originalUserInput: {},
tempDir,
codeQLCmd: codeql.getPath(),
@ -252,7 +254,7 @@ async function downloadCacheWithTime(trapCachingEnabled, codeQL, languages, logg
/**
* Load the config from the given file.
*/
async function loadConfig({ languagesInput, queriesInput, packsInput, buildModeInput, configFile, dbLocation, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeql, workspacePath, githubVersion, apiDetails, logger, }) {
async function loadConfig({ languagesInput, queriesInput, packsInput, buildModeInput, configFile, dbLocation, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeql, workspacePath, githubVersion, apiDetails, features, logger, }) {
let parsedYAML;
if (isLocal(configFile)) {
// Treat the config file as relative to the workspace
@ -263,11 +265,12 @@ async function loadConfig({ languagesInput, queriesInput, packsInput, buildModeI
parsedYAML = await getRemoteConfig(configFile, apiDetails);
}
const languages = await getLanguages(codeql, languagesInput, repository, logger);
const buildMode = await parseBuildModeInput(buildModeInput, languages, features, logger);
const augmentationProperties = calculateAugmentation(packsInput, queriesInput, languages);
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(trapCachingEnabled, codeql, languages, logger);
return {
languages,
buildMode: validateBuildModeInput(buildModeInput),
buildMode,
originalUserInput: parsedYAML,
tempDir,
codeQLCmd: codeql.getPath(),
@ -664,13 +667,20 @@ async function wrapEnvironment(env, operation) {
}
}
exports.wrapEnvironment = wrapEnvironment;
function validateBuildModeInput(buildModeInput) {
if (buildModeInput === undefined) {
// Exported for testing
async function parseBuildModeInput(input, languages, features, logger) {
if (input === undefined) {
return undefined;
}
if (!Object.values(BuildMode).includes(buildModeInput)) {
throw new util_1.ConfigurationError(`Invalid build mode: '${buildModeInput}'. Supported build modes are: ${Object.values(BuildMode).join(", ")}.`);
if (!Object.values(BuildMode).includes(input)) {
throw new util_1.ConfigurationError(`Invalid build mode: '${input}'. Supported build modes are: ${Object.values(BuildMode).join(", ")}.`);
}
return buildModeInput;
if (languages.includes(languages_1.Language.java) &&
(await features.getValue(feature_flags_1.Feature.DisableJavaBuildlessEnabled))) {
logger.warning("Scanning Java code without a build is temporarily unavailable. Falling back to 'autobuild' build mode.");
return BuildMode.Autobuild;
}
return input;
}
exports.parseBuildModeInput = parseBuildModeInput;
//# sourceMappingURL=config-utils.js.map

File diff suppressed because one or more lines are too long

View file

@ -36,6 +36,7 @@ const api = __importStar(require("./api-client"));
const codeql_1 = require("./codeql");
const configUtils = __importStar(require("./config-utils"));
const config_utils_1 = require("./config-utils");
const feature_flags_1 = require("./feature-flags");
const languages_1 = require("./languages");
const logging_1 = require("./logging");
const repository_1 = require("./repository");
@ -68,6 +69,7 @@ function createTestInitConfigInputs(overrides) {
apiURL: undefined,
registriesAuthTokens: undefined,
},
features: (0, testing_utils_1.createFeatures)([]),
logger: (0, logging_1.getRunnerLogger)(true),
}, overrides);
}
@ -763,4 +765,27 @@ const mockRepositoryNwo = (0, repository_1.parseRepositoryNwo)("owner/repo");
t.deepEqual(mockRequest.called, args.expectedApiCall);
});
});
(0, ava_1.default)("Build mode not overridden when disable Java buildless feature flag disabled", async (t) => {
const messages = [];
const buildMode = await configUtils.parseBuildModeInput("none", [languages_1.Language.java], (0, testing_utils_1.createFeatures)([]), (0, testing_utils_1.getRecordingLogger)(messages));
t.is(buildMode, config_utils_1.BuildMode.None);
t.deepEqual(messages, []);
});
(0, ava_1.default)("Build mode not overridden for other languages", async (t) => {
const messages = [];
const buildMode = await configUtils.parseBuildModeInput("none", [languages_1.Language.python], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.DisableJavaBuildlessEnabled]), (0, testing_utils_1.getRecordingLogger)(messages));
t.is(buildMode, config_utils_1.BuildMode.None);
t.deepEqual(messages, []);
});
(0, ava_1.default)("Build mode overridden when analyzing Java and disable Java buildless feature flag enabled", async (t) => {
const messages = [];
const buildMode = await configUtils.parseBuildModeInput("none", [languages_1.Language.java], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.DisableJavaBuildlessEnabled]), (0, testing_utils_1.getRecordingLogger)(messages));
t.is(buildMode, config_utils_1.BuildMode.Autobuild);
t.deepEqual(messages, [
{
message: "Scanning Java code without a build is temporarily unavailable. Falling back to 'autobuild' build mode.",
type: "warning",
},
]);
});
//# sourceMappingURL=config-utils.test.js.map

File diff suppressed because one or more lines are too long

1
lib/init-action.js generated
View file

@ -157,6 +157,7 @@ async function run() {
workspacePath: (0, util_1.getRequiredEnvParam)("GITHUB_WORKSPACE"),
githubVersion: gitHubVersion,
apiDetails,
features,
logger,
});
await (0, init_1.checkInstallPython311)(config.languages, codeql);

File diff suppressed because one or more lines are too long

View file

@ -15,12 +15,16 @@ import {
} from "./codeql";
import * as configUtils from "./config-utils";
import { BuildMode } from "./config-utils";
import { Feature } from "./feature-flags";
import { Language } from "./languages";
import { getRunnerLogger } from "./logging";
import { parseRepositoryNwo } from "./repository";
import {
setupTests,
mockLanguagesInRepo as mockLanguagesInRepo,
createFeatures,
getRecordingLogger,
LoggedMessage,
} from "./testing-utils";
import {
GitHubVariant,
@ -63,6 +67,7 @@ function createTestInitConfigInputs(
apiURL: undefined,
registriesAuthTokens: undefined,
},
features: createFeatures([]),
logger: getRunnerLogger(true),
},
overrides,
@ -1080,3 +1085,45 @@ const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
t.deepEqual(mockRequest.called, args.expectedApiCall);
});
});
test("Build mode not overridden when disable Java buildless feature flag disabled", async (t) => {
const messages: LoggedMessage[] = [];
const buildMode = await configUtils.parseBuildModeInput(
"none",
[Language.java],
createFeatures([]),
getRecordingLogger(messages),
);
t.is(buildMode, BuildMode.None);
t.deepEqual(messages, []);
});
test("Build mode not overridden for other languages", async (t) => {
const messages: LoggedMessage[] = [];
const buildMode = await configUtils.parseBuildModeInput(
"none",
[Language.python],
createFeatures([Feature.DisableJavaBuildlessEnabled]),
getRecordingLogger(messages),
);
t.is(buildMode, BuildMode.None);
t.deepEqual(messages, []);
});
test("Build mode overridden when analyzing Java and disable Java buildless feature flag enabled", async (t) => {
const messages: LoggedMessage[] = [];
const buildMode = await configUtils.parseBuildModeInput(
"none",
[Language.java],
createFeatures([Feature.DisableJavaBuildlessEnabled]),
getRecordingLogger(messages),
);
t.is(buildMode, BuildMode.Autobuild);
t.deepEqual(messages, [
{
message:
"Scanning Java code without a build is temporarily unavailable. Falling back to 'autobuild' build mode.",
type: "warning",
},
]);
});

View file

@ -7,6 +7,7 @@ import * as semver from "semver";
import * as api from "./api-client";
import { CodeQL, CODEQL_VERSION_LANGUAGE_ALIASING } from "./codeql";
import { Feature, FeatureEnablement } from "./feature-flags";
import { Language, parseLanguage } from "./languages";
import { Logger } from "./logging";
import { RepositoryNwo } from "./repository";
@ -420,6 +421,7 @@ export interface InitConfigInputs {
workspacePath: string;
githubVersion: GitHubVersion;
apiDetails: api.GitHubApiCombinedDetails;
features: FeatureEnablement;
logger: Logger;
}
@ -449,6 +451,7 @@ export async function getDefaultConfig({
tempDir,
codeql,
githubVersion,
features,
logger,
}: GetDefaultConfigInputs): Promise<Config> {
const languages = await getLanguages(
@ -457,6 +460,14 @@ export async function getDefaultConfig({
repository,
logger,
);
const buildMode = await parseBuildModeInput(
buildModeInput,
languages,
features,
logger,
);
const augmentationProperties = calculateAugmentation(
packsInput,
queriesInput,
@ -472,7 +483,7 @@ export async function getDefaultConfig({
return {
languages,
buildMode: validateBuildModeInput(buildModeInput),
buildMode,
originalUserInput: {},
tempDir,
codeQLCmd: codeql.getPath(),
@ -526,6 +537,7 @@ async function loadConfig({
workspacePath,
githubVersion,
apiDetails,
features,
logger,
}: LoadConfigInputs): Promise<Config> {
let parsedYAML: UserConfig;
@ -545,6 +557,13 @@ async function loadConfig({
logger,
);
const buildMode = await parseBuildModeInput(
buildModeInput,
languages,
features,
logger,
);
const augmentationProperties = calculateAugmentation(
packsInput,
queriesInput,
@ -560,7 +579,7 @@ async function loadConfig({
return {
languages,
buildMode: validateBuildModeInput(buildModeInput),
buildMode,
originalUserInput: parsedYAML,
tempDir,
codeQLCmd: codeql.getPath(),
@ -1073,19 +1092,33 @@ export async function wrapEnvironment(
}
}
function validateBuildModeInput(
buildModeInput: string | undefined,
): BuildMode | undefined {
if (buildModeInput === undefined) {
// Exported for testing
export async function parseBuildModeInput(
input: string | undefined,
languages: Language[],
features: FeatureEnablement,
logger: Logger,
): Promise<BuildMode | undefined> {
if (input === undefined) {
return undefined;
}
if (!Object.values(BuildMode).includes(buildModeInput as BuildMode)) {
if (!Object.values(BuildMode).includes(input as BuildMode)) {
throw new ConfigurationError(
`Invalid build mode: '${buildModeInput}'. Supported build modes are: ${Object.values(
`Invalid build mode: '${input}'. Supported build modes are: ${Object.values(
BuildMode,
).join(", ")}.`,
);
}
return buildModeInput as BuildMode;
if (
languages.includes(Language.java) &&
(await features.getValue(Feature.DisableJavaBuildlessEnabled))
) {
logger.warning(
"Scanning Java code without a build is temporarily unavailable. Falling back to 'autobuild' build mode.",
);
return BuildMode.Autobuild;
}
return input as BuildMode;
}

View file

@ -285,6 +285,7 @@ async function run() {
workspacePath: getRequiredEnvParam("GITHUB_WORKSPACE"),
githubVersion: gitHubVersion,
apiDetails,
features,
logger,
});