Skip to content

Commit aeab6d4

Browse files
Propagate reporter errors
1 parent 8f07a1c commit aeab6d4

File tree

7 files changed

+87
-65
lines changed

7 files changed

+87
-65
lines changed

packages/core/core/src/Parcel.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ export default class Parcel {
152152
this.#disposable.add(() => this.#watchEvents.dispose());
153153

154154
this.#reporterRunner = new ReporterRunner({
155-
config: this.#config,
156155
options: resolvedOptions,
156+
reporters: await this.#config.getReporters(),
157157
workerFarm: this.#farm,
158158
});
159159
this.#disposable.add(this.#reporterRunner);
@@ -313,7 +313,7 @@ export default class Parcel {
313313
if (options.shouldTrace) {
314314
tracer.enable();
315315
}
316-
this.#reporterRunner.report({
316+
await this.#reporterRunner.report({
317317
type: 'buildStart',
318318
});
319319

@@ -401,6 +401,11 @@ export default class Parcel {
401401
createValidationRequest({optionsRef: this.#optionsRef, assetRequests}),
402402
{force: assetRequests.length > 0},
403403
);
404+
405+
if (this.#reporterRunner.errors.length) {
406+
throw this.#reporterRunner.errors;
407+
}
408+
404409
return event;
405410
} catch (e) {
406411
if (e instanceof BuildAbortError) {

packages/core/core/src/ReporterRunner.js

+28-35
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
NamedBundle,
1313
} from './public/Bundle';
1414
import WorkerFarm, {bus} from '@parcel/workers';
15-
import ParcelConfig from './ParcelConfig';
1615
import logger, {
1716
patchConsole,
1817
unpatchConsole,
@@ -24,23 +23,24 @@ import BundleGraph from './BundleGraph';
2423
import {tracer, PluginTracer} from '@parcel/profiler';
2524

2625
type Opts = {|
27-
config: ParcelConfig,
2826
options: ParcelOptions,
27+
reporters: Array<LoadedPlugin<Reporter>>,
2928
workerFarm: WorkerFarm,
3029
|};
3130

3231
const instances: Set<ReporterRunner> = new Set();
3332

3433
export default class ReporterRunner {
3534
workerFarm: WorkerFarm;
36-
config: ParcelConfig;
35+
errors: Error[];
3736
options: ParcelOptions;
3837
pluginOptions: PluginOptions;
3938
reporters: Array<LoadedPlugin<Reporter>>;
4039

4140
constructor(opts: Opts) {
42-
this.config = opts.config;
41+
this.errors = [];
4342
this.options = opts.options;
43+
this.reporters = opts.reporters;
4444
this.workerFarm = opts.workerFarm;
4545
this.pluginOptions = new PluginOptions(this.options);
4646

@@ -86,40 +86,33 @@ export default class ReporterRunner {
8686
};
8787

8888
async report(event: ReporterEvent) {
89-
// We should catch all errors originating from reporter plugins to prevent infinite loops
90-
try {
91-
let reporters = this.reporters;
92-
if (!reporters) {
93-
this.reporters = await this.config.getReporters();
94-
reporters = this.reporters;
95-
}
96-
97-
for (let reporter of this.reporters) {
98-
let measurement;
99-
try {
100-
// To avoid an infinite loop we don't measure trace events, as they'll
101-
// result in another trace!
102-
if (event.type !== 'trace') {
103-
measurement = tracer.createMeasurement(reporter.name, 'reporter');
104-
}
105-
await reporter.plugin.report({
106-
event,
107-
options: this.pluginOptions,
108-
logger: new PluginLogger({origin: reporter.name}),
109-
tracer: new PluginTracer({
110-
origin: reporter.name,
111-
category: 'reporter',
112-
}),
113-
});
114-
} catch (reportError) {
89+
for (let reporter of this.reporters) {
90+
let measurement;
91+
try {
92+
// To avoid an infinite loop we don't measure trace events, as they'll
93+
// result in another trace!
94+
if (event.type !== 'trace') {
95+
measurement = tracer.createMeasurement(reporter.name, 'reporter');
96+
}
97+
await reporter.plugin.report({
98+
event,
99+
options: this.pluginOptions,
100+
logger: new PluginLogger({origin: reporter.name}),
101+
tracer: new PluginTracer({
102+
origin: reporter.name,
103+
category: 'reporter',
104+
}),
105+
});
106+
} catch (reportError) {
107+
if (event.type !== 'buildSuccess') {
108+
// This will be captured by consumers
115109
INTERNAL_ORIGINAL_CONSOLE.error(reportError);
116-
process.exitCode = 1;
117-
} finally {
118-
measurement && measurement.end();
119110
}
111+
112+
this.errors.push(reportError);
113+
} finally {
114+
measurement && measurement.end();
120115
}
121-
} catch (err) {
122-
INTERNAL_ORIGINAL_CONSOLE.error(err);
123116
}
124117
}
125118

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "@parcel/config-default",
3+
"reporters": ["./test-reporter"]
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export function main() {}

packages/core/integration-tests/test/integration/reporters-load-failure/yarn.lock

Whitespace-only changes.

packages/core/integration-tests/test/reporters.js

+46-27
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import assert from 'assert';
44
import {execSync} from 'child_process';
55
import path from 'path';
66

7-
import {INTERNAL_ORIGINAL_CONSOLE} from '@parcel/logger';
8-
import {bundle} from '@parcel/test-utils';
9-
import sinon from 'sinon';
7+
import {bundler} from '@parcel/test-utils';
108

119
describe('reporters', () => {
1210
let successfulEntry = path.join(
@@ -16,7 +14,14 @@ describe('reporters', () => {
1614
'index.js',
1715
);
1816

19-
let failingEntry = path.join(
17+
let loadReporterFailureEntry = path.join(
18+
__dirname,
19+
'integration',
20+
'reporters-load-failure',
21+
'index.js',
22+
);
23+
24+
let failingReporterEntry = path.join(
2025
__dirname,
2126
'integration',
2227
'reporters-failure',
@@ -32,42 +37,56 @@ describe('reporters', () => {
3237
);
3338
});
3439

35-
it('exit with an error code when an error is emitted', () => {
40+
it('exit with an error code when a reporter fails to load', () => {
3641
assert.throws(() =>
37-
execSync(`parcel build --no-cache ${failingEntry}`, {stdio: 'ignore'}),
42+
execSync(`parcel build --no-cache ${loadReporterFailureEntry}`, {
43+
stdio: 'ignore',
44+
}),
45+
);
46+
});
47+
48+
it('exit with an error code when a reporter emits an error', () => {
49+
assert.throws(() =>
50+
execSync(`parcel build --no-cache ${failingReporterEntry}`, {
51+
stdio: 'ignore',
52+
}),
3853
);
3954
});
4055
});
4156

4257
describe('running on the programmatic api', () => {
43-
let consoleError;
44-
let processExitCode;
58+
it('resolves when no errors are emitted', async () => {
59+
let buildEvent = await bundler(successfulEntry).run();
4560

46-
beforeEach(() => {
47-
processExitCode = process.exitCode;
48-
consoleError = sinon.stub(INTERNAL_ORIGINAL_CONSOLE, 'error');
61+
assert.equal(buildEvent.type, 'buildSuccess');
4962
});
5063

51-
afterEach(() => {
52-
process.exitCode = processExitCode;
53-
sinon.restore();
54-
});
55-
56-
it('exit successfully when no errors are emitted', async () => {
57-
await bundle(successfulEntry);
64+
it('rejects when a reporter fails to load', async () => {
65+
try {
66+
let buildEvent = await bundler(loadReporterFailureEntry).run();
5867

59-
assert(!process.exitCode);
68+
throw new Error(buildEvent);
69+
} catch (err) {
70+
assert.equal(err.name, 'Error');
71+
assert.deepEqual(
72+
err.diagnostics.map(d => d.message),
73+
['Cannot find Parcel plugin "./test-reporter"'],
74+
);
75+
}
6076
});
6177

62-
it('exit with an error code when an error is emitted', async () => {
63-
await bundle(failingEntry);
78+
it('rejects when a reporter emits an error', async () => {
79+
try {
80+
let buildEvent = await bundler(failingReporterEntry).run();
6481

65-
assert.equal(process.exitCode, 1);
66-
assert(
67-
consoleError.calledWithMatch({
68-
message: 'Failed to report buildSuccess',
69-
}),
70-
);
82+
throw new Error(buildEvent);
83+
} catch (err) {
84+
assert.equal(err.name, 'BuildError');
85+
assert.deepEqual(
86+
err.diagnostics.map(d => d.message),
87+
['Failed to report buildSuccess'],
88+
);
89+
}
7190
});
7291
});
7392
});

packages/core/parcel/src/cli.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ async function run(
404404
await exit(1);
405405
}
406406

407-
await exit(process.exitCode);
407+
await exit();
408408
}
409409
}
410410

0 commit comments

Comments
 (0)