@netlify/build 27.20.3 → 27.20.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/core/bin.js +42 -59
- package/lib/core/build.js +333 -536
- package/lib/core/config.js +94 -159
- package/lib/core/constants.js +95 -135
- package/lib/core/dev.js +26 -30
- package/lib/core/dry.js +18 -36
- package/lib/core/feature_flags.js +13 -16
- package/lib/core/flags.js +168 -169
- package/lib/core/lingering.js +44 -61
- package/lib/core/main.js +94 -136
- package/lib/core/missing_side_file.js +12 -24
- package/lib/core/normalize_flags.js +52 -63
- package/lib/core/severity.js +13 -15
- package/lib/core/user_node_version.js +26 -35
- package/lib/env/changes.js +29 -37
- package/lib/env/main.js +10 -15
- package/lib/env/metadata.js +63 -76
- package/lib/error/api.js +31 -40
- package/lib/error/build.js +27 -38
- package/lib/error/cancel.js +5 -6
- package/lib/error/colors.js +7 -9
- package/lib/error/handle.js +38 -49
- package/lib/error/info.js +26 -35
- package/lib/error/monitor/location.js +12 -17
- package/lib/error/monitor/normalize.js +75 -85
- package/lib/error/monitor/print.js +19 -41
- package/lib/error/monitor/report.js +102 -121
- package/lib/error/monitor/start.js +43 -56
- package/lib/error/parse/clean_stack.js +52 -69
- package/lib/error/parse/location.js +40 -52
- package/lib/error/parse/normalize.js +18 -23
- package/lib/error/parse/parse.js +59 -93
- package/lib/error/parse/plugin.js +42 -57
- package/lib/error/parse/properties.js +13 -20
- package/lib/error/parse/serialize_log.js +29 -37
- package/lib/error/parse/serialize_status.js +15 -23
- package/lib/error/parse/stack.js +29 -38
- package/lib/error/type.js +132 -150
- package/lib/install/functions.js +16 -24
- package/lib/install/local.js +31 -48
- package/lib/install/main.js +52 -66
- package/lib/install/missing.js +40 -53
- package/lib/log/colors.js +15 -22
- package/lib/log/description.js +16 -21
- package/lib/log/header.js +11 -13
- package/lib/log/header_func.js +11 -15
- package/lib/log/logger.js +88 -119
- package/lib/log/messages/compatibility.js +100 -158
- package/lib/log/messages/config.js +76 -92
- package/lib/log/messages/core.js +40 -60
- package/lib/log/messages/core_steps.js +63 -92
- package/lib/log/messages/dry.js +31 -53
- package/lib/log/messages/install.js +21 -28
- package/lib/log/messages/ipc.js +21 -30
- package/lib/log/messages/mutations.js +51 -71
- package/lib/log/messages/plugins.js +18 -31
- package/lib/log/messages/status.js +12 -14
- package/lib/log/messages/steps.js +14 -18
- package/lib/log/old_version.js +23 -32
- package/lib/log/serialize.js +7 -10
- package/lib/log/stream.js +48 -65
- package/lib/log/theme.js +22 -23
- package/lib/plugins/child/diff.js +31 -40
- package/lib/plugins/child/error.js +20 -26
- package/lib/plugins/child/lazy.js +11 -14
- package/lib/plugins/child/load.js +15 -22
- package/lib/plugins/child/logic.js +51 -58
- package/lib/plugins/child/main.js +32 -46
- package/lib/plugins/child/run.js +18 -27
- package/lib/plugins/child/status.js +52 -63
- package/lib/plugins/child/typescript.js +19 -36
- package/lib/plugins/child/utils.js +36 -49
- package/lib/plugins/child/validate.js +25 -28
- package/lib/plugins/compatibility.js +64 -92
- package/lib/plugins/error.js +29 -35
- package/lib/plugins/events.js +7 -12
- package/lib/plugins/expected_version.js +61 -99
- package/lib/plugins/ipc.js +79 -102
- package/lib/plugins/list.js +49 -62
- package/lib/plugins/load.js +44 -64
- package/lib/plugins/manifest/check.js +64 -85
- package/lib/plugins/manifest/load.js +34 -37
- package/lib/plugins/manifest/main.js +16 -21
- package/lib/plugins/manifest/path.js +18 -25
- package/lib/plugins/manifest/validate.js +77 -94
- package/lib/plugins/node_version.js +22 -42
- package/lib/plugins/options.js +45 -78
- package/lib/plugins/pinned_version.js +58 -106
- package/lib/plugins/resolve.js +91 -133
- package/lib/plugins/spawn.js +43 -61
- package/lib/plugins_core/add.js +26 -40
- package/lib/plugins_core/build_command.js +47 -72
- package/lib/plugins_core/deploy/buildbot_client.js +61 -87
- package/lib/plugins_core/deploy/index.js +47 -71
- package/lib/plugins_core/edge_functions/index.js +73 -116
- package/lib/plugins_core/edge_functions/lib/error.js +13 -17
- package/lib/plugins_core/edge_functions/lib/internal_manifest.js +45 -55
- package/lib/plugins_core/edge_functions/validate_manifest/validate_edge_functions_manifest.js +65 -80
- package/lib/plugins_core/functions/error.js +88 -128
- package/lib/plugins_core/functions/feature_flags.js +5 -5
- package/lib/plugins_core/functions/index.js +98 -145
- package/lib/plugins_core/functions/utils.js +36 -57
- package/lib/plugins_core/functions/zisi.js +35 -52
- package/lib/plugins_core/functions_install/index.js +8 -11
- package/lib/plugins_core/list.js +15 -22
- package/lib/status/add.js +26 -32
- package/lib/status/colors.js +14 -19
- package/lib/status/load_error.js +8 -9
- package/lib/status/report.js +72 -126
- package/lib/status/success.js +10 -14
- package/lib/steps/core_step.js +54 -89
- package/lib/steps/error.js +50 -87
- package/lib/steps/get.js +33 -41
- package/lib/steps/plugin.js +53 -83
- package/lib/steps/return.js +24 -51
- package/lib/steps/run_core_steps.js +119 -171
- package/lib/steps/run_step.js +154 -270
- package/lib/steps/run_steps.js +91 -174
- package/lib/steps/update_config.js +45 -72
- package/lib/telemetry/main.js +89 -128
- package/lib/time/aggregate.js +84 -110
- package/lib/time/main.js +23 -34
- package/lib/time/measure.js +11 -15
- package/lib/time/report.js +32 -44
- package/lib/utils/errors.js +10 -9
- package/lib/utils/json.js +11 -15
- package/lib/utils/omit.js +3 -4
- package/lib/utils/package.js +19 -22
- package/lib/utils/remove_falsy.js +5 -7
- package/lib/utils/resolve.js +30 -34
- package/lib/utils/runtime.js +4 -4
- package/lib/utils/semver.js +19 -25
- package/package.json +15 -8
|
@@ -2,95 +2,85 @@
|
|
|
2
2
|
// unique IDs, etc. which defeats that grouping. So we normalize those to make
|
|
3
3
|
// them consistent
|
|
4
4
|
export const normalizeGroupingMessage = function (message, type) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return messageB
|
|
15
|
-
}
|
|
16
|
-
|
|
5
|
+
const messageA = removeDependenciesLogs(message, type);
|
|
6
|
+
const messageB = NORMALIZE_REGEXPS.reduce(normalizeMessage, messageA);
|
|
7
|
+
// If this is a functions bundling error, we'll use additional normalization
|
|
8
|
+
// rules to group errors more aggressively.
|
|
9
|
+
if (type === 'functionsBundling') {
|
|
10
|
+
return FUNCTIONS_BUNDLING_REGEXPS.reduce(normalizeMessage, messageB);
|
|
11
|
+
}
|
|
12
|
+
return messageB;
|
|
13
|
+
};
|
|
17
14
|
// Discard debug/info installation information
|
|
18
15
|
const removeDependenciesLogs = function (message, type) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
16
|
+
if (type !== 'dependencies') {
|
|
17
|
+
return message;
|
|
18
|
+
}
|
|
19
|
+
return message.split('\n').filter(isErrorLine).join('\n');
|
|
20
|
+
};
|
|
26
21
|
const isErrorLine = function (line) {
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
22
|
+
return ERROR_LINES.some((errorLine) => line.startsWith(errorLine));
|
|
23
|
+
};
|
|
30
24
|
const ERROR_LINES = [
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
]
|
|
36
|
-
|
|
25
|
+
// Prefix for npm
|
|
26
|
+
'npm ERR!',
|
|
27
|
+
// Prefix for Yarn
|
|
28
|
+
'error',
|
|
29
|
+
];
|
|
37
30
|
const normalizeMessage = function (message, [regExp, replacement]) {
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
31
|
+
return message.replace(regExp, replacement);
|
|
32
|
+
};
|
|
41
33
|
const NORMALIZE_REGEXPS = [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
]
|
|
86
|
-
|
|
34
|
+
// Base64 URL
|
|
35
|
+
[/(data:[^;]+;base64),[\w+/-=]+/g, 'dataURI'],
|
|
36
|
+
// File paths
|
|
37
|
+
[/(["'`, ]|^)([^"'`, \n]*[/\\][^"'`, \n]*)(?=["'`, ]|$)/gm, '$1/file/path'],
|
|
38
|
+
// Semantic versions
|
|
39
|
+
[/\d+\.\d+\.\d+(-\d+)?/g, '1.0.0'],
|
|
40
|
+
[/version "[^"]+"/g, 'version "1.0.0"'],
|
|
41
|
+
// Cypress plugin prints the user's platform
|
|
42
|
+
[/^Platform: .*/gm, ''],
|
|
43
|
+
// URLs
|
|
44
|
+
[/https?:[\w.+~!$&'()*,;=:@/?#]+/g, 'https://domain.com'],
|
|
45
|
+
// Numbers, e.g. number of issues/problems
|
|
46
|
+
[/\d+/g, '0'],
|
|
47
|
+
// Hexadecimal strings
|
|
48
|
+
[/[\da-fA-F-]{6,}/g, 'hex'],
|
|
49
|
+
// On unknown inputs, we print the inputs
|
|
50
|
+
[/(does not accept any inputs but you specified: ).*/, '$1'],
|
|
51
|
+
[/(Unknown inputs for plugin).*/, '$1'],
|
|
52
|
+
[/(Plugin inputs should be one of: ).*/, '$1'],
|
|
53
|
+
// On required inputs, we print the inputs
|
|
54
|
+
[/^Plugin inputs[^]*/gm, ''],
|
|
55
|
+
[/(Required inputs for plugin).*/gm, '$1'],
|
|
56
|
+
// Netlify Functions validation check
|
|
57
|
+
[/(should target a directory, not a regular file):.*/, '$1'],
|
|
58
|
+
// zip-it-and-ship-it error when there is an `import()` but dependencies
|
|
59
|
+
// were not installed
|
|
60
|
+
[/(Cannot find module) '([^']+)'/g, "$1 'moduleName'"],
|
|
61
|
+
[/(A Netlify Function is using) "[^"]+"/g, '$1 "moduleName"'],
|
|
62
|
+
// Deploy upload errors include the filename
|
|
63
|
+
[/(Upload cancelled).*/g, '$1'],
|
|
64
|
+
[/(aborting upload of file).*/g, '$1'],
|
|
65
|
+
// netlify-plugin-inline-critical-css errors prints a list of file paths
|
|
66
|
+
[/Searched in: .*/g, ''],
|
|
67
|
+
// netlify-plugin-subfont prints font name in errors
|
|
68
|
+
[/(is not supported yet): .*/, '$1'],
|
|
69
|
+
// netlify-plugin-subfont prints generic information in every error that
|
|
70
|
+
// is highly build-specific
|
|
71
|
+
[/^(vers?ions|Plugin configuration|Subfont called with): {[^}]+}/gm, ''],
|
|
72
|
+
[/^Resolved entry points: \[[^\]]+]/gm, ''],
|
|
73
|
+
// netlify-plugin-minify-html parse error
|
|
74
|
+
[/(Parse Error):[^]*/, '$1'],
|
|
75
|
+
// Multiple empty lines
|
|
76
|
+
[/^\s*$/gm, ''],
|
|
77
|
+
];
|
|
87
78
|
const FUNCTIONS_BUNDLING_REGEXPS = [
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
]
|
|
79
|
+
// String literals and identifiers
|
|
80
|
+
[/"([^"]+)"/g, '""'],
|
|
81
|
+
[/'([^']+)'/g, "''"],
|
|
82
|
+
[/`([^`]+)`/g, '``'],
|
|
83
|
+
// Rust crates
|
|
84
|
+
[/(?:Downloaded \S+ v[\d.]+\s*)+/gm, 'Downloaded crates'],
|
|
85
|
+
[/(?:Compiling \S+ v[\d.]+\s*)+/gm, 'Compiled crates'],
|
|
86
|
+
];
|
|
@@ -1,42 +1,20 @@
|
|
|
1
|
-
import { log } from '../../log/logger.js'
|
|
2
|
-
|
|
1
|
+
import { log } from '../../log/logger.js';
|
|
3
2
|
// Print event payload instead of sending actual request during tests
|
|
4
|
-
export const printEventForTest = function (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const eventString = JSON.stringify(
|
|
23
|
-
{
|
|
24
|
-
errorClass,
|
|
25
|
-
errorMessage,
|
|
26
|
-
context,
|
|
27
|
-
groupingHash,
|
|
28
|
-
severity,
|
|
29
|
-
unhandled,
|
|
30
|
-
location,
|
|
31
|
-
packageName,
|
|
32
|
-
pluginPackageJson: pluginPackageJson !== undefined,
|
|
33
|
-
homepage,
|
|
34
|
-
tsConfig,
|
|
35
|
-
BUILD_ID,
|
|
36
|
-
other,
|
|
37
|
-
},
|
|
38
|
-
null,
|
|
39
|
-
2,
|
|
40
|
-
)
|
|
41
|
-
log(logs, `\nError monitoring payload:\n${eventString}`)
|
|
42
|
-
}
|
|
3
|
+
export const printEventForTest = function ({ name: errorClass, message: errorMessage }, { context, groupingHash, severity, unhandled, _metadata: { location, plugin: { packageName, homepage } = {}, pluginPackageJson, tsConfig, env: { BUILD_ID } = {}, other, }, }, logs) {
|
|
4
|
+
const eventString = JSON.stringify({
|
|
5
|
+
errorClass,
|
|
6
|
+
errorMessage,
|
|
7
|
+
context,
|
|
8
|
+
groupingHash,
|
|
9
|
+
severity,
|
|
10
|
+
unhandled,
|
|
11
|
+
location,
|
|
12
|
+
packageName,
|
|
13
|
+
pluginPackageJson: pluginPackageJson !== undefined,
|
|
14
|
+
homepage,
|
|
15
|
+
tsConfig,
|
|
16
|
+
BUILD_ID,
|
|
17
|
+
other,
|
|
18
|
+
}, null, 2);
|
|
19
|
+
log(logs, `\nError monitoring payload:\n${eventString}`);
|
|
20
|
+
};
|
|
@@ -1,139 +1,120 @@
|
|
|
1
|
-
import { type as osType, freemem, totalmem } from 'os'
|
|
2
|
-
import { promisify } from 'util'
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
import { getLocationMetadata } from './location.js'
|
|
12
|
-
import { normalizeGroupingMessage } from './normalize.js'
|
|
13
|
-
import { printEventForTest } from './print.js'
|
|
14
|
-
|
|
1
|
+
import { type as osType, freemem, totalmem } from 'os';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import osName from 'os-name';
|
|
4
|
+
import { getEnvMetadata } from '../../env/metadata.js';
|
|
5
|
+
import { log } from '../../log/logger.js';
|
|
6
|
+
import { parseErrorInfo } from '../parse/parse.js';
|
|
7
|
+
import { getHomepage } from '../parse/plugin.js';
|
|
8
|
+
import { getLocationMetadata } from './location.js';
|
|
9
|
+
import { normalizeGroupingMessage } from './normalize.js';
|
|
10
|
+
import { printEventForTest } from './print.js';
|
|
15
11
|
// Report a build failure for monitoring purpose
|
|
16
12
|
export const reportBuildError = async function ({ error, errorMonitor, childEnv, logs, testOpts }) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
13
|
+
if (errorMonitor === undefined) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const { errorInfo, type, severity, title, group = title } = parseErrorInfo(error);
|
|
17
|
+
const severityA = getSeverity(severity, errorInfo);
|
|
18
|
+
const groupA = getGroup(group, errorInfo);
|
|
19
|
+
const groupingHash = getGroupingHash(groupA, error, type, errorInfo);
|
|
20
|
+
const metadata = getMetadata(errorInfo, childEnv, groupingHash);
|
|
21
|
+
const app = getApp();
|
|
22
|
+
const eventProps = getEventProps({ severity: severityA, group: groupA, groupingHash, metadata, app });
|
|
23
|
+
const errorName = updateErrorName(error, type);
|
|
24
|
+
try {
|
|
25
|
+
await reportError({ errorMonitor, error, logs, testOpts, eventProps });
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
error.name = errorName;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
37
31
|
// Plugin authors test their plugins as local plugins. Errors there are more
|
|
38
32
|
// like development errors, and should be reported as `info` only.
|
|
39
33
|
const getSeverity = function (severity, { location: { loadedFrom } = {} }) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
34
|
+
if (loadedFrom === 'local' || severity === 'none') {
|
|
35
|
+
return 'info';
|
|
36
|
+
}
|
|
37
|
+
return severity;
|
|
38
|
+
};
|
|
47
39
|
const getGroup = function (group, errorInfo) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
40
|
+
if (typeof group !== 'function') {
|
|
41
|
+
return group;
|
|
42
|
+
}
|
|
43
|
+
return group(errorInfo);
|
|
44
|
+
};
|
|
55
45
|
const getGroupingHash = function (group, error, type, errorInfo = {}) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
46
|
+
// If the error has a `normalizedMessage`, we use it as the grouping hash.
|
|
47
|
+
if (errorInfo.normalizedMessage) {
|
|
48
|
+
return errorInfo.normalizedMessage;
|
|
49
|
+
}
|
|
50
|
+
const message = error instanceof Error && typeof error.message === 'string' ? error.message : String(error);
|
|
51
|
+
const messageA = normalizeGroupingMessage(message, type);
|
|
52
|
+
return `${group}\n${messageA}`;
|
|
53
|
+
};
|
|
66
54
|
const getMetadata = function ({ location, plugin, tsConfig }, childEnv, groupingHash) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
55
|
+
const pluginMetadata = getPluginMetadata({ location, plugin });
|
|
56
|
+
const envMetadata = getEnvMetadata(childEnv);
|
|
57
|
+
const locationMetadata = getLocationMetadata(location, envMetadata);
|
|
58
|
+
return { location: locationMetadata, ...pluginMetadata, tsConfig, env: envMetadata, other: { groupingHash } };
|
|
59
|
+
};
|
|
73
60
|
const getPluginMetadata = function ({ location, plugin }) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
61
|
+
if (plugin === undefined) {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
const { pluginPackageJson, ...pluginA } = plugin;
|
|
65
|
+
const homepage = getHomepage(pluginPackageJson, location);
|
|
66
|
+
return { plugin: { ...pluginA, homepage }, pluginPackageJson };
|
|
67
|
+
};
|
|
83
68
|
const getApp = function () {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
69
|
+
return {
|
|
70
|
+
osName: osType(),
|
|
71
|
+
osVersion: osName(),
|
|
72
|
+
freeMemory: freemem(),
|
|
73
|
+
totalMemory: totalmem(),
|
|
74
|
+
};
|
|
75
|
+
};
|
|
92
76
|
// `error.name` is shown proeminently in the Bugsnag UI. We need to update it to
|
|
93
77
|
// match error `type` since it is more granular and useful.
|
|
94
78
|
// But we change it back after Bugsnag is done reporting.
|
|
95
79
|
const updateErrorName = function (error, type) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
80
|
+
const { name } = error;
|
|
81
|
+
// This might fail if `name` is a getter or is non-writable.
|
|
82
|
+
try {
|
|
83
|
+
error.name = type;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// continue regardless error
|
|
87
|
+
}
|
|
88
|
+
return name;
|
|
89
|
+
};
|
|
106
90
|
const reportError = async function ({ errorMonitor, error, logs, testOpts, eventProps }) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
91
|
+
if (testOpts.errorMonitor) {
|
|
92
|
+
printEventForTest(error, eventProps, logs);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
await promisify(errorMonitor.notify)(error, (event) => onError(event, eventProps));
|
|
97
|
+
// Failsafe
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
log(logs, `Error monitor could not notify\n${error.stack}`);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
120
103
|
const getEventProps = function ({ severity, group, groupingHash, metadata, app }) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
104
|
+
// `unhandled` is used to calculate Releases "stabiity score", which is
|
|
105
|
+
// basically the percentage of unhandled errors. Since we handle all errors,
|
|
106
|
+
// we need to implement this according to error types.
|
|
107
|
+
const unhandled = severity === 'error';
|
|
108
|
+
return { severity, context: group, groupingHash, _metadata: metadata, app, unhandled };
|
|
109
|
+
};
|
|
128
110
|
// Add more information to Bugsnag events
|
|
129
111
|
const onError = function (event, eventProps) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
112
|
+
// Bugsnag client requires directly mutating the `event`
|
|
113
|
+
Object.assign(event, {
|
|
114
|
+
...eventProps,
|
|
115
|
+
unhandled: event.unhandled || eventProps.unhandled,
|
|
116
|
+
_metadata: { ...event._metadata, ...eventProps._metadata },
|
|
117
|
+
app: { ...event.app, ...eventProps.app },
|
|
118
|
+
});
|
|
119
|
+
return true;
|
|
120
|
+
};
|
|
@@ -1,71 +1,58 @@
|
|
|
1
|
-
import { fileURLToPath } from 'url'
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { ROOT_PACKAGE_JSON } from '../../utils/json.js'
|
|
8
|
-
|
|
9
|
-
const projectRoot = fileURLToPath(new URL('../../..', import.meta.url))
|
|
10
|
-
|
|
1
|
+
import { fileURLToPath } from 'url';
|
|
2
|
+
import Bugsnag from '@bugsnag/js';
|
|
3
|
+
import memoizeOne from 'memoize-one';
|
|
4
|
+
import { log } from '../../log/logger.js';
|
|
5
|
+
import { ROOT_PACKAGE_JSON } from '../../utils/json.js';
|
|
6
|
+
const projectRoot = fileURLToPath(new URL('../../..', import.meta.url));
|
|
11
7
|
// Start a client to monitor errors
|
|
12
8
|
export const startErrorMonitor = function ({ flags: { mode }, logs, bugsnagKey }) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const isTest = isBugsnagTest(bugsnagKey)
|
|
18
|
-
const releaseStage = getReleaseStage(mode)
|
|
19
|
-
const logger = getLogger(logs, isTest)
|
|
20
|
-
try {
|
|
21
|
-
const errorMonitor = startBugsnag({
|
|
22
|
-
apiKey: bugsnagKey,
|
|
23
|
-
appVersion: `${ROOT_PACKAGE_JSON.name} ${ROOT_PACKAGE_JSON.version}`,
|
|
24
|
-
appType: ROOT_PACKAGE_JSON.name,
|
|
25
|
-
releaseStage,
|
|
26
|
-
logger,
|
|
27
|
-
projectRoot,
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
// Allows knowing the percentage of failed builds per release
|
|
31
|
-
if (!isTest) {
|
|
32
|
-
errorMonitor.startSession()
|
|
9
|
+
if (!bugsnagKey) {
|
|
10
|
+
return;
|
|
33
11
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
12
|
+
const isTest = isBugsnagTest(bugsnagKey);
|
|
13
|
+
const releaseStage = getReleaseStage(mode);
|
|
14
|
+
const logger = getLogger(logs, isTest);
|
|
15
|
+
try {
|
|
16
|
+
const errorMonitor = startBugsnag({
|
|
17
|
+
apiKey: bugsnagKey,
|
|
18
|
+
appVersion: `${ROOT_PACKAGE_JSON.name} ${ROOT_PACKAGE_JSON.version}`,
|
|
19
|
+
appType: ROOT_PACKAGE_JSON.name,
|
|
20
|
+
releaseStage,
|
|
21
|
+
logger,
|
|
22
|
+
projectRoot,
|
|
23
|
+
});
|
|
24
|
+
// Allows knowing the percentage of failed builds per release
|
|
25
|
+
if (!isTest) {
|
|
26
|
+
errorMonitor.startSession();
|
|
27
|
+
}
|
|
28
|
+
return errorMonitor;
|
|
29
|
+
// Failsafe
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
log(logs, `Error monitor could not start\n${error.stack}`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
42
35
|
const isBugsnagTest = function (bugsnagKey) {
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const BUGSNAG_TEST_KEY = '00000000000000000000000000000000'
|
|
47
|
-
|
|
36
|
+
return bugsnagKey === BUGSNAG_TEST_KEY;
|
|
37
|
+
};
|
|
38
|
+
const BUGSNAG_TEST_KEY = '00000000000000000000000000000000';
|
|
48
39
|
// Bugsnag.start() caches a global instance and warns on duplicate calls.
|
|
49
40
|
// This ensures the warning message is not shown when calling the main function
|
|
50
41
|
// several times.
|
|
51
|
-
const startBugsnag = memoizeOne(Bugsnag.start.bind(Bugsnag), () => true)
|
|
52
|
-
|
|
42
|
+
const startBugsnag = memoizeOne(Bugsnag.start.bind(Bugsnag), () => true);
|
|
53
43
|
// Based the release stage on the `mode`
|
|
54
44
|
const getReleaseStage = function (mode = DEFAULT_RELEASE_STAGE) {
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const DEFAULT_RELEASE_STAGE = 'unknown'
|
|
59
|
-
|
|
45
|
+
return mode;
|
|
46
|
+
};
|
|
47
|
+
const DEFAULT_RELEASE_STAGE = 'unknown';
|
|
60
48
|
// We don't want Bugsnag logs except on warnings/errors.
|
|
61
49
|
// We also want to use our own `log` utility, unprefixed.
|
|
62
50
|
// In tests, we don't print Bugsnag because it sometimes randomly fails to
|
|
63
51
|
// send sessions, which prints warning messags in test snapshots.
|
|
64
52
|
const getLogger = function (logs, isTest) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
53
|
+
const logFunc = isTest ? noop : log.bind(null, logs);
|
|
54
|
+
return { debug: noop, info: noop, warn: logFunc, error: logFunc };
|
|
55
|
+
};
|
|
69
56
|
const noop = function () {
|
|
70
|
-
|
|
71
|
-
}
|
|
57
|
+
// this is a noop function
|
|
58
|
+
};
|