Skip to content

Commit 063f0ad

Browse files
committed
setup Sentry in the bundler plugin core
1 parent ee498fb commit 063f0ad

File tree

11 files changed

+1047
-36
lines changed

11 files changed

+1047
-36
lines changed

packages/bundler-plugin-core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"dependencies": {
4242
"@actions/core": "^1.10.1",
4343
"@actions/github": "^6.0.0",
44+
"@sentry/core": "^8.42.0",
4445
"chalk": "4.1.2",
4546
"semver": "^7.5.4",
4647
"unplugin": "^1.10.1",

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { type Client, type Scope } from "@sentry/core";
12
import {
23
type Asset,
34
type BundleAnalysisUploadPlugin,
@@ -22,6 +23,12 @@ import {
2223
Output,
2324
red,
2425
} from "./utils";
26+
import {
27+
createSentryInstance,
28+
telemetryPlugin,
29+
safeFlushTelemetry,
30+
setTelemetryDataOnScope,
31+
} from "./sentry/telemetry.ts";
2532

2633
export type {
2734
Asset,
@@ -36,6 +43,8 @@ export type {
3643
NormalizedOptions,
3744
ProviderUtilInputs,
3845
UploadOverrides,
46+
Client as SentryClient,
47+
Scope as SentryScope,
3948
};
4049

4150
export {
@@ -47,4 +56,8 @@ export {
4756
normalizePath,
4857
Output,
4958
red,
59+
createSentryInstance,
60+
telemetryPlugin,
61+
safeFlushTelemetry,
62+
setTelemetryDataOnScope,
5063
};
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import { describe, it, expect, vi, afterEach } from "vitest";
2+
import {
3+
createSentryInstance,
4+
setTelemetryDataOnScope,
5+
safeFlushTelemetry,
6+
telemetryPlugin,
7+
} from "../telemetry";
8+
import { type Client, type Scope } from "@sentry/core";
9+
import { type NormalizedOptions } from "../../utils/normalizeOptions";
10+
11+
const mocks = vi.hoisted(() => ({
12+
cyan: vi.fn(),
13+
}));
14+
15+
vi.mock("../../utils/logging", () => ({
16+
cyan: mocks.cyan,
17+
}));
18+
19+
afterEach(() => {
20+
vi.clearAllMocks();
21+
});
22+
23+
describe("telemetry", () => {
24+
describe("createSentryInstance", () => {
25+
it("creates instance with telemetry enabled", () => {
26+
const options = {
27+
telemetry: true,
28+
dryRun: false,
29+
} as NormalizedOptions;
30+
const pluginInfo = {
31+
name: "test-plugin",
32+
version: "1.0.0",
33+
};
34+
35+
const { sentryClient, sentryScope } = createSentryInstance(
36+
true,
37+
false,
38+
pluginInfo,
39+
options,
40+
);
41+
42+
expect(sentryClient).toBeDefined();
43+
expect(sentryScope).toBeDefined();
44+
});
45+
46+
it("creates instance with telemetry disabled", () => {
47+
const options = {
48+
telemetry: false,
49+
dryRun: false,
50+
} as NormalizedOptions;
51+
const pluginInfo = {
52+
name: "test-plugin",
53+
version: "1.0.0",
54+
};
55+
56+
const { sentryClient, sentryScope } = createSentryInstance(
57+
false,
58+
false,
59+
pluginInfo,
60+
options,
61+
);
62+
63+
expect(sentryClient).toBeDefined();
64+
expect(sentryScope).toBeDefined();
65+
});
66+
});
67+
68+
describe("setTelemetryDataOnScope", () => {
69+
it("sets correct tags for token auth", () => {
70+
const scope = {
71+
setTag: vi.fn(),
72+
} as unknown as Scope;
73+
74+
const options = {
75+
dryRun: false,
76+
uploadToken: "some-token",
77+
gitService: "github",
78+
} as NormalizedOptions;
79+
80+
const pluginInfo = {
81+
name: "test-plugin",
82+
version: "1.0.0",
83+
};
84+
85+
setTelemetryDataOnScope(options, pluginInfo, scope);
86+
87+
// eslint-disable-next-line @typescript-eslint/unbound-method
88+
expect(scope.setTag).toHaveBeenCalledWith("auth_mode", "token");
89+
// eslint-disable-next-line @typescript-eslint/unbound-method
90+
expect(scope.setTag).toHaveBeenCalledWith("git_service", "github");
91+
// eslint-disable-next-line @typescript-eslint/unbound-method
92+
expect(scope.setTag).toHaveBeenCalledWith("plugin.name", "test-plugin");
93+
// eslint-disable-next-line @typescript-eslint/unbound-method
94+
expect(scope.setTag).toHaveBeenCalledWith("plugin.version", "1.0.0");
95+
});
96+
97+
it("sets correct tags for github OIDC auth", () => {
98+
const scope = {
99+
setTag: vi.fn(),
100+
} as unknown as Scope;
101+
102+
const options = {
103+
dryRun: false,
104+
oidc: { useGitHubOIDC: true },
105+
} as NormalizedOptions;
106+
107+
const pluginInfo = {
108+
name: "test-plugin",
109+
version: "1.0.0",
110+
};
111+
112+
setTelemetryDataOnScope(options, pluginInfo, scope);
113+
114+
// eslint-disable-next-line @typescript-eslint/unbound-method
115+
expect(scope.setTag).toHaveBeenCalledWith("auth_mode", "github-oidc");
116+
});
117+
});
118+
119+
describe("safeFlushTelemetry", () => {
120+
it("handles successful flush", async () => {
121+
const client = {
122+
flush: vi.fn().mockResolvedValue(undefined),
123+
} as unknown as Client;
124+
125+
await safeFlushTelemetry(client);
126+
127+
// eslint-disable-next-line @typescript-eslint/unbound-method
128+
expect(client.flush).toHaveBeenCalledWith(2000);
129+
});
130+
131+
it("handles failed flush without throwing", async () => {
132+
const client = {
133+
flush: vi.fn().mockRejectedValue(new Error("Flush failed")),
134+
} as unknown as Client;
135+
136+
await expect(safeFlushTelemetry(client)).resolves.not.toThrow();
137+
});
138+
});
139+
140+
describe("telemetryPlugin", () => {
141+
it("logs message and starts span when telemetry enabled", async () => {
142+
const client = {
143+
flush: vi.fn().mockResolvedValue(undefined),
144+
getOptions: vi.fn().mockReturnValue(undefined),
145+
} as unknown as Client;
146+
147+
const scope = {
148+
getClient: vi.fn(() => client),
149+
} as unknown as Scope;
150+
151+
const plugin = telemetryPlugin({
152+
sentryClient: client,
153+
sentryScope: scope,
154+
shouldSendTelemetry: true,
155+
});
156+
157+
// @ts-expect-error: buildStart is not defined in the type
158+
await plugin.buildStart?.();
159+
160+
expect(mocks.cyan).toHaveBeenCalledWith(
161+
"Sending telemetry data on issues and performance to Codecov. To disable telemetry, set `options.telemetry` to `false`.",
162+
);
163+
// eslint-disable-next-line @typescript-eslint/unbound-method
164+
expect(client.flush).toHaveBeenCalled();
165+
});
166+
167+
it("does not log message or start span when telemetry disabled", async () => {
168+
const client = {
169+
flush: vi.fn().mockResolvedValue(undefined),
170+
} as unknown as Client;
171+
172+
const scope = {} as Scope;
173+
174+
const plugin = telemetryPlugin({
175+
sentryClient: client,
176+
sentryScope: scope,
177+
shouldSendTelemetry: false,
178+
});
179+
180+
// @ts-expect-error: buildStart is not defined in the type
181+
await plugin.buildStart?.();
182+
183+
expect(mocks.cyan).not.toHaveBeenCalled();
184+
// eslint-disable-next-line @typescript-eslint/unbound-method
185+
expect(client.flush).not.toHaveBeenCalled();
186+
});
187+
});
188+
});

0 commit comments

Comments
 (0)