Refactor handling of feature flags

This commit centralizes how feature flags are handled. All feature flags
must now add an entry in the `featureFlagConfig` dictionary. This
dictionary associates the flag with an environment variable name and
optionally a minimum version for CodeQL.

The new logic is:

- if the environment variable is set to false: disabled
- if the minimum version requirement specified and met: disabled
- if the environment variable is set to true: enable
- Otherwise check feature flag enablement from the server
This commit is contained in:
Andrew Eisenberg
2022-10-05 15:54:07 -07:00
parent 24c8de16fa
commit e5c3375225
27 changed files with 400 additions and 368 deletions

43
lib/feature-flags.js generated
View File

@@ -19,7 +19,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFeatureFlags = exports.GitHubFeatureFlags = exports.FeatureFlag = void 0;
exports.createFeatureFlags = exports.GitHubFeatureFlags = exports.featureFlagConfig = exports.FeatureFlag = void 0;
const api_client_1 = require("./api-client");
const util = __importStar(require("./util"));
var FeatureFlag;
@@ -30,6 +30,28 @@ var FeatureFlag;
FeatureFlag["GolangExtractionReconciliationEnabled"] = "golang_extraction_reconciliation_enabled";
FeatureFlag["CliConfigFileEnabled"] = "cli_config_file_enabled";
})(FeatureFlag = exports.FeatureFlag || (exports.FeatureFlag = {}));
exports.featureFlagConfig = {
[FeatureFlag.BypassToolcacheEnabled]: {
envVar: "CODEQL_BYPASS_TOOLCACHE",
minimumVersion: undefined,
},
[FeatureFlag.MlPoweredQueriesEnabled]: {
envVar: "CODEQL_VERSION_ML_POWERED_QUERIES",
minimumVersion: "2.7.5",
},
[FeatureFlag.TrapCachingEnabled]: {
envVar: "CODEQL_TRAP_CACHING",
minimumVersion: undefined,
},
[FeatureFlag.GolangExtractionReconciliationEnabled]: {
envVar: "CODEQL_GOLANG_EXTRACTION_RECONCILIATION",
minimumVersion: undefined,
},
[FeatureFlag.CliConfigFileEnabled]: {
envVar: "CODEQL_PASS_CONFIG_TO_CLI",
minimumVersion: "2.10.1",
},
};
class GitHubFeatureFlags {
constructor(gitHubVersion, apiDetails, repositoryNwo, logger) {
this.gitHubVersion = gitHubVersion;
@@ -37,11 +59,28 @@ class GitHubFeatureFlags {
this.repositoryNwo = repositoryNwo;
this.logger = logger;
}
async getValue(flag) {
async getValue(flag, codeql) {
// Bypassing the toolcache is disabled in test mode.
if (flag === FeatureFlag.BypassToolcacheEnabled && util.isInTestMode()) {
return false;
}
const envVar = (process.env[exports.featureFlagConfig[flag].envVar] || "").toLocaleLowerCase();
// Do not use this feature if user explicitly disables it via an environment variable.
if (envVar === "false") {
return false;
}
// Never use this feature if the CLI version explicitly can't support it.
const minimumVersion = exports.featureFlagConfig[flag].minimumVersion;
if (codeql && minimumVersion) {
if (!(await util.codeQlVersionAbove(codeql, minimumVersion))) {
return false;
}
}
// Use this feature if user explicitly enables it via an environment variable.
if (envVar === "true") {
return true;
}
// Ask the GitHub API if the feature is enabled.
const response = await this.getApiResponse();
if (response === undefined) {
this.logger.debug(`No feature flags API response for ${flag}, considering it disabled.`);