Skip to content

Commit 844ffbd

Browse files
committed
fix(core): Don't crash on recoverable CLI command error
1 parent ac96af1 commit 844ffbd

File tree

6 files changed

+177
-1
lines changed

6 files changed

+177
-1
lines changed

packages/bundler-plugin-core/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,10 @@ export function sentryUnpluginFactory({
170170
throw e;
171171
}
172172
} else {
173+
// setting the session to "crashed" b/c from a plugin perspective this run failed.
174+
// However, we're intentionally not rethrowing the error to avoid breaking the user build.
173175
sentrySession.status = "crashed";
174-
throw unknownError;
176+
logger.error("An error occurred. Couldn't finish all operations:", unknownError);
175177
}
176178
} finally {
177179
endSession();
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* eslint-disable jest/no-standalone-expect */
2+
/* eslint-disable jest/expect-expect */
3+
import path from "path";
4+
import { createCjsBundles } from "../../utils/create-cjs-bundles-promise";
5+
import { spawn } from "child_process";
6+
7+
describe("Doesn't crash when Sentry responds with HTTP errors during upload and release creation", () => {
8+
test("webpack4", async () => {
9+
const FAKE_SENTRY_PORT = "9876";
10+
11+
const sentryServer = spawn("node", ["fakeSentry.js"], {
12+
stdio: "inherit",
13+
env: { ...process.env, FAKE_SENTRY_PORT },
14+
});
15+
16+
await new Promise<void>((resolve) =>
17+
sentryServer.on("spawn", () => {
18+
resolve();
19+
})
20+
);
21+
22+
const outputDir = path.resolve(__dirname, "out");
23+
24+
for (const bundler of ["webpack4", "webpack5", "esbuild", "rollup", "vite"]) {
25+
await expect(
26+
createCjsBundles(
27+
{
28+
bundle: path.resolve(__dirname, "input", "bundle.js"),
29+
},
30+
outputDir,
31+
{
32+
url: `http://localhost:${FAKE_SENTRY_PORT}`,
33+
authToken: "fake-auth",
34+
org: "fake-org",
35+
project: "fake-project",
36+
release: {
37+
name: "1.0.0",
38+
},
39+
},
40+
[bundler]
41+
)
42+
).resolves.not.toThrow();
43+
}
44+
45+
sentryServer.kill();
46+
});
47+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { createServer } from "http";
2+
3+
const port = process.env["FAKE_SENTRY_PORT"] || 3000;
4+
5+
const server = createServer((req, res) => {
6+
res.statusCode = 503;
7+
res.end("Error: Santry unreachable");
8+
});
9+
10+
server.listen(port, () => {
11+
// eslint-disable-next-line no-console
12+
console.log(`Santry running on http://localhost:${port}/`);
13+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// eslint-disable-next-line no-console
2+
console.log("whatever");

packages/integration-tests/fixtures/error-no-handler/setup.ts

Whitespace-only changes.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import * as vite from "vite";
2+
import * as path from "path";
3+
import * as rollup from "rollup";
4+
import { default as webpack4 } from "webpack4";
5+
import { webpack as webpack5 } from "webpack5";
6+
import * as esbuild from "esbuild";
7+
import { Options } from "@sentry/bundler-plugin-core";
8+
import { sentryVitePlugin } from "@sentry/vite-plugin";
9+
import { sentryWebpackPlugin } from "@sentry/webpack-plugin";
10+
import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin";
11+
import { sentryRollupPlugin } from "@sentry/rollup-plugin";
12+
13+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
14+
const nodejsMajorversion = process.version.split(".")[0]!.slice(1);
15+
16+
export async function createCjsBundles(
17+
entrypoints: { [name: string]: string },
18+
outFolder: string,
19+
sentryUnpluginOptions: Options,
20+
plugins: string[] = []
21+
): Promise<void> {
22+
if (plugins.length === 0 || plugins.includes("vite")) {
23+
await vite.build({
24+
clearScreen: false,
25+
build: {
26+
sourcemap: true,
27+
outDir: path.join(outFolder, "vite"),
28+
rollupOptions: {
29+
input: entrypoints,
30+
output: {
31+
format: "cjs",
32+
entryFileNames: "[name].js",
33+
},
34+
},
35+
},
36+
plugins: [sentryVitePlugin(sentryUnpluginOptions)],
37+
});
38+
}
39+
if (plugins.length === 0 || plugins.includes("rollup")) {
40+
await rollup
41+
.rollup({
42+
input: entrypoints,
43+
plugins: [sentryRollupPlugin(sentryUnpluginOptions)],
44+
})
45+
.then((bundle) =>
46+
bundle.write({
47+
sourcemap: true,
48+
dir: path.join(outFolder, "rollup"),
49+
format: "cjs",
50+
exports: "named",
51+
})
52+
);
53+
}
54+
55+
if (plugins.length === 0 || plugins.includes("esbuild")) {
56+
await esbuild.build({
57+
sourcemap: true,
58+
entryPoints: entrypoints,
59+
outdir: path.join(outFolder, "esbuild"),
60+
plugins: [sentryEsbuildPlugin(sentryUnpluginOptions)],
61+
minify: true,
62+
bundle: true,
63+
format: "cjs",
64+
});
65+
}
66+
67+
// Webpack 4 doesn't work on Node.js versions >= 18
68+
if (parseInt(nodejsMajorversion) < 18 && (plugins.length === 0 || plugins.includes("webpack4"))) {
69+
webpack4(
70+
{
71+
devtool: "source-map",
72+
mode: "production",
73+
entry: entrypoints,
74+
cache: false,
75+
output: {
76+
path: path.join(outFolder, "webpack4"),
77+
libraryTarget: "commonjs",
78+
},
79+
target: "node", // needed for webpack 4 so we can access node api
80+
plugins: [sentryWebpackPlugin(sentryUnpluginOptions)],
81+
},
82+
(err) => {
83+
if (err) {
84+
throw err;
85+
}
86+
}
87+
);
88+
}
89+
90+
if (plugins.length === 0 || plugins.includes("webpack5")) {
91+
webpack5(
92+
{
93+
devtool: "source-map",
94+
cache: false,
95+
entry: entrypoints,
96+
output: {
97+
path: path.join(outFolder, "webpack5"),
98+
library: {
99+
type: "commonjs",
100+
},
101+
},
102+
mode: "production",
103+
plugins: [sentryWebpackPlugin(sentryUnpluginOptions)],
104+
},
105+
(err) => {
106+
if (err) {
107+
throw err;
108+
}
109+
}
110+
);
111+
}
112+
}

0 commit comments

Comments
 (0)