Skip to content

Commit 86414ac

Browse files
Luca ForstnerAbhiPrasad
andauthored
feat: Promote debug ID uploading to stable via sourcemaps option (#204)
Co-authored-by: Abhijeet Prasad <[email protected]>
1 parent 7ffe4a0 commit 86414ac

File tree

13 files changed

+167
-143
lines changed

13 files changed

+167
-143
lines changed

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

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
} from "./sentry/telemetry";
2121
import { Span, Transaction } from "@sentry/types";
2222
import { createLogger, Logger } from "./sentry/logger";
23-
import { InternalOptions, normalizeUserOptions, validateOptions } from "./options-mapping";
23+
import { NormalizedOptions, normalizeUserOptions, validateOptions } from "./options-mapping";
2424
import { getSentryCli } from "./sentry/cli";
2525
import { makeMain } from "@sentry/node";
2626
import os from "os";
@@ -70,18 +70,18 @@ const esbuildDebugIdInjectionFilePath = require.resolve(
7070
*
7171
* This release creation pipeline relies on Sentry CLI to execute the different steps.
7272
*/
73-
const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) => {
74-
const internalOptions = normalizeUserOptions(options);
73+
const unplugin = createUnplugin<Options, true>((userOptions, unpluginMetaContext) => {
74+
const options = normalizeUserOptions(userOptions);
7575

76-
const allowedToSendTelemetryPromise = shouldSendTelemetry(internalOptions);
76+
const allowedToSendTelemetryPromise = shouldSendTelemetry(options);
7777

7878
const { sentryHub, sentryClient } = makeSentryClient(
7979
"https://[email protected]/6690737",
8080
allowedToSendTelemetryPromise,
81-
internalOptions.project
81+
options.project
8282
);
8383

84-
addPluginOptionInformationToHub(internalOptions, sentryHub, unpluginMetaContext.framework);
84+
addPluginOptionInformationToHub(options, sentryHub, unpluginMetaContext.framework);
8585

8686
//TODO: This call is problematic because as soon as we set our hub as the current hub
8787
// we might interfere with other plugins that use Sentry. However, for now, we'll
@@ -92,23 +92,23 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
9292

9393
const logger = createLogger({
9494
prefix: `[sentry-${unpluginMetaContext.framework}-plugin]`,
95-
silent: internalOptions.silent,
96-
debug: internalOptions.debug,
95+
silent: options.silent,
96+
debug: options.debug,
9797
});
9898

99-
if (!validateOptions(internalOptions, logger)) {
99+
if (!validateOptions(options, logger)) {
100100
handleError(
101101
new Error("Options were not set correctly. See output above for more details."),
102102
logger,
103-
internalOptions.errorHandler
103+
options.errorHandler
104104
);
105105
}
106106

107-
const cli = getSentryCli(internalOptions, logger);
107+
const cli = getSentryCli(options, logger);
108108

109109
const releaseNamePromise = new Promise<string>((resolve) => {
110-
if (options.release) {
111-
resolve(options.release);
110+
if (userOptions.release) {
111+
resolve(userOptions.release);
112112
} else {
113113
resolve(cli.releases.proposeVersion());
114114
}
@@ -156,7 +156,7 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
156156
"Unable to determine a release name. Make sure to set the `release` option or use an environment that supports auto-detection https://docs.sentry.io/cli/releases/#creating-releases`"
157157
),
158158
logger,
159-
internalOptions.errorHandler
159+
options.errorHandler
160160
);
161161
}
162162

@@ -211,13 +211,13 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
211211
// a windows style path to `releaseInjectionTargets`
212212
const normalizedId = path.normalize(id);
213213

214-
if (internalOptions.releaseInjectionTargets) {
214+
if (options.releaseInjectionTargets) {
215215
// If there's an `releaseInjectionTargets` option transform (ie. inject the release varible) when the file path matches the option.
216-
if (typeof internalOptions.releaseInjectionTargets === "function") {
217-
return internalOptions.releaseInjectionTargets(normalizedId);
216+
if (typeof options.releaseInjectionTargets === "function") {
217+
return options.releaseInjectionTargets(normalizedId);
218218
}
219219

220-
return internalOptions.releaseInjectionTargets.some((entry) => {
220+
return options.releaseInjectionTargets.some((entry) => {
221221
if (entry instanceof RegExp) {
222222
return entry.test(normalizedId);
223223
} else {
@@ -247,7 +247,7 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
247247
async transform(code, id) {
248248
logger.debug('Called "transform":', { id });
249249

250-
if (!internalOptions.injectRelease) {
250+
if (!options.injectRelease) {
251251
return;
252252
}
253253

@@ -259,10 +259,10 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
259259
ms.append(
260260
generateGlobalInjectorCode({
261261
release: await releaseNamePromise,
262-
injectReleasesMap: internalOptions.injectReleasesMap,
263-
injectBuildInformation: internalOptions._experiments.injectBuildInformation || false,
264-
org: internalOptions.org,
265-
project: internalOptions.project,
262+
injectReleasesMap: options.injectReleasesMap,
263+
injectBuildInformation: options._experiments.injectBuildInformation || false,
264+
org: options.org,
265+
project: options.project,
266266
})
267267
);
268268
} else {
@@ -314,12 +314,12 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
314314

315315
try {
316316
if (!unpluginMetaContext.watchMode) {
317-
if (internalOptions._experiments.debugIdUpload) {
317+
if (options.sourcemaps?.assets) {
318318
const debugIdChunkFilePaths = (
319-
await glob(internalOptions._experiments.debugIdUpload.include, {
319+
await glob(options.sourcemaps.assets, {
320320
absolute: true,
321321
nodir: true,
322-
ignore: internalOptions._experiments.debugIdUpload.ignore,
322+
ignore: options.sourcemaps.ignore,
323323
})
324324
).filter((p) => p.endsWith(".js") || p.endsWith(".mjs") || p.endsWith(".cjs"));
325325

@@ -363,15 +363,15 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
363363
);
364364

365365
tmpUploadFolder = await sourceFileUploadFolderPromise;
366-
await uploadDebugIdSourcemaps(internalOptions, ctx, tmpUploadFolder, releaseName);
366+
await uploadDebugIdSourcemaps(options, ctx, tmpUploadFolder, releaseName);
367367
}
368368

369-
await createNewRelease(internalOptions, ctx, releaseName);
370-
await cleanArtifacts(internalOptions, ctx, releaseName);
371-
await uploadSourceMaps(internalOptions, ctx, releaseName);
372-
await setCommits(internalOptions, ctx, releaseName);
373-
await finalizeRelease(internalOptions, ctx, releaseName);
374-
await addDeploy(internalOptions, ctx, releaseName);
369+
await createNewRelease(options, ctx, releaseName);
370+
await cleanArtifacts(options, ctx, releaseName);
371+
await uploadSourceMaps(options, ctx, releaseName);
372+
await setCommits(options, ctx, releaseName);
373+
await finalizeRelease(options, ctx, releaseName);
374+
await addDeploy(options, ctx, releaseName);
375375
}
376376
transaction?.setStatus("ok");
377377
} catch (e: unknown) {
@@ -380,7 +380,7 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
380380
level: "error",
381381
message: "Error during writeBundle",
382382
});
383-
handleError(e, logger, internalOptions.errorHandler);
383+
handleError(e, logger, options.errorHandler);
384384
} finally {
385385
if (tmpUploadFolder) {
386386
fs.rm(tmpUploadFolder, { recursive: true, force: true }, () => {
@@ -402,7 +402,7 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
402402
rollup: {
403403
renderChunk(code, chunk) {
404404
if (
405-
options._experiments?.debugIdUpload &&
405+
options.sourcemaps?.assets &&
406406
[".js", ".mjs", ".cjs"].some((ending) => chunk.fileName.endsWith(ending)) // chunks could be any file (html, md, ...)
407407
) {
408408
return injectDebugIdSnippetIntoChunk(code);
@@ -414,7 +414,7 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
414414
vite: {
415415
renderChunk(code, chunk) {
416416
if (
417-
options._experiments?.debugIdUpload &&
417+
options.sourcemaps?.assets &&
418418
[".js", ".mjs", ".cjs"].some((ending) => chunk.fileName.endsWith(ending)) // chunks could be any file (html, md, ...)
419419
) {
420420
return injectDebugIdSnippetIntoChunk(code);
@@ -424,7 +424,7 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
424424
},
425425
},
426426
webpack(compiler) {
427-
if (options._experiments?.debugIdUpload) {
427+
if (options.sourcemaps?.assets) {
428428
// Cache inspired by https://github.com/webpack/webpack/pull/15454
429429
const cache = new WeakMap<sources.Source, sources.Source>();
430430

@@ -488,7 +488,7 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
488488
});
489489

490490
if (unpluginMetaContext.framework === "esbuild") {
491-
if (internalOptions._experiments.debugIdUpload) {
491+
if (options.sourcemaps?.assets) {
492492
plugins.push({
493493
name: "sentry-esbuild-debug-id-plugin",
494494
esbuild: {
@@ -507,7 +507,7 @@ const unplugin = createUnplugin<Options, true>((options, unpluginMetaContext) =>
507507
function handleError(
508508
unknownError: unknown,
509509
logger: Logger,
510-
errorHandler: InternalOptions["errorHandler"]
510+
errorHandler: NormalizedOptions["errorHandler"]
511511
) {
512512
if (unknownError instanceof Error) {
513513
logger.error(unknownError.message);

packages/bundler-plugin-core/src/options-mapping.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type OptionalInternalOptions = Partial<
3232
| "deploy"
3333
| "configFile"
3434
| "headers"
35+
| "sourcemaps"
3536
>
3637
>;
3738

@@ -40,7 +41,7 @@ type NormalizedInternalOptions = {
4041
include: InternalIncludeEntry[];
4142
};
4243

43-
export type InternalOptions = RequiredInternalOptions &
44+
export type NormalizedOptions = RequiredInternalOptions &
4445
OptionalInternalOptions &
4546
NormalizedInternalOptions;
4647

@@ -62,7 +63,7 @@ export type InternalIncludeEntry = RequiredInternalIncludeEntry &
6263

6364
export const SENTRY_SAAS_URL = "https://sentry.io";
6465

65-
export function normalizeUserOptions(userOptions: UserOptions): InternalOptions {
66+
export function normalizeUserOptions(userOptions: UserOptions) {
6667
const options = {
6768
// include is the only strictly required option
6869
// (normalizeInclude needs all userOptions to access top-level include options)
@@ -94,6 +95,7 @@ export function normalizeUserOptions(userOptions: UserOptions): InternalOptions
9495
injectReleasesMap: userOptions.injectReleasesMap ?? false,
9596
injectRelease: userOptions.injectRelease ?? true,
9697
uploadSourceMaps: userOptions.uploadSourceMaps ?? true,
98+
sourcemaps: userOptions.sourcemaps,
9799
_experiments: userOptions._experiments ?? {},
98100

99101
// These options and can also be set via env variables or the config file.
@@ -149,6 +151,10 @@ function normalizeReleaseInjectionTargets(
149151
* @return an array of `InternalIncludeEntry` objects.
150152
*/
151153
function normalizeInclude(userOptions: UserOptions): InternalIncludeEntry[] {
154+
if (!userOptions.include) {
155+
return [];
156+
}
157+
152158
return arrayify(userOptions.include)
153159
.map((includeItem) =>
154160
typeof includeItem === "string" ? { paths: [includeItem] } : includeItem
@@ -198,7 +204,7 @@ function normalizeIncludeEntry(
198204
*
199205
* @returns `true` if the options are valid, `false` otherwise
200206
*/
201-
export function validateOptions(options: InternalOptions, logger: Logger): boolean {
207+
export function validateOptions(options: NormalizedOptions, logger: Logger): boolean {
202208
if (options.injectReleasesMap && !options.org) {
203209
logger.error(
204210
"The `injectReleasesMap` option was set but it is only supported when the `org` option is also specified.",

packages/bundler-plugin-core/src/sentry/cli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import SentryCli, { SentryCliReleases } from "@sentry/cli";
2-
import { InternalOptions } from "../options-mapping";
2+
import { NormalizedOptions } from "../options-mapping";
33
import { Logger } from "./logger";
44

55
type SentryDryRunCLI = {
@@ -14,7 +14,7 @@ export type SentryCLILike = SentryCli | SentryDryRunCLI;
1414
* In case, users selected the `dryRun` options, this returns a stub
1515
* that makes no-ops out of most CLI operations
1616
*/
17-
export function getSentryCli(internalOptions: InternalOptions, logger: Logger): SentryCLILike {
17+
export function getSentryCli(internalOptions: NormalizedOptions, logger: Logger): SentryCLILike {
1818
const { silent, org, project, authToken, url, vcsRemote, headers } = internalOptions;
1919
const cli = new SentryCli(internalOptions.configFile, {
2020
url,

packages/bundler-plugin-core/src/sentry/releasePipeline.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
// - unnecessary functionality
88

99
import { logger } from "@sentry/utils";
10-
import { InternalOptions } from "../options-mapping";
10+
import { NormalizedOptions } from "../options-mapping";
1111
import { BuildContext } from "../types";
1212
import { addSpanToTransaction } from "./telemetry";
1313

1414
export async function createNewRelease(
15-
options: InternalOptions,
15+
options: NormalizedOptions,
1616
ctx: BuildContext,
1717
releaseName: string
1818
): Promise<void> {
@@ -32,7 +32,7 @@ export async function createNewRelease(
3232
}
3333

3434
export async function cleanArtifacts(
35-
options: InternalOptions,
35+
options: NormalizedOptions,
3636
ctx: BuildContext,
3737
releaseName: string
3838
): Promise<void> {
@@ -57,7 +57,7 @@ export async function cleanArtifacts(
5757
}
5858

5959
export async function uploadSourceMaps(
60-
options: InternalOptions,
60+
options: NormalizedOptions,
6161
ctx: BuildContext,
6262
releaseName: string
6363
): Promise<void> {
@@ -88,7 +88,7 @@ export async function uploadSourceMaps(
8888
}
8989

9090
export async function uploadDebugIdSourcemaps(
91-
options: InternalOptions,
91+
options: NormalizedOptions,
9292
ctx: BuildContext,
9393
folderPathToUpload: string,
9494
releaseName: string
@@ -121,7 +121,7 @@ export async function uploadDebugIdSourcemaps(
121121
}
122122

123123
export async function setCommits(
124-
options: InternalOptions,
124+
options: NormalizedOptions,
125125
ctx: BuildContext,
126126
releaseName: string
127127
): Promise<void> {
@@ -154,7 +154,7 @@ export async function setCommits(
154154
}
155155

156156
export async function finalizeRelease(
157-
options: InternalOptions,
157+
options: NormalizedOptions,
158158
ctx: BuildContext,
159159
releaseName: string
160160
): Promise<void> {
@@ -180,7 +180,7 @@ export async function finalizeRelease(
180180
}
181181

182182
export async function addDeploy(
183-
options: InternalOptions,
183+
options: NormalizedOptions,
184184
ctx: BuildContext,
185185
releaseName: string
186186
): Promise<void> {

packages/bundler-plugin-core/src/sentry/telemetry.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import SentryCli from "@sentry/cli";
22
import { defaultStackParser, Hub, makeNodeTransport, NodeClient, Span } from "@sentry/node";
3-
import { InternalOptions, SENTRY_SAAS_URL } from "../options-mapping";
3+
import { NormalizedOptions, SENTRY_SAAS_URL } from "../options-mapping";
44
import { BuildContext } from "../types";
55

66
const SENTRY_SAAS_HOSTNAME = "sentry.io";
@@ -81,7 +81,7 @@ export function addSpanToTransaction(
8181
}
8282

8383
export function addPluginOptionInformationToHub(
84-
options: InternalOptions,
84+
options: NormalizedOptions,
8585
hub: Hub,
8686
bundler: "rollup" | "webpack" | "vite" | "esbuild"
8787
) {
@@ -96,7 +96,7 @@ export function addPluginOptionInformationToHub(
9696
errorHandler,
9797
deploy,
9898
include,
99-
_experiments,
99+
sourcemaps,
100100
} = options;
101101

102102
hub.setTag("include", include.length > 1 ? "multiple-entries" : "single-entry");
@@ -125,7 +125,7 @@ export function addPluginOptionInformationToHub(
125125
if (errorHandler) {
126126
hub.setTag("error-handler", "custom");
127127
}
128-
if (_experiments.debugIdUpload) {
128+
if (sourcemaps?.assets) {
129129
hub.setTag("debug-id-upload", true);
130130
}
131131

@@ -140,7 +140,7 @@ export function addPluginOptionInformationToHub(
140140
hub.setUser({ id: org });
141141
}
142142

143-
export async function shouldSendTelemetry(options: InternalOptions): Promise<boolean> {
143+
export async function shouldSendTelemetry(options: NormalizedOptions): Promise<boolean> {
144144
const { silent, org, project, authToken, url, vcsRemote, headers, telemetry, dryRun } = options;
145145

146146
// `options.telemetry` defaults to true

0 commit comments

Comments
 (0)