diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 0ab72d31c2..3ca7093265 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -90761,6 +90761,12 @@ var Features = class { ); } gitHubFeatureFlags; + // Tracks features that have been queried at some point and the outcome. + queriedFeatures = {}; + /** Gets a record of features that were queried and the corresponding outcomes. */ + getQueriedFeatures() { + return this.queriedFeatures; + } async getDefaultCliVersion(variant) { return await this.gitHubFeatureFlags.getDefaultCliVersion(variant); } @@ -90777,6 +90783,11 @@ var Features = class { * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. */ async getValue(feature, codeql) { + const value = await this.getValueInternal(feature, codeql); + this.queriedFeatures[feature] = { value }; + return value; + } + async getValueInternal(feature, codeql) { const config = featureConfig[feature]; if (!codeql && config.minimumVersion) { throw new Error( @@ -93713,7 +93724,7 @@ function setJobStatusIfUnsuccessful(actionStatus) { ); } } -async function createStatusReportBase(actionName, status, actionStartedAt, config, diskInfo, logger, cause, exception2) { +async function createStatusReportBase(actionName, status, actionStartedAt, config, queriedFeatures, diskInfo, logger, cause, exception2) { try { const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || ""; const ref = await getRef(); @@ -93736,6 +93747,12 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi core12.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment); } const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags = void 0; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }) + ); + } const statusReport = { action_name: actionName, action_oid: "unknown", @@ -93747,6 +93764,7 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -93873,6 +93891,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error "failure", actionStartedAt, void 0, + {}, void 0, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error3)}`, @@ -95721,13 +95740,14 @@ async function postProcessAndUploadSarif(logger, features, uploadKind, checkoutP } // src/analyze-action.ts -async function sendStatusReport2(startedAt2, config, stats, error3, trapCacheUploadTime, dbCreationTimings, didUploadTrapCaches, trapCacheCleanup, dependencyCacheResults, databaseUploadResults, logger) { +async function sendStatusReport2(startedAt2, config, features, stats, error3, trapCacheUploadTime, dbCreationTimings, didUploadTrapCaches, trapCacheCleanup, dependencyCacheResults, databaseUploadResults, logger) { const status = getActionsStatus(error3, stats?.analyze_failure_language); const statusReportBase = await createStatusReportBase( "finish" /* Analyze */, status, startedAt2, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error3?.message, @@ -95816,6 +95836,7 @@ async function run(startedAt2) { let uploadResults = void 0; let runStats = void 0; let config = void 0; + let features = void 0; let trapCacheCleanupTelemetry = void 0; let trapCacheUploadTime = void 0; let dbCreationTimings = void 0; @@ -95831,6 +95852,7 @@ async function run(startedAt2) { "starting", startedAt2, config, + void 0, await checkDiskUsage(logger), logger ); @@ -95869,7 +95891,7 @@ async function run(startedAt2) { const repositoryNwo = getRepositoryNwo(); const gitHubVersion = await getGitHubVersion(); checkActionVersion(getActionVersion(), gitHubVersion); - const features = new Features( + features = new Features( gitHubVersion, repositoryNwo, getTemporaryDirectory(), @@ -95998,6 +96020,7 @@ async function run(startedAt2) { await sendStatusReport2( startedAt2, config, + features, error3 instanceof CodeQLAnalysisError ? error3.queriesStatusReport : void 0, error3 instanceof CodeQLAnalysisError ? error3.error : error3, trapCacheUploadTime, @@ -96014,6 +96037,7 @@ async function run(startedAt2) { await sendStatusReport2( startedAt2, config, + features, { ...runStats, ...uploadResults["code-scanning" /* CodeScanning */].statusReport @@ -96031,6 +96055,7 @@ async function run(startedAt2) { await sendStatusReport2( startedAt2, config, + features, { ...runStats }, void 0, trapCacheUploadTime, @@ -96045,6 +96070,7 @@ async function run(startedAt2) { await sendStatusReport2( startedAt2, config, + features, void 0, void 0, trapCacheUploadTime, diff --git a/lib/autobuild-action.js b/lib/autobuild-action.js index 0a73443cb4..01e054ed51 100644 --- a/lib/autobuild-action.js +++ b/lib/autobuild-action.js @@ -87094,6 +87094,12 @@ var Features = class { ); } gitHubFeatureFlags; + // Tracks features that have been queried at some point and the outcome. + queriedFeatures = {}; + /** Gets a record of features that were queried and the corresponding outcomes. */ + getQueriedFeatures() { + return this.queriedFeatures; + } async getDefaultCliVersion(variant) { return await this.gitHubFeatureFlags.getDefaultCliVersion(variant); } @@ -87110,6 +87116,11 @@ var Features = class { * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. */ async getValue(feature, codeql) { + const value = await this.getValueInternal(feature, codeql); + this.queriedFeatures[feature] = { value }; + return value; + } + async getValueInternal(feature, codeql) { const config = featureConfig[feature]; if (!codeql && config.minimumVersion) { throw new Error( @@ -88178,7 +88189,7 @@ function setJobStatusIfUnsuccessful(actionStatus) { ); } } -async function createStatusReportBase(actionName, status, actionStartedAt, config, diskInfo, logger, cause, exception2) { +async function createStatusReportBase(actionName, status, actionStartedAt, config, queriedFeatures, diskInfo, logger, cause, exception2) { try { const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || ""; const ref = await getRef(); @@ -88201,6 +88212,12 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi core12.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment); } const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags = void 0; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }) + ); + } const statusReport = { action_name: actionName, action_oid: "unknown", @@ -88212,6 +88229,7 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -88338,6 +88356,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error "failure", actionStartedAt, void 0, + {}, void 0, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error3)}`, @@ -88365,6 +88384,7 @@ async function sendCompletedStatusReport(config, logger, startedAt, allLanguages status, startedAt, config, + void 0, await checkDiskUsage(logger), logger, cause?.message, @@ -88390,6 +88410,7 @@ async function run(startedAt) { "starting", startedAt, config, + void 0, await checkDiskUsage(logger), logger ); diff --git a/lib/init-action-post.js b/lib/init-action-post.js index 97748d3946..b6b827301e 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -131403,6 +131403,12 @@ var Features = class { ); } gitHubFeatureFlags; + // Tracks features that have been queried at some point and the outcome. + queriedFeatures = {}; + /** Gets a record of features that were queried and the corresponding outcomes. */ + getQueriedFeatures() { + return this.queriedFeatures; + } async getDefaultCliVersion(variant) { return await this.gitHubFeatureFlags.getDefaultCliVersion(variant); } @@ -131419,6 +131425,11 @@ var Features = class { * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. */ async getValue(feature, codeql) { + const value = await this.getValueInternal(feature, codeql); + this.queriedFeatures[feature] = { value }; + return value; + } + async getValueInternal(feature, codeql) { const config = featureConfig[feature]; if (!codeql && config.minimumVersion) { throw new Error( @@ -135974,7 +135985,7 @@ function setJobStatusIfUnsuccessful(actionStatus) { ); } } -async function createStatusReportBase(actionName, status, actionStartedAt, config, diskInfo, logger, cause, exception2) { +async function createStatusReportBase(actionName, status, actionStartedAt, config, queriedFeatures, diskInfo, logger, cause, exception2) { try { const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || ""; const ref = await getRef(); @@ -135997,6 +136008,12 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi core15.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment); } const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags = void 0; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }) + ); + } const statusReport = { action_name: actionName, action_oid: "unknown", @@ -136008,6 +136025,7 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -136134,6 +136152,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error "failure", actionStartedAt, void 0, + {}, void 0, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error3)}`, @@ -136156,6 +136175,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error async function run2(startedAt) { const logger = getActionsLogger(); let config; + let features = void 0; let uploadFailedSarifResult; let dependencyCachingUsage; try { @@ -136163,7 +136183,7 @@ async function run2(startedAt) { const gitHubVersion = await getGitHubVersion(); checkGitHubVersionInRange(gitHubVersion, logger); const repositoryNwo = getRepositoryNwo(); - const features = new Features( + features = new Features( gitHubVersion, repositoryNwo, getTemporaryDirectory(), @@ -136197,6 +136217,7 @@ async function run2(startedAt) { getActionsStatus(error3), startedAt, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error3.message, @@ -136214,6 +136235,7 @@ async function run2(startedAt) { "success", startedAt, config, + features.getQueriedFeatures(), await checkDiskUsage(logger), logger ); diff --git a/lib/init-action.js b/lib/init-action.js index ee50500d73..e2531c3f9c 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -88252,6 +88252,12 @@ var Features = class { ); } gitHubFeatureFlags; + // Tracks features that have been queried at some point and the outcome. + queriedFeatures = {}; + /** Gets a record of features that were queried and the corresponding outcomes. */ + getQueriedFeatures() { + return this.queriedFeatures; + } async getDefaultCliVersion(variant) { return await this.gitHubFeatureFlags.getDefaultCliVersion(variant); } @@ -88268,6 +88274,11 @@ var Features = class { * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. */ async getValue(feature, codeql) { + const value = await this.getValueInternal(feature, codeql); + this.queriedFeatures[feature] = { value }; + return value; + } + async getValueInternal(feature, codeql) { const config = featureConfig[feature]; if (!codeql && config.minimumVersion) { throw new Error( @@ -91509,7 +91520,7 @@ function setJobStatusIfUnsuccessful(actionStatus) { ); } } -async function createStatusReportBase(actionName, status, actionStartedAt, config, diskInfo, logger, cause, exception2) { +async function createStatusReportBase(actionName, status, actionStartedAt, config, queriedFeatures, diskInfo, logger, cause, exception2) { try { const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || ""; const ref = await getRef(); @@ -91532,6 +91543,12 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi core11.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment); } const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags = void 0; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }) + ); + } const statusReport = { action_name: actionName, action_oid: "unknown", @@ -91543,6 +91560,7 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -91715,6 +91733,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error "failure", actionStartedAt, void 0, + {}, void 0, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error3)}`, @@ -91927,12 +91946,13 @@ var internal2 = { // src/init-action.ts var CODEQL_VERSION_JAR_MINIMIZATION = "2.23.0"; -async function sendStartingStatusReport(startedAt, config, logger) { +async function sendStartingStatusReport(startedAt, config, features, logger) { const statusReportBase = await createStatusReportBase( "init" /* Init */, "starting", startedAt, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger ); @@ -91940,12 +91960,13 @@ async function sendStartingStatusReport(startedAt, config, logger) { await sendStatusReport(statusReportBase); } } -async function sendCompletedStatusReport(startedAt, config, configFile, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, overlayBaseDatabaseStats, dependencyCachingResults, logger, error3) { +async function sendCompletedStatusReport(startedAt, config, features, configFile, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, overlayBaseDatabaseStats, dependencyCachingResults, logger, error3) { const statusReportBase = await createStatusReportBase( "init" /* Init */, getActionsStatus(error3), startedAt, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error3?.message, @@ -91994,7 +92015,7 @@ async function run(startedAt) { let config; let configFile; let codeql; - let features; + let features = void 0; let sourceRoot; let toolsDownloadStatusReport; let toolsFeatureFlagsValid; @@ -92041,7 +92062,12 @@ async function run(startedAt) { `Failed to parse analysis kinds for 'starting' status report: ${getErrorMessage(err)}` ); } - await sendStartingStatusReport(startedAt, { analysisKinds }, logger); + await sendStartingStatusReport( + startedAt, + { analysisKinds }, + features, + logger + ); if (process.env["CODEQL_ACTION_SETUP_CODEQL_HAS_RUN" /* SETUP_CODEQL_ACTION_HAS_RUN */] === "true") { throw new ConfigurationError( `The 'init' action should not be run in the same workflow as 'setup-codeql'.` @@ -92130,6 +92156,7 @@ async function run(startedAt) { error3 instanceof ConfigurationError ? "user-error" : "aborted", startedAt, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error3.message, @@ -92377,6 +92404,7 @@ exec ${goBinaryPath} "$@"` await sendCompletedStatusReport( startedAt, config, + features, void 0, // We only report config info on success. toolsDownloadStatusReport, @@ -92395,6 +92423,7 @@ exec ${goBinaryPath} "$@"` await sendCompletedStatusReport( startedAt, config, + features, configFile, toolsDownloadStatusReport, toolsFeatureFlagsValid, diff --git a/lib/resolve-environment-action.js b/lib/resolve-environment-action.js index cc6aa521cd..2b13dfaab0 100644 --- a/lib/resolve-environment-action.js +++ b/lib/resolve-environment-action.js @@ -87793,7 +87793,7 @@ function setJobStatusIfUnsuccessful(actionStatus) { ); } } -async function createStatusReportBase(actionName, status, actionStartedAt, config, diskInfo, logger, cause, exception2) { +async function createStatusReportBase(actionName, status, actionStartedAt, config, queriedFeatures, diskInfo, logger, cause, exception2) { try { const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || ""; const ref = await getRef(); @@ -87816,6 +87816,12 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi core11.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment); } const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags = void 0; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }) + ); + } const statusReport = { action_name: actionName, action_oid: "unknown", @@ -87827,6 +87833,7 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -87953,6 +87960,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error "failure", actionStartedAt, void 0, + {}, void 0, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error3)}`, @@ -87982,6 +87990,7 @@ async function run(startedAt) { "starting", startedAt, config, + void 0, await checkDiskUsage(logger), logger ); @@ -88021,6 +88030,7 @@ async function run(startedAt) { getActionsStatus(error3), startedAt, config, + void 0, await checkDiskUsage(logger), logger, error3.message, @@ -88037,6 +88047,7 @@ async function run(startedAt) { "success", startedAt, config, + void 0, await checkDiskUsage(logger), logger ); diff --git a/lib/setup-codeql-action.js b/lib/setup-codeql-action.js index 7182336aee..134e1dd43f 100644 --- a/lib/setup-codeql-action.js +++ b/lib/setup-codeql-action.js @@ -86995,6 +86995,12 @@ var Features = class { ); } gitHubFeatureFlags; + // Tracks features that have been queried at some point and the outcome. + queriedFeatures = {}; + /** Gets a record of features that were queried and the corresponding outcomes. */ + getQueriedFeatures() { + return this.queriedFeatures; + } async getDefaultCliVersion(variant) { return await this.gitHubFeatureFlags.getDefaultCliVersion(variant); } @@ -87011,6 +87017,11 @@ var Features = class { * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. */ async getValue(feature, codeql) { + const value = await this.getValueInternal(feature, codeql); + this.queriedFeatures[feature] = { value }; + return value; + } + async getValueInternal(feature, codeql) { const config = featureConfig[feature]; if (!codeql && config.minimumVersion) { throw new Error( @@ -89125,7 +89136,7 @@ function setJobStatusIfUnsuccessful(actionStatus) { ); } } -async function createStatusReportBase(actionName, status, actionStartedAt, config, diskInfo, logger, cause, exception2) { +async function createStatusReportBase(actionName, status, actionStartedAt, config, queriedFeatures, diskInfo, logger, cause, exception2) { try { const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || ""; const ref = await getRef(); @@ -89148,6 +89159,12 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi core11.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment); } const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags = void 0; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }) + ); + } const statusReport = { action_name: actionName, action_oid: "unknown", @@ -89159,6 +89176,7 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -89285,6 +89303,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error "failure", actionStartedAt, void 0, + {}, void 0, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error3)}`, @@ -89304,12 +89323,13 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error } // src/setup-codeql-action.ts -async function sendCompletedStatusReport(startedAt, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, logger, error3) { +async function sendCompletedStatusReport(startedAt, features, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, logger, error3) { const statusReportBase = await createStatusReportBase( "setup-codeql" /* SetupCodeQL */, getActionsStatus(error3), startedAt, void 0, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error3?.message, @@ -89341,6 +89361,7 @@ async function run(startedAt) { let toolsFeatureFlagsValid; let toolsSource; let toolsVersion; + let features = void 0; try { initializeEnvironment(getActionVersion()); const apiDetails = { @@ -89353,7 +89374,7 @@ async function run(startedAt) { checkGitHubVersionInRange(gitHubVersion, logger); checkActionVersion(getActionVersion(), gitHubVersion); const repositoryNwo = getRepositoryNwo(); - const features = new Features( + features = new Features( gitHubVersion, repositoryNwo, getTemporaryDirectory(), @@ -89367,6 +89388,7 @@ async function run(startedAt) { "starting", startedAt, void 0, + features.getQueriedFeatures(), await checkDiskUsage(logger), logger ); @@ -89401,6 +89423,7 @@ async function run(startedAt) { error3 instanceof ConfigurationError ? "user-error" : "failure", startedAt, void 0, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error3.message, @@ -89413,6 +89436,7 @@ async function run(startedAt) { } await sendCompletedStatusReport( startedAt, + features, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, diff --git a/lib/start-proxy-action.js b/lib/start-proxy-action.js index ea6f8c96c9..16ba6e21e4 100644 --- a/lib/start-proxy-action.js +++ b/lib/start-proxy-action.js @@ -104012,7 +104012,7 @@ function setJobStatusIfUnsuccessful(actionStatus) { ); } } -async function createStatusReportBase(actionName, status, actionStartedAt, config, diskInfo, logger, cause, exception2) { +async function createStatusReportBase(actionName, status, actionStartedAt, config, queriedFeatures, diskInfo, logger, cause, exception2) { try { const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || ""; const ref = await getRef(); @@ -104035,6 +104035,12 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi core10.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment); } const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags = void 0; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }) + ); + } const statusReport = { action_name: actionName, action_oid: "unknown", @@ -104046,6 +104052,7 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -104172,6 +104179,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error "failure", actionStartedAt, void 0, + {}, void 0, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error3)}`, @@ -104243,6 +104251,7 @@ async function sendSuccessStatusReport(startedAt, config, registry_types, logger "success", startedAt, config, + void 0, await checkDiskUsage(logger), logger ); @@ -104303,6 +104312,7 @@ async function run(startedAt) { { languages: language && [language] }, + void 0, await checkDiskUsage(logger), logger, "Error from start-proxy Action omitted" diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 4b775f252e..bdc0125159 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -89949,6 +89949,12 @@ var Features = class { ); } gitHubFeatureFlags; + // Tracks features that have been queried at some point and the outcome. + queriedFeatures = {}; + /** Gets a record of features that were queried and the corresponding outcomes. */ + getQueriedFeatures() { + return this.queriedFeatures; + } async getDefaultCliVersion(variant) { return await this.gitHubFeatureFlags.getDefaultCliVersion(variant); } @@ -89965,6 +89971,11 @@ var Features = class { * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. */ async getValue(feature, codeql) { + const value = await this.getValueInternal(feature, codeql); + this.queriedFeatures[feature] = { value }; + return value; + } + async getValueInternal(feature, codeql) { const config = featureConfig[feature]; if (!codeql && config.minimumVersion) { throw new Error( @@ -90356,7 +90367,7 @@ function setJobStatusIfUnsuccessful(actionStatus) { ); } } -async function createStatusReportBase(actionName, status, actionStartedAt, config, diskInfo, logger, cause, exception2) { +async function createStatusReportBase(actionName, status, actionStartedAt, config, queriedFeatures, diskInfo, logger, cause, exception2) { try { const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || ""; const ref = await getRef(); @@ -90379,6 +90390,12 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi core9.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment); } const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags = void 0; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }) + ); + } const statusReport = { action_name: actionName, action_oid: "unknown", @@ -90390,6 +90407,7 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -90516,6 +90534,7 @@ async function sendUnhandledErrorStatusReport(actionName, actionStartedAt, error "failure", actionStartedAt, void 0, + {}, void 0, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error3)}`, @@ -94158,12 +94177,13 @@ async function postProcessAndUploadSarif(logger, features, uploadKind, checkoutP } // src/upload-sarif-action.ts -async function sendSuccessStatusReport(startedAt, uploadStats, logger) { +async function sendSuccessStatusReport(startedAt, features, uploadStats, logger) { const statusReportBase = await createStatusReportBase( "upload-sarif" /* UploadSarif */, "success", startedAt, void 0, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger ); @@ -94177,13 +94197,14 @@ async function sendSuccessStatusReport(startedAt, uploadStats, logger) { } async function run(startedAt) { const logger = getActionsLogger(); + let features = void 0; try { initializeEnvironment(getActionVersion()); const gitHubVersion = await getGitHubVersion(); checkActionVersion(getActionVersion(), gitHubVersion); persistInputs(); const repositoryNwo = getRepositoryNwo(); - const features = new Features( + features = new Features( gitHubVersion, repositoryNwo, getTemporaryDirectory(), @@ -94194,6 +94215,7 @@ async function run(startedAt) { "starting", startedAt, void 0, + features.getQueriedFeatures(), await checkDiskUsage(logger), logger ); @@ -94236,6 +94258,7 @@ async function run(startedAt) { } await sendSuccessStatusReport( startedAt, + features, codeScanningResult?.statusReport || {}, logger ); @@ -94248,6 +94271,7 @@ async function run(startedAt) { getActionsStatus(error3), startedAt, void 0, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, message, diff --git a/src/analyze-action.ts b/src/analyze-action.ts index 3cc1ad019a..52257574b3 100644 --- a/src/analyze-action.ts +++ b/src/analyze-action.ts @@ -76,6 +76,7 @@ interface FinishWithTrapUploadStatusReport extends FinishStatusReport { async function sendStatusReport( startedAt: Date, config: Config | undefined, + features: Features | undefined, stats: AnalysisStatusReport | undefined, error: Error | undefined, trapCacheUploadTime: number | undefined, @@ -92,6 +93,7 @@ async function sendStatusReport( status, startedAt, config, + features?.getQueriedFeatures(), await util.checkDiskUsage(logger), logger, error?.message, @@ -218,6 +220,7 @@ async function run(startedAt: Date) { | undefined = undefined; let runStats: QueriesStatusReport | undefined = undefined; let config: Config | undefined = undefined; + let features: Features | undefined = undefined; let trapCacheCleanupTelemetry: TrapCacheCleanupStatusReport | undefined = undefined; let trapCacheUploadTime: number | undefined = undefined; @@ -239,6 +242,7 @@ async function run(startedAt: Date) { "starting", startedAt, config, + undefined, await util.checkDiskUsage(logger), logger, ); @@ -293,7 +297,7 @@ async function run(startedAt: Date) { util.checkActionVersion(actionsUtil.getActionVersion(), gitHubVersion); - const features = new Features( + features = new Features( gitHubVersion, repositoryNwo, actionsUtil.getTemporaryDirectory(), @@ -460,6 +464,7 @@ async function run(startedAt: Date) { await sendStatusReport( startedAt, config, + features, error instanceof CodeQLAnalysisError ? error.queriesStatusReport : undefined, @@ -482,6 +487,7 @@ async function run(startedAt: Date) { await sendStatusReport( startedAt, config, + features, { ...runStats, ...uploadResults[analyses.AnalysisKind.CodeScanning].statusReport, @@ -499,6 +505,7 @@ async function run(startedAt: Date) { await sendStatusReport( startedAt, config, + features, { ...runStats }, undefined, trapCacheUploadTime, @@ -513,6 +520,7 @@ async function run(startedAt: Date) { await sendStatusReport( startedAt, config, + features, undefined, undefined, trapCacheUploadTime, diff --git a/src/autobuild-action.ts b/src/autobuild-action.ts index a1465f1103..c12d528d1a 100644 --- a/src/autobuild-action.ts +++ b/src/autobuild-action.ts @@ -54,6 +54,7 @@ async function sendCompletedStatusReport( status, startedAt, config, + undefined, await checkDiskUsage(logger), logger, cause?.message, @@ -83,6 +84,7 @@ async function run(startedAt: Date) { "starting", startedAt, config, + undefined, await checkDiskUsage(logger), logger, ); diff --git a/src/feature-flags.test.ts b/src/feature-flags.test.ts index cdab85e279..62760b3162 100644 --- a/src/feature-flags.test.ts +++ b/src/feature-flags.test.ts @@ -92,6 +92,31 @@ test(`Feature flags are requested in GHEC-DR`, async (t) => { }); }); +test("Queried feature flags are recorded", async (t) => { + await withTmpDir(async (tmpDir) => { + const loggedMessages = []; + const features = setUpFeatureFlagTests( + tmpDir, + getRecordingLogger(loggedMessages), + { type: GitHubVariant.DOTCOM }, + ); + + mockFeatureFlagApiEndpoint(200, initializeFeatures(true)); + + // No features should have been queried initially. + t.is(Object.keys(features.getQueriedFeatures()).length, 0); + + // Query all features. + const allFeatures = Object.values(Feature); + for (const feature of allFeatures) { + await getFeatureIncludingCodeQlIfRequired(features, feature); + } + + // All features should have a been queried. + t.is(Object.keys(features.getQueriedFeatures()).length, allFeatures.length); + }); +}); + test("API response missing and features use default value", async (t) => { await withTmpDir(async (tmpDir) => { const loggedMessages: LoggedMessage[] = []; @@ -562,7 +587,7 @@ function setUpFeatureFlagTests( tmpDir: string, logger = getRunnerLogger(true), gitHubVersion = { type: GitHubVariant.DOTCOM } as util.GitHubVersion, -): FeatureEnablement { +): Features { setupActionsVars(tmpDir, tmpDir); return new Features(gitHubVersion, testRepositoryNwo, tmpDir, logger); diff --git a/src/feature-flags.ts b/src/feature-flags.ts index 8de68a28d7..c9f9dcb8f9 100644 --- a/src/feature-flags.ts +++ b/src/feature-flags.ts @@ -345,6 +345,17 @@ export interface FeatureEnablement { */ type GitHubFeatureFlagsApiResponse = Partial>; +// Even though we are currently only tracking the value of queried features, we use an object +// here rather than just a boolean to keep open the possibility of also tracking the reason +// for why a particular value was resolved (i.e. because of an environment variable or API result) +// in the future. +export interface QueriedFeatureStatus { + value: boolean; +} + +/** A partial mapping of feature flags to the outcome of querying them. */ +export type QueriedFeatures = Partial>; + export const FEATURE_FLAGS_FILE_NAME = "cached-feature-flags.json"; /** @@ -355,6 +366,9 @@ export const FEATURE_FLAGS_FILE_NAME = "cached-feature-flags.json"; export class Features implements FeatureEnablement { private gitHubFeatureFlags: GitHubFeatureFlags; + // Tracks features that have been queried at some point and the outcome. + private queriedFeatures: QueriedFeatures = {}; + constructor( gitHubVersion: util.GitHubVersion, repositoryNwo: RepositoryNwo, @@ -369,6 +383,11 @@ export class Features implements FeatureEnablement { ); } + /** Gets a record of features that were queried and the corresponding outcomes. */ + public getQueriedFeatures() { + return this.queriedFeatures; + } + async getDefaultCliVersion( variant: util.GitHubVariant, ): Promise { @@ -388,6 +407,15 @@ 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 { + const value = await this.getValueInternal(feature, codeql); + this.queriedFeatures[feature] = { value }; + return value; + } + + private async getValueInternal( + feature: Feature, + codeql?: CodeQL, + ): Promise { // 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[ diff --git a/src/init-action-post.ts b/src/init-action-post.ts index cfae096938..5016bb53c4 100644 --- a/src/init-action-post.ts +++ b/src/init-action-post.ts @@ -50,6 +50,7 @@ async function run(startedAt: Date) { const logger = getActionsLogger(); let config: Config | undefined; + let features: Features | undefined = undefined; let uploadFailedSarifResult: | initActionPostHelper.UploadFailedSarifResult | undefined; @@ -62,7 +63,7 @@ async function run(startedAt: Date) { checkGitHubVersionInRange(gitHubVersion, logger); const repositoryNwo = getRepositoryNwo(); - const features = new Features( + features = new Features( gitHubVersion, repositoryNwo, getTemporaryDirectory(), @@ -107,6 +108,7 @@ async function run(startedAt: Date) { getActionsStatus(error), startedAt, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error.message, @@ -125,6 +127,7 @@ async function run(startedAt: Date) { "success", startedAt, config, + features.getQueriedFeatures(), await checkDiskUsage(logger), logger, ); diff --git a/src/init-action.ts b/src/init-action.ts index 0d92f46ef9..20a2734c12 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -108,6 +108,7 @@ export const CODEQL_VERSION_JAR_MINIMIZATION = "2.23.0"; async function sendStartingStatusReport( startedAt: Date, config: Partial | undefined, + features: Features | undefined, logger: Logger, ) { const statusReportBase = await createStatusReportBase( @@ -115,6 +116,7 @@ async function sendStartingStatusReport( "starting", startedAt, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, ); @@ -126,6 +128,7 @@ async function sendStartingStatusReport( async function sendCompletedStatusReport( startedAt: Date, config: configUtils.Config | undefined, + features: Features | undefined, configFile: string | undefined, toolsDownloadStatusReport: ToolsDownloadStatusReport | undefined, toolsFeatureFlagsValid: boolean | undefined, @@ -141,6 +144,7 @@ async function sendCompletedStatusReport( getActionsStatus(error), startedAt, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error?.message, @@ -203,7 +207,7 @@ async function run(startedAt: Date) { let config: configUtils.Config | undefined; let configFile: string | undefined; let codeql: CodeQL; - let features: Features; + let features: Features | undefined = undefined; let sourceRoot: string; let toolsDownloadStatusReport: ToolsDownloadStatusReport | undefined; let toolsFeatureFlagsValid: boolean | undefined; @@ -277,7 +281,12 @@ async function run(startedAt: Date) { } // Send a status report indicating that an analysis is starting. - await sendStartingStatusReport(startedAt, { analysisKinds }, logger); + await sendStartingStatusReport( + startedAt, + { analysisKinds }, + features, + logger, + ); // Throw a `ConfigurationError` if the `setup-codeql` action has been run. if (process.env[EnvVar.SETUP_CODEQL_ACTION_HAS_RUN] === "true") { @@ -383,6 +392,7 @@ async function run(startedAt: Date) { error instanceof ConfigurationError ? "user-error" : "aborted", startedAt, config, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error.message, @@ -754,6 +764,7 @@ async function run(startedAt: Date) { await sendCompletedStatusReport( startedAt, config, + features, undefined, // We only report config info on success. toolsDownloadStatusReport, toolsFeatureFlagsValid, @@ -771,6 +782,7 @@ async function run(startedAt: Date) { await sendCompletedStatusReport( startedAt, config, + features, configFile, toolsDownloadStatusReport, toolsFeatureFlagsValid, diff --git a/src/resolve-environment-action.ts b/src/resolve-environment-action.ts index 253a342d7f..b948f49f07 100644 --- a/src/resolve-environment-action.ts +++ b/src/resolve-environment-action.ts @@ -44,6 +44,7 @@ async function run(startedAt: Date) { "starting", startedAt, config, + undefined, await checkDiskUsage(logger), logger, ); @@ -91,6 +92,7 @@ async function run(startedAt: Date) { getActionsStatus(error), startedAt, config, + undefined, await checkDiskUsage(logger), logger, error.message, @@ -109,6 +111,7 @@ async function run(startedAt: Date) { "success", startedAt, config, + undefined, await checkDiskUsage(logger), logger, ); diff --git a/src/setup-codeql-action.ts b/src/setup-codeql-action.ts index 31c8986679..7dc2b485ec 100644 --- a/src/setup-codeql-action.ts +++ b/src/setup-codeql-action.ts @@ -42,6 +42,7 @@ import { */ async function sendCompletedStatusReport( startedAt: Date, + features: Features | undefined, toolsDownloadStatusReport: ToolsDownloadStatusReport | undefined, toolsFeatureFlagsValid: boolean | undefined, toolsSource: ToolsSource, @@ -54,6 +55,7 @@ async function sendCompletedStatusReport( getActionsStatus(error), startedAt, undefined, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error?.message, @@ -97,6 +99,7 @@ async function run(startedAt: Date): Promise { let toolsFeatureFlagsValid: boolean | undefined; let toolsSource: ToolsSource; let toolsVersion: string; + let features: Features | undefined = undefined; try { initializeEnvironment(getActionVersion()); @@ -114,7 +117,7 @@ async function run(startedAt: Date): Promise { const repositoryNwo = getRepositoryNwo(); - const features = new Features( + features = new Features( gitHubVersion, repositoryNwo, getTemporaryDirectory(), @@ -130,6 +133,7 @@ async function run(startedAt: Date): Promise { "starting", startedAt, undefined, + features.getQueriedFeatures(), await checkDiskUsage(logger), logger, ); @@ -166,6 +170,7 @@ async function run(startedAt: Date): Promise { error instanceof ConfigurationError ? "user-error" : "failure", startedAt, undefined, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, error.message, @@ -179,6 +184,7 @@ async function run(startedAt: Date): Promise { await sendCompletedStatusReport( startedAt, + features, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, diff --git a/src/start-proxy-action.ts b/src/start-proxy-action.ts index b682d07d30..0c6be7e5e1 100644 --- a/src/start-proxy-action.ts +++ b/src/start-proxy-action.ts @@ -111,6 +111,7 @@ async function sendSuccessStatusReport( "success", startedAt, config, + undefined, await util.checkDiskUsage(logger), logger, ); @@ -193,6 +194,7 @@ async function run(startedAt: Date) { { languages: language && [language], }, + undefined, await util.checkDiskUsage(logger), logger, "Error from start-proxy Action omitted", diff --git a/src/status-report.test.ts b/src/status-report.test.ts index e051c54a27..02027aa56c 100644 --- a/src/status-report.test.ts +++ b/src/status-report.test.ts @@ -4,6 +4,7 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import { Config } from "./config-utils"; import { EnvVar } from "./environment"; +import { Feature, QueriedFeatures } from "./feature-flags"; import { KnownLanguage } from "./languages"; import { getRunnerLogger } from "./logging"; import { ToolsSource } from "./setup-codeql"; @@ -46,6 +47,10 @@ test("createStatusReportBase", async (t) => { await withTmpDir(async (tmpDir: string) => { setupEnvironmentAndStub(tmpDir); + const features: QueriedFeatures = Object.fromEntries( + Object.values(Feature).map((key) => [key, { value: true }]), + ); + const statusReport = await createStatusReportBase( ActionName.Init, "failure", @@ -54,6 +59,7 @@ test("createStatusReportBase", async (t) => { buildMode: BuildMode.None, languages: [KnownLanguage.java, KnownLanguage.swift], }), + features, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), "failure cause", @@ -75,6 +81,9 @@ test("createStatusReportBase", async (t) => { t.is(statusReport.cause, "failure cause"); t.is(statusReport.commit_oid, process.env["GITHUB_SHA"]!); t.is(statusReport.exception, "exception stack trace"); + if (t.assert(statusReport.feature_flags)) { + t.is(statusReport.feature_flags.length, Object.keys(features).length); + } t.is(statusReport.job_name, process.env["GITHUB_JOB"] || ""); t.is(typeof statusReport.job_run_uuid, "string"); t.is(statusReport.languages, "java,swift"); @@ -101,6 +110,7 @@ test("createStatusReportBase - empty configuration", async (t) => { "success", new Date("May 19, 2023 05:19:00"), {}, + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), ); @@ -123,6 +133,7 @@ test("createStatusReportBase - partial configuration", async (t) => { { languages: ["go"], }, + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), ); @@ -146,6 +157,7 @@ test("createStatusReportBase_firstParty", async (t) => { "failure", new Date("May 19, 2023 05:19:00"), createTestConfig({}), + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), "failure cause", @@ -162,6 +174,7 @@ test("createStatusReportBase_firstParty", async (t) => { "failure", new Date("May 19, 2023 05:19:00"), createTestConfig({}), + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), "failure cause", @@ -179,6 +192,7 @@ test("createStatusReportBase_firstParty", async (t) => { "failure", new Date("May 19, 2023 05:19:00"), createTestConfig({}), + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), "failure cause", @@ -195,6 +209,7 @@ test("createStatusReportBase_firstParty", async (t) => { "failure", new Date("May 19, 2023 05:19:00"), createTestConfig({}), + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), "failure cause", @@ -212,6 +227,7 @@ test("createStatusReportBase_firstParty", async (t) => { "failure", new Date("May 19, 2023 05:19:00"), createTestConfig({}), + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), "failure cause", @@ -228,6 +244,7 @@ test("createStatusReportBase_firstParty", async (t) => { "failure", new Date("May 19, 2023 05:19:00"), createTestConfig({}), + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), "failure cause", @@ -307,6 +324,7 @@ const testCreateInitWithConfigStatusReport = test.macro({ "failure", new Date("May 19, 2023 05:19:00"), config, + undefined, { numAvailableBytes: 100, numTotalBytes: 500 }, getRunnerLogger(false), "failure cause", diff --git a/src/status-report.ts b/src/status-report.ts index 4471b3ce9f..2a127554a8 100644 --- a/src/status-report.ts +++ b/src/status-report.ts @@ -16,6 +16,7 @@ import { parseRegistriesWithoutCredentials, type Config } from "./config-utils"; import { DependencyCacheRestoreStatusReport } from "./dependency-caching"; import { DocUrl } from "./doc-url"; import { EnvVar } from "./environment"; +import { QueriedFeatures, QueriedFeatureStatus } from "./feature-flags"; import { getRef } from "./git-utils"; import { Logger } from "./logging"; import { OverlayBaseDatabaseDownloadStats } from "./overlay-database-utils"; @@ -83,6 +84,12 @@ export enum JobStatus { ConfigErrorStatus = "JOB_STATUS_CONFIGURATION_ERROR", } +/** Information about the outcome of a querying a feature flag during this step. */ +export interface QueriedFeatureStatusReport extends QueriedFeatureStatus { + // The name of the feature. + feature: string; +} + export interface StatusReportBase { /** Name of the action being executed. */ action_name: ActionName; @@ -112,6 +119,8 @@ export interface StatusReportBase { completed_at?: string; /** Stack trace of the failure (or undefined if status is not failure). */ exception?: string; + /** Outcomes of querying feature flags during this step. */ + feature_flags?: QueriedFeatureStatusReport[]; /** Whether this is a first-party (CodeQL) run of the action. */ first_party_analysis: boolean; /** Job name from the workflow. */ @@ -253,6 +262,10 @@ export interface EventReport { * @param actionName The name of the action, e.g. 'init', 'finish', 'upload-sarif' * @param status The status. Must be 'success', 'failure', or 'starting' * @param actionStartedAt The time this action started executing. + * @param config The configuration for the action, even partially, if any. + * @param queriedFeatures Information about queried feature flags, if available. + * @param diskInfo Information about disk usage, if available. + * @param logger The logger to use. * @param cause Cause of failure (only supply if status is 'failure') * @param exception Exception (only supply if status is 'failure') * @returns undefined if an exception was thrown. @@ -262,6 +275,7 @@ export async function createStatusReportBase( status: ActionStatus, actionStartedAt: Date, config: Partial | undefined, + queriedFeatures: QueriedFeatures | undefined, diskInfo: DiskUsage | undefined, logger: Logger, cause?: string, @@ -294,6 +308,13 @@ export async function createStatusReportBase( const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true"; + let featureFlags: QueriedFeatureStatusReport[] | undefined = undefined; + if (queriedFeatures) { + featureFlags = Object.entries(queriedFeatures).map( + ([feature, outcome]) => ({ feature, ...outcome }), + ); + } + const statusReport: StatusReportBase = { action_name: actionName, action_oid: "unknown", // TODO decide if it's possible to fill this in @@ -304,6 +325,7 @@ export async function createStatusReportBase( analysis_key, build_mode: config?.buildMode, commit_oid: commitOid, + feature_flags: featureFlags, first_party_analysis: isFirstPartyAnalysis(actionName), job_name: jobName, job_run_uuid: jobRunUUID, @@ -518,7 +540,7 @@ export interface InitWithConfigStatusReport extends InitStatusReport { /** Stringified JSON array of registry configuration objects, from the 'registries' config field or workflow input. **/ registries: string; - /** Stringified JSON object representing a query-filters, from the 'query-filters' config field. **/ + /** Stringified JSON object representing query-filters, from the 'query-filters' config field. **/ query_filters: string; /** Path to the specified code scanning config file, from the 'config-file' config field. */ config_file: string; @@ -623,6 +645,7 @@ export async function sendUnhandledErrorStatusReport( "failure", actionStartedAt, undefined, + {}, undefined, logger, `Unhandled CodeQL Action error: ${getErrorMessage(error)}`, diff --git a/src/upload-sarif-action.ts b/src/upload-sarif-action.ts index 5273909bad..753ad01f9d 100644 --- a/src/upload-sarif-action.ts +++ b/src/upload-sarif-action.ts @@ -34,6 +34,7 @@ interface UploadSarifStatusReport async function sendSuccessStatusReport( startedAt: Date, + features: Features | undefined, uploadStats: upload_lib.UploadStatusReport, logger: Logger, ) { @@ -42,6 +43,7 @@ async function sendSuccessStatusReport( "success", startedAt, undefined, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, ); @@ -59,6 +61,7 @@ async function run(startedAt: Date) { // possible, and only use safe functions outside. const logger = getActionsLogger(); + let features: Features | undefined = undefined; try { initializeEnvironment(getActionVersion()); @@ -70,7 +73,7 @@ async function run(startedAt: Date) { actionsUtil.persistInputs(); const repositoryNwo = getRepositoryNwo(); - const features = new Features( + features = new Features( gitHubVersion, repositoryNwo, getTemporaryDirectory(), @@ -82,6 +85,7 @@ async function run(startedAt: Date) { "starting", startedAt, undefined, + features.getQueriedFeatures(), await checkDiskUsage(logger), logger, ); @@ -135,6 +139,7 @@ async function run(startedAt: Date) { } await sendSuccessStatusReport( startedAt, + features, codeScanningResult?.statusReport || {}, logger, ); @@ -152,6 +157,7 @@ async function run(startedAt: Date) { getActionsStatus(error), startedAt, undefined, + features?.getQueriedFeatures(), await checkDiskUsage(logger), logger, message,