Skip to content

Split statuses code into several files #1288

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/build/src/core/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ const { pipeOutput, unpipeOutput } = require('../log/stream')
const { startTimer, endTimer } = require('../log/timer')
const { EVENTS } = require('../plugins/events')
const { callChild } = require('../plugins/ipc')

const { getSuccessStatus, addStatus } = require('./status')
const { getSuccessStatus, addStatus } = require('../status/add')

// Get commands for all events
const getCommands = function(pluginsCommands, netlifyConfig) {
Expand Down
2 changes: 1 addition & 1 deletion packages/build/src/core/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ const { startUtils } = require('../plugins/child/utils')
const { loadPlugins } = require('../plugins/load')
const { getPluginsOptions } = require('../plugins/options')
const { startPlugins, stopPlugins } = require('../plugins/spawn')
const { reportStatuses } = require('../status/report')
const { trackBuildComplete } = require('../telemetry/complete')

const { getCommands, runCommands } = require('./commands')
const { normalizeFlags, loadConfig } = require('./config')
const { doDryRun } = require('./dry')
const { reportStatuses } = require('./status')

/**
* Netlify Build
Expand Down
134 changes: 0 additions & 134 deletions packages/build/src/core/status.js

This file was deleted.

2 changes: 1 addition & 1 deletion packages/build/src/plugins/load.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { reportPluginLoadError } = require('../core/status')
const { reportPluginLoadError } = require('../status/report')

const { callChild } = require('./ipc')

Expand Down
2 changes: 1 addition & 1 deletion packages/build/src/plugins/manifest/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { reportPluginLoadError } = require('../../core/status')
const { reportPluginLoadError } = require('../../status/report')

const { checkInputs } = require('./check')
const { loadManifest } = require('./load')
Expand Down
56 changes: 56 additions & 0 deletions packages/build/src/status/add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// The last event handler of a plugin (except for `onError` and `onEnd`)
// defaults to `utils.status.show({ state: 'success' })` without any `summary`.
const getSuccessStatus = function(newStatus, { commands, event, package }) {
if (newStatus === undefined && isLastMainCommand({ commands, event, package })) {
return IMPLICIT_STATUS
}

return newStatus
}

const isLastMainCommand = function({ commands, event, package }) {
const mainCommands = commands.filter(command => command.package === package && isMainCommand(command))
return mainCommands.length === 0 || mainCommands[mainCommands.length - 1].event === event
}

const isMainCommand = function({ event }) {
return event !== 'onEnd' && event !== 'onError'
}

const IMPLICIT_STATUS = { state: 'success', implicit: true }

// Merge plugin status to the list of plugin statuses.
const addStatus = function({ newStatus, statuses, event, package, packageJson: { version } = {} }) {
// Either:
// - `build.command`
// - no status was set
if (newStatus === undefined) {
return statuses
}

const formerStatus = statuses.find(status => status.package === package)
if (!canOverrideStatus(formerStatus, newStatus)) {
return statuses
}

// Overrides plugin's previous status and add more information
const newStatuses = statuses.filter(status => status !== formerStatus)
return [...newStatuses, { ...newStatus, event, package, version }]
}

const canOverrideStatus = function(formerStatus, newStatus) {
// No previous status
if (formerStatus === undefined) {
return true
}

// Implicit statuses can never override
if (newStatus.implicit) {
return false
}

// Error statuses can only be overwritten by other error statuses
return formerStatus.state === 'success' || newStatus.state !== 'success'
}

module.exports = { getSuccessStatus, addStatus }
25 changes: 25 additions & 0 deletions packages/build/src/status/colors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const stripAnsi = require('strip-ansi')

// Remove colors from statuses
const removeStatusesColors = function(statuses) {
return statuses.map(removeStatusColors)
}

const removeStatusColors = function(status) {
const attributes = COLOR_ATTRIBUTES.map(attribute => removeAttrColor(status, attribute))
return Object.assign({}, status, ...attributes)
}

const COLOR_ATTRIBUTES = ['title', 'summary', 'text']

const removeAttrColor = function(status, attribute) {
const value = status[attribute]
if (value === undefined) {
return {}
}

const valueA = stripAnsi(value)
return { [attribute]: valueA }
}

module.exports = { removeStatusesColors }
57 changes: 57 additions & 0 deletions packages/build/src/status/report.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const { env } = require('process')

const { serializeErrorStatus } = require('../error/parse/serialize_status')
const { logStatuses } = require('../log/main')

const { removeStatusesColors } = require('./colors')

// Errors that happen during plugin loads should be reported as error statuses
const reportPluginLoadError = async function({ error, api, mode, event, package, version }) {
const errorStatus = serializeErrorStatus(error)
const statuses = [{ ...errorStatus, event, package, version }]
await reportStatuses(statuses, api, mode)
}

const reportStatuses = async function(statuses, api, mode) {
const statusesA = removeStatusesColors(statuses)
printStatuses(statusesA, mode)
await sendStatuses(statusesA, api, mode)
}

// When not in production, print statuses to console.
// Only print successful ones, since errors are logged afterwards.
const printStatuses = function(statuses, mode) {
if (mode === 'buildbot') {
return
}

const successStatuses = statuses.filter(shouldPrintStatus)

if (successStatuses.length === 0) {
return
}

logStatuses(successStatuses)
}

const shouldPrintStatus = function({ state, summary }) {
return state === 'success' && summary !== undefined
}

// In production, send statuses to the API
const sendStatuses = async function(statuses, api, mode) {
if ((mode !== 'buildbot' && env.NETLIFY_BUILD_TEST_STATUS !== '1') || api === undefined || !env.DEPLOY_ID) {
return
}

await Promise.all(statuses.map(status => sendStatus(api, status)))
}

const sendStatus = async function(api, { package, version, state, event, title, summary, text }) {
await api.createPluginRun({
deploy_id: env.DEPLOY_ID,
body: { package, version, state, reporting_event: event, title, summary, text },
})
}

module.exports = { reportPluginLoadError, reportStatuses }