diff --git a/.changeset/green-goats-thank.md b/.changeset/green-goats-thank.md new file mode 100644 index 00000000..f9d422f7 --- /dev/null +++ b/.changeset/green-goats-thank.md @@ -0,0 +1,15 @@ +--- +"@codecov/nextjs-webpack-plugin": minor +"@codecov/bundler-plugin-core": minor +"@codecov/remix-vite-plugin": minor +"@codecov/solidstart-plugin": minor +"@codecov/sveltekit-plugin": minor +"@codecov/webpack-plugin": minor +"@codecov/rollup-plugin": minor +"@codecov/astro-plugin": minor +"@codecov/nuxt-plugin": minor +"@codecov/vite-plugin": minor +"@codecov/bundle-analyzer": minor +--- + +Add Sentry to the bundler plugins to start collecting issues and telemetry diff --git a/.changeset/wise-toys-hug.md b/.changeset/wise-toys-hug.md new file mode 100644 index 00000000..7902f1bf --- /dev/null +++ b/.changeset/wise-toys-hug.md @@ -0,0 +1,14 @@ +--- +"@codecov/nextjs-webpack-plugin": patch +"@codecov/bundler-plugin-core": patch +"@codecov/remix-vite-plugin": patch +"@codecov/solidstart-plugin": patch +"@codecov/sveltekit-plugin": patch +"@codecov/webpack-plugin": patch +"@codecov/rollup-plugin": patch +"@codecov/astro-plugin": patch +"@codecov/nuxt-plugin": patch +"@codecov/vite-plugin": patch +--- + +Fix issue not using the correct webpack in the nextjs plugin diff --git a/integration-tests/fixtures/generate-bundle-stats/astro/astro-base.config.mjs b/integration-tests/fixtures/generate-bundle-stats/astro/astro-base.config.mjs index e53a9549..d9e32b23 100644 --- a/integration-tests/fixtures/generate-bundle-stats/astro/astro-base.config.mjs +++ b/integration-tests/fixtures/generate-bundle-stats/astro/astro-base.config.mjs @@ -26,6 +26,7 @@ export default defineConfig({ bundleName: "test-astro-v4", uploadToken: "test-token", apiUrl: process.env.API_URL, + telemetry: false, }), ], }); diff --git a/integration-tests/fixtures/generate-bundle-stats/nextjs/next-base.config.mjs b/integration-tests/fixtures/generate-bundle-stats/nextjs/next-base.config.mjs index bf18c485..49104d33 100644 --- a/integration-tests/fixtures/generate-bundle-stats/nextjs/next-base.config.mjs +++ b/integration-tests/fixtures/generate-bundle-stats/nextjs/next-base.config.mjs @@ -10,6 +10,7 @@ export default { uploadToken: "test-token", apiUrl: process.env.API_URL, webpack: options.webpack, + telemetry: false, debug: true, }), ); diff --git a/integration-tests/fixtures/generate-bundle-stats/nuxt/nuxt-base.config.ts b/integration-tests/fixtures/generate-bundle-stats/nuxt/nuxt-base.config.ts index a306bde2..497e2d29 100644 --- a/integration-tests/fixtures/generate-bundle-stats/nuxt/nuxt-base.config.ts +++ b/integration-tests/fixtures/generate-bundle-stats/nuxt/nuxt-base.config.ts @@ -11,6 +11,7 @@ const config: ReturnType = defineNuxtConfig({ bundleName: "test-nuxt-v3", uploadToken: "test-token", apiUrl: process.env.API_URL, + telemetry: false, }, ], ], diff --git a/integration-tests/fixtures/generate-bundle-stats/remix/vite-base.config.ts b/integration-tests/fixtures/generate-bundle-stats/remix/vite-base.config.ts index fe5468a0..c56a8daa 100644 --- a/integration-tests/fixtures/generate-bundle-stats/remix/vite-base.config.ts +++ b/integration-tests/fixtures/generate-bundle-stats/remix/vite-base.config.ts @@ -26,6 +26,7 @@ export default defineConfig({ bundleName: "test-remix-v2", uploadToken: "test-token", apiUrl: process.env.API_URL, + telemetry: false, }), ], }); diff --git a/integration-tests/fixtures/generate-bundle-stats/rollup/rollup-base.config.cjs b/integration-tests/fixtures/generate-bundle-stats/rollup/rollup-base.config.cjs index 3a8c557c..02bf4d3b 100644 --- a/integration-tests/fixtures/generate-bundle-stats/rollup/rollup-base.config.cjs +++ b/integration-tests/fixtures/generate-bundle-stats/rollup/rollup-base.config.cjs @@ -22,6 +22,7 @@ module.exports = defineConfig({ bundleName: "test-rollup-v3", uploadToken: "test-token", apiUrl: process.env.API_URL, + telemetry: false, }), ], }); diff --git a/integration-tests/fixtures/generate-bundle-stats/solidstart/app-base.config.ts b/integration-tests/fixtures/generate-bundle-stats/solidstart/app-base.config.ts index c51751e7..5ca1ed79 100644 --- a/integration-tests/fixtures/generate-bundle-stats/solidstart/app-base.config.ts +++ b/integration-tests/fixtures/generate-bundle-stats/solidstart/app-base.config.ts @@ -22,6 +22,7 @@ export default defineConfig({ bundleName: "test-solidstart-v1", uploadToken: "test-token", apiUrl: process.env.API_URL, + telemetry: false, // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any, ], diff --git a/integration-tests/fixtures/generate-bundle-stats/sveltekit/vite-base.config.ts b/integration-tests/fixtures/generate-bundle-stats/sveltekit/vite-base.config.ts index 590a48a1..34525a26 100644 --- a/integration-tests/fixtures/generate-bundle-stats/sveltekit/vite-base.config.ts +++ b/integration-tests/fixtures/generate-bundle-stats/sveltekit/vite-base.config.ts @@ -22,6 +22,7 @@ export default defineConfig({ bundleName: "test-sveltekit-v2", uploadToken: "test-token", apiUrl: process.env.API_URL, + telemetry: false, }), ], }); diff --git a/integration-tests/fixtures/generate-bundle-stats/vite/vite-base.config.ts b/integration-tests/fixtures/generate-bundle-stats/vite/vite-base.config.ts index 9bcbd41a..d2c319ec 100644 --- a/integration-tests/fixtures/generate-bundle-stats/vite/vite-base.config.ts +++ b/integration-tests/fixtures/generate-bundle-stats/vite/vite-base.config.ts @@ -24,6 +24,7 @@ export default defineConfig({ bundleName: "test-vite-v5", uploadToken: "test-token", apiUrl: process.env.API_URL, + telemetry: false, }), ], }); diff --git a/integration-tests/fixtures/generate-bundle-stats/webpack/webpack-base.config.cjs b/integration-tests/fixtures/generate-bundle-stats/webpack/webpack-base.config.cjs index bcc60070..8a9e48aa 100644 --- a/integration-tests/fixtures/generate-bundle-stats/webpack/webpack-base.config.cjs +++ b/integration-tests/fixtures/generate-bundle-stats/webpack/webpack-base.config.cjs @@ -19,6 +19,7 @@ module.exports = { bundleName: "test-webpack-v5", uploadToken: "test-token", apiUrl: process.env.API_URL, + telemetry: false, }), ], }; diff --git a/packages/astro-plugin/src/astro-bundle-analysis/__tests__/astroBundleAnalysisPlugin.test.ts b/packages/astro-plugin/src/astro-bundle-analysis/__tests__/astroBundleAnalysisPlugin.test.ts index df7b397a..8f4b5440 100644 --- a/packages/astro-plugin/src/astro-bundle-analysis/__tests__/astroBundleAnalysisPlugin.test.ts +++ b/packages/astro-plugin/src/astro-bundle-analysis/__tests__/astroBundleAnalysisPlugin.test.ts @@ -2,6 +2,11 @@ import { Output } from "@codecov/bundler-plugin-core"; import { describe, it, expect } from "vitest"; import { astroBundleAnalysisPlugin } from "../astroBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("astroBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -15,7 +20,10 @@ describe("astroBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/astro-plugin/src/astro-bundle-analysis/astroBundleAnalysisPlugin.ts b/packages/astro-plugin/src/astro-bundle-analysis/astroBundleAnalysisPlugin.ts index 4ca18e43..dc72b9ca 100644 --- a/packages/astro-plugin/src/astro-bundle-analysis/astroBundleAnalysisPlugin.ts +++ b/packages/astro-plugin/src/astro-bundle-analysis/astroBundleAnalysisPlugin.ts @@ -5,11 +5,6 @@ import { } from "@codecov/bundler-plugin-core"; import { getBundleName } from "./getBundleName"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - interface AstroBundleAnalysisArgs extends BundleAnalysisUploadPluginArgs { target: "client" | "server"; } @@ -21,10 +16,12 @@ type AstroBundleAnalysisPlugin = ( export const astroBundleAnalysisPlugin: AstroBundleAnalysisPlugin = ({ output, target, + pluginName, + pluginVersion, }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, vite: { generateBundle(this, options) { // TODO - remove this once we hard fail on not having a bundle name @@ -46,7 +43,7 @@ export const astroBundleAnalysisPlugin: AstroBundleAnalysisPlugin = ({ output.lockBundleName(); // manually set this to avoid resetting in the vite plugin - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, }, }); diff --git a/packages/astro-plugin/src/index.ts b/packages/astro-plugin/src/index.ts index ee6191a2..eb51dce4 100644 --- a/packages/astro-plugin/src/index.ts +++ b/packages/astro-plugin/src/index.ts @@ -5,6 +5,8 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { _internal_viteBundleAnalysisPlugin } from "@codecov/vite-plugin"; import { type AstroIntegration } from "astro"; @@ -12,8 +14,10 @@ import { type PluginOption } from "vite"; import { astroBundleAnalysisPlugin } from "./astro-bundle-analysis/astroBundleAnalysisPlugin"; -// @ts-expect-error - This is a placeholder for the package name. +// @ts-expect-error this value is being replaced by rollup const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; interface AstroPluginFactoryOptions extends Options { // type can be found from the AstroIntegration type @@ -37,12 +41,35 @@ const astroPluginFactory = createVitePlugin( } const plugins: UnpluginOptions[] = []; - const output = new Output(normalizedOptions.options); const options = normalizedOptions.options; + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + metaFramework: "astro", + }); + const output = new Output(options, sentryConfig); if (options.enableBundleAnalysis) { plugins.push( - astroBundleAnalysisPlugin({ output, target }), - _internal_viteBundleAnalysisPlugin({ output }), + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), + astroBundleAnalysisPlugin({ + output, + target, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), + _internal_viteBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), ); } diff --git a/packages/bundler-plugin-core/package.json b/packages/bundler-plugin-core/package.json index 70be4395..98515461 100644 --- a/packages/bundler-plugin-core/package.json +++ b/packages/bundler-plugin-core/package.json @@ -41,6 +41,7 @@ "dependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.0", + "@sentry/core": "^8.42.0", "chalk": "4.1.2", "semver": "^7.5.4", "unplugin": "^1.10.1", diff --git a/packages/bundler-plugin-core/src/index.ts b/packages/bundler-plugin-core/src/index.ts index 5f1ec528..231bf2d3 100644 --- a/packages/bundler-plugin-core/src/index.ts +++ b/packages/bundler-plugin-core/src/index.ts @@ -1,3 +1,4 @@ +import { type Client, type Scope } from "@sentry/core"; import { type Asset, type BundleAnalysisUploadPlugin, @@ -22,6 +23,12 @@ import { Output, red, } from "./utils"; +import { + createSentryInstance, + telemetryPlugin, + safeFlushTelemetry, + setTelemetryDataOnScope, +} from "./sentry/telemetry.ts"; export type { Asset, @@ -36,6 +43,8 @@ export type { NormalizedOptions, ProviderUtilInputs, UploadOverrides, + Client as SentryClient, + Scope as SentryScope, }; export { @@ -47,4 +56,8 @@ export { normalizePath, Output, red, + createSentryInstance, + telemetryPlugin, + safeFlushTelemetry, + setTelemetryDataOnScope, }; diff --git a/packages/bundler-plugin-core/src/sentry/__tests__/telemetry.test.ts b/packages/bundler-plugin-core/src/sentry/__tests__/telemetry.test.ts new file mode 100644 index 00000000..5e386d47 --- /dev/null +++ b/packages/bundler-plugin-core/src/sentry/__tests__/telemetry.test.ts @@ -0,0 +1,188 @@ +import { describe, it, expect, vi, afterEach } from "vitest"; +import { + createSentryInstance, + setTelemetryDataOnScope, + safeFlushTelemetry, + telemetryPlugin, +} from "../telemetry"; +import { type Client, type Scope } from "@sentry/core"; +import { type NormalizedOptions } from "../../utils/normalizeOptions"; + +const mocks = vi.hoisted(() => ({ + cyan: vi.fn(), +})); + +vi.mock("../../utils/logging", () => ({ + cyan: mocks.cyan, +})); + +afterEach(() => { + vi.clearAllMocks(); +}); + +describe("telemetry", () => { + describe("createSentryInstance", () => { + it("creates instance with telemetry enabled", () => { + const { sentryClient, sentryScope } = createSentryInstance({ + telemetry: true, + isDryRun: false, + pluginName: "test-plugin", + pluginVersion: "1.0.0", + bundler: "test-bundler", + }); + + expect(sentryClient).toBeDefined(); + expect(sentryScope).toBeDefined(); + }); + + it("creates instance with telemetry disabled", () => { + const { sentryClient, sentryScope } = createSentryInstance({ + telemetry: false, + isDryRun: false, + pluginName: "test-plugin", + pluginVersion: "1.0.0", + bundler: "test-bundler", + }); + + expect(sentryClient).toBeDefined(); + expect(sentryScope).toBeDefined(); + }); + }); + + describe("setTelemetryDataOnScope", () => { + it("sets correct tags for token auth", () => { + const scope = { + setTag: vi.fn(), + } as unknown as Scope; + + const options = { + dryRun: false, + uploadToken: "some-token", + gitService: "github", + } as NormalizedOptions; + + const pluginInfo = { + name: "test-plugin", + version: "1.0.0", + }; + + setTelemetryDataOnScope( + options, + pluginInfo, + scope, + "test-bundler", + "none", + ); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(scope.setTag).toHaveBeenCalledWith("auth_mode", "token"); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(scope.setTag).toHaveBeenCalledWith("git_service", "github"); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(scope.setTag).toHaveBeenCalledWith("plugin.name", "test-plugin"); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(scope.setTag).toHaveBeenCalledWith("plugin.version", "1.0.0"); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(scope.setTag).toHaveBeenCalledWith("bundler", "test-bundler"); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(scope.setTag).toHaveBeenCalledWith("meta_framework", "none"); + }); + + it("sets correct tags for github OIDC auth", () => { + const scope = { + setTag: vi.fn(), + } as unknown as Scope; + + const options = { + dryRun: false, + oidc: { useGitHubOIDC: true }, + } as NormalizedOptions; + + const pluginInfo = { + name: "test-plugin", + version: "1.0.0", + }; + + setTelemetryDataOnScope( + options, + pluginInfo, + scope, + "test-bundler", + "none", + ); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(scope.setTag).toHaveBeenCalledWith("auth_mode", "github-oidc"); + }); + }); + + describe("safeFlushTelemetry", () => { + it("handles successful flush", async () => { + const client = { + flush: vi.fn().mockResolvedValue(undefined), + } as unknown as Client; + + await safeFlushTelemetry(client); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(client.flush).toHaveBeenCalledWith(2000); + }); + + it("handles failed flush without throwing", async () => { + const client = { + flush: vi.fn().mockRejectedValue(new Error("Flush failed")), + } as unknown as Client; + + await expect(safeFlushTelemetry(client)).resolves.not.toThrow(); + }); + }); + + describe("telemetryPlugin", () => { + it("logs message and starts span when telemetry enabled", async () => { + const client = { + flush: vi.fn().mockResolvedValue(undefined), + getOptions: vi.fn().mockReturnValue(undefined), + } as unknown as Client; + + const scope = { + getClient: vi.fn(() => client), + } as unknown as Scope; + + const plugin = telemetryPlugin({ + sentryClient: client, + sentryScope: scope, + telemetry: true, + }); + + // @ts-expect-error: buildStart is not defined in the type + await plugin.buildStart?.(); + + expect(mocks.cyan).toHaveBeenCalledWith( + "Sending telemetry data on issues and performance to Codecov. To disable telemetry, set `options.telemetry` to `false`.", + ); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(client.flush).toHaveBeenCalled(); + }); + + it("does not log message or start span when telemetry disabled", async () => { + const client = { + flush: vi.fn().mockResolvedValue(undefined), + } as unknown as Client; + + const scope = {} as Scope; + + const plugin = telemetryPlugin({ + sentryClient: client, + sentryScope: scope, + telemetry: false, + }); + + // @ts-expect-error: buildStart is not defined in the type + await plugin.buildStart?.(); + + expect(mocks.cyan).not.toHaveBeenCalled(); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(client.flush).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/packages/bundler-plugin-core/src/sentry/__tests__/transports.test.ts b/packages/bundler-plugin-core/src/sentry/__tests__/transports.test.ts new file mode 100644 index 00000000..12940f73 --- /dev/null +++ b/packages/bundler-plugin-core/src/sentry/__tests__/transports.test.ts @@ -0,0 +1,177 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { describe, it, expect, vi } from "vitest"; + +import { + createRequestExecutor, + makeNodeTransport, + makeOptionallyEnabledNodeTransport, + streamFromBody, +} from "../transports.ts"; +import { type Envelope } from "@sentry/core"; + +const mocks = vi.hoisted(() => ({ + statusCode: 200, + requestCalled: vi.fn(), +})); + +// Mock the node:https module +vi.mock("node:https", () => { + return { + request: vi.fn((options: any, callback: (arg?: any) => void) => { + const response = { + statusCode: mocks.statusCode, + setEncoding: vi.fn(), + headers: {}, + on: vi.fn((event: any, handler: (arg?: any) => void) => { + if (event === "data") { + handler("mocked data"); + } + if (event === "end") { + handler(); + } + }), + }; + callback(response); + mocks.requestCalled(options); + return { + end: vi.fn(), + write: vi.fn(), + }; + }), + }; +}); + +describe("transports", () => { + describe("streamFromBody", () => { + it("should return a readable stream from a Uint8Array", () => { + const body = new Uint8Array([1, 2, 3]); + const stream = streamFromBody(body); + + expect(stream.read()).toEqual(Buffer.from(body)); + }); + }); + + describe("createRequestExecutor", () => { + it("should create a request executor", () => { + const executor = createRequestExecutor({ + url: "https://localhost/upload", + recordDroppedEvent: () => { + /* */ + }, + }); + + expect(executor).toBeDefined(); + expect(typeof executor).toBe("function"); + }); + + describe("when the request is successful", () => { + it("should return a response", async () => { + const makeRequest = createRequestExecutor({ + url: "https://localhost/upload", + recordDroppedEvent: () => { + /* */ + }, + }); + + const response = await makeRequest({ + body: new Uint8Array([1, 2, 3]), + }); + + await vi.waitFor(() => expect(response.statusCode).toBe(200)); + }); + }); + + describe("when the request fails", () => { + it("should return a response", async () => { + mocks.statusCode = 500; + + const makeRequest = createRequestExecutor({ + url: "https://localhost/upload", + recordDroppedEvent: () => { + /* */ + }, + }); + + const response = await makeRequest({ + body: new Uint8Array([1, 2, 3]), + }); + + await vi.waitFor(() => expect(response.statusCode).toBe(500)); + }); + }); + }); + + describe("makeNodeTransport", () => { + it("should create a node transport object", () => { + const transport = makeNodeTransport({ + url: "https://localhost/upload", + recordDroppedEvent: () => { + /* */ + }, + }); + + expect(transport).toBeDefined(); + expect(typeof transport).toBe("object"); + }); + }); + + describe("makeOptionallyEnabledNodeTransport", () => { + it("should create an optionally enabled node transport", () => { + const transport = makeOptionallyEnabledNodeTransport(true); + + expect(transport).toBeDefined(); + expect(typeof transport).toBe("function"); + }); + + describe("when the transport is enabled", () => { + it("should send requests", async () => { + const transport = makeOptionallyEnabledNodeTransport(true); + + const transportObject = transport({ + url: "https://localhost/upload", + recordDroppedEvent: () => { + /* */ + }, + }); + + const mockEnvelope: Envelope = [ + { event_id: "test-event-id", sent_at: new Date().toISOString() }, + [], + ]; + + await transportObject.send(mockEnvelope); + + expect(mocks.requestCalled).toHaveBeenCalled(); + expect(mocks.requestCalled).toHaveBeenCalledWith({ + headers: {}, + hostname: "localhost", + method: "POST", + path: "/upload", + port: "", + protocol: "https:", + }); + }); + }); + + describe("when the transport is disabled", () => { + it("should not send requests", async () => { + const transport = makeOptionallyEnabledNodeTransport(false); + + const transportObject = transport({ + url: "https://localhost/upload", + recordDroppedEvent: () => { + /* */ + }, + }); + + const mockEnvelope: Envelope = [ + { event_id: "test-event-id", sent_at: new Date().toISOString() }, + [], + ]; + const response = await transportObject.send(mockEnvelope); + + await vi.waitFor(() => expect(response.statusCode).toBe(200)); + }); + }); + }); +}); diff --git a/packages/bundler-plugin-core/src/sentry/telemetry.ts b/packages/bundler-plugin-core/src/sentry/telemetry.ts new file mode 100644 index 00000000..610dcd6a --- /dev/null +++ b/packages/bundler-plugin-core/src/sentry/telemetry.ts @@ -0,0 +1,190 @@ +/** + * Copied and modified from: + * https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/main/packages/bundler-plugin-core/src/sentry/telemetry.ts + */ +import { + Scope, + ServerRuntimeClient, + type ServerRuntimeClientOptions, + createStackParser, + nodeStackLineParser, + type Client, + startSpan, +} from "@sentry/core"; +import { type UnpluginOptions } from "unplugin"; +import { type NormalizedOptions } from "../utils/normalizeOptions"; +import { makeOptionallyEnabledNodeTransport } from "./transports"; +import { cyan } from "../utils/logging"; + +const stackParser = createStackParser(nodeStackLineParser()); + +interface CreateSentryInstanceOptions { + telemetry: boolean; + isDryRun: boolean; + pluginName: string; + pluginVersion: string; + options?: NormalizedOptions; + bundler: string; + metaFramework?: string; +} + +export function createSentryInstance({ + telemetry, + isDryRun, + pluginName, + pluginVersion, + options, + bundler, + metaFramework, +}: CreateSentryInstanceOptions): { + sentryScope: Scope; + sentryClient: Client; +} { + // setting to 0 will ensure that no data is sent + let sampleRate = 0; + let tracesSampleRate = 0; + // just being really explicit here as to what we're checking for + // currently we're not tracking dry runs as they're more for debugging, and + // are not interacting with our systems - up for debate whether we want to + // keep this + if (telemetry === true && isDryRun === false) { + sampleRate = 1; + tracesSampleRate = 1; + } + + const clientOptions: ServerRuntimeClientOptions = { + platform: "node", + runtime: { name: "node", version: global.process.version }, + + dsn: "https://942e283ea612c29cc3371c6d27f57e58@o26192.ingest.us.sentry.io/4506739665207296", + + tracesSampleRate, + sampleRate, + + release: pluginVersion, + integrations: [], + tracePropagationTargets: ["api.codecov.io"], + + stackParser, + + beforeSend: (event) => { + event.exception?.values?.forEach((exception) => { + // Stack track may have some PII + delete exception.stacktrace; + }); + + delete event.server_name; // Server name might contain PII + return event; + }, + + beforeSendTransaction: (event) => { + delete event.server_name; // Server name might contain PII + return event; + }, + + // We create a transport that stalls sending events until we know that we're allowed to + transport: makeOptionallyEnabledNodeTransport(telemetry), + }; + + const client = new ServerRuntimeClient(clientOptions); + const scope = new Scope(); + scope.setClient(client); + + if (options) { + setTelemetryDataOnScope( + options, + { name: pluginName, version: pluginVersion }, + scope, + bundler, + metaFramework, + ); + } + + return { sentryScope: scope, sentryClient: client }; +} + +interface PluginInfo { + name: string; + version: string; +} + +export function setTelemetryDataOnScope( + options: NormalizedOptions, + pluginInfo: PluginInfo, + scope: Scope, + bundler: string, + metaFramework?: string, +) { + // some general information about where the plugins are being ram + scope.setTag("node", process.version); + scope.setTag("platform", process.platform); + + // determine which plugin and it's version that's being used + scope.setTag("plugin.name", pluginInfo.name); + scope.setTag("plugin.version", pluginInfo.version); + + // determine the method of authorization + let authMode = options.dryRun ? "dry-run" : "tokenless"; + if (options.uploadToken && options.uploadToken !== "") { + authMode = "token"; + } else if (options.oidc?.useGitHubOIDC) { + authMode = "github-oidc"; + } + scope.setTag("auth_mode", authMode); + + // determine what git services are being used to auth with tokenless + if (options.gitService) { + scope.setTag("git_service", options.gitService); + } + + // want to see if we're mainly running in ci envs compared to local builds + scope.setTag("ci", !!process.env.CI); + + // track which bundlers and meta-frameworks are being used + scope.setTag("meta_framework", metaFramework ?? "none"); + scope.setTag("bundler", bundler); +} + +/** Flushing the SDK client can fail. We never want to crash the plugin because of telemetry. */ +export async function safeFlushTelemetry(sentryClient: Client) { + try { + await sentryClient.flush(2000); + } catch { + // Noop when flushing fails. + // We don't even need to log anything because there's likely nothing the user can do and they likely will not care. + } +} + +interface TelemetryPluginOptions { + sentryClient: Client; + sentryScope: Scope; + telemetry: boolean; +} + +export function telemetryPlugin({ + sentryClient, + sentryScope, + telemetry, +}: TelemetryPluginOptions): UnpluginOptions { + return { + name: "codecov-telemetry-plugin", + async buildStart() { + if (telemetry) { + cyan( + "Sending telemetry data on issues and performance to Codecov. To disable telemetry, set `options.telemetry` to `false`.", + ); + startSpan( + { + name: "Codecov Bundler Plugin Execution", + op: "bundler-plugin-execution", + scope: sentryScope, + }, + () => { + // + }, + ); + await safeFlushTelemetry(sentryClient); + } + }, + }; +} diff --git a/packages/bundler-plugin-core/src/sentry/transports.ts b/packages/bundler-plugin-core/src/sentry/transports.ts new file mode 100644 index 00000000..4d588105 --- /dev/null +++ b/packages/bundler-plugin-core/src/sentry/transports.ts @@ -0,0 +1,126 @@ +/** + * Copied from: + * https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/main/packages/bundler-plugin-core/src/sentry/transports.ts + */ +/** This is a simplified version of the Sentry Node SDK's HTTP transport. */ +import * as https from "node:https"; +import { Readable } from "node:stream"; +import { createGzip } from "node:zlib"; +import { + createTransport, + suppressTracing, + type BaseTransportOptions, + type Transport, + type TransportMakeRequestResponse, + type TransportRequest, + type TransportRequestExecutor, +} from "@sentry/core"; + +// Estimated maximum size for reasonable standalone event +const GZIP_THRESHOLD = 1024 * 32; + +/** + * Gets a stream from a Uint8Array or string Readable.from is ideal but was added in node.js v12.3.0 + * and v10.17.0. + */ +export function streamFromBody(body: Uint8Array | string): Readable { + return new Readable({ + read() { + this.push(body); + this.push(null); + }, + }); +} + +/** Creates a RequestExecutor to be used with `createTransport`. */ +export function createRequestExecutor( + options: BaseTransportOptions, +): TransportRequestExecutor { + const { hostname, pathname, port, protocol, search } = new URL(options.url); + + return function makeRequest( + request: TransportRequest, + ): Promise { + return new Promise((resolve, reject) => { + suppressTracing(() => { + let body = streamFromBody(request.body); + + const headers: Record = {}; + + if (request.body.length > GZIP_THRESHOLD) { + headers["content-encoding"] = "gzip"; + body = body.pipe(createGzip()); + } + + const req = https.request( + { + method: "POST", + headers, + hostname, + path: `${pathname}${search}`, + port, + protocol, + }, + (res) => { + res.on("data", () => { + // Drain socket + }); + + res.on("end", () => { + // Drain socket + }); + + res.setEncoding("utf8"); + + // "Key-value pairs of header names and values. Header names are lower-cased." + // https://nodejs.org/api/http.html#http_message_headers + const retryAfterHeader = res.headers["retry-after"] ?? null; + const rateLimitsHeader = + res.headers["x-sentry-rate-limits"] ?? null; + + resolve({ + statusCode: res.statusCode, + headers: { + "retry-after": retryAfterHeader, + "x-sentry-rate-limits": Array.isArray(rateLimitsHeader) + ? rateLimitsHeader[0] ?? null + : rateLimitsHeader, + }, + }); + }, + ); + + req.on("error", reject); + body.pipe(req); + }); + }); + }; +} + +/** + * Creates a Transport that uses native the native 'http' and 'https' modules to send events to + * Sentry. + */ +export function makeNodeTransport(options: BaseTransportOptions) { + const requestExecutor = createRequestExecutor(options); + return createTransport(options, requestExecutor); +} + +/** A transport that can be optionally enabled as a later time than it's creation. */ +export function makeOptionallyEnabledNodeTransport( + shouldSendTelemetry: boolean, +): (options: BaseTransportOptions) => Transport { + return (nodeTransportOptions) => { + const nodeTransport = makeNodeTransport(nodeTransportOptions); + return { + flush: (timeout) => nodeTransport.flush(timeout), + send: async (request) => { + if (shouldSendTelemetry) { + return nodeTransport.send(request); + } + + return { statusCode: 200 }; + }, + }; + }; +} diff --git a/packages/bundler-plugin-core/src/types.ts b/packages/bundler-plugin-core/src/types.ts index 131c26c2..ea7860d1 100644 --- a/packages/bundler-plugin-core/src/types.ts +++ b/packages/bundler-plugin-core/src/types.ts @@ -51,6 +51,8 @@ export interface OutputPayload { export interface BundleAnalysisUploadPluginArgs { output: Output; + pluginName: string; + pluginVersion: string; } export interface ExtendedBAUploadArgs @@ -144,6 +146,15 @@ export interface Options { */ dryRun?: boolean; + /** + * When enabled telemetry data will be sent to Codecov. + * + * Example: `telemetry: false` + * + * Defaults to `true` + */ + telemetry?: boolean; + /** Options for OIDC authentication. */ oidc?: { /** diff --git a/packages/bundler-plugin-core/src/utils/Output.ts b/packages/bundler-plugin-core/src/utils/Output.ts index 37a8e378..033bbaa0 100644 --- a/packages/bundler-plugin-core/src/utils/Output.ts +++ b/packages/bundler-plugin-core/src/utils/Output.ts @@ -1,3 +1,4 @@ +import { type Client, type Scope, startSpan } from "@sentry/core"; import { type Asset, type Chunk, @@ -12,6 +13,12 @@ import { detectProvider } from "./provider.ts"; import { uploadStats } from "./uploadStats.ts"; import { type ValidGitService } from "./normalizeOptions"; import { debug } from "./logging.ts"; +import { safeFlushTelemetry } from "../sentry/telemetry.ts"; + +interface SentryConfig { + sentryClient?: Client; + sentryScope?: Scope; +} class Output { // base user options @@ -27,6 +34,7 @@ class Output { debug: boolean; gitService?: ValidGitService; #internalOriginalBundleName: string; + telemetry: boolean; // uploader overrides branch?: string; build?: string; @@ -55,8 +63,10 @@ class Output { bundleName: false, pluginDetails: false, }; + sentryClient?: Client; + sentryScope?: Scope; - constructor(userOptions: NormalizedOptions) { + constructor(userOptions: NormalizedOptions, sentryConfig?: SentryConfig) { this.version = "3"; this.apiUrl = userOptions.apiUrl; this.dryRun = userOptions.dryRun; @@ -67,6 +77,9 @@ class Output { this.gitService = userOptions.gitService; this.#internalOriginalBundleName = userOptions.bundleName; this.oidc = userOptions.oidc; + this.telemetry = userOptions.telemetry; + this.sentryClient = sentryConfig?.sentryClient; + this.sentryScope = sentryConfig?.sentryScope; if (userOptions.uploadOverrides) { this.branch = userOptions.uploadOverrides.branch; @@ -148,45 +161,185 @@ class Output { }; const envs = process.env; const inputs: ProviderUtilInputs = { envs, args }; - const provider = await detectProvider(inputs, this); - - let url = ""; try { - url = await getPreSignedURL({ - apiUrl: this.apiUrl, - uploadToken: this.uploadToken, - gitService: this.gitService, - oidc: this.oidc, - retryCount: this.retryCount, - serviceParams: provider, - }); - } catch (error) { - if (emitError) { - throw error; - } + return await startSpan( + { + name: "Output Write", + op: "output.write", + scope: this.sentryScope, + forceTransaction: true, + }, + async (outputWriteSpan) => { + const provider = await startSpan( + { + name: "Detect Provider", + op: "output.write.detectProvider", + scope: this.sentryScope, + parentSpan: outputWriteSpan, + }, + async () => { + let detectedProvider; + try { + detectedProvider = await detectProvider(inputs, this); + } catch (error) { + if (this.sentryClient && this.sentryScope) { + this.sentryScope.addBreadcrumb({ + category: "output.write.detectProvider", + level: "error", + data: { error }, + }); + // this is being set as info because this could be caused by user error + this.sentryClient.captureMessage( + "Error in detectProvider", + "info", + undefined, + this.sentryScope, + ); + await safeFlushTelemetry(this.sentryClient); + } - debug(`Error getting pre-signed URL: "${error}"`, { - enabled: this.debug, - }); - return; - } + if (emitError) { + throw error; + } - try { - await uploadStats({ - preSignedUrl: url, - bundleName: this.bundleName, - message: this.bundleStatsToJson(), - retryCount: this?.retryCount, - }); + debug(`Error getting provider: "${error}"`, { + enabled: this.debug, + }); + return; + } + + return detectedProvider; + }, + ); + + // early return if no provider + if (!provider) return; + + if (this.sentryScope) { + this.sentryScope.setTag("service", provider.service); + + const slug = provider.slug ?? ""; + const repoIndex = slug.lastIndexOf("/") + 1; + // -1 to trim the trailing slash + const owner = slug.substring(0, repoIndex - 1).trimEnd(); + if (owner.length > 0) { + this.sentryScope.setTag("owner", owner); + } + + const repo = slug.substring(repoIndex, slug.length); + if (repo.length > 0) { + this.sentryScope.setTag("repo", repo); + } + } + + const presignedURL = await startSpan( + { + name: "Get Pre-Signed URL", + op: "output.write.getPreSignedURL", + scope: this.sentryScope, + parentSpan: outputWriteSpan, + }, + async () => { + let url = ""; + try { + url = await getPreSignedURL({ + apiUrl: this.apiUrl, + uploadToken: this.uploadToken, + gitService: this.gitService, + oidc: this.oidc, + retryCount: this.retryCount, + serviceParams: provider, + }); + } catch (error) { + if (this.sentryClient && this.sentryScope) { + this.sentryScope.addBreadcrumb({ + category: "output.write.getPreSignedURL", + level: "error", + data: { error }, + }); + // only setting this as info because this could be caused by user error + this.sentryClient.captureMessage( + "Error in getPreSignedURL", + "info", + undefined, + this.sentryScope, + ); + await safeFlushTelemetry(this.sentryClient); + } + + if (emitError) { + throw error; + } + + debug(`Error getting pre-signed URL: "${error}"`, { + enabled: this.debug, + }); + return; + } + + return url; + }, + ); + + // early return if no url + if (!presignedURL || presignedURL === "") return; + + await startSpan( + { + name: "Upload Stats", + op: "output.write.uploadStats", + scope: this.sentryScope, + parentSpan: outputWriteSpan, + }, + async () => { + try { + await uploadStats({ + preSignedUrl: presignedURL, + bundleName: this.bundleName, + message: this.bundleStatsToJson(), + retryCount: this?.retryCount, + }); + } catch (error) { + // this is being set as an error because this could not be caused by a user error + if (this.sentryClient && this.sentryScope) { + this.sentryScope.addBreadcrumb({ + category: "output.write.uploadStats", + level: "error", + data: { error }, + }); + this.sentryClient.captureMessage( + "Error in uploadStats", + "error", + undefined, + this.sentryScope, + ); + await safeFlushTelemetry(this.sentryClient); + } + + if (emitError) { + throw error; + } + + debug(`Error uploading stats: "${error}"`, { + enabled: this.debug, + }); + return; + } + }, + ); + + if (this.sentryClient) { + await safeFlushTelemetry(this.sentryClient); + } + + return; + }, + ); } catch (error) { if (emitError) { throw error; } - debug(`Error uploading stats: "${error}"`, { enabled: this.debug }); - return; } - - return; } bundleStatsToJson() { diff --git a/packages/bundler-plugin-core/src/utils/__tests__/Output.test.ts b/packages/bundler-plugin-core/src/utils/__tests__/Output.test.ts index 8150a245..666b5dd3 100644 --- a/packages/bundler-plugin-core/src/utils/__tests__/Output.test.ts +++ b/packages/bundler-plugin-core/src/utils/__tests__/Output.test.ts @@ -8,18 +8,29 @@ import { afterAll, type MockInstance, type Mock, + beforeEach, } from "vitest"; +import { type Scope, type Client } from "@sentry/core"; +import chalk from "chalk"; import { detectProvider } from "../provider"; import { Output } from "../Output"; -import chalk from "chalk"; vi.mock("../provider"); +vi.mock("@sentry/core", async () => { + const original = await vi.importActual("@sentry/core"); + return { + ...original, + startSpan: (_data: unknown, callback: (...args: unknown[]) => unknown) => + callback(), + }; +}); + const mockedDetectProvider = detectProvider as Mock; afterEach(() => { - vi.resetAllMocks(); + vi.clearAllMocks(); }); let consoleSpy: MockInstance; @@ -113,6 +124,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -140,6 +152,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -159,6 +172,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.end(); @@ -178,6 +192,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.setPlugin("test-plugin", "0.0.1"); @@ -199,6 +214,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.setPlugin("test-plugin", "0.0.1"); @@ -224,6 +240,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.setBundleName("new-bundle"); @@ -242,6 +259,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.setBundleName("new-bundle"); @@ -265,6 +283,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); output.end(); @@ -309,6 +328,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); output.end(); @@ -319,6 +339,160 @@ describe("Output", () => { }); }); + describe("fails to detect provider", () => { + beforeEach(() => { + mockedDetectProvider.mockRejectedValue( + new Error("Failed to detect provider"), + ); + }); + + it("throws an error", async () => { + const output = new Output({ + apiUrl: "http://localhost", + bundleName: "output-test", + debug: false, + dryRun: false, + enableBundleAnalysis: true, + retryCount: 1, + uploadToken: "token", + telemetry: false, + }); + + output.start(); + output.end(); + + try { + await output.write(); + } catch (error) { + expect(error).toBeInstanceOf(Error); + expect((error as Error).message).toBe("Failed to detect provider"); + } + }); + + it("logs error when debug is enabled", async () => { + const output = new Output({ + apiUrl: "http://localhost", + bundleName: "output-test", + debug: true, + dryRun: false, + enableBundleAnalysis: true, + retryCount: 1, + uploadToken: "token", + telemetry: false, + }); + + output.start(); + output.end(); + + await output.write(); + + expect(consoleSpy).toHaveBeenCalledWith( + `[codecov] ${chalk.italic.yellow( + 'Error getting provider: "Error: Failed to detect provider"', + )}`, + ); + }); + + it("captures a message to sentry", async () => { + const sentryClient = { + captureMessage: vi.fn(), + } as unknown as Client; + + const sentryScope = { + getClient: vi.fn(), + setTag: vi.fn(), + addBreadcrumb: vi.fn(), + } as unknown as Scope; + + const output = new Output( + { + apiUrl: "http://localhost", + bundleName: "output-test", + debug: true, + dryRun: false, + enableBundleAnalysis: true, + retryCount: 1, + uploadToken: "token", + telemetry: false, + }, + { sentryClient, sentryScope }, + ); + + output.start(); + output.end(); + + await output.write(); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryClient.captureMessage).toHaveBeenCalledWith( + "Error in detectProvider", + "info", + undefined, + sentryScope, + ); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryScope.addBreadcrumb).toHaveBeenCalledWith({ + category: "output.write.detectProvider", + level: "error", + data: { error: Error("Failed to detect provider") }, + }); + }); + }); + + describe("successful detection of provider", () => { + it("sets the owner and repo tags", async () => { + setup({}); + const sentryClient = { + captureMessage: vi.fn(), + } as unknown as Client; + + const sentryScope = { + getClient: vi.fn(), + setTag: vi.fn(), + addBreadcrumb: vi.fn(), + } as unknown as Scope; + + const output = new Output( + { + apiUrl: "http://localhost", + bundleName: "output-test", + debug: false, + dryRun: false, + enableBundleAnalysis: true, + retryCount: 1, + uploadToken: "token", + telemetry: false, + }, + { sentryClient, sentryScope }, + ); + + output.start(); + output.end(); + + await output.write(); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryScope.setTag).toHaveBeenNthCalledWith( + 1, + "service", + "github", + ); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryScope.setTag).toHaveBeenNthCalledWith( + 2, + "owner", + "codecov", + ); + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryScope.setTag).toHaveBeenNthCalledWith( + 3, + "repo", + "codecov-javascript-bundler-plugins", + ); + }); + }); + describe("fails to fetch pre-signed URL", () => { it("immediately returns", async () => { setup({ urlSendError: true }); @@ -331,6 +505,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -350,6 +525,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -375,6 +551,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -384,6 +561,54 @@ describe("Output", () => { "Failed to fetch pre-signed URL", ); }); + + it("captures message to sentry", async () => { + setup({ urlSendError: true }); + + const sentryClient = { + captureMessage: vi.fn(), + } as unknown as Client; + + const sentryScope = { + getClient: vi.fn(), + setTag: vi.fn(), + addBreadcrumb: vi.fn(), + } as unknown as Scope; + + const output = new Output( + { + apiUrl: "http://localhost", + bundleName: "output-test", + debug: false, + dryRun: false, + enableBundleAnalysis: true, + retryCount: 1, + uploadToken: "token", + telemetry: false, + }, + { sentryClient, sentryScope }, + ); + + output.start(); + output.end(); + + await output.write(); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryClient.captureMessage).toHaveBeenCalledWith( + "Error in getPreSignedURL", + "info", + undefined, + sentryScope, + ); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryScope.addBreadcrumb).toHaveBeenCalledWith({ + category: "output.write.getPreSignedURL", + level: "error", + data: { error: Error("Failed to fetch pre-signed URL") }, + }); + }); }); describe("successful fetch of pre-signed URL", () => { @@ -401,6 +626,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -448,6 +674,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -471,6 +698,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -500,6 +728,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); @@ -509,6 +738,58 @@ describe("Output", () => { "Failed to upload stats", ); }); + + it("captures message to sentry", async () => { + setup({ + urlData: { url: "http://localhost/upload/stats/" }, + urlStatus: 200, + statsSendError: true, + }); + + const sentryClient = { + captureMessage: vi.fn(), + } as unknown as Client; + + const sentryScope = { + getClient: vi.fn(), + setTag: vi.fn(), + addBreadcrumb: vi.fn(), + } as unknown as Scope; + + const output = new Output( + { + apiUrl: "http://localhost", + bundleName: "output-test", + debug: false, + dryRun: false, + enableBundleAnalysis: true, + retryCount: 1, + uploadToken: "token", + telemetry: false, + }, + { sentryClient, sentryScope }, + ); + + output.start(); + output.end(); + + await output.write(); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryClient.captureMessage).toHaveBeenCalledWith( + "Error in uploadStats", + "error", + undefined, + sentryScope, + ); + + // eslint-disable-next-line @typescript-eslint/unbound-method + expect(sentryScope.addBreadcrumb).toHaveBeenCalledWith({ + category: "output.write.uploadStats", + level: "error", + data: { error: Error("Failed to upload stats") }, + }); + }); }); describe("successful uploading of stats", () => { @@ -528,6 +809,7 @@ describe("Output", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "token", + telemetry: false, }); output.start(); diff --git a/packages/bundler-plugin-core/src/utils/__tests__/normalizeOptions.test.ts b/packages/bundler-plugin-core/src/utils/__tests__/normalizeOptions.test.ts index a5a02c40..1f003811 100644 --- a/packages/bundler-plugin-core/src/utils/__tests__/normalizeOptions.test.ts +++ b/packages/bundler-plugin-core/src/utils/__tests__/normalizeOptions.test.ts @@ -39,6 +39,7 @@ const tests: Test[] = [ retryCount: 3, enableBundleAnalysis: false, debug: false, + telemetry: true, }, }, }, @@ -62,6 +63,7 @@ const tests: Test[] = [ }, debug: true, gitService: "bitbucket", + telemetry: false, oidc: { useGitHubOIDC: true, gitHubOIDCTokenAudience: "https://codecov.io", @@ -87,6 +89,7 @@ const tests: Test[] = [ }, debug: true, gitService: "bitbucket", + telemetry: false, oidc: { useGitHubOIDC: true, gitHubOIDCTokenAudience: "https://codecov.io", @@ -128,6 +131,8 @@ const tests: Test[] = [ debug: "true", // @ts-expect-error - testing invalid input gitService: 123, + // @ts-expect-error - testing invalid input + telemetry: "true", oidc: { // @ts-expect-error - testing invalid input useGitHubOIDC: "true", @@ -155,6 +160,7 @@ const tests: Test[] = [ "`gitService` must be a valid git service.", "`useGitHubOIDC` must be a boolean.", "`gitHubOIDCTokenAudience` must be a string.", + "`telemetry` must be a boolean.", ], }, }, diff --git a/packages/bundler-plugin-core/src/utils/__tests__/provider.test.ts b/packages/bundler-plugin-core/src/utils/__tests__/provider.test.ts index 4fdd8115..837fb013 100644 --- a/packages/bundler-plugin-core/src/utils/__tests__/provider.test.ts +++ b/packages/bundler-plugin-core/src/utils/__tests__/provider.test.ts @@ -47,6 +47,7 @@ describe("detectProvider", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const result = await detectProvider(inputs, output); @@ -65,6 +66,7 @@ describe("detectProvider", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); try { diff --git a/packages/bundler-plugin-core/src/utils/normalizeOptions.ts b/packages/bundler-plugin-core/src/utils/normalizeOptions.ts index 6dbedd88..6efff8b2 100644 --- a/packages/bundler-plugin-core/src/utils/normalizeOptions.ts +++ b/packages/bundler-plugin-core/src/utils/normalizeOptions.ts @@ -146,6 +146,11 @@ const optionsSchemaFactory = (options: Options) => ) .optional(), oidc: OIDCSchema.optional(), + telemetry: z + .boolean({ + invalid_type_error: "`telemetry` must be a boolean.", + }) + .default(true), }); interface NormalizedOptionsFailure { diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/AppVeyorCI.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/AppVeyorCI.test.ts index 624f5a70..41cf2940 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/AppVeyorCI.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/AppVeyorCI.test.ts @@ -88,6 +88,7 @@ describe("AppveyorCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AppVeyorCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -130,6 +131,7 @@ describe("AppveyorCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AppVeyorCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -171,6 +173,7 @@ describe("AppveyorCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AppVeyorCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -200,6 +203,7 @@ describe("AppveyorCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AppVeyorCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/AzurePipelines.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/AzurePipelines.test.ts index c3ebcd01..c371a453 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/AzurePipelines.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/AzurePipelines.test.ts @@ -65,6 +65,7 @@ describe("Azure Pipelines CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AzurePipelines.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -107,6 +108,7 @@ describe("Azure Pipelines CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AzurePipelines.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -149,6 +151,7 @@ describe("Azure Pipelines CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AzurePipelines.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -194,6 +197,7 @@ describe("Azure Pipelines CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AzurePipelines.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -240,6 +244,7 @@ describe("Azure Pipelines CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AzurePipelines.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -280,6 +285,7 @@ describe("Azure Pipelines CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await AzurePipelines.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Bitbucket.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Bitbucket.test.ts index 8d098c25..f8f62417 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Bitbucket.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Bitbucket.test.ts @@ -69,6 +69,7 @@ describe("Bitbucket Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitbucket.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -104,6 +105,7 @@ describe("Bitbucket Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitbucket.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -138,6 +140,7 @@ describe("Bitbucket Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitbucket.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -180,6 +183,7 @@ describe("Bitbucket Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitbucket.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -224,6 +228,7 @@ describe("Bitbucket Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitbucket.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Bitrise.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Bitrise.test.ts index 0cb91d3c..50ec3543 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Bitrise.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Bitrise.test.ts @@ -84,6 +84,7 @@ describe("Bitrise Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitrise.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -128,6 +129,7 @@ describe("Bitrise Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitrise.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -172,6 +174,7 @@ describe("Bitrise Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitrise.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -226,6 +229,7 @@ describe("Bitrise Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Bitrise.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Buildkite.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Buildkite.test.ts index 13a2191a..00e10f1d 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Buildkite.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Buildkite.test.ts @@ -68,6 +68,7 @@ describe("Buildkite Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Buildkite.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -108,6 +109,7 @@ describe("Buildkite Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Buildkite.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/CircleCI.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/CircleCI.test.ts index cda8b487..973d94e7 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/CircleCI.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/CircleCI.test.ts @@ -71,6 +71,7 @@ describe("CircleCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await CircleCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -109,6 +110,7 @@ describe("CircleCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await CircleCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -154,6 +156,7 @@ describe("CircleCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await CircleCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Cirrus.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Cirrus.test.ts index 23761de8..84ba5d07 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Cirrus.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Cirrus.test.ts @@ -68,6 +68,7 @@ describe("Cirrus Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Cirrus.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -114,6 +115,7 @@ describe("Cirrus Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Cirrus.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/CloudflarePages.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/CloudflarePages.test.ts index c634732b..d1eca607 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/CloudflarePages.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/CloudflarePages.test.ts @@ -65,6 +65,7 @@ describe("CloudflarePages Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await CloudflarePages.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -104,6 +105,7 @@ describe("CloudflarePages Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await CloudflarePages.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -133,6 +135,7 @@ describe("CloudflarePages Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await CloudflarePages.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/CodeBuild.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/CodeBuild.test.ts index 25ea6a35..e1b0d263 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/CodeBuild.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/CodeBuild.test.ts @@ -68,6 +68,7 @@ describe("CodeBuild Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await CodeBuild.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -113,6 +114,7 @@ describe("CodeBuild Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await CodeBuild.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Drone.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Drone.test.ts index 4fecbe18..c3c72989 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Drone.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Drone.test.ts @@ -68,6 +68,7 @@ describe("Drone Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Drone.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -115,6 +116,7 @@ describe("Drone Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Drone.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -152,6 +154,7 @@ describe("Drone Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Drone.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/GitHubActions.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/GitHubActions.test.ts index 1d5525eb..cb2d06fa 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/GitHubActions.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/GitHubActions.test.ts @@ -153,6 +153,7 @@ describe("GitHub Actions Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitHubActions.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -181,6 +182,7 @@ describe("GitHub Actions Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitHubActions.getServiceParams(inputs, output); @@ -244,6 +246,7 @@ describe("GitHub Actions Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitHubActions.getServiceParams(inputs, output); @@ -300,6 +303,7 @@ describe("GitHub Actions Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitHubActions.getServiceParams(inputs, output); @@ -355,6 +359,7 @@ describe("GitHub Actions Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitHubActions.getServiceParams(inputs, output); @@ -419,6 +424,7 @@ describe("GitHub Actions Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitHubActions.getServiceParams(inputs, output); @@ -459,6 +465,7 @@ describe("GitHub Actions Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitHubActions.getServiceParams(inputs, output); @@ -503,6 +510,7 @@ describe("GitHub Actions Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitHubActions.getServiceParams(inputs, output); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/GitLabCI.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/GitLabCI.test.ts index bdc3dd54..f7a0e41f 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/GitLabCI.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/GitLabCI.test.ts @@ -68,6 +68,7 @@ describe("GitLabCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitLabCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -105,6 +106,7 @@ describe("GitLabCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitLabCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -139,6 +141,7 @@ describe("GitLabCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitLabCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -159,6 +162,7 @@ describe("GitLabCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); it("can get the slug from http", async () => { @@ -250,6 +254,7 @@ describe("GitLabCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await GitLabCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/HerokuCI.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/HerokuCI.test.ts index 3f6c961c..183a04f9 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/HerokuCI.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/HerokuCI.test.ts @@ -67,6 +67,7 @@ describe("HerokuCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await HerokuCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -108,6 +109,7 @@ describe("HerokuCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await HerokuCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -145,6 +147,7 @@ describe("HerokuCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await HerokuCI.getServiceParams(inputs, output); expect(expected).toBeTruthy(); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/JenkinsCI.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/JenkinsCI.test.ts index eab10f89..b61f2d7f 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/JenkinsCI.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/JenkinsCI.test.ts @@ -77,6 +77,7 @@ describe("Jenkins CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await JenkinsCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -110,6 +111,7 @@ describe("Jenkins CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await JenkinsCI.getServiceParams(inputs, output); expect(params.slug).toBe("testOrg/testRepo"); @@ -149,6 +151,7 @@ describe("Jenkins CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await JenkinsCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -187,6 +190,7 @@ describe("Jenkins CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await JenkinsCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Local.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Local.test.ts index 96a08abd..62359082 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Local.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Local.test.ts @@ -69,6 +69,7 @@ describe("Local Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Local.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -107,6 +108,7 @@ describe("Local Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Local.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -125,6 +127,7 @@ describe("Local Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const spawnSync = td.replace(childProcess, "spawnSync"); await expect(Local.getServiceParams(inputs, output)).rejects.toThrow(); @@ -188,6 +191,7 @@ describe("Local Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Local.getServiceParams(inputs, output); expect(params.slug).toBe("testOrg/testRepo"); @@ -226,6 +230,7 @@ describe("Local Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); await expect(Local.getServiceParams(inputs, output)).rejects.toThrow(); }); @@ -264,6 +269,7 @@ describe("Local Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Local.getServiceParams(inputs, output); expect(params.slug).toBe("testOrg/testRepo"); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Netlify.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Netlify.test.ts index 2727ba11..db531efe 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Netlify.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Netlify.test.ts @@ -66,6 +66,7 @@ describe("Netlify Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Netlify.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -106,6 +107,7 @@ describe("Netlify Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Netlify.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -135,6 +137,7 @@ describe("Netlify Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Netlify.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Render.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Render.test.ts index 27515ddd..c1ab9e96 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Render.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Render.test.ts @@ -66,6 +66,7 @@ describe("Render Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Render.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -106,6 +107,7 @@ describe("Render Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Render.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -135,6 +137,7 @@ describe("Render Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Render.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/TeamCity.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/TeamCity.test.ts index 56728532..24621c77 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/TeamCity.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/TeamCity.test.ts @@ -73,6 +73,7 @@ describe("TeamCity Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TeamCity.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -115,6 +116,7 @@ describe("TeamCity Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TeamCity.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -164,6 +166,7 @@ describe("TeamCity Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TeamCity.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -200,6 +203,7 @@ describe("TeamCity Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TeamCity.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/TravisCI.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/TravisCI.test.ts index 54e612f2..b1bc9655 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/TravisCI.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/TravisCI.test.ts @@ -83,6 +83,7 @@ describe("TravisCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TravisCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -124,6 +125,7 @@ describe("TravisCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TravisCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -164,6 +166,7 @@ describe("TravisCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TravisCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -205,6 +208,7 @@ describe("TravisCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TravisCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -234,6 +238,7 @@ describe("TravisCI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await TravisCI.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Vercel.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Vercel.test.ts index 8caf0c53..4c92fe98 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Vercel.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Vercel.test.ts @@ -67,6 +67,7 @@ describe("Vercel Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Vercel.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -108,6 +109,7 @@ describe("Vercel Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Vercel.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -137,6 +139,7 @@ describe("Vercel Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Vercel.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Werker.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Werker.test.ts index f75f90b7..01c3a7a3 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Werker.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Werker.test.ts @@ -68,6 +68,7 @@ describe("Wercker CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Wercker.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -114,6 +115,7 @@ describe("Wercker CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Wercker.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -142,6 +144,7 @@ describe("Wercker CI Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await Wercker.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/Woodpecker.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/Woodpecker.test.ts index 97508e46..333ccb7c 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/Woodpecker.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/Woodpecker.test.ts @@ -69,6 +69,7 @@ describe("Woodpecker Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await providerWoodpecker.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -119,6 +120,7 @@ describe("Woodpecker Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await providerWoodpecker.getServiceParams(inputs, output); expect(params).toMatchObject(expected); @@ -147,6 +149,7 @@ describe("Woodpecker Params", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const params = await providerWoodpecker.getServiceParams(inputs, output); expect(params).toMatchObject(expected); diff --git a/packages/bundler-plugin-core/src/utils/providers/__tests__/index.test.ts b/packages/bundler-plugin-core/src/utils/providers/__tests__/index.test.ts index 33c34432..fa8dc384 100644 --- a/packages/bundler-plugin-core/src/utils/providers/__tests__/index.test.ts +++ b/packages/bundler-plugin-core/src/utils/providers/__tests__/index.test.ts @@ -72,6 +72,7 @@ describe("CI Providers", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const serviceParams = await provider.getServiceParams(inputs, output); @@ -100,6 +101,7 @@ describe("CI Providers", () => { dryRun: true, enableBundleAnalysis: true, retryCount: 0, + telemetry: false, }); const serviceParams = await provider.getServiceParams(inputs, output); diff --git a/packages/nextjs-webpack-plugin/src/index.ts b/packages/nextjs-webpack-plugin/src/index.ts index a0e7351c..5405283c 100644 --- a/packages/nextjs-webpack-plugin/src/index.ts +++ b/packages/nextjs-webpack-plugin/src/index.ts @@ -11,10 +11,17 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { nextJSWebpackBundleAnalysisPlugin } from "./nextjs-webpack-bundle-analysis/nextJSWebpackBundleAnalysisPlugin.ts"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + interface NextPluginOptions extends Options { webpack: typeof webpack | null; } @@ -38,15 +45,29 @@ const codecovNextJSWebpackPluginFactory = createWebpackPlugin< } const plugins: UnpluginOptions[] = []; - const output = new Output(normalizedOptions.options); const options = normalizedOptions.options; + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + metaFramework: "nextjs", + }); + const output = new Output(options, sentryConfig); if (options.enableBundleAnalysis) { plugins.push( + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), nextJSWebpackBundleAnalysisPlugin({ output, - options: { - webpack: userOptions.webpack, - }, + options: { webpack: userOptions.webpack }, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }), ); } diff --git a/packages/nextjs-webpack-plugin/src/nextjs-webpack-bundle-analysis/__tests__/nextJSWebpackBundleAnalysisPlugin.test.ts b/packages/nextjs-webpack-plugin/src/nextjs-webpack-bundle-analysis/__tests__/nextJSWebpackBundleAnalysisPlugin.test.ts index 65551ab6..9b826a5b 100644 --- a/packages/nextjs-webpack-plugin/src/nextjs-webpack-bundle-analysis/__tests__/nextJSWebpackBundleAnalysisPlugin.test.ts +++ b/packages/nextjs-webpack-plugin/src/nextjs-webpack-bundle-analysis/__tests__/nextJSWebpackBundleAnalysisPlugin.test.ts @@ -3,6 +3,11 @@ import { describe, it, expect } from "vitest"; import * as webpack from "webpack"; import { nextJSWebpackBundleAnalysisPlugin } from "../nextJSWebpackBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("webpackBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -15,10 +20,13 @@ describe("webpackBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), options: { webpack: webpack, }, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/nextjs-webpack-plugin/src/nextjs-webpack-bundle-analysis/nextJSWebpackBundleAnalysisPlugin.ts b/packages/nextjs-webpack-plugin/src/nextjs-webpack-bundle-analysis/nextJSWebpackBundleAnalysisPlugin.ts index c6ad3305..1ee70da5 100644 --- a/packages/nextjs-webpack-plugin/src/nextjs-webpack-bundle-analysis/nextJSWebpackBundleAnalysisPlugin.ts +++ b/packages/nextjs-webpack-plugin/src/nextjs-webpack-bundle-analysis/nextJSWebpackBundleAnalysisPlugin.ts @@ -1,5 +1,5 @@ import { red, type ExtendedBAUploadPlugin } from "@codecov/bundler-plugin-core"; -import type * as webpack from "webpack"; +import type * as TWebpack from "webpack"; import { _internal_processAssets as processAssets, @@ -7,20 +7,15 @@ import { _internal_processModules as processModules, } from "@codecov/webpack-plugin"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - export const nextJSWebpackBundleAnalysisPlugin: ExtendedBAUploadPlugin<{ - webpack: typeof webpack | null; -}> = ({ output, options: { webpack } }) => ({ + webpack: typeof TWebpack | null; +}> = ({ output, pluginName, pluginVersion, options }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, buildStart: () => { output.start(); - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, buildEnd: () => { output.end(); @@ -29,8 +24,8 @@ export const nextJSWebpackBundleAnalysisPlugin: ExtendedBAUploadPlugin<{ await output.write(); }, webpack(compiler) { - compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => { - if (!webpack) { + compiler.hooks.thisCompilation.tap(pluginName, (compilation) => { + if (!options.webpack) { red( "Unable to run bundle analysis, Webpack wasn't passed successfully.", ); @@ -39,10 +34,17 @@ export const nextJSWebpackBundleAnalysisPlugin: ExtendedBAUploadPlugin<{ compilation.hooks.processAssets.tapPromise( { - name: PLUGIN_NAME, - stage: webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT, + name: pluginName, + stage: options.webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT, }, async () => { + if (!options.webpack) { + red( + "Unable to run bundle analysis, Webpack wasn't passed successfully.", + ); + return; + } + output.setBundleName(output.originalBundleName); // Webpack base chunk format options: https://webpack.js.org/configuration/output/#outputchunkformat if (typeof compilation.outputOptions.chunkFormat === "string") { @@ -70,7 +72,7 @@ export const nextJSWebpackBundleAnalysisPlugin: ExtendedBAUploadPlugin<{ output.bundler = { name: "webpack", - version: webpack.version, + version: options.webpack.version, }; const outputOptions = compilation.outputOptions; @@ -101,7 +103,7 @@ export const nextJSWebpackBundleAnalysisPlugin: ExtendedBAUploadPlugin<{ // only output file if running dry run if (output.dryRun) { - const { RawSource } = webpack.sources; + const { RawSource } = options.webpack.sources; compilation.emitAsset( `${output.bundleName}-stats.json`, new RawSource(output.bundleStatsToJson()), diff --git a/packages/nuxt-plugin/src/index.ts b/packages/nuxt-plugin/src/index.ts index 83794fc5..d1130262 100644 --- a/packages/nuxt-plugin/src/index.ts +++ b/packages/nuxt-plugin/src/index.ts @@ -6,6 +6,8 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { _internal_viteBundleAnalysisPlugin } from "@codecov/vite-plugin"; import { addVitePlugin, defineNuxtModule } from "@nuxt/kit"; @@ -13,8 +15,10 @@ import { addVitePlugin, defineNuxtModule } from "@nuxt/kit"; import { nuxtBundleAnalysisPlugin } from "./nuxt-bundle-analysis/nuxtBundleAnalysisPlugin"; import { type NuxtModule } from "nuxt/schema"; -// @ts-expect-error - This is a placeholder for the package name. +// @ts-expect-error this value is being replaced by rollup const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; const codecovNuxtPluginFactory = createVitePlugin( (userOptions, unpluginMetaContext) => { @@ -33,12 +37,35 @@ const codecovNuxtPluginFactory = createVitePlugin( } const plugins: UnpluginOptions[] = []; - const output = new Output(normalizedOptions.options); const options = normalizedOptions.options; + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + metaFramework: "nuxt", + }); + const output = new Output(options, sentryConfig); + if (options.enableBundleAnalysis) { plugins.push( - nuxtBundleAnalysisPlugin({ output }), - _internal_viteBundleAnalysisPlugin({ output }), + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), + nuxtBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), + _internal_viteBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), ); } diff --git a/packages/nuxt-plugin/src/nuxt-bundle-analysis/__tests__/nuxtBundleAnalysisPlugin.test.ts b/packages/nuxt-plugin/src/nuxt-bundle-analysis/__tests__/nuxtBundleAnalysisPlugin.test.ts index 092df0e3..84da0a9f 100644 --- a/packages/nuxt-plugin/src/nuxt-bundle-analysis/__tests__/nuxtBundleAnalysisPlugin.test.ts +++ b/packages/nuxt-plugin/src/nuxt-bundle-analysis/__tests__/nuxtBundleAnalysisPlugin.test.ts @@ -2,6 +2,11 @@ import { Output } from "@codecov/bundler-plugin-core"; import { describe, it, expect } from "vitest"; import { nuxtBundleAnalysisPlugin } from "../nuxtBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("nuxtBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -14,7 +19,10 @@ describe("nuxtBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/nuxt-plugin/src/nuxt-bundle-analysis/nuxtBundleAnalysisPlugin.ts b/packages/nuxt-plugin/src/nuxt-bundle-analysis/nuxtBundleAnalysisPlugin.ts index b96707d4..604b92b1 100644 --- a/packages/nuxt-plugin/src/nuxt-bundle-analysis/nuxtBundleAnalysisPlugin.ts +++ b/packages/nuxt-plugin/src/nuxt-bundle-analysis/nuxtBundleAnalysisPlugin.ts @@ -4,17 +4,14 @@ import { } from "@codecov/bundler-plugin-core"; import { getBundleName } from "./getBundleName"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - export const nuxtBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output, + pluginName, + pluginVersion, }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, vite: { generateBundle(this, options) { // TODO - remove this once we hard fail on not having a bundle name @@ -36,7 +33,7 @@ export const nuxtBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output.lockBundleName(); // manually set this to avoid resetting in the vite plugin - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, }, }); diff --git a/packages/remix-vite-plugin/src/index.ts b/packages/remix-vite-plugin/src/index.ts index 561c0ba9..1f43145c 100644 --- a/packages/remix-vite-plugin/src/index.ts +++ b/packages/remix-vite-plugin/src/index.ts @@ -10,11 +10,18 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { _internal_viteBundleAnalysisPlugin } from "@codecov/vite-plugin"; import { remixBundleAnalysisPlugin } from "./remix-bundle-analysis/remixBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + const codecovRemixVitePluginFactory = createVitePlugin( (userOptions, unpluginMetaContext) => { if (checkNodeVersion(unpluginMetaContext)) { @@ -32,12 +39,35 @@ const codecovRemixVitePluginFactory = createVitePlugin( } const plugins: UnpluginOptions[] = []; - const output = new Output(normalizedOptions.options); const options = normalizedOptions.options; + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + metaFramework: "remix", + }); + const output = new Output(options, sentryConfig); + if (options.enableBundleAnalysis) { plugins.push( - remixBundleAnalysisPlugin({ output }), - _internal_viteBundleAnalysisPlugin({ output }), + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), + remixBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), + _internal_viteBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), ); } diff --git a/packages/remix-vite-plugin/src/remix-bundle-analysis/__tests__/remixBundleAnalysisPlugin.test.ts b/packages/remix-vite-plugin/src/remix-bundle-analysis/__tests__/remixBundleAnalysisPlugin.test.ts index e74d8b5d..0383c1d2 100644 --- a/packages/remix-vite-plugin/src/remix-bundle-analysis/__tests__/remixBundleAnalysisPlugin.test.ts +++ b/packages/remix-vite-plugin/src/remix-bundle-analysis/__tests__/remixBundleAnalysisPlugin.test.ts @@ -2,6 +2,11 @@ import { Output } from "@codecov/bundler-plugin-core"; import { describe, it, expect } from "vitest"; import { remixBundleAnalysisPlugin } from "../remixBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("remixBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -14,7 +19,10 @@ describe("remixBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/remix-vite-plugin/src/remix-bundle-analysis/remixBundleAnalysisPlugin.ts b/packages/remix-vite-plugin/src/remix-bundle-analysis/remixBundleAnalysisPlugin.ts index 6e43c9d1..9d1c894b 100644 --- a/packages/remix-vite-plugin/src/remix-bundle-analysis/remixBundleAnalysisPlugin.ts +++ b/packages/remix-vite-plugin/src/remix-bundle-analysis/remixBundleAnalysisPlugin.ts @@ -4,17 +4,14 @@ import { } from "@codecov/bundler-plugin-core"; import { getBundleName } from "./getBundleName"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - export const remixBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output, + pluginName, + pluginVersion, }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, vite: { generateBundle(this, options) { // TODO - remove this once we hard fail on not having a bundle name @@ -36,7 +33,7 @@ export const remixBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output.lockBundleName(); // manually set this to avoid resetting in the vite plugin - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, }, }); diff --git a/packages/rollup-plugin/src/index.ts b/packages/rollup-plugin/src/index.ts index e7d82685..c11aae0d 100644 --- a/packages/rollup-plugin/src/index.ts +++ b/packages/rollup-plugin/src/index.ts @@ -10,10 +10,17 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { rollupBundleAnalysisPlugin } from "./rollup-bundle-analysis/rollupBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + const codecovRollupPluginFactory = createRollupPlugin( (userOptions, unpluginMetaContext) => { if (checkNodeVersion(unpluginMetaContext)) { @@ -31,12 +38,28 @@ const codecovRollupPluginFactory = createRollupPlugin( } const plugins: UnpluginOptions[] = []; - const output = new Output(normalizedOptions.options); const options = normalizedOptions.options; + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + }); + const output = new Output(options, sentryConfig); + if (options.enableBundleAnalysis) { plugins.push( + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), rollupBundleAnalysisPlugin({ output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }), ); } diff --git a/packages/rollup-plugin/src/rollup-bundle-analysis/__tests__/rollupBundleAnalysisPlugin.test.ts b/packages/rollup-plugin/src/rollup-bundle-analysis/__tests__/rollupBundleAnalysisPlugin.test.ts index d0f4592a..a4e63639 100644 --- a/packages/rollup-plugin/src/rollup-bundle-analysis/__tests__/rollupBundleAnalysisPlugin.test.ts +++ b/packages/rollup-plugin/src/rollup-bundle-analysis/__tests__/rollupBundleAnalysisPlugin.test.ts @@ -2,6 +2,11 @@ import { Output } from "@codecov/bundler-plugin-core"; import { describe, it, expect } from "vitest"; import { rollupBundleAnalysisPlugin } from "../rollupBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("rollupBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -14,7 +19,10 @@ describe("rollupBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/rollup-plugin/src/rollup-bundle-analysis/rollupBundleAnalysisPlugin.ts b/packages/rollup-plugin/src/rollup-bundle-analysis/rollupBundleAnalysisPlugin.ts index 31ffd7de..fcf4a199 100644 --- a/packages/rollup-plugin/src/rollup-bundle-analysis/rollupBundleAnalysisPlugin.ts +++ b/packages/rollup-plugin/src/rollup-bundle-analysis/rollupBundleAnalysisPlugin.ts @@ -8,20 +8,17 @@ import { createRollupAsset, } from "@codecov/bundler-plugin-core"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - export const rollupBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output, + pluginName, + pluginVersion, }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, buildStart: () => { output.start(); - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, buildEnd: () => { output.end(); diff --git a/packages/solidstart-plugin/src/index.ts b/packages/solidstart-plugin/src/index.ts index acaa3713..06b5e299 100644 --- a/packages/solidstart-plugin/src/index.ts +++ b/packages/solidstart-plugin/src/index.ts @@ -10,11 +10,18 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { _internal_viteBundleAnalysisPlugin } from "@codecov/vite-plugin"; import { solidstartBundleAnalysisPlugin } from "./solidstart-bundle-analysis/solidstartBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + const codecovSolidStartPluginFactory = createVitePlugin( (userOptions, unpluginMetaContext) => { if (checkNodeVersion(unpluginMetaContext)) { @@ -32,12 +39,35 @@ const codecovSolidStartPluginFactory = createVitePlugin( } const plugins: UnpluginOptions[] = []; - const output = new Output(normalizedOptions.options); const options = normalizedOptions.options; + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + metaFramework: "solidstart", + }); + const output = new Output(options, sentryConfig); + if (options.enableBundleAnalysis) { plugins.push( - solidstartBundleAnalysisPlugin({ output }), - _internal_viteBundleAnalysisPlugin({ output }), + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), + solidstartBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), + _internal_viteBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), ); } diff --git a/packages/solidstart-plugin/src/solidstart-bundle-analysis/__tests__/solidstartBundleAnalysisPlugin.test.ts b/packages/solidstart-plugin/src/solidstart-bundle-analysis/__tests__/solidstartBundleAnalysisPlugin.test.ts index 8e21392f..5123109c 100644 --- a/packages/solidstart-plugin/src/solidstart-bundle-analysis/__tests__/solidstartBundleAnalysisPlugin.test.ts +++ b/packages/solidstart-plugin/src/solidstart-bundle-analysis/__tests__/solidstartBundleAnalysisPlugin.test.ts @@ -2,6 +2,11 @@ import { Output } from "@codecov/bundler-plugin-core"; import { describe, it, expect } from "vitest"; import { solidstartBundleAnalysisPlugin } from "../solidstartBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("solidstartBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -14,7 +19,10 @@ describe("solidstartBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/solidstart-plugin/src/solidstart-bundle-analysis/solidstartBundleAnalysisPlugin.ts b/packages/solidstart-plugin/src/solidstart-bundle-analysis/solidstartBundleAnalysisPlugin.ts index a0d0d278..47d18793 100644 --- a/packages/solidstart-plugin/src/solidstart-bundle-analysis/solidstartBundleAnalysisPlugin.ts +++ b/packages/solidstart-plugin/src/solidstart-bundle-analysis/solidstartBundleAnalysisPlugin.ts @@ -4,17 +4,14 @@ import { } from "@codecov/bundler-plugin-core"; import { getBundleName } from "./getBundleName"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - export const solidstartBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output, + pluginName, + pluginVersion, }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, vite: { generateBundle(this, options) { // TODO - remove this once we hard fail on not having a bundle name @@ -36,7 +33,7 @@ export const solidstartBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output.lockBundleName(); // manually set this to avoid resetting in the vite plugin - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, }, }); diff --git a/packages/sveltekit-plugin/src/index.ts b/packages/sveltekit-plugin/src/index.ts index bae3d613..d34bb76a 100644 --- a/packages/sveltekit-plugin/src/index.ts +++ b/packages/sveltekit-plugin/src/index.ts @@ -10,11 +10,18 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { _internal_viteBundleAnalysisPlugin } from "@codecov/vite-plugin"; import { sveltekitBundleAnalysisPlugin } from "./sveltekit-bundle-analysis/sveltekitBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + const codecovSvelteKitPluginFactory = createVitePlugin( (userOptions, unpluginMetaContext) => { if (checkNodeVersion(unpluginMetaContext)) { @@ -32,12 +39,36 @@ const codecovSvelteKitPluginFactory = createVitePlugin( } const plugins: UnpluginOptions[] = []; - const output = new Output(normalizedOptions.options); const options = normalizedOptions.options; + + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + metaFramework: "sveltekit", + }); + const output = new Output(options, sentryConfig); + if (options.enableBundleAnalysis) { plugins.push( - sveltekitBundleAnalysisPlugin({ output }), - _internal_viteBundleAnalysisPlugin({ output }), + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), + sveltekitBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), + _internal_viteBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), ); } diff --git a/packages/sveltekit-plugin/src/sveltekit-bundle-analysis/__tests__/sveltekitBundleAnalysisPlugin.test.ts b/packages/sveltekit-plugin/src/sveltekit-bundle-analysis/__tests__/sveltekitBundleAnalysisPlugin.test.ts index f63fba01..ae1cf5a8 100644 --- a/packages/sveltekit-plugin/src/sveltekit-bundle-analysis/__tests__/sveltekitBundleAnalysisPlugin.test.ts +++ b/packages/sveltekit-plugin/src/sveltekit-bundle-analysis/__tests__/sveltekitBundleAnalysisPlugin.test.ts @@ -2,6 +2,11 @@ import { Output } from "@codecov/bundler-plugin-core"; import { describe, it, expect } from "vitest"; import { sveltekitBundleAnalysisPlugin } from "../sveltekitBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("sveltekitBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -14,7 +19,10 @@ describe("sveltekitBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/sveltekit-plugin/src/sveltekit-bundle-analysis/sveltekitBundleAnalysisPlugin.ts b/packages/sveltekit-plugin/src/sveltekit-bundle-analysis/sveltekitBundleAnalysisPlugin.ts index 24ef67c2..2f6e11aa 100644 --- a/packages/sveltekit-plugin/src/sveltekit-bundle-analysis/sveltekitBundleAnalysisPlugin.ts +++ b/packages/sveltekit-plugin/src/sveltekit-bundle-analysis/sveltekitBundleAnalysisPlugin.ts @@ -4,17 +4,14 @@ import { } from "@codecov/bundler-plugin-core"; import { getBundleName } from "./getBundleName"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - export const sveltekitBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output, + pluginName, + pluginVersion, }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, vite: { generateBundle(this, options) { // TODO - remove this once we hard fail on not having a bundle name @@ -36,7 +33,7 @@ export const sveltekitBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output.lockBundleName(); // manually set this to avoid resetting in the vite plugin - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, }, }); diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts index 09bc83ad..63d4cbd4 100644 --- a/packages/vite-plugin/src/index.ts +++ b/packages/vite-plugin/src/index.ts @@ -10,10 +10,17 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { viteBundleAnalysisPlugin } from "./vite-bundle-analysis/viteBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + const codecovVitePluginFactory = createVitePlugin( (userOptions, unpluginMetaContext) => { if (checkNodeVersion(unpluginMetaContext)) { @@ -32,9 +39,29 @@ const codecovVitePluginFactory = createVitePlugin( const plugins: UnpluginOptions[] = []; const options = normalizedOptions.options; + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + }); + const output = new Output(options, sentryConfig); + if (options.enableBundleAnalysis) { - const output = new Output(normalizedOptions.options); - plugins.push(viteBundleAnalysisPlugin({ output })); + plugins.push( + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), + viteBundleAnalysisPlugin({ + output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + }), + ); } return plugins; diff --git a/packages/vite-plugin/src/vite-bundle-analysis/__tests__/viteBundleAnalysisPlugin.test.ts b/packages/vite-plugin/src/vite-bundle-analysis/__tests__/viteBundleAnalysisPlugin.test.ts index 3c062107..2fd50f0c 100644 --- a/packages/vite-plugin/src/vite-bundle-analysis/__tests__/viteBundleAnalysisPlugin.test.ts +++ b/packages/vite-plugin/src/vite-bundle-analysis/__tests__/viteBundleAnalysisPlugin.test.ts @@ -2,6 +2,11 @@ import { Output } from "@codecov/bundler-plugin-core"; import { describe, it, expect } from "vitest"; import { viteBundleAnalysisPlugin } from "../viteBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("viteBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -14,7 +19,10 @@ describe("viteBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/vite-plugin/src/vite-bundle-analysis/viteBundleAnalysisPlugin.ts b/packages/vite-plugin/src/vite-bundle-analysis/viteBundleAnalysisPlugin.ts index 5e3ee91b..8ae9677b 100644 --- a/packages/vite-plugin/src/vite-bundle-analysis/viteBundleAnalysisPlugin.ts +++ b/packages/vite-plugin/src/vite-bundle-analysis/viteBundleAnalysisPlugin.ts @@ -8,20 +8,17 @@ import { createRollupAsset, } from "@codecov/bundler-plugin-core"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - export const viteBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output, + pluginName, + pluginVersion, }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, buildStart: () => { output.start(); - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, buildEnd: () => { output.end(); diff --git a/packages/webpack-plugin/src/index.ts b/packages/webpack-plugin/src/index.ts index b18943b6..36bdc0e5 100644 --- a/packages/webpack-plugin/src/index.ts +++ b/packages/webpack-plugin/src/index.ts @@ -10,6 +10,8 @@ import { checkNodeVersion, Output, handleErrors, + createSentryInstance, + telemetryPlugin, } from "@codecov/bundler-plugin-core"; import { webpackBundleAnalysisPlugin } from "./webpack-bundle-analysis/webpackBundleAnalysisPlugin"; @@ -21,6 +23,11 @@ import { processModules, } from "./webpack-bundle-analysis/utils"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + const codecovWebpackPluginFactory = createWebpackPlugin( (userOptions, unpluginMetaContext) => { if (checkNodeVersion(unpluginMetaContext)) { @@ -38,12 +45,28 @@ const codecovWebpackPluginFactory = createWebpackPlugin( } const plugins: UnpluginOptions[] = []; - const output = new Output(normalizedOptions.options); const options = normalizedOptions.options; + const sentryConfig = createSentryInstance({ + telemetry: options.telemetry, + isDryRun: options.dryRun, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, + options, + bundler: unpluginMetaContext.framework, + }); + const output = new Output(options, sentryConfig); + if (options.enableBundleAnalysis) { plugins.push( + telemetryPlugin({ + sentryClient: sentryConfig.sentryClient, + sentryScope: sentryConfig.sentryScope, + telemetry: options.telemetry, + }), webpackBundleAnalysisPlugin({ output, + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }), ); } diff --git a/packages/webpack-plugin/src/webpack-bundle-analysis/__tests__/webpackBundleAnalysisPlugin.test.ts b/packages/webpack-plugin/src/webpack-bundle-analysis/__tests__/webpackBundleAnalysisPlugin.test.ts index 1ef383be..f4e31285 100644 --- a/packages/webpack-plugin/src/webpack-bundle-analysis/__tests__/webpackBundleAnalysisPlugin.test.ts +++ b/packages/webpack-plugin/src/webpack-bundle-analysis/__tests__/webpackBundleAnalysisPlugin.test.ts @@ -2,6 +2,11 @@ import { Output } from "@codecov/bundler-plugin-core"; import { describe, it, expect } from "vitest"; import { webpackBundleAnalysisPlugin } from "../webpackBundleAnalysisPlugin"; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_NAME = __PACKAGE_NAME__ as string; +// @ts-expect-error this value is being replaced by rollup +const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; + describe("webpackBundleAnalysisPlugin", () => { describe("when called", () => { it("returns a plugin object", () => { @@ -14,7 +19,10 @@ describe("webpackBundleAnalysisPlugin", () => { enableBundleAnalysis: true, retryCount: 1, uploadToken: "test-token", + telemetry: false, }), + pluginName: PLUGIN_NAME, + pluginVersion: PLUGIN_VERSION, }); expect(plugin).toMatchSnapshot(); diff --git a/packages/webpack-plugin/src/webpack-bundle-analysis/webpackBundleAnalysisPlugin.ts b/packages/webpack-plugin/src/webpack-bundle-analysis/webpackBundleAnalysisPlugin.ts index ab60fec0..23a837fe 100644 --- a/packages/webpack-plugin/src/webpack-bundle-analysis/webpackBundleAnalysisPlugin.ts +++ b/packages/webpack-plugin/src/webpack-bundle-analysis/webpackBundleAnalysisPlugin.ts @@ -4,20 +4,17 @@ import type * as TWebpack from "webpack"; import { processAssets, processChunks, processModules } from "./utils"; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_NAME = __PACKAGE_NAME__ as string; -// @ts-expect-error this value is being replaced by rollup -const PLUGIN_VERSION = __PACKAGE_VERSION__ as string; - export const webpackBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ output, + pluginName, + pluginVersion, }) => ({ version: output.version, - name: PLUGIN_NAME, - pluginVersion: PLUGIN_VERSION, + name: pluginName, + pluginVersion, buildStart: () => { output.start(); - output.setPlugin(PLUGIN_NAME, PLUGIN_VERSION); + output.setPlugin(pluginName, pluginVersion); }, buildEnd: () => { output.end(); @@ -29,10 +26,10 @@ export const webpackBundleAnalysisPlugin: BundleAnalysisUploadPlugin = ({ const generatedRequire = createRequire(import.meta.url); const webpack = generatedRequire("webpack") as typeof TWebpack; - compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => { + compiler.hooks.thisCompilation.tap(pluginName, (compilation) => { compilation.hooks.processAssets.tapPromise( { - name: PLUGIN_NAME, + name: pluginName, stage: webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT, }, async () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e17331f0..e09af1ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1017,6 +1017,9 @@ importers: '@actions/github': specifier: ^6.0.0 version: 6.0.0 + '@sentry/core': + specifier: ^8.42.0 + version: 8.42.0 chalk: specifier: 4.1.2 version: 4.1.2 @@ -4694,6 +4697,10 @@ packages: '@rushstack/eslint-patch@1.7.2': resolution: {integrity: sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==} + '@sentry/core@8.42.0': + resolution: {integrity: sha512-ac6O3pgoIbU6rpwz6LlwW0wp3/GAHuSI0C5IsTgIY6baN8rOBnlAtG6KrHDDkGmUQ2srxkDJu9n1O6Td3cBCqw==} + engines: {node: '>=14.18'} + '@shikijs/core@1.23.1': resolution: {integrity: sha512-NuOVgwcHgVC6jBVH5V7iblziw6iQbWWHrj5IlZI3Fqu2yx9awH7OIQkXIcsHsUmY19ckwSgUMgrqExEyP5A0TA==} @@ -16495,6 +16502,8 @@ snapshots: '@rushstack/eslint-patch@1.7.2': {} + '@sentry/core@8.42.0': {} + '@shikijs/core@1.23.1': dependencies: '@shikijs/engine-javascript': 1.23.1