Merge pull request #2236 from github/henrymercer/feature-flags-with-tool-feature-dependencies
Allow feature flags to specify tool feature requirements
This commit is contained in:
commit
5a599c68cf
6 changed files with 177 additions and 15 deletions
22
lib/feature-flags.js
generated
22
lib/feature-flags.js
generated
|
|
@ -29,6 +29,7 @@ const path = __importStar(require("path"));
|
||||||
const semver = __importStar(require("semver"));
|
const semver = __importStar(require("semver"));
|
||||||
const api_client_1 = require("./api-client");
|
const api_client_1 = require("./api-client");
|
||||||
const defaults = __importStar(require("./defaults.json"));
|
const defaults = __importStar(require("./defaults.json"));
|
||||||
|
const tools_features_1 = require("./tools-features");
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
const DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_";
|
const DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_";
|
||||||
const DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled";
|
const DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled";
|
||||||
|
|
@ -48,6 +49,7 @@ exports.CODEQL_VERSION_FINE_GRAINED_PARALLELISM = "2.15.1";
|
||||||
*/
|
*/
|
||||||
var Feature;
|
var Feature;
|
||||||
(function (Feature) {
|
(function (Feature) {
|
||||||
|
Feature["AutobuildDirectTracingEnabled"] = "autobuild_direct_tracing_enabled";
|
||||||
Feature["CliSarifMerge"] = "cli_sarif_merge_enabled";
|
Feature["CliSarifMerge"] = "cli_sarif_merge_enabled";
|
||||||
Feature["CppDependencyInstallation"] = "cpp_dependency_installation_enabled";
|
Feature["CppDependencyInstallation"] = "cpp_dependency_installation_enabled";
|
||||||
Feature["CppTrapCachingEnabled"] = "cpp_trap_caching_enabled";
|
Feature["CppTrapCachingEnabled"] = "cpp_trap_caching_enabled";
|
||||||
|
|
@ -57,6 +59,12 @@ var Feature;
|
||||||
Feature["QaTelemetryEnabled"] = "qa_telemetry_enabled";
|
Feature["QaTelemetryEnabled"] = "qa_telemetry_enabled";
|
||||||
})(Feature || (exports.Feature = Feature = {}));
|
})(Feature || (exports.Feature = Feature = {}));
|
||||||
exports.featureConfig = {
|
exports.featureConfig = {
|
||||||
|
[Feature.AutobuildDirectTracingEnabled]: {
|
||||||
|
envVar: "CODEQL_ACTION_AUTOBUILD_BUILD_MODE_DIRECT_TRACING",
|
||||||
|
minimumVersion: undefined,
|
||||||
|
toolsFeature: tools_features_1.ToolsFeature.TraceCommandUseBuildMode,
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
[Feature.CliSarifMerge]: {
|
[Feature.CliSarifMerge]: {
|
||||||
envVar: "CODEQL_ACTION_CLI_SARIF_MERGE",
|
envVar: "CODEQL_ACTION_CLI_SARIF_MERGE",
|
||||||
// This is guarded by a `supportsFeature` check rather than by a version check.
|
// This is guarded by a `supportsFeature` check rather than by a version check.
|
||||||
|
|
@ -124,6 +132,9 @@ class Features {
|
||||||
if (!codeql && exports.featureConfig[feature].minimumVersion) {
|
if (!codeql && exports.featureConfig[feature].minimumVersion) {
|
||||||
throw new Error(`Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`);
|
throw new Error(`Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`);
|
||||||
}
|
}
|
||||||
|
if (!codeql && exports.featureConfig[feature].toolsFeature) {
|
||||||
|
throw new Error(`Internal error: A required tools feature is specified for feature ${feature}, but no instance of CodeQL was provided.`);
|
||||||
|
}
|
||||||
const envVar = (process.env[exports.featureConfig[feature].envVar] || "").toLocaleLowerCase();
|
const envVar = (process.env[exports.featureConfig[feature].envVar] || "").toLocaleLowerCase();
|
||||||
// Do not use this feature if user explicitly disables it via an environment variable.
|
// Do not use this feature if user explicitly disables it via an environment variable.
|
||||||
if (envVar === "false") {
|
if (envVar === "false") {
|
||||||
|
|
@ -143,6 +154,17 @@ class Features {
|
||||||
`version ${minimumVersion} for feature ${feature}.`);
|
`version ${minimumVersion} for feature ${feature}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const toolsFeature = exports.featureConfig[feature].toolsFeature;
|
||||||
|
if (codeql && toolsFeature) {
|
||||||
|
if (!(await codeql.supportsFeature(toolsFeature))) {
|
||||||
|
this.logger.debug(`Feature ${feature} is disabled because the CodeQL CLI version does not support the ` +
|
||||||
|
`required tools feature ${toolsFeature}.`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.logger.debug(`CodeQL CLI version ${(await codeql.getVersion()).version} supports the required tools feature ${toolsFeature} for feature ${feature}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Use this feature if user explicitly enables it via an environment variable.
|
// Use this feature if user explicitly enables it via an environment variable.
|
||||||
if (envVar === "true") {
|
if (envVar === "true") {
|
||||||
this.logger.debug(`Feature ${feature} is enabled via the environment variable ${exports.featureConfig[feature].envVar}.`);
|
this.logger.debug(`Feature ${feature} is enabled via the environment variable ${exports.featureConfig[feature].envVar}.`);
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
49
lib/feature-flags.test.js
generated
49
lib/feature-flags.test.js
generated
|
|
@ -34,6 +34,7 @@ const feature_flags_1 = require("./feature-flags");
|
||||||
const logging_1 = require("./logging");
|
const logging_1 = require("./logging");
|
||||||
const repository_1 = require("./repository");
|
const repository_1 = require("./repository");
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
|
const tools_features_1 = require("./tools-features");
|
||||||
const util_1 = require("./util");
|
const util_1 = require("./util");
|
||||||
(0, testing_utils_1.setupTests)(ava_1.default);
|
(0, testing_utils_1.setupTests)(ava_1.default);
|
||||||
ava_1.default.beforeEach(() => {
|
ava_1.default.beforeEach(() => {
|
||||||
|
|
@ -129,14 +130,17 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
|
||||||
t.assert(!(await features.getValue(feature, includeCodeQlIfRequired(feature))));
|
t.assert(!(await features.getValue(feature, includeCodeQlIfRequired(feature))));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (feature_flags_1.featureConfig[feature].minimumVersion !== undefined) {
|
if (feature_flags_1.featureConfig[feature].minimumVersion !== undefined ||
|
||||||
|
feature_flags_1.featureConfig[feature].toolsFeature !== undefined) {
|
||||||
(0, ava_1.default)(`Getting feature '${feature} should throw if no codeql is provided`, async (t) => {
|
(0, ava_1.default)(`Getting feature '${feature} should throw if no codeql is provided`, async (t) => {
|
||||||
await (0, util_1.withTmpDir)(async (tmpDir) => {
|
await (0, util_1.withTmpDir)(async (tmpDir) => {
|
||||||
const features = setUpFeatureFlagTests(tmpDir);
|
const features = setUpFeatureFlagTests(tmpDir);
|
||||||
const expectedFeatureEnablement = initializeFeatures(true);
|
const expectedFeatureEnablement = initializeFeatures(true);
|
||||||
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
|
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
|
||||||
await t.throwsAsync(async () => features.getValue(feature), {
|
await t.throwsAsync(async () => features.getValue(feature), {
|
||||||
message: `Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`,
|
message: `Internal error: A ${feature_flags_1.featureConfig[feature].minimumVersion !== undefined
|
||||||
|
? "minimum version"
|
||||||
|
: "required tools feature"} is specified for feature ${feature}, but no instance of CodeQL was provided.`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -165,14 +169,42 @@ for (const feature of Object.keys(feature_flags_1.featureConfig)) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (feature_flags_1.featureConfig[feature].toolsFeature !== undefined) {
|
||||||
|
(0, ava_1.default)(`Feature '${feature}' is disabled if the required tools feature is not enabled`, async (t) => {
|
||||||
|
await (0, util_1.withTmpDir)(async (tmpDir) => {
|
||||||
|
const features = setUpFeatureFlagTests(tmpDir);
|
||||||
|
const expectedFeatureEnablement = initializeFeatures(true);
|
||||||
|
(0, testing_utils_1.mockFeatureFlagApiEndpoint)(200, expectedFeatureEnablement);
|
||||||
|
// feature should be disabled when the required tools feature is not enabled
|
||||||
|
let codeql = (0, testing_utils_1.mockCodeQLVersion)("2.0.0");
|
||||||
|
t.assert(!(await features.getValue(feature, codeql)));
|
||||||
|
// even setting the env var to true should not enable the feature if
|
||||||
|
// the required tools feature is not enabled
|
||||||
|
process.env[feature_flags_1.featureConfig[feature].envVar] = "true";
|
||||||
|
t.assert(!(await features.getValue(feature, codeql)));
|
||||||
|
// feature should be enabled when the required tools feature is enabled
|
||||||
|
// and env var is not set
|
||||||
|
process.env[feature_flags_1.featureConfig[feature].envVar] = "";
|
||||||
|
codeql = (0, testing_utils_1.mockCodeQLVersion)("2.0.0", {
|
||||||
|
[feature_flags_1.featureConfig[feature].toolsFeature]: true,
|
||||||
|
});
|
||||||
|
t.assert(await features.getValue(feature, codeql));
|
||||||
|
// set env var to false and check that the feature is now disabled
|
||||||
|
process.env[feature_flags_1.featureConfig[feature].envVar] = "false";
|
||||||
|
t.assert(!(await features.getValue(feature, codeql)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// If we ever run into a situation where we no longer have any features that
|
// If we ever run into a situation where we no longer have any features that
|
||||||
// specify a minimum version, then we will have a bunch of code no longer being
|
// specify a minimum version or required tools feature, then we will have a
|
||||||
// tested. This is unlikely, and this test will fail if that happens.
|
// bunch of code no longer being tested. This is unlikely, and this test will
|
||||||
|
// fail if that happens.
|
||||||
// If we do end up in that situation, then we should consider adding a synthetic
|
// If we do end up in that situation, then we should consider adding a synthetic
|
||||||
// feature with a minimum version that is only used for tests.
|
// feature with a minimum version that is only used for tests.
|
||||||
(0, ava_1.default)("At least one feature has a minimum version specified", (t) => {
|
(0, ava_1.default)("At least one feature has a minimum version specified", (t) => {
|
||||||
t.assert(Object.values(feature_flags_1.featureConfig).some((f) => f.minimumVersion !== undefined), "At least one feature should have a minimum version specified");
|
t.assert(Object.values(feature_flags_1.featureConfig).some((f) => f.minimumVersion !== undefined), "At least one feature should have a minimum version specified");
|
||||||
|
t.assert(Object.values(feature_flags_1.featureConfig).some((f) => f.toolsFeature !== undefined), "At least one feature should have a required tools feature specified");
|
||||||
// An even less likely scenario is that we no longer have any features.
|
// An even less likely scenario is that we no longer have any features.
|
||||||
t.assert(Object.values(feature_flags_1.featureConfig).length > 0, "There should be at least one feature");
|
t.assert(Object.values(feature_flags_1.featureConfig).length > 0, "There should be at least one feature");
|
||||||
});
|
});
|
||||||
|
|
@ -321,9 +353,14 @@ function setUpFeatureFlagTests(tmpDir, logger = (0, logging_1.getRunnerLogger)(t
|
||||||
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
|
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
|
||||||
return new feature_flags_1.Features(gitHubVersion, testRepositoryNwo, tmpDir, logger);
|
return new feature_flags_1.Features(gitHubVersion, testRepositoryNwo, tmpDir, logger);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Returns an argument to pass to `getValue` that if required includes a CodeQL object meeting the
|
||||||
|
* minimum version or tool feature requirements specified by the feature.
|
||||||
|
*/
|
||||||
function includeCodeQlIfRequired(feature) {
|
function includeCodeQlIfRequired(feature) {
|
||||||
return feature_flags_1.featureConfig[feature].minimumVersion !== undefined
|
return feature_flags_1.featureConfig[feature].minimumVersion !== undefined ||
|
||||||
? (0, testing_utils_1.mockCodeQLVersion)("9.9.9")
|
feature_flags_1.featureConfig[feature].toolsFeature !== undefined
|
||||||
|
? (0, testing_utils_1.mockCodeQLVersion)("9.9.9", Object.fromEntries(Object.values(tools_features_1.ToolsFeature).map((v) => [v, true])))
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
//# sourceMappingURL=feature-flags.test.js.map
|
//# sourceMappingURL=feature-flags.test.js.map
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -21,6 +21,7 @@ import {
|
||||||
setupActionsVars,
|
setupActionsVars,
|
||||||
setupTests,
|
setupTests,
|
||||||
} from "./testing-utils";
|
} from "./testing-utils";
|
||||||
|
import { ToolsFeature } from "./tools-features";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util";
|
import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util";
|
||||||
|
|
||||||
|
|
@ -197,7 +198,10 @@ for (const feature of Object.keys(featureConfig)) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (featureConfig[feature].minimumVersion !== undefined) {
|
if (
|
||||||
|
featureConfig[feature].minimumVersion !== undefined ||
|
||||||
|
featureConfig[feature].toolsFeature !== undefined
|
||||||
|
) {
|
||||||
test(`Getting feature '${feature} should throw if no codeql is provided`, async (t) => {
|
test(`Getting feature '${feature} should throw if no codeql is provided`, async (t) => {
|
||||||
await withTmpDir(async (tmpDir) => {
|
await withTmpDir(async (tmpDir) => {
|
||||||
const features = setUpFeatureFlagTests(tmpDir);
|
const features = setUpFeatureFlagTests(tmpDir);
|
||||||
|
|
@ -206,7 +210,11 @@ for (const feature of Object.keys(featureConfig)) {
|
||||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||||
|
|
||||||
await t.throwsAsync(async () => features.getValue(feature as Feature), {
|
await t.throwsAsync(async () => features.getValue(feature as Feature), {
|
||||||
message: `Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`,
|
message: `Internal error: A ${
|
||||||
|
featureConfig[feature].minimumVersion !== undefined
|
||||||
|
? "minimum version"
|
||||||
|
: "required tools feature"
|
||||||
|
} is specified for feature ${feature}, but no instance of CodeQL was provided.`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -243,11 +251,44 @@ for (const feature of Object.keys(featureConfig)) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (featureConfig[feature].toolsFeature !== undefined) {
|
||||||
|
test(`Feature '${feature}' is disabled if the required tools feature is not enabled`, async (t) => {
|
||||||
|
await withTmpDir(async (tmpDir) => {
|
||||||
|
const features = setUpFeatureFlagTests(tmpDir);
|
||||||
|
|
||||||
|
const expectedFeatureEnablement = initializeFeatures(true);
|
||||||
|
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||||
|
|
||||||
|
// feature should be disabled when the required tools feature is not enabled
|
||||||
|
let codeql = mockCodeQLVersion("2.0.0");
|
||||||
|
t.assert(!(await features.getValue(feature as Feature, codeql)));
|
||||||
|
|
||||||
|
// even setting the env var to true should not enable the feature if
|
||||||
|
// the required tools feature is not enabled
|
||||||
|
process.env[featureConfig[feature].envVar] = "true";
|
||||||
|
t.assert(!(await features.getValue(feature as Feature, codeql)));
|
||||||
|
|
||||||
|
// feature should be enabled when the required tools feature is enabled
|
||||||
|
// and env var is not set
|
||||||
|
process.env[featureConfig[feature].envVar] = "";
|
||||||
|
codeql = mockCodeQLVersion("2.0.0", {
|
||||||
|
[featureConfig[feature].toolsFeature]: true,
|
||||||
|
});
|
||||||
|
t.assert(await features.getValue(feature as Feature, codeql));
|
||||||
|
|
||||||
|
// set env var to false and check that the feature is now disabled
|
||||||
|
process.env[featureConfig[feature].envVar] = "false";
|
||||||
|
t.assert(!(await features.getValue(feature as Feature, codeql)));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we ever run into a situation where we no longer have any features that
|
// If we ever run into a situation where we no longer have any features that
|
||||||
// specify a minimum version, then we will have a bunch of code no longer being
|
// specify a minimum version or required tools feature, then we will have a
|
||||||
// tested. This is unlikely, and this test will fail if that happens.
|
// bunch of code no longer being tested. This is unlikely, and this test will
|
||||||
|
// fail if that happens.
|
||||||
// If we do end up in that situation, then we should consider adding a synthetic
|
// If we do end up in that situation, then we should consider adding a synthetic
|
||||||
// feature with a minimum version that is only used for tests.
|
// feature with a minimum version that is only used for tests.
|
||||||
test("At least one feature has a minimum version specified", (t) => {
|
test("At least one feature has a minimum version specified", (t) => {
|
||||||
|
|
@ -256,6 +297,11 @@ test("At least one feature has a minimum version specified", (t) => {
|
||||||
"At least one feature should have a minimum version specified",
|
"At least one feature should have a minimum version specified",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
t.assert(
|
||||||
|
Object.values(featureConfig).some((f) => f.toolsFeature !== undefined),
|
||||||
|
"At least one feature should have a required tools feature specified",
|
||||||
|
);
|
||||||
|
|
||||||
// An even less likely scenario is that we no longer have any features.
|
// An even less likely scenario is that we no longer have any features.
|
||||||
t.assert(
|
t.assert(
|
||||||
Object.values(featureConfig).length > 0,
|
Object.values(featureConfig).length > 0,
|
||||||
|
|
@ -512,8 +558,16 @@ function setUpFeatureFlagTests(
|
||||||
return new Features(gitHubVersion, testRepositoryNwo, tmpDir, logger);
|
return new Features(gitHubVersion, testRepositoryNwo, tmpDir, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an argument to pass to `getValue` that if required includes a CodeQL object meeting the
|
||||||
|
* minimum version or tool feature requirements specified by the feature.
|
||||||
|
*/
|
||||||
function includeCodeQlIfRequired(feature: string) {
|
function includeCodeQlIfRequired(feature: string) {
|
||||||
return featureConfig[feature].minimumVersion !== undefined
|
return featureConfig[feature].minimumVersion !== undefined ||
|
||||||
? mockCodeQLVersion("9.9.9")
|
featureConfig[feature].toolsFeature !== undefined
|
||||||
|
? mockCodeQLVersion(
|
||||||
|
"9.9.9",
|
||||||
|
Object.fromEntries(Object.values(ToolsFeature).map((v) => [v, true])),
|
||||||
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import type { CodeQL } from "./codeql";
|
||||||
import * as defaults from "./defaults.json";
|
import * as defaults from "./defaults.json";
|
||||||
import { Logger } from "./logging";
|
import { Logger } from "./logging";
|
||||||
import { RepositoryNwo } from "./repository";
|
import { RepositoryNwo } from "./repository";
|
||||||
|
import { ToolsFeature } from "./tools-features";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
|
|
||||||
const DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_";
|
const DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_";
|
||||||
|
|
@ -44,6 +45,7 @@ export interface FeatureEnablement {
|
||||||
* Each value of this enum should end with `_enabled`.
|
* Each value of this enum should end with `_enabled`.
|
||||||
*/
|
*/
|
||||||
export enum Feature {
|
export enum Feature {
|
||||||
|
AutobuildDirectTracingEnabled = "autobuild_direct_tracing_enabled",
|
||||||
CliSarifMerge = "cli_sarif_merge_enabled",
|
CliSarifMerge = "cli_sarif_merge_enabled",
|
||||||
CppDependencyInstallation = "cpp_dependency_installation_enabled",
|
CppDependencyInstallation = "cpp_dependency_installation_enabled",
|
||||||
CppTrapCachingEnabled = "cpp_trap_caching_enabled",
|
CppTrapCachingEnabled = "cpp_trap_caching_enabled",
|
||||||
|
|
@ -55,8 +57,34 @@ export enum Feature {
|
||||||
|
|
||||||
export const featureConfig: Record<
|
export const featureConfig: Record<
|
||||||
Feature,
|
Feature,
|
||||||
{ envVar: string; minimumVersion: string | undefined; defaultValue: boolean }
|
{
|
||||||
|
/**
|
||||||
|
* Environment variable for explicitly enabling or disabling the feature.
|
||||||
|
*
|
||||||
|
* This overrides enablement status from the feature flags API.
|
||||||
|
*/
|
||||||
|
envVar: string;
|
||||||
|
/**
|
||||||
|
* Minimum version of the CLI, if applicable.
|
||||||
|
*
|
||||||
|
* Prefer using `ToolsFeature`s for future flags.
|
||||||
|
*/
|
||||||
|
minimumVersion: string | undefined;
|
||||||
|
/** Required tools feature, if applicable. */
|
||||||
|
toolsFeature?: ToolsFeature;
|
||||||
|
/**
|
||||||
|
* Default value in environments where the feature flags API is not available,
|
||||||
|
* such as GitHub Enterprise Server.
|
||||||
|
*/
|
||||||
|
defaultValue: boolean;
|
||||||
|
}
|
||||||
> = {
|
> = {
|
||||||
|
[Feature.AutobuildDirectTracingEnabled]: {
|
||||||
|
envVar: "CODEQL_ACTION_AUTOBUILD_BUILD_MODE_DIRECT_TRACING",
|
||||||
|
minimumVersion: undefined,
|
||||||
|
toolsFeature: ToolsFeature.TraceCommandUseBuildMode,
|
||||||
|
defaultValue: false,
|
||||||
|
},
|
||||||
[Feature.CliSarifMerge]: {
|
[Feature.CliSarifMerge]: {
|
||||||
envVar: "CODEQL_ACTION_CLI_SARIF_MERGE",
|
envVar: "CODEQL_ACTION_CLI_SARIF_MERGE",
|
||||||
// This is guarded by a `supportsFeature` check rather than by a version check.
|
// This is guarded by a `supportsFeature` check rather than by a version check.
|
||||||
|
|
@ -151,6 +179,11 @@ export class Features implements FeatureEnablement {
|
||||||
`Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`,
|
`Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (!codeql && featureConfig[feature].toolsFeature) {
|
||||||
|
throw new Error(
|
||||||
|
`Internal error: A required tools feature is specified for feature ${feature}, but no instance of CodeQL was provided.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const envVar = (
|
const envVar = (
|
||||||
process.env[featureConfig[feature].envVar] || ""
|
process.env[featureConfig[feature].envVar] || ""
|
||||||
|
|
@ -182,6 +215,22 @@ export class Features implements FeatureEnablement {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const toolsFeature = featureConfig[feature].toolsFeature;
|
||||||
|
if (codeql && toolsFeature) {
|
||||||
|
if (!(await codeql.supportsFeature(toolsFeature))) {
|
||||||
|
this.logger.debug(
|
||||||
|
`Feature ${feature} is disabled because the CodeQL CLI version does not support the ` +
|
||||||
|
`required tools feature ${toolsFeature}.`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
this.logger.debug(
|
||||||
|
`CodeQL CLI version ${
|
||||||
|
(await codeql.getVersion()).version
|
||||||
|
} supports the required tools feature ${toolsFeature} for feature ${feature}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use this feature if user explicitly enables it via an environment variable.
|
// Use this feature if user explicitly enables it via an environment variable.
|
||||||
if (envVar === "true") {
|
if (envVar === "true") {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue