Compare commits

...

2 Commits

Author SHA1 Message Date
Henry Mercer
5d063dd3af Populate database upload results telemetry 2025-12-15 12:55:12 +00:00
Henry Mercer
8e921c3145 Return status report from cleanupAndUploadDatabases 2025-12-15 12:55:12 +00:00
4 changed files with 97 additions and 27 deletions

39
lib/analyze-action.js generated
View File

@@ -91674,27 +91674,28 @@ var fs13 = __toESM(require("fs"));
async function cleanupAndUploadDatabases(repositoryNwo, codeql, config, apiDetails, features, logger) {
if (getRequiredInput("upload-database") !== "true") {
logger.debug("Database upload disabled in workflow. Skipping upload.");
return;
return [];
}
if (!config.analysisKinds.includes("code-scanning" /* CodeScanning */)) {
logger.debug(
`Not uploading database because 'analysis-kinds: ${"code-scanning" /* CodeScanning */}' is not enabled.`
);
return;
return [];
}
if (isInTestMode()) {
logger.debug("In test mode. Skipping database upload.");
return;
return [];
}
if (config.gitHubVersion.type !== 0 /* DOTCOM */ && config.gitHubVersion.type !== 2 /* GHE_DOTCOM */) {
logger.debug("Not running against github.com or GHEC-DR. Skipping upload.");
return;
return [];
}
if (!await isAnalyzingDefaultBranch()) {
logger.debug("Not analyzing default branch. Skipping upload.");
return;
return [];
}
const cleanupLevel = config.overlayDatabaseMode === "overlay-base" /* OverlayBase */ && await features.getValue("upload_overlay_db_to_api" /* UploadOverlayDbToApi */) ? "overlay" /* Overlay */ : "clear" /* Clear */;
const isOverlayBase = config.overlayDatabaseMode === "overlay-base" /* OverlayBase */ && await features.getValue("upload_overlay_db_to_api" /* UploadOverlayDbToApi */);
const cleanupLevel = isOverlayBase ? "overlay" /* Overlay */ : "clear" /* Clear */;
await withGroupAsync("Cleaning up databases", async () => {
await codeql.databaseCleanupCluster(config, cleanupLevel);
});
@@ -91705,6 +91706,7 @@ async function cleanupAndUploadDatabases(repositoryNwo, codeql, config, apiDetai
if (uploadsBaseUrl.endsWith("/")) {
uploadsBaseUrl = uploadsBaseUrl.slice(0, -1);
}
const reports = [];
for (const language of config.languages) {
try {
const bundledDb = await bundleDb(config, language, codeql, language);
@@ -91714,6 +91716,7 @@ async function cleanupAndUploadDatabases(repositoryNwo, codeql, config, apiDetai
getRequiredInput("checkout_path")
);
try {
const startTime = Date.now();
await client.request(
`POST /repos/:owner/:repo/code-scanning/codeql/databases/:language?name=:name&commit_oid=:commit_oid`,
{
@@ -91731,14 +91734,26 @@ async function cleanupAndUploadDatabases(repositoryNwo, codeql, config, apiDetai
}
}
);
const endTime = Date.now();
reports.push({
language,
zipped_upload_size_bytes: bundledDbSize,
is_overlay_base: isOverlayBase,
upload_duration_ms: endTime - startTime
});
logger.debug(`Successfully uploaded database for ${language}`);
} finally {
bundledDbReadStream.close();
}
} catch (e) {
logger.warning(`Failed to upload database for ${language}: ${e}`);
reports.push({
language,
error: getErrorMessage(e)
});
}
}
return reports;
}
// src/status-report.ts
@@ -93799,7 +93814,7 @@ async function postProcessAndUploadSarif(logger, features, uploadKind, checkoutP
}
// src/analyze-action.ts
async function sendStatusReport2(startedAt, config, stats, error3, trapCacheUploadTime, dbCreationTimings, didUploadTrapCaches, trapCacheCleanup, dependencyCacheResults, logger) {
async function sendStatusReport2(startedAt, config, stats, error3, trapCacheUploadTime, dbCreationTimings, didUploadTrapCaches, trapCacheCleanup, dependencyCacheResults, databaseUploadResults, logger) {
const status = getActionsStatus(error3, stats?.analyze_failure_language);
const statusReportBase = await createStatusReportBase(
"finish" /* Analyze */,
@@ -93817,7 +93832,8 @@ async function sendStatusReport2(startedAt, config, stats, error3, trapCacheUplo
...stats || {},
...dbCreationTimings || {},
...trapCacheCleanup || {},
dependency_caching_upload_results: dependencyCacheResults
dependency_caching_upload_results: dependencyCacheResults,
database_upload_results: databaseUploadResults
};
if (config && didUploadTrapCaches) {
const trapCacheUploadStatusReport = {
@@ -93899,6 +93915,7 @@ async function run() {
let dbCreationTimings = void 0;
let didUploadTrapCaches = false;
let dependencyCacheResults;
let databaseUploadResults = [];
initializeEnvironment(getActionVersion());
persistInputs();
const logger = getActionsLogger();
@@ -94054,7 +94071,7 @@ async function run() {
logger.info("Not uploading results");
}
await cleanupAndUploadOverlayBaseDatabaseToCache(codeql, config, logger);
await cleanupAndUploadDatabases(
databaseUploadResults = await cleanupAndUploadDatabases(
repositoryNwo,
codeql,
config,
@@ -94108,6 +94125,7 @@ async function run() {
didUploadTrapCaches,
trapCacheCleanupTelemetry,
dependencyCacheResults,
databaseUploadResults,
logger
);
return;
@@ -94126,6 +94144,7 @@ async function run() {
didUploadTrapCaches,
trapCacheCleanupTelemetry,
dependencyCacheResults,
databaseUploadResults,
logger
);
} else if (runStats !== void 0) {
@@ -94139,6 +94158,7 @@ async function run() {
didUploadTrapCaches,
trapCacheCleanupTelemetry,
dependencyCacheResults,
databaseUploadResults,
logger
);
} else {
@@ -94152,6 +94172,7 @@ async function run() {
didUploadTrapCaches,
trapCacheCleanupTelemetry,
dependencyCacheResults,
databaseUploadResults,
logger
);
}

11
package-lock.json generated
View File

@@ -1798,6 +1798,7 @@
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz",
"integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0",
@@ -2568,6 +2569,7 @@
"integrity": "sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.46.4",
"@typescript-eslint/types": "8.46.4",
@@ -3164,6 +3166,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3739,6 +3742,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001669",
"electron-to-chromium": "^1.5.41",
@@ -4592,6 +4596,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"dev": true,
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -4646,6 +4651,7 @@
"version": "8.3.0",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
@@ -4917,6 +4923,7 @@
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
"integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
"dev": true,
"peer": true,
"dependencies": {
"array-includes": "^3.1.7",
"array.prototype.findlastindex": "^1.2.3",
@@ -7351,6 +7358,7 @@
"integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -8341,6 +8349,7 @@
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -8549,6 +8558,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -8622,6 +8632,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.17.0.tgz",
"integrity": "sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==",
"dev": true,
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.17.0",
"@typescript-eslint/types": "8.17.0",

View File

@@ -25,7 +25,10 @@ import {
isCodeQualityEnabled,
isCodeScanningEnabled,
} from "./config-utils";
import { cleanupAndUploadDatabases } from "./database-upload";
import {
cleanupAndUploadDatabases,
DatabaseUploadResult,
} from "./database-upload";
import {
DependencyCacheUploadStatusReport,
uploadDependencyCaches,
@@ -59,15 +62,13 @@ interface AnalysisStatusReport
extends uploadLib.UploadStatusReport,
QueriesStatusReport {}
interface DependencyCachingUploadStatusReport {
dependency_caching_upload_results?: DependencyCacheUploadStatusReport;
}
interface FinishStatusReport
extends StatusReportBase,
DatabaseCreationTimings,
AnalysisStatusReport,
DependencyCachingUploadStatusReport {}
AnalysisStatusReport {
dependency_caching_upload_results?: DependencyCacheUploadStatusReport;
database_upload_results: DatabaseUploadResult[];
}
interface FinishWithTrapUploadStatusReport extends FinishStatusReport {
/** Size of TRAP caches that we uploaded, in bytes. */
@@ -86,6 +87,7 @@ async function sendStatusReport(
didUploadTrapCaches: boolean,
trapCacheCleanup: TrapCacheCleanupStatusReport | undefined,
dependencyCacheResults: DependencyCacheUploadStatusReport | undefined,
databaseUploadResults: DatabaseUploadResult[],
logger: Logger,
) {
const status = getActionsStatus(error, stats?.analyze_failure_language);
@@ -106,6 +108,7 @@ async function sendStatusReport(
...(dbCreationTimings || {}),
...(trapCacheCleanup || {}),
dependency_caching_upload_results: dependencyCacheResults,
database_upload_results: databaseUploadResults,
};
if (config && didUploadTrapCaches) {
const trapCacheUploadStatusReport: FinishWithTrapUploadStatusReport = {
@@ -223,6 +226,7 @@ async function run() {
let dbCreationTimings: DatabaseCreationTimings | undefined = undefined;
let didUploadTrapCaches = false;
let dependencyCacheResults: DependencyCacheUploadStatusReport | undefined;
let databaseUploadResults: DatabaseUploadResult[] = [];
util.initializeEnvironment(actionsUtil.getActionVersion());
// Make inputs accessible in the `post` step, details at
@@ -424,7 +428,7 @@ async function run() {
// Possibly upload the database bundles for remote queries.
// Note: Take care with the ordering of this call since databases may be cleaned up
// at the `overlay` or `clear` level.
await cleanupAndUploadDatabases(
databaseUploadResults = await cleanupAndUploadDatabases(
repositoryNwo,
codeql,
config,
@@ -496,6 +500,7 @@ async function run() {
didUploadTrapCaches,
trapCacheCleanupTelemetry,
dependencyCacheResults,
databaseUploadResults,
logger,
);
return;
@@ -518,6 +523,7 @@ async function run() {
didUploadTrapCaches,
trapCacheCleanupTelemetry,
dependencyCacheResults,
databaseUploadResults,
logger,
);
} else if (runStats !== undefined) {
@@ -531,6 +537,7 @@ async function run() {
didUploadTrapCaches,
trapCacheCleanupTelemetry,
dependencyCacheResults,
databaseUploadResults,
logger,
);
} else {
@@ -544,6 +551,7 @@ async function run() {
didUploadTrapCaches,
trapCacheCleanupTelemetry,
dependencyCacheResults,
databaseUploadResults,
logger,
);
}

View File

@@ -13,6 +13,20 @@ import { RepositoryNwo } from "./repository";
import * as util from "./util";
import { bundleDb, CleanupLevel, parseGitHubUrl } from "./util";
/** Information about a database upload. */
export interface DatabaseUploadResult {
/** Language of the database. */
language: string;
/** Size of the zipped database in bytes. */
zipped_upload_size_bytes?: number;
/** Whether the uploaded database is an overlay base. */
is_overlay_base?: boolean;
/** Time taken to upload database in milliseconds. */
upload_duration_ms?: number;
/** If there was an error during database upload, this is its message. */
error?: string;
}
export async function cleanupAndUploadDatabases(
repositoryNwo: RepositoryNwo,
codeql: CodeQL,
@@ -20,22 +34,22 @@ export async function cleanupAndUploadDatabases(
apiDetails: GitHubApiDetails,
features: FeatureEnablement,
logger: Logger,
): Promise<void> {
): Promise<DatabaseUploadResult[]> {
if (actionsUtil.getRequiredInput("upload-database") !== "true") {
logger.debug("Database upload disabled in workflow. Skipping upload.");
return;
return [];
}
if (!config.analysisKinds.includes(AnalysisKind.CodeScanning)) {
logger.debug(
`Not uploading database because 'analysis-kinds: ${AnalysisKind.CodeScanning}' is not enabled.`,
);
return;
return [];
}
if (util.isInTestMode()) {
logger.debug("In test mode. Skipping database upload.");
return;
return [];
}
// Do nothing when not running against github.com
@@ -44,20 +58,22 @@ export async function cleanupAndUploadDatabases(
config.gitHubVersion.type !== util.GitHubVariant.GHE_DOTCOM
) {
logger.debug("Not running against github.com or GHEC-DR. Skipping upload.");
return;
return [];
}
if (!(await gitUtils.isAnalyzingDefaultBranch())) {
// We only want to upload a database if we are analyzing the default branch.
logger.debug("Not analyzing default branch. Skipping upload.");
return;
return [];
}
const cleanupLevel =
// If config.overlayDatabaseMode is OverlayBase, then we have overlay base databases for all languages.
const isOverlayBase =
config.overlayDatabaseMode === OverlayDatabaseMode.OverlayBase &&
(await features.getValue(Feature.UploadOverlayDbToApi))
? CleanupLevel.Overlay
: CleanupLevel.Clear;
(await features.getValue(Feature.UploadOverlayDbToApi));
const cleanupLevel = isOverlayBase
? CleanupLevel.Overlay
: CleanupLevel.Clear;
// Clean up the database, since intermediate results may still be written to the
// database if there is high RAM pressure.
@@ -77,6 +93,7 @@ export async function cleanupAndUploadDatabases(
uploadsBaseUrl = uploadsBaseUrl.slice(0, -1);
}
const reports: DatabaseUploadResult[] = [];
for (const language of config.languages) {
try {
// Upload the database bundle.
@@ -90,6 +107,7 @@ export async function cleanupAndUploadDatabases(
actionsUtil.getRequiredInput("checkout_path"),
);
try {
const startTime = Date.now();
await client.request(
`POST /repos/:owner/:repo/code-scanning/codeql/databases/:language?name=:name&commit_oid=:commit_oid`,
{
@@ -107,6 +125,13 @@ export async function cleanupAndUploadDatabases(
},
},
);
const endTime = Date.now();
reports.push({
language,
zipped_upload_size_bytes: bundledDbSize,
is_overlay_base: isOverlayBase,
upload_duration_ms: endTime - startTime,
});
logger.debug(`Successfully uploaded database for ${language}`);
} finally {
bundledDbReadStream.close();
@@ -114,6 +139,11 @@ export async function cleanupAndUploadDatabases(
} catch (e) {
// Log a warning but don't fail the workflow
logger.warning(`Failed to upload database for ${language}: ${e}`);
reports.push({
language,
error: util.getErrorMessage(e),
});
}
}
return reports;
}