Skip to content

Commit

Permalink
Merge aeab6d4 into e1d3cbe
Browse files Browse the repository at this point in the history
  • Loading branch information
MonicaOlejniczak authored May 23, 2024
2 parents e1d3cbe + aeab6d4 commit ef421f2
Show file tree
Hide file tree
Showing 16 changed files with 166 additions and 36 deletions.
9 changes: 7 additions & 2 deletions packages/core/core/src/Parcel.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ export default class Parcel {
this.#disposable.add(() => this.#watchEvents.dispose());

this.#reporterRunner = new ReporterRunner({
config: this.#config,
options: resolvedOptions,
reporters: await this.#config.getReporters(),
workerFarm: this.#farm,
});
this.#disposable.add(this.#reporterRunner);
Expand Down Expand Up @@ -313,7 +313,7 @@ export default class Parcel {
if (options.shouldTrace) {
tracer.enable();
}
this.#reporterRunner.report({
await this.#reporterRunner.report({
type: 'buildStart',
});

Expand Down Expand Up @@ -401,6 +401,11 @@ export default class Parcel {
createValidationRequest({optionsRef: this.#optionsRef, assetRequests}),
{force: assetRequests.length > 0},
);

if (this.#reporterRunner.errors.length) {
throw this.#reporterRunner.errors;
}

return event;
} catch (e) {
if (e instanceof BuildAbortError) {
Expand Down
62 changes: 28 additions & 34 deletions packages/core/core/src/ReporterRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
NamedBundle,
} from './public/Bundle';
import WorkerFarm, {bus} from '@parcel/workers';
import ParcelConfig from './ParcelConfig';
import logger, {
patchConsole,
unpatchConsole,
Expand All @@ -24,23 +23,24 @@ import BundleGraph from './BundleGraph';
import {tracer, PluginTracer} from '@parcel/profiler';

type Opts = {|
config: ParcelConfig,
options: ParcelOptions,
reporters: Array<LoadedPlugin<Reporter>>,
workerFarm: WorkerFarm,
|};

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

export default class ReporterRunner {
workerFarm: WorkerFarm;
config: ParcelConfig;
errors: Error[];
options: ParcelOptions;
pluginOptions: PluginOptions;
reporters: Array<LoadedPlugin<Reporter>>;

constructor(opts: Opts) {
this.config = opts.config;
this.errors = [];
this.options = opts.options;
this.reporters = opts.reporters;
this.workerFarm = opts.workerFarm;
this.pluginOptions = new PluginOptions(this.options);

Expand Down Expand Up @@ -86,39 +86,33 @@ export default class ReporterRunner {
};

async report(event: ReporterEvent) {
// We should catch all errors originating from reporter plugins to prevent infinite loops
try {
let reporters = this.reporters;
if (!reporters) {
this.reporters = await this.config.getReporters();
reporters = this.reporters;
}

for (let reporter of this.reporters) {
let measurement;
try {
// To avoid an infinite loop we don't measure trace events, as they'll
// result in another trace!
if (event.type !== 'trace') {
measurement = tracer.createMeasurement(reporter.name, 'reporter');
}
await reporter.plugin.report({
event,
options: this.pluginOptions,
logger: new PluginLogger({origin: reporter.name}),
tracer: new PluginTracer({
origin: reporter.name,
category: 'reporter',
}),
});
} catch (reportError) {
for (let reporter of this.reporters) {
let measurement;
try {
// To avoid an infinite loop we don't measure trace events, as they'll
// result in another trace!
if (event.type !== 'trace') {
measurement = tracer.createMeasurement(reporter.name, 'reporter');
}
await reporter.plugin.report({
event,
options: this.pluginOptions,
logger: new PluginLogger({origin: reporter.name}),
tracer: new PluginTracer({
origin: reporter.name,
category: 'reporter',
}),
});
} catch (reportError) {
if (event.type !== 'buildSuccess') {
// This will be captured by consumers
INTERNAL_ORIGINAL_CONSOLE.error(reportError);
} finally {
measurement && measurement.end();
}

this.errors.push(reportError);
} finally {
measurement && measurement.end();
}
} catch (err) {
INTERNAL_ORIGINAL_CONSOLE.error(err);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "@parcel/config-default",
"reporters": ["./test-reporter"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export function main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const { Reporter } = require('@parcel/plugin');

module.exports = new Reporter({
async report({ event }) {
if (event.type === 'buildSuccess') {
throw new Error('Failed to report buildSuccess');
}
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "test-reporter",
"version": "1.0.0",
"main": "index.js"
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "@parcel/config-default",
"reporters": ["./test-reporter"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export function main() {}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "@parcel/config-default",
"reporters": ["./test-reporter"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export function main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { Reporter } = require('@parcel/plugin');

module.exports = new Reporter({
async report({ event }) {}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "test-reporter",
"version": "1.0.0",
"main": "index.js"
}
Empty file.
92 changes: 92 additions & 0 deletions packages/core/integration-tests/test/reporters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// @flow

import assert from 'assert';
import {execSync} from 'child_process';
import path from 'path';

import {bundler} from '@parcel/test-utils';

describe('reporters', () => {
let successfulEntry = path.join(
__dirname,
'integration',
'reporters-success',
'index.js',
);

let loadReporterFailureEntry = path.join(
__dirname,
'integration',
'reporters-load-failure',
'index.js',
);

let failingReporterEntry = path.join(
__dirname,
'integration',
'reporters-failure',
'index.js',
);

describe('running on the cli', () => {
it('exit successfully when no errors are emitted', () => {
assert.doesNotThrow(() =>
execSync(`parcel build --no-cache ${successfulEntry}`, {
stdio: 'ignore',
}),
);
});

it('exit with an error code when a reporter fails to load', () => {
assert.throws(() =>
execSync(`parcel build --no-cache ${loadReporterFailureEntry}`, {
stdio: 'ignore',
}),
);
});

it('exit with an error code when a reporter emits an error', () => {
assert.throws(() =>
execSync(`parcel build --no-cache ${failingReporterEntry}`, {
stdio: 'ignore',
}),
);
});
});

describe('running on the programmatic api', () => {
it('resolves when no errors are emitted', async () => {
let buildEvent = await bundler(successfulEntry).run();

assert.equal(buildEvent.type, 'buildSuccess');
});

it('rejects when a reporter fails to load', async () => {
try {
let buildEvent = await bundler(loadReporterFailureEntry).run();

throw new Error(buildEvent);
} catch (err) {
assert.equal(err.name, 'Error');
assert.deepEqual(
err.diagnostics.map(d => d.message),
['Cannot find Parcel plugin "./test-reporter"'],
);
}
});

it('rejects when a reporter emits an error', async () => {
try {
let buildEvent = await bundler(failingReporterEntry).run();

throw new Error(buildEvent);
} catch (err) {
assert.equal(err.name, 'BuildError');
assert.deepEqual(
err.diagnostics.map(d => d.message),
['Failed to report buildSuccess'],
);
}
});
});
});

0 comments on commit ef421f2

Please sign in to comment.