import * as core from "@actions/core"; import { Action, ActionState, runInActions } from "./action-common"; import * as actionsUtil from "./actions-util"; import { getActionVersion, getTemporaryDirectory } from "./actions-util"; import * as analyses from "./analyses"; import { getGitHubVersion } from "./api-client"; import { initFeatures } from "./feature-flags"; import { Logger } from "./logging"; import { getRepositoryNwo } from "./repository"; import { InvalidSarifUploadError } from "./sarif"; import { createStatusReportBase, sendStatusReport, StatusReportBase, getActionsStatus, ActionName, isThirdPartyAnalysis, } from "./status-report"; import * as upload_lib from "./upload-lib"; import { postProcessAndUploadSarif } from "./upload-sarif"; import { ConfigurationError, checkActionVersion, checkDiskUsage, initializeEnvironment, shouldSkipSarifUpload, wrapError, } from "./util"; interface UploadSarifStatusReport extends StatusReportBase, upload_lib.UploadStatusReport {} async function sendSuccessStatusReport( startedAt: Date, uploadStats: upload_lib.UploadStatusReport, logger: Logger, ) { const statusReportBase = await createStatusReportBase( ActionName.UploadSarif, "success", startedAt, undefined, await checkDiskUsage(logger), logger, ); if (statusReportBase !== undefined) { const statusReport: UploadSarifStatusReport = { ...statusReportBase, ...uploadStats, }; await sendStatusReport(statusReport); } } async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) { // To capture errors appropriately, keep as much code within the try-catch as // possible, and only use safe functions outside. try { initializeEnvironment(getActionVersion()); const gitHubVersion = await getGitHubVersion(); checkActionVersion(getActionVersion(), gitHubVersion); // Make inputs accessible in the `post` step. actionsUtil.persistInputs(); const repositoryNwo = getRepositoryNwo(); const features = initFeatures( gitHubVersion, repositoryNwo, getTemporaryDirectory(), logger, ); const startingStatusReportBase = await createStatusReportBase( ActionName.UploadSarif, "starting", startedAt, undefined, await checkDiskUsage(logger), logger, ); if (startingStatusReportBase !== undefined) { await sendStatusReport(startingStatusReportBase); } // `sarifPath` can either be a path to a single file, or a path to a directory. const sarifPath = actionsUtil.getRequiredInput("sarif_file"); const checkoutPath = actionsUtil.getRequiredInput("checkout_path"); const category = actionsUtil.getOptionalInput("category"); const uploadResults = await postProcessAndUploadSarif( logger, features, "always", checkoutPath, sarifPath, category, ); // Fail if we didn't upload anything. if (Object.keys(uploadResults).length === 0) { throw new ConfigurationError( `No SARIF files found to upload in "${sarifPath}".`, ); } const codeScanningResult = uploadResults[analyses.AnalysisKind.CodeScanning]; if (codeScanningResult !== undefined) { core.setOutput("sarif-id", codeScanningResult.sarifID); } core.setOutput("sarif-ids", JSON.stringify(uploadResults)); // We don't upload results in test mode, so don't wait for processing if (shouldSkipSarifUpload()) { core.debug( "SARIF upload disabled by an environment variable. Waiting for processing is disabled.", ); } else if (actionsUtil.getRequiredInput("wait-for-processing") === "true") { if (codeScanningResult !== undefined) { await upload_lib.waitForProcessing( getRepositoryNwo(), codeScanningResult.sarifID, logger, ); } // The code quality service does not currently have an endpoint to wait for SARIF processing, // so we can't wait for that here. } await sendSuccessStatusReport( startedAt, codeScanningResult?.statusReport || {}, logger, ); } catch (unwrappedError) { const error = isThirdPartyAnalysis(ActionName.UploadSarif) && unwrappedError instanceof InvalidSarifUploadError ? new ConfigurationError(unwrappedError.message) : wrapError(unwrappedError); const message = error.message; core.setFailed(message); const errorStatusReportBase = await createStatusReportBase( ActionName.UploadSarif, getActionsStatus(error), startedAt, undefined, await checkDiskUsage(logger), logger, message, error.stack, ); if (errorStatusReportBase !== undefined) { await sendStatusReport(errorStatusReportBase); } return; } } /** Defines the `upload-sarif` Action. */ const uploadSarif: Action = { name: ActionName.UploadSarif, run, }; export async function runWrapper() { await runInActions(uploadSarif); }