Pull out a dedicated status report file
This commit is contained in:
parent
c55207f0a2
commit
c6d284324b
41 changed files with 768 additions and 669 deletions
|
|
@ -5,7 +5,7 @@ import test from "ava";
|
|||
import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import { computeAutomationID, createStatusReportBase } from "./api-client";
|
||||
import { computeAutomationID } from "./api-client";
|
||||
import { EnvVar } from "./environment";
|
||||
import { setupActionsVars, setupTests } from "./testing-utils";
|
||||
import { initializeEnvironment, withTmpDir } from "./util";
|
||||
|
|
@ -267,53 +267,3 @@ test("isAnalyzingDefaultBranch()", async (t) => {
|
|||
getAdditionalInputStub.restore();
|
||||
});
|
||||
});
|
||||
|
||||
test("createStatusReportBase", async (t) => {
|
||||
await withTmpDir(async (tmpDir: string) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
|
||||
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||
process.env["GITHUB_SHA"] = "a".repeat(40);
|
||||
process.env["GITHUB_RUN_ID"] = "100";
|
||||
process.env["GITHUB_RUN_ATTEMPT"] = "2";
|
||||
process.env["GITHUB_REPOSITORY"] = "octocat/HelloWorld";
|
||||
process.env["CODEQL_ACTION_ANALYSIS_KEY"] = "analysis-key";
|
||||
process.env["RUNNER_OS"] = "macOS";
|
||||
|
||||
const getRequiredInput = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
getRequiredInput.withArgs("matrix").resolves("input/matrix");
|
||||
|
||||
const statusReport = await createStatusReportBase(
|
||||
"init",
|
||||
"failure",
|
||||
new Date("May 19, 2023 05:19:00"),
|
||||
"failure cause",
|
||||
"exception stack trace",
|
||||
);
|
||||
|
||||
t.assert(typeof statusReport.job_run_uuid === "string");
|
||||
t.assert(statusReport.workflow_run_id === 100);
|
||||
t.assert(statusReport.workflow_run_attempt === 2);
|
||||
t.assert(
|
||||
statusReport.workflow_name === (process.env["GITHUB_WORKFLOW"] || ""),
|
||||
);
|
||||
t.assert(statusReport.job_name === (process.env["GITHUB_JOB"] || ""));
|
||||
t.assert(statusReport.analysis_key === "analysis-key");
|
||||
t.assert(statusReport.commit_oid === process.env["GITHUB_SHA"]);
|
||||
t.assert(statusReport.ref === process.env["GITHUB_REF"]);
|
||||
t.assert(statusReport.action_name === "init");
|
||||
t.assert(statusReport.action_oid === "unknown");
|
||||
t.assert(
|
||||
statusReport.started_at === process.env[EnvVar.WORKFLOW_STARTED_AT],
|
||||
);
|
||||
t.assert(
|
||||
statusReport.action_started_at ===
|
||||
new Date("May 19, 2023 05:19:00").toISOString(),
|
||||
);
|
||||
t.assert(statusReport.status === "failure");
|
||||
t.assert(statusReport.cause === "failure cause");
|
||||
t.assert(statusReport.exception === "exception stack trace");
|
||||
t.assert(statusReport.runner_os === process.env["RUNNER_OS"]);
|
||||
t.assert(typeof statusReport.action_version === "string");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -239,126 +239,6 @@ function getRefFromEnv(): string {
|
|||
return refEnv;
|
||||
}
|
||||
|
||||
export type ActionName =
|
||||
| "init"
|
||||
| "autobuild"
|
||||
| "finish"
|
||||
| "upload-sarif"
|
||||
| "init-post"
|
||||
| "resolve-environment";
|
||||
export type ActionStatus =
|
||||
| "starting"
|
||||
| "aborted"
|
||||
| "success"
|
||||
| "failure"
|
||||
| "user-error";
|
||||
|
||||
// Any status report may include an array of EventReports associated with it.
|
||||
export interface EventReport {
|
||||
/** An enumerable description of the event. */
|
||||
event: string;
|
||||
/** Time this event started. */
|
||||
started_at: string;
|
||||
/** Time this event ended. */
|
||||
completed_at: string;
|
||||
/** eg: `success`, `failure`, `timeout`, etc. */
|
||||
exit_status?: string;
|
||||
/** If the event is language-specific. */
|
||||
language?: string;
|
||||
/**
|
||||
* A generic JSON blob of data related to this event.
|
||||
* Use Object.assign() to append additional fields to the object.
|
||||
*/
|
||||
properties?: object;
|
||||
}
|
||||
|
||||
export interface StatusReportBase {
|
||||
/**
|
||||
* UUID representing the job run that this status report belongs to. We
|
||||
* generate our own UUID here because Actions currently does not expose a
|
||||
* unique job run identifier. This UUID will allow us to more easily match
|
||||
* reports from different steps in the same workflow job.
|
||||
*
|
||||
* If and when Actions does expose a unique job ID, we plan to populate a
|
||||
* separate int field, `job_run_id`, with the Actions-generated identifier,
|
||||
* as it will allow us to more easily join our telemetry data with Actions
|
||||
* telemetry tables.
|
||||
*/
|
||||
job_run_uuid: string;
|
||||
/** ID of the workflow run containing the action run. */
|
||||
workflow_run_id: number;
|
||||
/** Attempt number of the run containing the action run. */
|
||||
workflow_run_attempt: number;
|
||||
/** Workflow name. Converted to analysis_name further down the pipeline.. */
|
||||
workflow_name: string;
|
||||
/** Job name from the workflow. */
|
||||
job_name: string;
|
||||
/** Analysis key, normally composed from the workflow path and job name. */
|
||||
analysis_key: string;
|
||||
/** Value of the matrix for this instantiation of the job. */
|
||||
matrix_vars?: string;
|
||||
/** Commit oid that the workflow was triggered on. */
|
||||
commit_oid: string;
|
||||
/** Ref that the workflow was triggered on. */
|
||||
ref: string;
|
||||
/** Name of the action being executed. */
|
||||
action_name: ActionName;
|
||||
/** Version of the action being executed, as a ref. */
|
||||
action_ref?: string;
|
||||
/** Version of the action being executed, as a commit oid. */
|
||||
action_oid: string;
|
||||
/** Time the first action started. Normally the init action. */
|
||||
started_at: string;
|
||||
/** Time this action started. */
|
||||
action_started_at: string;
|
||||
/** Time this action completed, or undefined if not yet completed. */
|
||||
completed_at?: string;
|
||||
/** State this action is currently in. */
|
||||
status: ActionStatus;
|
||||
/**
|
||||
* Testing environment: Set if non-production environment.
|
||||
* The server accepts one of the following values:
|
||||
* `["", "qa-rc", "qa-rc-1", "qa-rc-2", "qa-experiment-1", "qa-experiment-2", "qa-experiment-3"]`.
|
||||
*/
|
||||
testing_environment: string;
|
||||
/**
|
||||
* Information about the enablement of the ML-powered JS query pack.
|
||||
*
|
||||
* @see {@link util.getMlPoweredJsQueriesStatus}
|
||||
*/
|
||||
ml_powered_javascript_queries?: string;
|
||||
/** Cause of the failure (or undefined if status is not failure). */
|
||||
cause?: string;
|
||||
/** Stack trace of the failure (or undefined if status is not failure). */
|
||||
exception?: string;
|
||||
/** Action runner operating system (context runner.os). */
|
||||
runner_os: string;
|
||||
/** Action runner hardware architecture (context runner.arch). */
|
||||
runner_arch?: string;
|
||||
/** Action runner operating system release (x.y.z from os.release()). */
|
||||
runner_os_release?: string;
|
||||
/** Action version (x.y.z from package.json). */
|
||||
action_version: string;
|
||||
/** CodeQL CLI version (x.y.z from the CLI). */
|
||||
codeql_version?: string;
|
||||
}
|
||||
|
||||
export interface DatabaseCreationTimings {
|
||||
scanned_language_extraction_duration_ms?: number;
|
||||
trap_import_duration_ms?: number;
|
||||
}
|
||||
|
||||
export function getActionsStatus(
|
||||
error?: unknown,
|
||||
otherFailureCause?: string,
|
||||
): ActionStatus {
|
||||
if (error || otherFailureCause) {
|
||||
return error instanceof UserError ? "user-error" : "failure";
|
||||
} else {
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
|
||||
export function getActionVersion(): string {
|
||||
return pkg.version!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import * as actionsUtil from "./actions-util";
|
|||
import * as analyze from "./analyze";
|
||||
import * as api from "./api-client";
|
||||
import * as configUtils from "./config-utils";
|
||||
import * as statusReport from "./status-report";
|
||||
import {
|
||||
setupTests,
|
||||
setupActionsVars,
|
||||
|
|
@ -27,9 +28,9 @@ test("analyze action with RAM & threads from environment variables", async (t) =
|
|||
process.env["GITHUB_REPOSITORY"] = "github/codeql-action-fake-repository";
|
||||
process.env["GITHUB_API_URL"] = "https://api.github.com";
|
||||
sinon
|
||||
.stub(api, "createStatusReportBase")
|
||||
.resolves({} as actionsUtil.StatusReportBase);
|
||||
sinon.stub(api, "sendStatusReport").resolves(true);
|
||||
.stub(statusReport, "createStatusReportBase")
|
||||
.resolves({} as statusReport.StatusReportBase);
|
||||
sinon.stub(statusReport, "sendStatusReport").resolves(true);
|
||||
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
|
||||
|
||||
const gitHubVersion: util.GitHubVersion = {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import * as actionsUtil from "./actions-util";
|
|||
import * as analyze from "./analyze";
|
||||
import * as api from "./api-client";
|
||||
import * as configUtils from "./config-utils";
|
||||
import * as statusReport from "./status-report";
|
||||
import {
|
||||
setupTests,
|
||||
setupActionsVars,
|
||||
|
|
@ -27,9 +28,9 @@ test("analyze action with RAM & threads from action inputs", async (t) => {
|
|||
process.env["GITHUB_REPOSITORY"] = "github/codeql-action-fake-repository";
|
||||
process.env["GITHUB_API_URL"] = "https://api.github.com";
|
||||
sinon
|
||||
.stub(api, "createStatusReportBase")
|
||||
.resolves({} as actionsUtil.StatusReportBase);
|
||||
sinon.stub(api, "sendStatusReport").resolves(true);
|
||||
.stub(statusReport, "createStatusReportBase")
|
||||
.resolves({} as statusReport.StatusReportBase);
|
||||
sinon.stub(statusReport, "sendStatusReport").resolves(true);
|
||||
const gitHubVersion: util.GitHubVersion = {
|
||||
type: util.GitHubVariant.DOTCOM,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { performance } from "perf_hooks";
|
|||
import * as core from "@actions/core";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import { DatabaseCreationTimings } from "./actions-util";
|
||||
import {
|
||||
CodeQLAnalysisError,
|
||||
dbIsFinalized,
|
||||
|
|
@ -15,7 +14,6 @@ import {
|
|||
runQueries,
|
||||
} from "./analyze";
|
||||
import { getApiDetails, getGitHubVersion } from "./api-client";
|
||||
import * as api from "./api-client";
|
||||
import { runAutobuild } from "./autobuild";
|
||||
import { getCodeQL } from "./codeql";
|
||||
import { Config, getConfig, getMlPoweredJsQueriesStatus } from "./config-utils";
|
||||
|
|
@ -25,6 +23,13 @@ import { Feature, Features } from "./feature-flags";
|
|||
import { Language } from "./languages";
|
||||
import { getActionsLogger, Logger } from "./logging";
|
||||
import { parseRepositoryNwo } from "./repository";
|
||||
import * as statusReport from "./status-report";
|
||||
import {
|
||||
createStatusReportBase,
|
||||
DatabaseCreationTimings,
|
||||
getActionsStatus,
|
||||
StatusReportBase,
|
||||
} from "./status-report";
|
||||
import { getTotalCacheSize, uploadTrapCaches } from "./trap-caching";
|
||||
import * as uploadLib from "./upload-lib";
|
||||
import { UploadResult } from "./upload-lib";
|
||||
|
|
@ -36,8 +41,8 @@ interface AnalysisStatusReport
|
|||
QueriesStatusReport {}
|
||||
|
||||
interface FinishStatusReport
|
||||
extends actionsUtil.StatusReportBase,
|
||||
actionsUtil.DatabaseCreationTimings,
|
||||
extends StatusReportBase,
|
||||
DatabaseCreationTimings,
|
||||
AnalysisStatusReport {}
|
||||
|
||||
interface FinishWithTrapUploadStatusReport extends FinishStatusReport {
|
||||
|
|
@ -57,18 +62,15 @@ export async function sendStatusReport(
|
|||
didUploadTrapCaches: boolean,
|
||||
logger: Logger,
|
||||
) {
|
||||
const status = actionsUtil.getActionsStatus(
|
||||
error,
|
||||
stats?.analyze_failure_language,
|
||||
);
|
||||
const statusReportBase = await api.createStatusReportBase(
|
||||
const status = getActionsStatus(error, stats?.analyze_failure_language);
|
||||
const statusReportBase = await createStatusReportBase(
|
||||
"finish",
|
||||
status,
|
||||
startedAt,
|
||||
error?.message,
|
||||
error?.stack,
|
||||
);
|
||||
const statusReport: FinishStatusReport = {
|
||||
const report: FinishStatusReport = {
|
||||
...statusReportBase,
|
||||
...(config
|
||||
? {
|
||||
|
|
@ -80,15 +82,15 @@ export async function sendStatusReport(
|
|||
};
|
||||
if (config && didUploadTrapCaches) {
|
||||
const trapCacheUploadStatusReport: FinishWithTrapUploadStatusReport = {
|
||||
...statusReport,
|
||||
...report,
|
||||
trap_cache_upload_duration_ms: Math.round(trapCacheUploadTime || 0),
|
||||
trap_cache_upload_size_bytes: Math.round(
|
||||
await getTotalCacheSize(config.trapCaches, logger),
|
||||
),
|
||||
};
|
||||
await api.sendStatusReport(trapCacheUploadStatusReport);
|
||||
await statusReport.sendStatusReport(trapCacheUploadStatusReport);
|
||||
} else {
|
||||
await api.sendStatusReport(statusReport);
|
||||
await statusReport.sendStatusReport(report);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,8 +183,8 @@ async function run() {
|
|||
const logger = getActionsLogger();
|
||||
try {
|
||||
if (
|
||||
!(await api.sendStatusReport(
|
||||
await api.createStatusReportBase("finish", "starting", startedAt),
|
||||
!(await statusReport.sendStatusReport(
|
||||
await createStatusReportBase("finish", "starting", startedAt),
|
||||
))
|
||||
) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import * as toolrunner from "@actions/exec/lib/toolrunner";
|
|||
import del from "del";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
import { DatabaseCreationTimings, EventReport } from "./actions-util";
|
||||
import * as analysisPaths from "./analysis-paths";
|
||||
import { CodeQL, getCodeQL } from "./codeql";
|
||||
import * as configUtils from "./config-utils";
|
||||
|
|
@ -18,6 +17,7 @@ import {
|
|||
} from "./feature-flags";
|
||||
import { isScannedLanguage, Language } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
import { DatabaseCreationTimings, EventReport } from "./status-report";
|
||||
import { endTracingForCluster } from "./tracer-config";
|
||||
import { validateSarifFileSchema } from "./upload-lib";
|
||||
import * as util from "./util";
|
||||
|
|
|
|||
|
|
@ -1,31 +1,14 @@
|
|||
import * as os from "os";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as githubUtils from "@actions/github/lib/utils";
|
||||
import * as retry from "@octokit/plugin-retry";
|
||||
import consoleLogLevel from "console-log-level";
|
||||
|
||||
import { getActionVersion, getRequiredInput } from "./actions-util";
|
||||
import {
|
||||
ActionName,
|
||||
ActionStatus,
|
||||
StatusReportBase,
|
||||
getActionVersion,
|
||||
getOptionalInput,
|
||||
getRef,
|
||||
getRequiredInput,
|
||||
getWorkflowEventName,
|
||||
getWorkflowRunAttempt,
|
||||
getWorkflowRunID,
|
||||
} from "./actions-util";
|
||||
import { EnvVar } from "./environment";
|
||||
import {
|
||||
getCachedCodeQlVersion,
|
||||
getRequiredEnvParam,
|
||||
GITHUB_DOTCOM_URL,
|
||||
GitHubVariant,
|
||||
GitHubVersion,
|
||||
isHTTPError,
|
||||
isInTestMode,
|
||||
parseGitHubUrl,
|
||||
parseMatrixInput,
|
||||
} from "./util";
|
||||
|
|
@ -136,187 +119,6 @@ export async function getGitHubVersion(): Promise<GitHubVersion> {
|
|||
return cachedGitHubVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a StatusReport.
|
||||
*
|
||||
* @param actionName The name of the action, e.g. 'init', 'finish', 'upload-sarif'
|
||||
* @param status The status. Must be 'success', 'failure', or 'starting'
|
||||
* @param startedAt The time this action started executing.
|
||||
* @param cause Cause of failure (only supply if status is 'failure')
|
||||
* @param exception Exception (only supply if status is 'failure')
|
||||
*/
|
||||
export async function createStatusReportBase(
|
||||
actionName: ActionName,
|
||||
status: ActionStatus,
|
||||
actionStartedAt: Date,
|
||||
cause?: string,
|
||||
exception?: string,
|
||||
): Promise<StatusReportBase> {
|
||||
const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || "";
|
||||
const ref = await getRef();
|
||||
const jobRunUUID = process.env[EnvVar.JOB_RUN_UUID] || "";
|
||||
const workflowRunID = getWorkflowRunID();
|
||||
const workflowRunAttempt = getWorkflowRunAttempt();
|
||||
const workflowName = process.env["GITHUB_WORKFLOW"] || "";
|
||||
const jobName = process.env["GITHUB_JOB"] || "";
|
||||
const analysis_key = await getAnalysisKey();
|
||||
let workflowStartedAt = process.env[EnvVar.WORKFLOW_STARTED_AT];
|
||||
if (workflowStartedAt === undefined) {
|
||||
workflowStartedAt = actionStartedAt.toISOString();
|
||||
core.exportVariable(EnvVar.WORKFLOW_STARTED_AT, workflowStartedAt);
|
||||
}
|
||||
const runnerOs = getRequiredEnvParam("RUNNER_OS");
|
||||
const codeQlCliVersion = getCachedCodeQlVersion();
|
||||
const actionRef = process.env["GITHUB_ACTION_REF"];
|
||||
const testingEnvironment = process.env[EnvVar.TESTING_ENVIRONMENT] || "";
|
||||
// re-export the testing environment variable so that it is available to subsequent steps,
|
||||
// even if it was only set for this step
|
||||
if (testingEnvironment !== "") {
|
||||
core.exportVariable(EnvVar.TESTING_ENVIRONMENT, testingEnvironment);
|
||||
}
|
||||
|
||||
const statusReport: StatusReportBase = {
|
||||
job_run_uuid: jobRunUUID,
|
||||
workflow_run_id: workflowRunID,
|
||||
workflow_run_attempt: workflowRunAttempt,
|
||||
workflow_name: workflowName,
|
||||
job_name: jobName,
|
||||
analysis_key,
|
||||
commit_oid: commitOid,
|
||||
ref,
|
||||
action_name: actionName,
|
||||
action_ref: actionRef,
|
||||
action_oid: "unknown", // TODO decide if it's possible to fill this in
|
||||
started_at: workflowStartedAt,
|
||||
action_started_at: actionStartedAt.toISOString(),
|
||||
status,
|
||||
testing_environment: testingEnvironment,
|
||||
runner_os: runnerOs,
|
||||
action_version: getActionVersion(),
|
||||
};
|
||||
|
||||
// Add optional parameters
|
||||
if (cause) {
|
||||
statusReport.cause = cause;
|
||||
}
|
||||
if (exception) {
|
||||
statusReport.exception = exception;
|
||||
}
|
||||
if (
|
||||
status === "success" ||
|
||||
status === "failure" ||
|
||||
status === "aborted" ||
|
||||
status === "user-error"
|
||||
) {
|
||||
statusReport.completed_at = new Date().toISOString();
|
||||
}
|
||||
const matrix = getRequiredInput("matrix");
|
||||
if (matrix) {
|
||||
statusReport.matrix_vars = matrix;
|
||||
}
|
||||
if ("RUNNER_ARCH" in process.env) {
|
||||
// RUNNER_ARCH is available only in GHES 3.4 and later
|
||||
// Values other than X86, X64, ARM, or ARM64 are discarded server side
|
||||
statusReport.runner_arch = process.env["RUNNER_ARCH"];
|
||||
}
|
||||
if (runnerOs === "Windows" || runnerOs === "macOS") {
|
||||
statusReport.runner_os_release = os.release();
|
||||
}
|
||||
if (codeQlCliVersion !== undefined) {
|
||||
statusReport.codeql_version = codeQlCliVersion;
|
||||
}
|
||||
|
||||
return statusReport;
|
||||
}
|
||||
|
||||
const GENERIC_403_MSG =
|
||||
"The repo on which this action is running is not opted-in to CodeQL code scanning.";
|
||||
const GENERIC_404_MSG =
|
||||
"Not authorized to use the CodeQL code scanning feature on this repo.";
|
||||
const OUT_OF_DATE_MSG =
|
||||
"CodeQL Action is out-of-date. Please upgrade to the latest version of codeql-action.";
|
||||
const INCOMPATIBLE_MSG =
|
||||
"CodeQL Action version is incompatible with the code scanning endpoint. Please update to a compatible version of codeql-action.";
|
||||
|
||||
/**
|
||||
* Send a status report to the code_scanning/analysis/status endpoint.
|
||||
*
|
||||
* Optionally checks the response from the API endpoint and sets the action
|
||||
* as failed if the status report failed. This is only expected to be used
|
||||
* when sending a 'starting' report.
|
||||
*
|
||||
* Returns whether sending the status report was successful of not.
|
||||
*/
|
||||
export async function sendStatusReport<S extends StatusReportBase>(
|
||||
statusReport: S,
|
||||
): Promise<boolean> {
|
||||
const statusReportJSON = JSON.stringify(statusReport);
|
||||
core.debug(`Sending status report: ${statusReportJSON}`);
|
||||
// If in test mode we don't want to upload the results
|
||||
if (isInTestMode()) {
|
||||
core.debug("In test mode. Status reports are not uploaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
const nwo = getRequiredEnvParam("GITHUB_REPOSITORY");
|
||||
const [owner, repo] = nwo.split("/");
|
||||
const client = getApiClient();
|
||||
|
||||
try {
|
||||
await client.request(
|
||||
"PUT /repos/:owner/:repo/code-scanning/analysis/status",
|
||||
{
|
||||
owner,
|
||||
repo,
|
||||
data: statusReportJSON,
|
||||
},
|
||||
);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
if (isHTTPError(e)) {
|
||||
switch (e.status) {
|
||||
case 403:
|
||||
if (
|
||||
getWorkflowEventName() === "push" &&
|
||||
process.env["GITHUB_ACTOR"] === "dependabot[bot]"
|
||||
) {
|
||||
core.setFailed(
|
||||
'Workflows triggered by Dependabot on the "push" event run with read-only access. ' +
|
||||
"Uploading Code Scanning results requires write access. " +
|
||||
'To use Code Scanning with Dependabot, please ensure you are using the "pull_request" event for this workflow and avoid triggering on the "push" event for Dependabot branches. ' +
|
||||
"See https://docs.github.com/en/code-security/secure-coding/configuring-code-scanning#scanning-on-push for more information on how to configure these events.",
|
||||
);
|
||||
} else {
|
||||
core.setFailed(e.message || GENERIC_403_MSG);
|
||||
}
|
||||
return false;
|
||||
case 404:
|
||||
core.setFailed(GENERIC_404_MSG);
|
||||
return false;
|
||||
case 422:
|
||||
// schema incompatibility when reporting status
|
||||
// this means that this action version is no longer compatible with the API
|
||||
// we still want to continue as it is likely the analysis endpoint will work
|
||||
if (getRequiredEnvParam("GITHUB_SERVER_URL") !== GITHUB_DOTCOM_URL) {
|
||||
core.debug(INCOMPATIBLE_MSG);
|
||||
} else {
|
||||
core.debug(OUT_OF_DATE_MSG);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// something else has gone wrong and the request/response will be logged by octokit
|
||||
// it's possible this is a transient error and we should continue scanning
|
||||
core.error(
|
||||
"An unexpected error occurred when sending code scanning status report.",
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the currently executing workflow relative to the repository root.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
import * as core from "@actions/core";
|
||||
|
||||
import {
|
||||
getActionsStatus,
|
||||
getActionVersion,
|
||||
getOptionalInput,
|
||||
getTemporaryDirectory,
|
||||
StatusReportBase,
|
||||
} from "./actions-util";
|
||||
import {
|
||||
createStatusReportBase,
|
||||
getGitHubVersion,
|
||||
sendStatusReport,
|
||||
} from "./api-client";
|
||||
import { getGitHubVersion } from "./api-client";
|
||||
import { determineAutobuildLanguages, runAutobuild } from "./autobuild";
|
||||
import * as configUtils from "./config-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Language } from "./languages";
|
||||
import { getActionsLogger } from "./logging";
|
||||
import {
|
||||
StatusReportBase,
|
||||
getActionsStatus,
|
||||
createStatusReportBase,
|
||||
sendStatusReport,
|
||||
} from "./status-report";
|
||||
import {
|
||||
checkGitHubVersionInRange,
|
||||
initializeEnvironment,
|
||||
|
|
|
|||
|
|
@ -6,22 +6,19 @@
|
|||
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import {
|
||||
getActionsStatus,
|
||||
getTemporaryDirectory,
|
||||
printDebugLogs,
|
||||
StatusReportBase,
|
||||
} from "./actions-util";
|
||||
import {
|
||||
createStatusReportBase,
|
||||
getGitHubVersion,
|
||||
sendStatusReport,
|
||||
} from "./api-client";
|
||||
import { getTemporaryDirectory, printDebugLogs } from "./actions-util";
|
||||
import { getGitHubVersion } from "./api-client";
|
||||
import * as debugArtifacts from "./debug-artifacts";
|
||||
import { Features } from "./feature-flags";
|
||||
import * as initActionPostHelper from "./init-action-post-helper";
|
||||
import { getActionsLogger } from "./logging";
|
||||
import { parseRepositoryNwo } from "./repository";
|
||||
import {
|
||||
StatusReportBase,
|
||||
sendStatusReport,
|
||||
createStatusReportBase,
|
||||
getActionsStatus,
|
||||
} from "./status-report";
|
||||
import {
|
||||
checkGitHubVersionInRange,
|
||||
getRequiredEnvParam,
|
||||
|
|
|
|||
|
|
@ -4,18 +4,12 @@ import * as core from "@actions/core";
|
|||
import { v4 as uuidV4 } from "uuid";
|
||||
|
||||
import {
|
||||
getActionsStatus,
|
||||
getActionVersion,
|
||||
getOptionalInput,
|
||||
getRequiredInput,
|
||||
getTemporaryDirectory,
|
||||
StatusReportBase,
|
||||
} from "./actions-util";
|
||||
import {
|
||||
createStatusReportBase,
|
||||
getGitHubVersion,
|
||||
sendStatusReport,
|
||||
} from "./api-client";
|
||||
import { getGitHubVersion } from "./api-client";
|
||||
import { CodeQL } from "./codeql";
|
||||
import * as configUtils from "./config-utils";
|
||||
import { getMlPoweredJsQueriesStatus } from "./config-utils";
|
||||
|
|
@ -26,6 +20,12 @@ import { Language } from "./languages";
|
|||
import { getActionsLogger, Logger } from "./logging";
|
||||
import { parseRepositoryNwo } from "./repository";
|
||||
import { ToolsSource } from "./setup-codeql";
|
||||
import {
|
||||
StatusReportBase,
|
||||
createStatusReportBase,
|
||||
getActionsStatus,
|
||||
sendStatusReport,
|
||||
} from "./status-report";
|
||||
import { getTotalCacheSize } from "./trap-caching";
|
||||
import {
|
||||
checkForTimeout,
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import * as core from "@actions/core";
|
||||
|
||||
import {
|
||||
getActionsStatus,
|
||||
getOptionalInput,
|
||||
getRequiredInput,
|
||||
getTemporaryDirectory,
|
||||
} from "./actions-util";
|
||||
import {
|
||||
createStatusReportBase,
|
||||
getGitHubVersion,
|
||||
sendStatusReport,
|
||||
} from "./api-client";
|
||||
import { getGitHubVersion } from "./api-client";
|
||||
import { CommandInvocationError } from "./codeql";
|
||||
import * as configUtils from "./config-utils";
|
||||
import { Language, resolveAlias } from "./languages";
|
||||
import { getActionsLogger } from "./logging";
|
||||
import { runResolveBuildEnvironment } from "./resolve-environment";
|
||||
import {
|
||||
sendStatusReport,
|
||||
createStatusReportBase,
|
||||
getActionsStatus,
|
||||
} from "./status-report";
|
||||
import { checkForTimeout, checkGitHubVersionInRange, wrapError } from "./util";
|
||||
|
||||
const ACTION_NAME = "resolve-environment";
|
||||
|
|
|
|||
60
src/status-report.test.ts
Normal file
60
src/status-report.test.ts
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import test from "ava";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import { EnvVar } from "./environment";
|
||||
import { createStatusReportBase } from "./status-report";
|
||||
import { setupTests, setupActionsVars } from "./testing-utils";
|
||||
import { withTmpDir } from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
test("createStatusReportBase", async (t) => {
|
||||
await withTmpDir(async (tmpDir: string) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
|
||||
process.env["CODEQL_ACTION_ANALYSIS_KEY"] = "analysis-key";
|
||||
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||
process.env["GITHUB_REPOSITORY"] = "octocat/HelloWorld";
|
||||
process.env["GITHUB_RUN_ATTEMPT"] = "2";
|
||||
process.env["GITHUB_RUN_ID"] = "100";
|
||||
process.env["GITHUB_SHA"] = "a".repeat(40);
|
||||
process.env["RUNNER_OS"] = "macOS";
|
||||
|
||||
const getRequiredInput = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
getRequiredInput.withArgs("matrix").resolves("input/matrix");
|
||||
|
||||
const statusReport = await createStatusReportBase(
|
||||
"init",
|
||||
"failure",
|
||||
new Date("May 19, 2023 05:19:00"),
|
||||
"failure cause",
|
||||
"exception stack trace",
|
||||
);
|
||||
|
||||
t.assert(typeof statusReport.job_run_uuid === "string");
|
||||
t.assert(statusReport.workflow_run_id === 100);
|
||||
t.assert(statusReport.workflow_run_attempt === 2);
|
||||
t.assert(
|
||||
statusReport.workflow_name === (process.env["GITHUB_WORKFLOW"] || ""),
|
||||
);
|
||||
t.assert(statusReport.job_name === (process.env["GITHUB_JOB"] || ""));
|
||||
t.assert(statusReport.analysis_key === "analysis-key");
|
||||
t.assert(statusReport.commit_oid === process.env["GITHUB_SHA"]);
|
||||
t.assert(statusReport.ref === process.env["GITHUB_REF"]);
|
||||
t.assert(statusReport.action_name === "init");
|
||||
t.assert(statusReport.action_oid === "unknown");
|
||||
t.assert(
|
||||
statusReport.started_at === process.env[EnvVar.WORKFLOW_STARTED_AT],
|
||||
);
|
||||
t.assert(
|
||||
statusReport.action_started_at ===
|
||||
new Date("May 19, 2023 05:19:00").toISOString(),
|
||||
);
|
||||
t.assert(statusReport.status === "failure");
|
||||
t.assert(statusReport.cause === "failure cause");
|
||||
t.assert(statusReport.exception === "exception stack trace");
|
||||
t.assert(statusReport.runner_os === process.env["RUNNER_OS"]);
|
||||
t.assert(typeof statusReport.action_version === "string");
|
||||
});
|
||||
});
|
||||
324
src/status-report.ts
Normal file
324
src/status-report.ts
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
import * as os from "os";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import {
|
||||
getWorkflowEventName,
|
||||
getOptionalInput,
|
||||
getRef,
|
||||
getWorkflowRunID,
|
||||
getWorkflowRunAttempt,
|
||||
getActionVersion,
|
||||
getRequiredInput,
|
||||
} from "./actions-util";
|
||||
import { getAnalysisKey, getApiClient } from "./api-client";
|
||||
import { EnvVar } from "./environment";
|
||||
import {
|
||||
UserError,
|
||||
isHTTPError,
|
||||
getRequiredEnvParam,
|
||||
getCachedCodeQlVersion,
|
||||
isInTestMode,
|
||||
GITHUB_DOTCOM_URL,
|
||||
} from "./util";
|
||||
|
||||
export type ActionName =
|
||||
| "init"
|
||||
| "autobuild"
|
||||
| "finish"
|
||||
| "upload-sarif"
|
||||
| "init-post"
|
||||
| "resolve-environment";
|
||||
export type ActionStatus =
|
||||
| "starting"
|
||||
| "aborted"
|
||||
| "success"
|
||||
| "failure"
|
||||
| "user-error";
|
||||
|
||||
export interface StatusReportBase {
|
||||
/**
|
||||
* UUID representing the job run that this status report belongs to. We
|
||||
* generate our own UUID here because Actions currently does not expose a
|
||||
* unique job run identifier. This UUID will allow us to more easily match
|
||||
* reports from different steps in the same workflow job.
|
||||
*
|
||||
* If and when Actions does expose a unique job ID, we plan to populate a
|
||||
* separate int field, `job_run_id`, with the Actions-generated identifier,
|
||||
* as it will allow us to more easily join our telemetry data with Actions
|
||||
* telemetry tables.
|
||||
*/
|
||||
job_run_uuid: string;
|
||||
/** ID of the workflow run containing the action run. */
|
||||
workflow_run_id: number;
|
||||
/** Attempt number of the run containing the action run. */
|
||||
workflow_run_attempt: number;
|
||||
/** Workflow name. Converted to analysis_name further down the pipeline.. */
|
||||
workflow_name: string;
|
||||
/** Job name from the workflow. */
|
||||
job_name: string;
|
||||
/** Analysis key, normally composed from the workflow path and job name. */
|
||||
analysis_key: string;
|
||||
/** Value of the matrix for this instantiation of the job. */
|
||||
matrix_vars?: string;
|
||||
/** Commit oid that the workflow was triggered on. */
|
||||
commit_oid: string;
|
||||
/** Ref that the workflow was triggered on. */
|
||||
ref: string;
|
||||
/** Name of the action being executed. */
|
||||
action_name: ActionName;
|
||||
/** Version of the action being executed, as a ref. */
|
||||
action_ref?: string;
|
||||
/** Version of the action being executed, as a commit oid. */
|
||||
action_oid: string;
|
||||
/** Time the first action started. Normally the init action. */
|
||||
started_at: string;
|
||||
/** Time this action started. */
|
||||
action_started_at: string;
|
||||
/** Time this action completed, or undefined if not yet completed. */
|
||||
completed_at?: string;
|
||||
/** State this action is currently in. */
|
||||
status: ActionStatus;
|
||||
/**
|
||||
* Testing environment: Set if non-production environment.
|
||||
* The server accepts one of the following values:
|
||||
* `["", "qa-rc", "qa-rc-1", "qa-rc-2", "qa-experiment-1", "qa-experiment-2", "qa-experiment-3"]`.
|
||||
*/
|
||||
testing_environment: string;
|
||||
/**
|
||||
* Information about the enablement of the ML-powered JS query pack.
|
||||
*
|
||||
* @see {@link util.getMlPoweredJsQueriesStatus}
|
||||
*/
|
||||
ml_powered_javascript_queries?: string;
|
||||
/** Cause of the failure (or undefined if status is not failure). */
|
||||
cause?: string;
|
||||
/** Stack trace of the failure (or undefined if status is not failure). */
|
||||
exception?: string;
|
||||
/** Action runner operating system (context runner.os). */
|
||||
runner_os: string;
|
||||
/** Action runner hardware architecture (context runner.arch). */
|
||||
runner_arch?: string;
|
||||
/** Action runner operating system release (x.y.z from os.release()). */
|
||||
runner_os_release?: string;
|
||||
/** Action version (x.y.z from package.json). */
|
||||
action_version: string;
|
||||
/** CodeQL CLI version (x.y.z from the CLI). */
|
||||
codeql_version?: string;
|
||||
}
|
||||
|
||||
export interface DatabaseCreationTimings {
|
||||
scanned_language_extraction_duration_ms?: number;
|
||||
trap_import_duration_ms?: number;
|
||||
}
|
||||
|
||||
export function getActionsStatus(
|
||||
error?: unknown,
|
||||
otherFailureCause?: string,
|
||||
): ActionStatus {
|
||||
if (error || otherFailureCause) {
|
||||
return error instanceof UserError ? "user-error" : "failure";
|
||||
} else {
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
|
||||
// Any status report may include an array of EventReports associated with it.
|
||||
export interface EventReport {
|
||||
/** An enumerable description of the event. */
|
||||
event: string;
|
||||
/** Time this event started. */
|
||||
started_at: string;
|
||||
/** Time this event ended. */
|
||||
completed_at: string;
|
||||
/** eg: `success`, `failure`, `timeout`, etc. */
|
||||
exit_status?: string;
|
||||
/** If the event is language-specific. */
|
||||
language?: string;
|
||||
/**
|
||||
* A generic JSON blob of data related to this event.
|
||||
* Use Object.assign() to append additional fields to the object.
|
||||
*/
|
||||
properties?: object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose a StatusReport.
|
||||
*
|
||||
* @param actionName The name of the action, e.g. 'init', 'finish', 'upload-sarif'
|
||||
* @param status The status. Must be 'success', 'failure', or 'starting'
|
||||
* @param startedAt The time this action started executing.
|
||||
* @param cause Cause of failure (only supply if status is 'failure')
|
||||
* @param exception Exception (only supply if status is 'failure')
|
||||
*/
|
||||
export async function createStatusReportBase(
|
||||
actionName: ActionName,
|
||||
status: ActionStatus,
|
||||
actionStartedAt: Date,
|
||||
cause?: string,
|
||||
exception?: string,
|
||||
): Promise<StatusReportBase> {
|
||||
const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || "";
|
||||
const ref = await getRef();
|
||||
const jobRunUUID = process.env[EnvVar.JOB_RUN_UUID] || "";
|
||||
const workflowRunID = getWorkflowRunID();
|
||||
const workflowRunAttempt = getWorkflowRunAttempt();
|
||||
const workflowName = process.env["GITHUB_WORKFLOW"] || "";
|
||||
const jobName = process.env["GITHUB_JOB"] || "";
|
||||
const analysis_key = await getAnalysisKey();
|
||||
let workflowStartedAt = process.env[EnvVar.WORKFLOW_STARTED_AT];
|
||||
if (workflowStartedAt === undefined) {
|
||||
workflowStartedAt = actionStartedAt.toISOString();
|
||||
core.exportVariable(EnvVar.WORKFLOW_STARTED_AT, workflowStartedAt);
|
||||
}
|
||||
const runnerOs = getRequiredEnvParam("RUNNER_OS");
|
||||
const codeQlCliVersion = getCachedCodeQlVersion();
|
||||
const actionRef = process.env["GITHUB_ACTION_REF"];
|
||||
const testingEnvironment = process.env[EnvVar.TESTING_ENVIRONMENT] || "";
|
||||
// re-export the testing environment variable so that it is available to subsequent steps,
|
||||
// even if it was only set for this step
|
||||
if (testingEnvironment !== "") {
|
||||
core.exportVariable(EnvVar.TESTING_ENVIRONMENT, testingEnvironment);
|
||||
}
|
||||
|
||||
const statusReport: StatusReportBase = {
|
||||
job_run_uuid: jobRunUUID,
|
||||
workflow_run_id: workflowRunID,
|
||||
workflow_run_attempt: workflowRunAttempt,
|
||||
workflow_name: workflowName,
|
||||
job_name: jobName,
|
||||
analysis_key,
|
||||
commit_oid: commitOid,
|
||||
ref,
|
||||
action_name: actionName,
|
||||
action_ref: actionRef,
|
||||
action_oid: "unknown", // TODO decide if it's possible to fill this in
|
||||
started_at: workflowStartedAt,
|
||||
action_started_at: actionStartedAt.toISOString(),
|
||||
status,
|
||||
testing_environment: testingEnvironment,
|
||||
runner_os: runnerOs,
|
||||
action_version: getActionVersion(),
|
||||
};
|
||||
|
||||
// Add optional parameters
|
||||
if (cause) {
|
||||
statusReport.cause = cause;
|
||||
}
|
||||
if (exception) {
|
||||
statusReport.exception = exception;
|
||||
}
|
||||
if (
|
||||
status === "success" ||
|
||||
status === "failure" ||
|
||||
status === "aborted" ||
|
||||
status === "user-error"
|
||||
) {
|
||||
statusReport.completed_at = new Date().toISOString();
|
||||
}
|
||||
const matrix = getRequiredInput("matrix");
|
||||
if (matrix) {
|
||||
statusReport.matrix_vars = matrix;
|
||||
}
|
||||
if ("RUNNER_ARCH" in process.env) {
|
||||
// RUNNER_ARCH is available only in GHES 3.4 and later
|
||||
// Values other than X86, X64, ARM, or ARM64 are discarded server side
|
||||
statusReport.runner_arch = process.env["RUNNER_ARCH"];
|
||||
}
|
||||
if (runnerOs === "Windows" || runnerOs === "macOS") {
|
||||
statusReport.runner_os_release = os.release();
|
||||
}
|
||||
if (codeQlCliVersion !== undefined) {
|
||||
statusReport.codeql_version = codeQlCliVersion;
|
||||
}
|
||||
|
||||
return statusReport;
|
||||
}
|
||||
|
||||
const GENERIC_403_MSG =
|
||||
"The repo on which this action is running is not opted-in to CodeQL code scanning.";
|
||||
const GENERIC_404_MSG =
|
||||
"Not authorized to use the CodeQL code scanning feature on this repo.";
|
||||
const OUT_OF_DATE_MSG =
|
||||
"CodeQL Action is out-of-date. Please upgrade to the latest version of codeql-action.";
|
||||
const INCOMPATIBLE_MSG =
|
||||
"CodeQL Action version is incompatible with the code scanning endpoint. Please update to a compatible version of codeql-action.";
|
||||
|
||||
/**
|
||||
* Send a status report to the code_scanning/analysis/status endpoint.
|
||||
*
|
||||
* Optionally checks the response from the API endpoint and sets the action
|
||||
* as failed if the status report failed. This is only expected to be used
|
||||
* when sending a 'starting' report.
|
||||
*
|
||||
* Returns whether sending the status report was successful of not.
|
||||
*/
|
||||
export async function sendStatusReport<S extends StatusReportBase>(
|
||||
statusReport: S,
|
||||
): Promise<boolean> {
|
||||
const statusReportJSON = JSON.stringify(statusReport);
|
||||
core.debug(`Sending status report: ${statusReportJSON}`);
|
||||
// If in test mode we don't want to upload the results
|
||||
if (isInTestMode()) {
|
||||
core.debug("In test mode. Status reports are not uploaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
const nwo = getRequiredEnvParam("GITHUB_REPOSITORY");
|
||||
const [owner, repo] = nwo.split("/");
|
||||
const client = getApiClient();
|
||||
|
||||
try {
|
||||
await client.request(
|
||||
"PUT /repos/:owner/:repo/code-scanning/analysis/status",
|
||||
{
|
||||
owner,
|
||||
repo,
|
||||
data: statusReportJSON,
|
||||
},
|
||||
);
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
if (isHTTPError(e)) {
|
||||
switch (e.status) {
|
||||
case 403:
|
||||
if (
|
||||
getWorkflowEventName() === "push" &&
|
||||
process.env["GITHUB_ACTOR"] === "dependabot[bot]"
|
||||
) {
|
||||
core.setFailed(
|
||||
'Workflows triggered by Dependabot on the "push" event run with read-only access. ' +
|
||||
"Uploading Code Scanning results requires write access. " +
|
||||
'To use Code Scanning with Dependabot, please ensure you are using the "pull_request" event for this workflow and avoid triggering on the "push" event for Dependabot branches. ' +
|
||||
"See https://docs.github.com/en/code-security/secure-coding/configuring-code-scanning#scanning-on-push for more information on how to configure these events.",
|
||||
);
|
||||
} else {
|
||||
core.setFailed(e.message || GENERIC_403_MSG);
|
||||
}
|
||||
return false;
|
||||
case 404:
|
||||
core.setFailed(GENERIC_404_MSG);
|
||||
return false;
|
||||
case 422:
|
||||
// schema incompatibility when reporting status
|
||||
// this means that this action version is no longer compatible with the API
|
||||
// we still want to continue as it is likely the analysis endpoint will work
|
||||
if (getRequiredEnvParam("GITHUB_SERVER_URL") !== GITHUB_DOTCOM_URL) {
|
||||
core.debug(INCOMPATIBLE_MSG);
|
||||
} else {
|
||||
core.debug(OUT_OF_DATE_MSG);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// something else has gone wrong and the request/response will be logged by octokit
|
||||
// it's possible this is a transient error and we should continue scanning
|
||||
core.error(
|
||||
"An unexpected error occurred when sending code scanning status report.",
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,14 @@ import * as core from "@actions/core";
|
|||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import { getActionVersion } from "./actions-util";
|
||||
import { createStatusReportBase, sendStatusReport } from "./api-client";
|
||||
import { getActionsLogger } from "./logging";
|
||||
import { parseRepositoryNwo } from "./repository";
|
||||
import {
|
||||
createStatusReportBase,
|
||||
sendStatusReport,
|
||||
StatusReportBase,
|
||||
getActionsStatus,
|
||||
} from "./status-report";
|
||||
import * as upload_lib from "./upload-lib";
|
||||
import {
|
||||
getRequiredEnvParam,
|
||||
|
|
@ -14,7 +19,7 @@ import {
|
|||
} from "./util";
|
||||
|
||||
interface UploadSarifStatusReport
|
||||
extends actionsUtil.StatusReportBase,
|
||||
extends StatusReportBase,
|
||||
upload_lib.UploadStatusReport {}
|
||||
|
||||
async function sendSuccessStatusReport(
|
||||
|
|
@ -72,7 +77,7 @@ async function run() {
|
|||
await sendStatusReport(
|
||||
await createStatusReportBase(
|
||||
"upload-sarif",
|
||||
actionsUtil.getActionsStatus(error),
|
||||
getActionsStatus(error),
|
||||
startedAt,
|
||||
message,
|
||||
error.stack,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue