Add catch-all error reporting for errors that slip through run

This commit is contained in:
Henry Mercer
2026-01-22 13:14:53 +00:00
parent 14bd76753f
commit 229e0cd749
17 changed files with 447 additions and 101 deletions

View File

@@ -41,6 +41,7 @@ import {
createStatusReportBase,
DatabaseCreationTimings,
getActionsStatus,
sendUnexpectedErrorStatusReport,
StatusReportBase,
} from "./status-report";
import {
@@ -208,11 +209,10 @@ async function runAutobuildIfLegacyGoWorkflow(config: Config, logger: Logger) {
await runAutobuild(config, KnownLanguage.go, logger);
}
async function run() {
async function run(startedAt: Date) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const startedAt = new Date();
let uploadResults:
| Partial<Record<analyses.AnalysisKind, UploadResult>>
| undefined = undefined;
@@ -526,13 +526,22 @@ async function run() {
}
}
export const runPromise = run();
// Module-level startedAt so it can be accessed by runWrapper for error reporting
const startedAt = new Date();
export const runPromise = run(startedAt);
async function runWrapper() {
const logger = getActionsLogger();
try {
await runPromise;
} catch (error) {
core.setFailed(`analyze action failed: ${util.getErrorMessage(error)}`);
await sendUnexpectedErrorStatusReport(
ActionName.Analyze,
startedAt,
error,
logger,
);
}
await util.checkForTimeout();
}

View File

@@ -17,6 +17,7 @@ import {
getActionsStatus,
createStatusReportBase,
sendStatusReport,
sendUnexpectedErrorStatusReport,
ActionName,
} from "./status-report";
import { endTracingForCluster } from "./tracer-config";
@@ -68,11 +69,10 @@ async function sendCompletedStatusReport(
}
}
async function run() {
async function run(startedAt: Date) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const startedAt = new Date();
const logger = getActionsLogger();
let config: Config | undefined;
let currentLanguage: Language | undefined;
@@ -143,10 +143,18 @@ async function run() {
}
async function runWrapper() {
const startedAt = new Date();
const logger = getActionsLogger();
try {
await run();
await run(startedAt);
} catch (error) {
core.setFailed(`autobuild action failed. ${getErrorMessage(error)}`);
await sendUnexpectedErrorStatusReport(
ActionName.Autobuild,
startedAt,
error,
logger,
);
}
}

View File

@@ -28,6 +28,7 @@ import { getRepositoryNwo } from "./repository";
import {
StatusReportBase,
sendStatusReport,
sendUnexpectedErrorStatusReport,
createStatusReportBase,
getActionsStatus,
ActionName,
@@ -41,12 +42,11 @@ interface InitPostStatusReport
initActionPostHelper.JobStatusReport,
initActionPostHelper.DependencyCachingUsageReport {}
async function runWrapper() {
async function run(startedAt: Date) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const logger = getActionsLogger();
const startedAt = new Date();
let config: Config | undefined;
let uploadFailedSarifResult:
| initActionPostHelper.UploadFailedSarifResult
@@ -139,4 +139,20 @@ async function runWrapper() {
}
}
async function runWrapper() {
const startedAt = new Date();
const logger = getActionsLogger();
try {
await run(startedAt);
} catch (error) {
core.setFailed(`init post action failed: ${wrapError(error).message}`);
await sendUnexpectedErrorStatusReport(
ActionName.InitPost,
startedAt,
error,
logger,
);
}
}
void runWrapper();

View File

@@ -64,6 +64,7 @@ import {
createStatusReportBase,
getActionsStatus,
sendStatusReport,
sendUnexpectedErrorStatusReport,
} from "./status-report";
import { ZstdAvailability } from "./tar";
import { ToolsDownloadStatusReport } from "./tools-download";
@@ -191,11 +192,10 @@ async function sendCompletedStatusReport(
}
}
async function run() {
async function run(startedAt: Date) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const startedAt = new Date();
const logger = getActionsLogger();
let apiDetails: GitHubApiCombinedDetails;
@@ -805,10 +805,18 @@ async function recordZstdAvailability(
}
async function runWrapper() {
const startedAt = new Date();
const logger = getActionsLogger();
try {
await run();
await run(startedAt);
} catch (error) {
core.setFailed(`init action failed: ${getErrorMessage(error)}`);
await sendUnexpectedErrorStatusReport(
ActionName.Init,
startedAt,
error,
logger,
);
}
await checkForTimeout();
}

View File

@@ -13,6 +13,7 @@ import { getActionsLogger } from "./logging";
import { runResolveBuildEnvironment } from "./resolve-environment";
import {
sendStatusReport,
sendUnexpectedErrorStatusReport,
createStatusReportBase,
getActionsStatus,
ActionName,
@@ -29,11 +30,10 @@ import {
const ENVIRONMENT_OUTPUT_NAME = "environment";
async function run() {
async function run(startedAt: Date) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const startedAt = new Date();
const logger = getActionsLogger();
let config: Config | undefined;
@@ -118,14 +118,22 @@ async function run() {
}
async function runWrapper() {
const startedAt = new Date();
const logger = getActionsLogger();
try {
await run();
await run(startedAt);
} catch (error) {
core.setFailed(
`${ActionName.ResolveEnvironment} action failed: ${getErrorMessage(
error,
)}`,
);
await sendUnexpectedErrorStatusReport(
ActionName.ResolveEnvironment,
startedAt,
error,
logger,
);
}
await checkForTimeout();
}

View File

@@ -22,6 +22,7 @@ import {
createStatusReportBase,
getActionsStatus,
sendStatusReport,
sendUnexpectedErrorStatusReport,
} from "./status-report";
import { ToolsDownloadStatusReport } from "./tools-download";
import {
@@ -85,11 +86,10 @@ async function sendCompletedStatusReport(
}
/** The main behaviour of this action. */
async function run(): Promise<void> {
async function run(startedAt: Date): Promise<void> {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const startedAt = new Date();
const logger = getActionsLogger();
let codeql: CodeQL;
@@ -189,10 +189,18 @@ async function run(): Promise<void> {
/** Run the action and catch any unhandled errors. */
async function runWrapper(): Promise<void> {
const startedAt = new Date();
const logger = getActionsLogger();
try {
await run();
await run(startedAt);
} catch (error) {
core.setFailed(`setup-codeql action failed: ${getErrorMessage(error)}`);
await sendUnexpectedErrorStatusReport(
ActionName.SetupCodeQL,
startedAt,
error,
logger,
);
}
await checkForTimeout();
}

View File

@@ -22,6 +22,7 @@ import {
createStatusReportBase,
getActionsStatus,
sendStatusReport,
sendUnexpectedErrorStatusReport,
StatusReportBase,
} from "./status-report";
import * as util from "./util";
@@ -122,12 +123,10 @@ async function sendSuccessStatusReport(
}
}
async function runWrapper() {
async function run(startedAt: Date) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const startedAt = new Date();
const logger = getActionsLogger();
let language: KnownLanguage | undefined;
@@ -203,6 +202,23 @@ async function runWrapper() {
}
}
async function runWrapper() {
const startedAt = new Date();
const logger = getActionsLogger();
try {
await run(startedAt);
} catch (error) {
core.setFailed(`start-proxy action failed: ${util.getErrorMessage(error)}`);
await sendUnexpectedErrorStatusReport(
ActionName.StartProxy,
startedAt,
error,
logger,
);
}
}
async function startProxy(
binPath: string,
config: ProxyConfig,

View File

@@ -606,3 +606,30 @@ export async function createInitWithConfigStatusReport(
),
};
}
export async function sendUnexpectedErrorStatusReport(
actionName: ActionName,
actionStartedAt: Date,
error: unknown,
logger: Logger,
): Promise<void> {
try {
const statusReport = await createStatusReportBase(
actionName,
"failure",
actionStartedAt,
undefined,
undefined,
logger,
undefined,
getErrorMessage(error),
);
if (statusReport !== undefined) {
await sendStatusReport(statusReport);
}
} catch (e) {
logger.warning(
`Caught an exception while sending the error status report: ${e}.`,
);
}
}

View File

@@ -10,6 +10,7 @@ import { getRepositoryNwo } from "./repository";
import {
createStatusReportBase,
sendStatusReport,
sendUnexpectedErrorStatusReport,
StatusReportBase,
getActionsStatus,
ActionName,
@@ -53,11 +54,10 @@ async function sendSuccessStatusReport(
}
}
async function run() {
async function run(startedAt: Date) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const startedAt = new Date();
const logger = getActionsLogger();
try {
@@ -165,12 +165,20 @@ async function run() {
}
async function runWrapper() {
const startedAt = new Date();
const logger = getActionsLogger();
try {
await run();
await run(startedAt);
} catch (error) {
core.setFailed(
`codeql/upload-sarif action failed: ${getErrorMessage(error)}`,
);
await sendUnexpectedErrorStatusReport(
ActionName.UploadSarif,
startedAt,
error,
logger,
);
}
}