Skip to content

Commit 02f2737

Browse files
committed
fix(core): Avoid console output and telemetry init when plugins are disabled
1 parent 3ba65eb commit 02f2737

File tree

3 files changed

+219
-7
lines changed

3 files changed

+219
-7
lines changed

packages/bundler-plugin-core/src/build-plugin-manager.ts

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import * as dotenv from "dotenv";
1212
import * as fs from "fs";
1313
import * as os from "os";
1414
import * as path from "path";
15-
import { normalizeUserOptions, validateOptions } from "./options-mapping";
16-
import { createLogger } from "./logger";
15+
import { NormalizedOptions, normalizeUserOptions, validateOptions } from "./options-mapping";
16+
import { createLogger, Logger } from "./logger";
1717
import {
1818
allowedToSendTelemetry,
1919
createSentryInstance,
@@ -25,7 +25,60 @@ import { glob } from "glob";
2525
import { defaultRewriteSourcesHook, prepareBundleForDebugIdUpload } from "./debug-id-upload";
2626
import { dynamicSamplingContextToSentryBaggageHeader } from "@sentry/utils";
2727

28-
export type SentryBuildPluginManager = ReturnType<typeof createSentryBuildPluginManager>;
28+
export type SentryBuildPluginManager = {
29+
/**
30+
* A logger instance that takes the options passed to the build plugin manager into account. (for silencing and log level etc.)
31+
*/
32+
logger: Logger;
33+
34+
/**
35+
* Options after normalization. Includes things like the inferred release name.
36+
*/
37+
normalizedOptions: NormalizedOptions;
38+
/**
39+
* Magic strings and their replacement values that can be used for bundle size optimizations. This already takes
40+
* into account the options passed to the build plugin manager.
41+
*/
42+
bundleSizeOptimizationReplacementValues: SentrySDKBuildFlags;
43+
/**
44+
* Metadata that should be injected into bundles if possible. Takes into account options passed to the build plugin manager.
45+
*/
46+
// See `generateModuleMetadataInjectorCode` for how this should be used exactly
47+
bundleMetadata: Record<string, unknown>;
48+
49+
/**
50+
* Contains utility functions for emitting telemetry via the build plugin manager.
51+
*/
52+
telemetry: {
53+
/**
54+
* Emits a `Sentry Bundler Plugin execution` signal.
55+
*/
56+
emitBundlerPluginExecutionSignal(): Promise<void>;
57+
};
58+
59+
/**
60+
* Will potentially create a release based on the build plugin manager options.
61+
*
62+
* Also
63+
* - finalizes the release
64+
* - sets commits
65+
* - uploads legacy sourcemaps
66+
* - adds deploy information
67+
*/
68+
createRelease(): Promise<void>;
69+
70+
/**
71+
* Uploads sourcemaps using the "Debug ID" method. This function takes a list of build artifact paths that will be uploaded
72+
*/
73+
uploadSourcemaps(buildArtifactPaths: string[]): Promise<void>;
74+
75+
/**
76+
* Will delete artifacts based on the passed `sourcemaps.filesToDeleteAfterUpload` option.
77+
*/
78+
deleteArtifacts(): Promise<void>;
79+
80+
createDependencyOnBuildArtifacts: () => () => void;
81+
};
2982

3083
/**
3184
* Creates a build plugin manager that exposes primitives for everything that a Sentry JavaScript SDK or build tooling may do during a build.
@@ -44,7 +97,7 @@ export function createSentryBuildPluginManager(
4497
*/
4598
loggerPrefix: string;
4699
}
47-
) {
100+
): SentryBuildPluginManager {
48101
const logger = createLogger({
49102
prefix: bundlerPluginMetaContext.loggerPrefix,
50103
silent: userOptions.silent ?? false,
@@ -73,6 +126,36 @@ export function createSentryBuildPluginManager(
73126

74127
const options = normalizeUserOptions(userOptions);
75128

129+
if (options.disable) {
130+
// Early-return a noop build plugin manager instance so that we
131+
// don't continue validating options, setting up Sentry, etc.
132+
// Otherwise we might create side-effects or log messages that
133+
// users don't expect from a disabled plugin.
134+
return {
135+
normalizedOptions: options,
136+
logger,
137+
bundleSizeOptimizationReplacementValues: {},
138+
telemetry: {
139+
emitBundlerPluginExecutionSignal: async () => {
140+
/* noop */
141+
},
142+
},
143+
bundleMetadata: {},
144+
createRelease: async () => {
145+
/* noop */
146+
},
147+
uploadSourcemaps: async () => {
148+
/* noop */
149+
},
150+
deleteArtifacts: async () => {
151+
/* noop */
152+
},
153+
createDependencyOnBuildArtifacts: () => () => {
154+
/* noop */
155+
},
156+
};
157+
}
158+
76159
const shouldSendTelemetry = allowedToSendTelemetry(options);
77160
const { sentryScope, sentryClient } = createSentryInstance(
78161
options,

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

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,90 @@
11
import { Logger } from "./logger";
2-
import { Options as UserOptions, SetCommitsOptions } from "./types";
2+
import {
3+
Options as UserOptions,
4+
SetCommitsOptions,
5+
RewriteSourcesHook,
6+
ResolveSourceMapHook,
7+
IncludeEntry,
8+
ModuleMetadata,
9+
ModuleMetadataCallback,
10+
} from "./types";
311
import { determineReleaseName } from "./utils";
412

5-
export type NormalizedOptions = ReturnType<typeof normalizeUserOptions>;
13+
export type NormalizedOptions = {
14+
org: string | undefined;
15+
project: string | undefined;
16+
authToken: string | undefined;
17+
url: string;
18+
headers: Record<string, string> | undefined;
19+
debug: boolean;
20+
silent: boolean;
21+
errorHandler: ((err: Error) => void) | undefined;
22+
telemetry: boolean;
23+
disable: boolean;
24+
sourcemaps:
25+
| {
26+
disable?: boolean;
27+
assets?: string | string[];
28+
ignore?: string | string[];
29+
rewriteSources?: RewriteSourcesHook;
30+
resolveSourceMap?: ResolveSourceMapHook;
31+
filesToDeleteAfterUpload?: string | string[] | Promise<string | string[] | undefined>;
32+
}
33+
| undefined;
34+
release: {
35+
name: string | undefined;
36+
inject: boolean;
37+
create: boolean;
38+
finalize: boolean;
39+
vcsRemote: string;
40+
setCommits:
41+
| (SetCommitsOptions & {
42+
shouldNotThrowOnFailure?: boolean;
43+
})
44+
| false
45+
| undefined;
46+
dist?: string;
47+
deploy?: {
48+
env: string;
49+
started?: number | string;
50+
finished?: number | string;
51+
time?: number;
52+
name?: string;
53+
url?: string;
54+
};
55+
uploadLegacySourcemaps?: string | IncludeEntry | Array<string | IncludeEntry>;
56+
};
57+
bundleSizeOptimizations:
58+
| {
59+
excludeDebugStatements?: boolean;
60+
excludeTracing?: boolean;
61+
excludeReplayCanvas?: boolean;
62+
excludeReplayShadowDom?: boolean;
63+
excludeReplayIframe?: boolean;
64+
excludeReplayWorker?: boolean;
65+
}
66+
| undefined;
67+
reactComponentAnnotation:
68+
| {
69+
enabled?: boolean;
70+
ignoredComponents?: string[];
71+
}
72+
| undefined;
73+
_metaOptions: {
74+
telemetry: {
75+
metaFramework: string | undefined;
76+
};
77+
};
78+
applicationKey: string | undefined;
79+
moduleMetadata: ModuleMetadata | ModuleMetadataCallback | undefined;
80+
_experiments: {
81+
injectBuildInformation?: boolean;
82+
} & Record<string, unknown>;
83+
};
684

785
export const SENTRY_SAAS_URL = "https://sentry.io";
886

9-
export function normalizeUserOptions(userOptions: UserOptions) {
87+
export function normalizeUserOptions(userOptions: UserOptions): NormalizedOptions {
1088
const options = {
1189
org: userOptions.org ?? process.env["SENTRY_ORG"],
1290
project: userOptions.project ?? process.env["SENTRY_PROJECT"],
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { createSentryBuildPluginManager } from "../src/build-plugin-manager";
2+
3+
describe("createSentryBuildPluginManager", () => {
4+
describe("when disabled", () => {
5+
it("initializes a no-op build plugin manager", () => {
6+
const buildPluginManager = createSentryBuildPluginManager(
7+
{
8+
disable: true,
9+
},
10+
{
11+
buildTool: "webpack",
12+
loggerPrefix: "[sentry-webpack-plugin]",
13+
}
14+
);
15+
16+
expect(buildPluginManager).toBeDefined();
17+
expect(buildPluginManager.logger).toBeDefined();
18+
expect(buildPluginManager.normalizedOptions.disable).toBe(true);
19+
});
20+
21+
it("does not log anything to the console", () => {
22+
const logSpy = jest.spyOn(console, "log");
23+
const infoSpy = jest.spyOn(console, "info");
24+
const debugSpy = jest.spyOn(console, "debug");
25+
const warnSpy = jest.spyOn(console, "warn");
26+
const errorSpy = jest.spyOn(console, "error");
27+
28+
createSentryBuildPluginManager(
29+
{
30+
disable: true,
31+
release: {
32+
deploy: {
33+
// An empty string triggers a validation error (but satisfies the type checker)
34+
env: "",
35+
},
36+
},
37+
},
38+
{
39+
buildTool: "webpack",
40+
loggerPrefix: "[sentry-webpack-plugin]",
41+
}
42+
);
43+
44+
expect(logSpy).not.toHaveBeenCalled();
45+
expect(infoSpy).not.toHaveBeenCalled();
46+
expect(debugSpy).not.toHaveBeenCalled();
47+
expect(warnSpy).not.toHaveBeenCalled();
48+
expect(errorSpy).not.toHaveBeenCalled();
49+
});
50+
});
51+
});

0 commit comments

Comments
 (0)