mirror of
https://github.com/github/codeql-action.git
synced 2026-04-28 18:08:53 +00:00
Add OfflineFeatures class
This commit is contained in:
+101
-35
@@ -354,33 +354,15 @@ type GitHubFeatureFlagsApiResponse = Partial<Record<Feature, boolean>>;
|
||||
export const FEATURE_FLAGS_FILE_NAME = "cached-feature-flags.json";
|
||||
|
||||
/**
|
||||
* Determines the enablement status of a number of features.
|
||||
* If feature enablement is not able to be determined locally, a request to the
|
||||
* GitHub API is made to determine the enablement status.
|
||||
* Determines the enablement status of a number of features locally without
|
||||
* consulting the GitHub API.
|
||||
*/
|
||||
export class Features implements FeatureEnablement {
|
||||
private gitHubFeatureFlags: GitHubFeatureFlags;
|
||||
|
||||
constructor(
|
||||
gitHubVersion: util.GitHubVersion,
|
||||
repositoryNwo: RepositoryNwo,
|
||||
tempDir: string,
|
||||
private readonly logger: Logger,
|
||||
) {
|
||||
this.gitHubFeatureFlags = new GitHubFeatureFlags(
|
||||
gitHubVersion,
|
||||
repositoryNwo,
|
||||
path.join(tempDir, FEATURE_FLAGS_FILE_NAME),
|
||||
logger,
|
||||
);
|
||||
}
|
||||
export class OfflineFeatures implements FeatureEnablement {
|
||||
constructor(protected readonly logger: Logger) {}
|
||||
|
||||
async getDefaultCliVersion(
|
||||
variant: util.GitHubVariant,
|
||||
_variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
if (supportsFeatureFlags(variant)) {
|
||||
return await this.gitHubFeatureFlags.getDefaultCliVersionFromFlags();
|
||||
}
|
||||
return {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
@@ -388,6 +370,16 @@ export class Features implements FeatureEnablement {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `FeatureConfig` for `feature`.
|
||||
*/
|
||||
getFeatureConfig(feature: Feature): FeatureConfig {
|
||||
// Narrow the type to FeatureConfig to avoid type errors. To avoid unsafe use of `as`, we
|
||||
// check that the required properties exist using `satisfies`.
|
||||
return featureConfig[feature] satisfies FeatureConfig as FeatureConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether `feature` is enabled without consulting the GitHub API.
|
||||
*
|
||||
* @param feature The feature to check.
|
||||
* @param codeql An optional CodeQL object. If provided, and a `minimumVersion` is specified for the
|
||||
@@ -400,11 +392,22 @@ export class Features implements FeatureEnablement {
|
||||
* @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided.
|
||||
*/
|
||||
async getValue(feature: Feature, codeql?: CodeQL): Promise<boolean> {
|
||||
// Narrow the type to FeatureConfig to avoid type errors. To avoid unsafe use of `as`, we
|
||||
// check that the required properties exist using `satisfies`.
|
||||
const config = featureConfig[
|
||||
feature
|
||||
] satisfies FeatureConfig as FeatureConfig;
|
||||
const offlineValue = await this.getOfflineValue(feature, codeql);
|
||||
if (offlineValue !== undefined) {
|
||||
return offlineValue;
|
||||
}
|
||||
|
||||
return this.getDefaultValue(feature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether `feature` is enabled using the CLI and environment variables.
|
||||
*/
|
||||
protected async getOfflineValue(
|
||||
feature: Feature,
|
||||
codeql?: CodeQL,
|
||||
): Promise<boolean | undefined> {
|
||||
const config = this.getFeatureConfig(feature);
|
||||
|
||||
if (!codeql && config.minimumVersion) {
|
||||
throw new Error(
|
||||
@@ -470,6 +473,74 @@ export class Features implements FeatureEnablement {
|
||||
return true;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Gets the default value of `feature`. */
|
||||
protected async getDefaultValue(feature: Feature): Promise<boolean> {
|
||||
const config = this.getFeatureConfig(feature);
|
||||
const defaultValue = config.defaultValue;
|
||||
this.logger.debug(
|
||||
`Feature ${feature} is ${
|
||||
defaultValue ? "enabled" : "disabled"
|
||||
} due to its default value.`,
|
||||
);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the enablement status of a number of features.
|
||||
* If feature enablement is not able to be determined locally, a request to the
|
||||
* GitHub API is made to determine the enablement status.
|
||||
*/
|
||||
export class Features extends OfflineFeatures {
|
||||
private gitHubFeatureFlags: GitHubFeatureFlags;
|
||||
|
||||
constructor(
|
||||
gitHubVersion: util.GitHubVersion,
|
||||
repositoryNwo: RepositoryNwo,
|
||||
tempDir: string,
|
||||
logger: Logger,
|
||||
) {
|
||||
super(logger);
|
||||
|
||||
this.gitHubFeatureFlags = new GitHubFeatureFlags(
|
||||
gitHubVersion,
|
||||
repositoryNwo,
|
||||
path.join(tempDir, FEATURE_FLAGS_FILE_NAME),
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
async getDefaultCliVersion(
|
||||
variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
if (supportsFeatureFlags(variant)) {
|
||||
return await this.gitHubFeatureFlags.getDefaultCliVersionFromFlags();
|
||||
}
|
||||
return super.getDefaultCliVersion(variant);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param feature The feature to check.
|
||||
* @param codeql An optional CodeQL object. If provided, and a `minimumVersion` is specified for the
|
||||
* feature, the version of the CodeQL CLI will be checked against the minimum version.
|
||||
* If the version is less than the minimum version, the feature will be considered
|
||||
* disabled. If not provided, and a `minimumVersion` is specified for the feature, the
|
||||
* this function will throw.
|
||||
* @returns true if the feature is enabled, false otherwise.
|
||||
*
|
||||
* @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided.
|
||||
*/
|
||||
async getValue(feature: Feature, codeql?: CodeQL): Promise<boolean> {
|
||||
// Check whether the feature is enabled locally.
|
||||
const offlineValue = await this.getOfflineValue(feature, codeql);
|
||||
if (offlineValue !== undefined) {
|
||||
return offlineValue;
|
||||
}
|
||||
|
||||
// Ask the GitHub API if the feature is enabled.
|
||||
const apiValue = await this.gitHubFeatureFlags.getValue(feature);
|
||||
if (apiValue !== undefined) {
|
||||
@@ -481,13 +552,8 @@ export class Features implements FeatureEnablement {
|
||||
return apiValue;
|
||||
}
|
||||
|
||||
const defaultValue = config.defaultValue;
|
||||
this.logger.debug(
|
||||
`Feature ${feature} is ${
|
||||
defaultValue ? "enabled" : "disabled"
|
||||
} due to its default value.`,
|
||||
);
|
||||
return defaultValue;
|
||||
// Return the default value.
|
||||
return this.getDefaultValue(feature);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user