Send overall job status in init-post status report (#2097)

Co-authored-by: Henry Mercer <henry@henrymercer.name>
This commit is contained in:
Angela P Wen 2024-01-26 05:11:46 -08:00 committed by GitHub
parent 16150320c5
commit 61bf02577c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 139 additions and 8 deletions

8
lib/environment.js generated
View file

@ -1,6 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EnvVar = void 0;
/**
* Environment variables used by the CodeQL Action.
*
* We recommend prefixing environment variables with `CODEQL_ACTION_`
* to reduce the risk that they are overwritten by other steps.
*/
var EnvVar;
(function (EnvVar) {
/** Whether the `analyze` Action completes successfully. */
@ -30,6 +36,8 @@ var EnvVar;
EnvVar["HAS_WARNED_ABOUT_DISK_SPACE"] = "CODEQL_ACTION_HAS_WARNED_ABOUT_DISK_SPACE";
/** UUID representing the current job run. */
EnvVar["JOB_RUN_UUID"] = "JOB_RUN_UUID";
/** Status for the entire job, submitted to the status report in `init-post` */
EnvVar["JOB_STATUS"] = "CODEQL_ACTION_JOB_STATUS";
EnvVar["ODASA_TRACER_CONFIGURATION"] = "ODASA_TRACER_CONFIGURATION";
/**
* What percentage of the total amount of RAM over 8 GB that the Action should reserve for the

View file

@ -1 +1 @@
{"version":3,"file":"environment.js","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":";;;AAAA,IAAY,MAsEX;AAtED,WAAY,MAAM;IAChB,2DAA2D;IAC3D,+FAAqF,CAAA;IAErF,gEAAgE;IAChE,qEAA2D,CAAA;IAE3D;;;OAGG;IACH,yFAA+E,CAAA;IAE/E;;;OAGG;IACH,yEAA+D,CAAA;IAE/D,gFAAgF;IAChF,6DAAmD,CAAA;IAEnD;;;OAGG;IACH,uEAA6D,CAAA;IAE7D,gEAAgE;IAChE,mEAAyD,CAAA;IAEzD,kFAAkF;IAClF,mFAAyE,CAAA;IAEzE,6CAA6C;IAC7C,uCAA6B,CAAA;IAE7B,mEAAyD,CAAA;IAEzD;;;OAGG;IACH,2FAAiF,CAAA;IAEjF,mFAAmF;IACnF,6FAAmF,CAAA;IAEnF,qFAAqF;IACrF,+CAAqC,CAAA;IAErC,mEAAyD,CAAA;IAEzD,kEAAkE;IAClE,2CAAiC,CAAA;IAEjC;;;;;;OAMG;IACH,4DAAkD,CAAA;IAElD;;;OAGG;IACH,wDAA8C,CAAA;AAChD,CAAC,EAtEW,MAAM,sBAAN,MAAM,QAsEjB"}
{"version":3,"file":"environment.js","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,IAAY,MAyEX;AAzED,WAAY,MAAM;IAChB,2DAA2D;IAC3D,+FAAqF,CAAA;IAErF,gEAAgE;IAChE,qEAA2D,CAAA;IAE3D;;;OAGG;IACH,yFAA+E,CAAA;IAE/E;;;OAGG;IACH,yEAA+D,CAAA;IAE/D,gFAAgF;IAChF,6DAAmD,CAAA;IAEnD;;;OAGG;IACH,uEAA6D,CAAA;IAE7D,gEAAgE;IAChE,mEAAyD,CAAA;IAEzD,kFAAkF;IAClF,mFAAyE,CAAA;IAEzE,6CAA6C;IAC7C,uCAA6B,CAAA;IAE7B,+EAA+E;IAC/E,iDAAuC,CAAA;IAEvC,mEAAyD,CAAA;IAEzD;;;OAGG;IACH,2FAAiF,CAAA;IAEjF,mFAAmF;IACnF,6FAAmF,CAAA;IAEnF,qFAAqF;IACrF,+CAAqC,CAAA;IAErC,mEAAyD,CAAA;IAEzD,kEAAkE;IAClE,2CAAiC,CAAA;IAEjC;;;;;;OAMG;IACH,4DAAkD,CAAA;IAElD;;;OAGG;IACH,wDAA8C,CAAA;AAChD,CAAC,EAzEW,MAAM,sBAAN,MAAM,QAyEjB"}

View file

@ -23,7 +23,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = exports.tryUploadSarifIfRunFailed = void 0;
exports.getFinalJobStatus = exports.run = exports.tryUploadSarifIfRunFailed = void 0;
const core = __importStar(require("@actions/core"));
const github = __importStar(require("@actions/github"));
const actionsUtil = __importStar(require("./actions-util"));
const api_client_1 = require("./api-client");
@ -32,6 +33,7 @@ const config_utils_1 = require("./config-utils");
const environment_1 = require("./environment");
const feature_flags_1 = require("./feature-flags");
const repository_1 = require("./repository");
const status_report_1 = require("./status-report");
const uploadLib = __importStar(require("./upload-lib"));
const util_1 = require("./util");
const workflow_1 = require("./workflow");
@ -81,6 +83,12 @@ async function maybeUploadFailedSarif(config, repositoryNwo, features, logger) {
}
async function tryUploadSarifIfRunFailed(config, repositoryNwo, features, logger) {
if (process.env[environment_1.EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY] !== "true") {
// If analyze didn't complete successfully and the job status hasn't
// already been set to Failure/ConfigurationError previously, this
// means that something along the way failed in a step that is not
// owned by the Action, for example a manual build step. We
// consider this a configuration error.
core.exportVariable(environment_1.EnvVar.JOB_STATUS, process.env[environment_1.EnvVar.JOB_STATUS] ?? status_report_1.JobStatus.ConfigurationError);
try {
return await maybeUploadFailedSarif(config, repositoryNwo, features, logger);
}
@ -90,6 +98,7 @@ async function tryUploadSarifIfRunFailed(config, repositoryNwo, features, logger
}
}
else {
core.exportVariable(environment_1.EnvVar.JOB_STATUS, process.env[environment_1.EnvVar.JOB_STATUS] ?? status_report_1.JobStatus.Success);
return {
upload_failed_run_skipped_because: "Analyze Action completed successfully",
};
@ -185,4 +194,19 @@ async function removeUploadedSarif(uploadFailedSarifResult, logger) {
logger.warning("Could not delete the uploaded SARIF analysis because a SARIF ID wasn't provided by the API when uploading the SARIF file.");
}
}
/**
* Returns the final job status sent in the `init-post` Action, based on the
* current value of the JOB_STATUS environment variable. If the variable is
* unset, or if its value is not one of the JobStatus enum values, returns
* Unknown. Otherwise it returns the status set in the environment variable.
*/
function getFinalJobStatus() {
const jobStatusFromEnvironment = process.env[environment_1.EnvVar.JOB_STATUS];
if (!jobStatusFromEnvironment ||
!Object.values(status_report_1.JobStatus).includes(jobStatusFromEnvironment)) {
return status_report_1.JobStatus.Unknown;
}
return jobStatusFromEnvironment;
}
exports.getFinalJobStatus = getFinalJobStatus;
//# sourceMappingURL=init-action-post-helper.js.map

File diff suppressed because one or more lines are too long

View file

@ -59,6 +59,7 @@ async function runWrapper() {
const statusReport = {
...statusReportBase,
...uploadFailedSarifResult,
job_status: initActionPostHelper.getFinalJobStatus(),
};
await (0, status_report_1.sendStatusReport)(statusReport);
}

View file

@ -1 +1 @@
{"version":3,"file":"init-action-post.js","sourceRoot":"","sources":["../src/init-action-post.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,oDAAsC;AAEtC,iDAAuE;AACvE,6CAAgD;AAChD,kEAAoD;AACpD,mDAA2C;AAC3C,gFAAkE;AAClE,uCAA6C;AAC7C,6CAAkD;AAClD,mDAKyB;AACzB,iCAKgB;AAMhB,KAAK,UAAU,UAAU;IACvB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;IAC7B,IAAI,uBAES,CAAC;IACd,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,0BAAgB,GAAE,CAAC;QAClC,MAAM,aAAa,GAAG,MAAM,IAAA,6BAAgB,GAAE,CAAC;QAC/C,IAAA,gCAAyB,EAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAEjD,MAAM,aAAa,GAAG,IAAA,+BAAkB,EACtC,IAAA,0BAAmB,EAAC,mBAAmB,CAAC,CACzC,CAAC;QACF,MAAM,QAAQ,GAAG,IAAI,wBAAQ,CAC3B,aAAa,EACb,aAAa,EACb,IAAA,oCAAqB,GAAE,EACvB,MAAM,CACP,CAAC;QAEF,uBAAuB,GAAG,MAAM,oBAAoB,CAAC,GAAG,CACtD,cAAc,CAAC,iCAAiC,EAChD,cAAc,CAAC,uBAAuB,EACtC,6BAAc,EACd,aAAa,EACb,QAAQ,EACR,MAAM,CACP,CAAC;IACJ,CAAC;IAAC,OAAO,cAAc,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,IAAA,gBAAS,EAAC,cAAc,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAE9B,MAAM,IAAA,gCAAgB,EACpB,MAAM,IAAA,sCAAsB,EAC1B,WAAW,EACX,IAAA,gCAAgB,EAAC,KAAK,CAAC,EACvB,SAAS,EACT,MAAM,IAAA,qBAAc,GAAE,EACtB,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,KAAK,CACZ,CACF,CAAC;QACF,OAAO;IACT,CAAC;IACD,MAAM,gBAAgB,GAAG,MAAM,IAAA,sCAAsB,EACnD,WAAW,EACX,SAAS,EACT,SAAS,EACT,MAAM,IAAA,qBAAc,GAAE,CACvB,CAAC;IACF,MAAM,YAAY,GAAyB;QACzC,GAAG,gBAAgB;QACnB,GAAG,uBAAuB;KAC3B,CAAC;IACF,MAAM,IAAA,gCAAgB,EAAC,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,EAAE,CAAC"}
{"version":3,"file":"init-action-post.js","sourceRoot":"","sources":["../src/init-action-post.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,oDAAsC;AAEtC,iDAAuE;AACvE,6CAAgD;AAChD,kEAAoD;AACpD,mDAA2C;AAC3C,gFAAkE;AAClE,uCAA6C;AAC7C,6CAAkD;AAClD,mDAKyB;AACzB,iCAKgB;AAOhB,KAAK,UAAU,UAAU;IACvB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;IAC7B,IAAI,uBAES,CAAC;IACd,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,0BAAgB,GAAE,CAAC;QAClC,MAAM,aAAa,GAAG,MAAM,IAAA,6BAAgB,GAAE,CAAC;QAC/C,IAAA,gCAAyB,EAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QAEjD,MAAM,aAAa,GAAG,IAAA,+BAAkB,EACtC,IAAA,0BAAmB,EAAC,mBAAmB,CAAC,CACzC,CAAC;QACF,MAAM,QAAQ,GAAG,IAAI,wBAAQ,CAC3B,aAAa,EACb,aAAa,EACb,IAAA,oCAAqB,GAAE,EACvB,MAAM,CACP,CAAC;QAEF,uBAAuB,GAAG,MAAM,oBAAoB,CAAC,GAAG,CACtD,cAAc,CAAC,iCAAiC,EAChD,cAAc,CAAC,uBAAuB,EACtC,6BAAc,EACd,aAAa,EACb,QAAQ,EACR,MAAM,CACP,CAAC;IACJ,CAAC;IAAC,OAAO,cAAc,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,IAAA,gBAAS,EAAC,cAAc,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAE9B,MAAM,IAAA,gCAAgB,EACpB,MAAM,IAAA,sCAAsB,EAC1B,WAAW,EACX,IAAA,gCAAgB,EAAC,KAAK,CAAC,EACvB,SAAS,EACT,MAAM,IAAA,qBAAc,GAAE,EACtB,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,KAAK,CACZ,CACF,CAAC;QACF,OAAO;IACT,CAAC;IACD,MAAM,gBAAgB,GAAG,MAAM,IAAA,sCAAsB,EACnD,WAAW,EACX,SAAS,EACT,SAAS,EACT,MAAM,IAAA,qBAAc,GAAE,CACvB,CAAC;IACF,MAAM,YAAY,GAAyB;QACzC,GAAG,gBAAgB;QACnB,GAAG,uBAAuB;QAC1B,UAAU,EAAE,oBAAoB,CAAC,iBAAiB,EAAE;KACrD,CAAC;IACF,MAAM,IAAA,gCAAgB,EAAC,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,KAAK,UAAU,EAAE,CAAC"}

24
lib/status-report.js generated
View file

@ -23,13 +23,21 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.sendStatusReport = exports.createStatusReportBase = exports.getActionsStatus = void 0;
exports.sendStatusReport = exports.createStatusReportBase = exports.getActionsStatus = exports.JobStatus = void 0;
const os = __importStar(require("os"));
const core = __importStar(require("@actions/core"));
const actions_util_1 = require("./actions-util");
const api_client_1 = require("./api-client");
const environment_1 = require("./environment");
const util_1 = require("./util");
/** Overall status of the entire job. String values match the Hydro schema. */
var JobStatus;
(function (JobStatus) {
JobStatus["Unknown"] = "JOB_STATUS_UNKNOWN";
JobStatus["Success"] = "JOB_STATUS_SUCCESS";
JobStatus["Failure"] = "JOB_STATUS_FAILURE";
JobStatus["ConfigurationError"] = "JOB_STATUS_CONFIGURATION_ERROR";
})(JobStatus || (exports.JobStatus = JobStatus = {}));
function getActionsStatus(error, otherFailureCause) {
if (error || otherFailureCause) {
return error instanceof util_1.UserError ? "user-error" : "failure";
@ -39,6 +47,19 @@ function getActionsStatus(error, otherFailureCause) {
}
}
exports.getActionsStatus = getActionsStatus;
/**
* Sets the overall job status environment variable to configuration error
* or failure, unless it's already been set to one of these values in a
* previous step.
*/
function setJobStatusIfUnsuccessful(actionStatus) {
if (actionStatus === "user-error") {
core.exportVariable(environment_1.EnvVar.JOB_STATUS, process.env[environment_1.EnvVar.JOB_STATUS] ?? JobStatus.ConfigurationError);
}
else if (actionStatus === "failure" || actionStatus === "aborted") {
core.exportVariable(environment_1.EnvVar.JOB_STATUS, process.env[environment_1.EnvVar.JOB_STATUS] ?? JobStatus.Failure);
}
}
/**
* Compose a StatusReport.
*
@ -141,6 +162,7 @@ const INCOMPATIBLE_MSG = "CodeQL Action version is incompatible with the code sc
* Returns whether sending the status report was successful of not.
*/
async function sendStatusReport(statusReport) {
setJobStatusIfUnsuccessful(statusReport.status);
const statusReportJSON = JSON.stringify(statusReport);
core.debug(`Sending status report: ${statusReportJSON}`);
// If in test mode we don't want to upload the results

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,9 @@
/**
* Environment variables used by the CodeQL Action.
*
* We recommend prefixing environment variables with `CODEQL_ACTION_`
* to reduce the risk that they are overwritten by other steps.
*/
export enum EnvVar {
/** Whether the `analyze` Action completes successfully. */
ANALYZE_DID_COMPLETE_SUCCESSFULLY = "CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY",
@ -35,6 +41,9 @@ export enum EnvVar {
/** UUID representing the current job run. */
JOB_RUN_UUID = "JOB_RUN_UUID",
/** Status for the entire job, submitted to the status report in `init-post` */
JOB_STATUS = "CODEQL_ACTION_JOB_STATUS",
ODASA_TRACER_CONFIGURATION = "ODASA_TRACER_CONFIGURATION",
/**

View file

@ -1,3 +1,4 @@
import * as core from "@actions/core";
import * as github from "@actions/github";
import * as actionsUtil from "./actions-util";
@ -8,6 +9,7 @@ import { EnvVar } from "./environment";
import { Feature, FeatureEnablement } from "./feature-flags";
import { Logger } from "./logging";
import { RepositoryNwo, parseRepositoryNwo } from "./repository";
import { JobStatus } from "./status-report";
import * as uploadLib from "./upload-lib";
import {
delay,
@ -36,6 +38,10 @@ export interface UploadFailedSarifResult extends uploadLib.UploadStatusReport {
sarifID?: string;
}
export interface JobStatusReport {
job_status: JobStatus;
}
function createFailedUploadFailedSarifResult(
error: unknown,
): UploadFailedSarifResult {
@ -121,6 +127,15 @@ export async function tryUploadSarifIfRunFailed(
logger: Logger,
): Promise<UploadFailedSarifResult> {
if (process.env[EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY] !== "true") {
// If analyze didn't complete successfully and the job status hasn't
// already been set to Failure/ConfigurationError previously, this
// means that something along the way failed in a step that is not
// owned by the Action, for example a manual build step. We
// consider this a configuration error.
core.exportVariable(
EnvVar.JOB_STATUS,
process.env[EnvVar.JOB_STATUS] ?? JobStatus.ConfigurationError,
);
try {
return await maybeUploadFailedSarif(
config,
@ -135,6 +150,10 @@ export async function tryUploadSarifIfRunFailed(
return createFailedUploadFailedSarifResult(e);
}
} else {
core.exportVariable(
EnvVar.JOB_STATUS,
process.env[EnvVar.JOB_STATUS] ?? JobStatus.Success,
);
return {
upload_failed_run_skipped_because:
"Analyze Action completed successfully",
@ -282,3 +301,20 @@ async function removeUploadedSarif(
);
}
}
/**
* Returns the final job status sent in the `init-post` Action, based on the
* current value of the JOB_STATUS environment variable. If the variable is
* unset, or if its value is not one of the JobStatus enum values, returns
* Unknown. Otherwise it returns the status set in the environment variable.
*/
export function getFinalJobStatus(): JobStatus {
const jobStatusFromEnvironment = process.env[EnvVar.JOB_STATUS];
if (
!jobStatusFromEnvironment ||
!Object.values(JobStatus).includes(jobStatusFromEnvironment as JobStatus)
) {
return JobStatus.Unknown;
}
return jobStatusFromEnvironment as JobStatus;
}

View file

@ -28,7 +28,8 @@ import {
interface InitPostStatusReport
extends StatusReportBase,
initActionPostHelper.UploadFailedSarifResult {}
initActionPostHelper.UploadFailedSarifResult,
initActionPostHelper.JobStatusReport {}
async function runWrapper() {
const startedAt = new Date();
@ -83,6 +84,7 @@ async function runWrapper() {
const statusReport: InitPostStatusReport = {
...statusReportBase,
...uploadFailedSarifResult,
job_status: initActionPostHelper.getFinalJobStatus(),
};
await sendStatusReport(statusReport);
}

View file

@ -32,12 +32,20 @@ export type ActionName =
| "upload-sarif";
export type ActionStatus =
| "aborted"
| "aborted" // Only used in the init Action, if init failed before initializing the tracer due to something other than a configuration error.
| "failure"
| "starting"
| "success"
| "user-error";
/** Overall status of the entire job. String values match the Hydro schema. */
export enum JobStatus {
Unknown = "JOB_STATUS_UNKNOWN",
Success = "JOB_STATUS_SUCCESS",
Failure = "JOB_STATUS_FAILURE",
ConfigurationError = "JOB_STATUS_CONFIGURATION_ERROR",
}
export interface StatusReportBase {
/** Name of the action being executed. */
action_name: ActionName;
@ -133,6 +141,25 @@ export function getActionsStatus(
}
}
/**
* Sets the overall job status environment variable to configuration error
* or failure, unless it's already been set to one of these values in a
* previous step.
*/
function setJobStatusIfUnsuccessful(actionStatus: ActionStatus) {
if (actionStatus === "user-error") {
core.exportVariable(
EnvVar.JOB_STATUS,
process.env[EnvVar.JOB_STATUS] ?? JobStatus.ConfigurationError,
);
} else if (actionStatus === "failure" || actionStatus === "aborted") {
core.exportVariable(
EnvVar.JOB_STATUS,
process.env[EnvVar.JOB_STATUS] ?? JobStatus.Failure,
);
}
}
// Any status report may include an array of EventReports associated with it.
export interface EventReport {
/** Time this event ended. */
@ -273,6 +300,8 @@ const INCOMPATIBLE_MSG =
export async function sendStatusReport<S extends StatusReportBase>(
statusReport: S,
): Promise<boolean> {
setJobStatusIfUnsuccessful(statusReport.status);
const statusReportJSON = JSON.stringify(statusReport);
core.debug(`Sending status report: ${statusReportJSON}`);
// If in test mode we don't want to upload the results