UNPKG

@netlify/build

Version:
91 lines (90 loc) 4.31 kB
import { addEventToActiveSpan } from '@netlify/opentelemetry-utils'; import { cancelBuild } from '../error/cancel.js'; import { handleBuildError } from '../error/handle.js'; import { getFullErrorInfo, parseErrorInfo } from '../error/parse/parse.js'; import { serializeErrorStatus } from '../error/parse/serialize_status.js'; import { isPluginLocation } from '../error/types.js'; import { isSoftFailEvent } from '../plugins/events.js'; import { addBuildErrorToActiveSpan } from '../tracing/main.js'; import { isTrustedPlugin } from './plugin.js'; /** * Handle build command errors and plugin errors: * - usually, propagate the error to make the build stop. * - `utils.build.cancelBuild()` also cancels the build by calling the API * - `utils.build.failPlugin()` or post-deploy errors do not make the build * stop, but are still reported, and prevent future events from the same * plugin. * This also computes error statuses that are sent to the API. */ export const handleStepError = function ({ event, newError, childEnv, mode, api, errorMonitor, deployId, coreStep, netlifyConfig, logs, debug, testOpts, }) { addBuildErrorToActiveSpan(newError); // Core steps do not report error statuses if (coreStep !== undefined) { return { newError }; } const fullErrorInfo = getFullErrorInfo({ error: newError, colors: false, debug }); const { errorInfo, message, title, type } = fullErrorInfo; if (type === 'failPlugin' || isSoftFailEvent(event)) { return handleFailPlugin({ fullErrorInfo, newError, childEnv, mode, errorMonitor, netlifyConfig, logs, debug, testOpts, }); } if (type === 'cancelBuild') { const cancellationAttributes = { 'build.cancellation.title': title, 'build.cancellation.message': message, }; if (isPluginLocation(errorInfo.location)) { cancellationAttributes['build.cancellation.packageName'] = errorInfo.location.packageName; } addEventToActiveSpan('build.cancelled', cancellationAttributes); return handleCancelBuild({ fullErrorInfo, newError, api, deployId }); } return handleFailBuild({ fullErrorInfo, newError }); }; /* On `utils.build.failPlugin()` or during `onSuccess` or `onEnd` */ const handleFailPlugin = async function ({ fullErrorInfo, newError, childEnv, mode, errorMonitor, netlifyConfig, logs, debug, testOpts, }) { const newStatus = serializeErrorStatus({ fullErrorInfo, state: 'failed_plugin' }); await handleBuildError(newError, { errorMonitor, netlifyConfig, childEnv, mode, logs, debug, testOpts }); // TODO we should probably use type guard here, but due to the way we build these errorInfo objects I'm not 100% // confident we have all the properties currently required by the type const location = fullErrorInfo.errorInfo.location; return { failedPlugin: [location.packageName], newStatus }; }; /* On `utils.build.cancelBuild()` */ const handleCancelBuild = async function ({ fullErrorInfo, newError, api, deployId }) { const newStatus = serializeErrorStatus({ fullErrorInfo, state: 'canceled_build' }); await cancelBuild({ api, deployId }); return { newError, newStatus }; }; /* On `utils.build.failBuild()` or uncaught exception */ const handleFailBuild = function ({ fullErrorInfo, newError }) { const newStatus = serializeErrorStatus({ fullErrorInfo, state: 'failed_build' }); return { newError, newStatus }; }; /* Unlike community plugins, core plugin and trusted plugin bugs should be handled as system errors */ export const getPluginErrorType = function (error, loadedFrom, packageName) { if (isTrustedPluginBug(error, packageName)) { return { type: 'trustedPlugin' }; } if (!isCorePluginBug(error, loadedFrom)) { return {}; } return { type: 'corePlugin' }; }; const isCorePluginBug = function (error, loadedFrom) { const { severity } = parseErrorInfo(error); return severity === 'warning' && loadedFrom === 'core'; }; const isTrustedPluginBug = function (error, packageName) { const { severity } = parseErrorInfo(error); return severity === 'warning' && isTrustedPlugin(packageName); };