diff --git a/packages/unplugin/src/index.ts b/packages/unplugin/src/index.ts index 2b8cbade..d989e6b3 100644 --- a/packages/unplugin/src/index.ts +++ b/packages/unplugin/src/index.ts @@ -1,8 +1,15 @@ import { createUnplugin } from "unplugin"; import MagicString from "magic-string"; import { getReleaseName } from "./getReleaseName"; -import { Options } from "./types"; -import { makeSentryFacade } from "./sentry/facade"; +import { Options, BuildContext } from "./types"; +import { + createNewRelease, + cleanArtifacts, + addDeploy, + finalizeRelease, + setCommits, + uploadSourceMaps, +} from "./sentry/releasePipeline"; import "@sentry/tracing"; import { addSpanToTransaction, captureMinimalError, makeSentryClient } from "./sentry/telemetry"; import { Span, Transaction } from "@sentry/types"; @@ -132,8 +139,7 @@ const unplugin = createUnplugin((originalOptions, unpluginMetaContext) name: "plugin-execution", }); releaseInjectionSpan = addSpanToTransaction( - sentryHub, - transaction, + { hub: sentryHub, parentSpan: transaction }, "release-injection", "release-injection" ); @@ -272,11 +278,9 @@ const unplugin = createUnplugin((originalOptions, unpluginMetaContext) buildEnd() { releaseInjectionSpan?.finish(); const releasePipelineSpan = - sentryHub && transaction && addSpanToTransaction( - sentryHub, - transaction, + { hub: sentryHub, parentSpan: transaction }, "release-creation", "release-creation-pipeline" ); @@ -294,15 +298,14 @@ const unplugin = createUnplugin((originalOptions, unpluginMetaContext) // That's good for them but a hassle for us. Let's try to normalize this into one data type // (I vote IncludeEntry[]) and continue with that down the line - const sentryFacade = makeSentryFacade(release, options, sentryHub); + const ctx: BuildContext = { hub: sentryHub, parentSpan: releasePipelineSpan }; - sentryFacade - .createNewRelease() - .then(() => sentryFacade.cleanArtifacts()) - .then(() => sentryFacade.uploadSourceMaps()) - .then(() => sentryFacade.setCommits()) // this is a noop for now - .then(() => sentryFacade.finalizeRelease()) - .then(() => sentryFacade.addDeploy()) // this is a noop for now + createNewRelease(release, options, ctx) + .then(() => cleanArtifacts(release, options, ctx)) + .then(() => uploadSourceMaps(release, options, ctx)) + .then(() => setCommits(ctx)) // this is a noop for now + .then(() => finalizeRelease(release, options, ctx)) + .then(() => addDeploy(ctx)) // this is a noop for now .catch((e) => { //TODO: invoke error handler here // https://github.com/getsentry/sentry-webpack-plugin/blob/137503f3ac6fe423b16c5c50379859c86e689017/src/index.js#L540-L547 diff --git a/packages/unplugin/src/sentry/facade.ts b/packages/unplugin/src/sentry/releasePipeline.ts similarity index 78% rename from packages/unplugin/src/sentry/facade.ts rename to packages/unplugin/src/sentry/releasePipeline.ts index 105882f6..56d088ae 100644 --- a/packages/unplugin/src/sentry/facade.ts +++ b/packages/unplugin/src/sentry/releasePipeline.ts @@ -6,45 +6,17 @@ // - huge download // - unnecessary functionality -import { Hub } from "@sentry/node"; -import { Span } from "@sentry/types"; -import { Options } from "../types"; +import { Options, BuildContext } from "../types"; import { createRelease, deleteAllReleaseArtifacts, uploadReleaseFile, updateRelease } from "./api"; import { getFiles } from "./sourcemaps"; import { addSpanToTransaction } from "./telemetry"; -export type SentryFacade = { - createNewRelease: () => Promise; - cleanArtifacts: () => Promise; - uploadSourceMaps: () => Promise; - setCommits: () => Promise; - finalizeRelease: () => Promise; - addDeploy: () => Promise; -}; - -/** - * Factory function that provides all necessary Sentry functionality for creating - * a release on Sentry. This includes uploading source maps and finalizing the release - */ -export function makeSentryFacade(release: string, options: Options, sentryHub: Hub): SentryFacade { - const span = sentryHub.getScope()?.getSpan(); - return { - createNewRelease: () => createNewRelease(release, options, sentryHub, span), - cleanArtifacts: () => cleanArtifacts(release, options, sentryHub, span), - uploadSourceMaps: () => uploadSourceMaps(release, options, sentryHub, span), - setCommits: () => setCommits(/* release, */ sentryHub, span), - finalizeRelease: () => finalizeRelease(release, options, sentryHub, span), - addDeploy: () => addDeploy(/* release, */ sentryHub, span), - }; -} - -async function createNewRelease( +export async function createNewRelease( release: string, options: Options, - sentryHub: Hub, - parentSpan?: Span + ctx: BuildContext ): Promise { - const span = addSpanToTransaction(sentryHub, parentSpan, "create-new-release"); + const span = addSpanToTransaction(ctx, "create-new-release"); // TODO: pull these checks out of here and simplify them if (options.authToken === undefined) { @@ -71,7 +43,7 @@ async function createNewRelease( org: options.org, project: options.project, sentryUrl: options.url, - sentryHub, + sentryHub: ctx.hub, }); // eslint-disable-next-line no-console @@ -81,13 +53,12 @@ async function createNewRelease( return Promise.resolve("nothing to do here"); } -async function uploadSourceMaps( +export async function uploadSourceMaps( release: string, options: Options, - sentryHub: Hub, - parentSpan?: Span + ctx: BuildContext ): Promise { - const span = addSpanToTransaction(sentryHub, parentSpan, "upload-sourceMaps"); + const span = addSpanToTransaction(ctx, "upload-sourceMaps"); // This is what Sentry CLI does: // TODO: 0. Preprocess source maps // - (Out of scope for now) @@ -160,7 +131,7 @@ async function uploadSourceMaps( sentryUrl: url, filename: file.name, fileContent: file.content, - sentryHub, + sentryHub: ctx.hub, }) ) ).then(() => { @@ -171,13 +142,12 @@ async function uploadSourceMaps( }); } -async function finalizeRelease( +export async function finalizeRelease( release: string, options: Options, - sentryHub: Hub, - parentSpan?: Span + ctx: BuildContext ): Promise { - const span = addSpanToTransaction(sentryHub, parentSpan, "finalize-release"); + const span = addSpanToTransaction(ctx, "finalize-release"); if (options.finalize) { const { authToken, org, url, project } = options; @@ -195,7 +165,7 @@ async function finalizeRelease( release, sentryUrl: url, project, - sentryHub, + sentryHub: ctx.hub, }); // eslint-disable-next-line no-console console.log("[Sentry-plugin] Successfully finalized release."); @@ -205,13 +175,12 @@ async function finalizeRelease( return Promise.resolve("nothing to do here"); } -async function cleanArtifacts( +export async function cleanArtifacts( release: string, options: Options, - sentryHub: Hub, - parentSpan?: Span + ctx: BuildContext ): Promise { - const span = addSpanToTransaction(sentryHub, parentSpan, "clean-artifacts"); + const span = addSpanToTransaction(ctx, "clean-artifacts"); if (options.cleanArtifacts) { // TODO: pull these checks out of here and simplify them @@ -247,7 +216,7 @@ async function cleanArtifacts( release, sentryUrl: options.url, project: options.project, - sentryHub, + sentryHub: ctx.hub, }); // eslint-disable-next-line no-console @@ -260,23 +229,21 @@ async function cleanArtifacts( // TODO: Stuff we worry about later: -async function setCommits( +export async function setCommits( /* version: string, */ - sentryHub: Hub, - parentSpan?: Span + ctx: BuildContext ): Promise { - const span = addSpanToTransaction(sentryHub, parentSpan, "set-commits"); + const span = addSpanToTransaction(ctx, "set-commits"); span?.finish(); return Promise.resolve("Noop"); } -async function addDeploy( +export async function addDeploy( /* version: string, */ - sentryHub: Hub, - parentSpan?: Span + ctx: BuildContext ): Promise { - const span = addSpanToTransaction(sentryHub, parentSpan, "add-deploy"); + const span = addSpanToTransaction(ctx, "add-deploy"); span?.finish(); return Promise.resolve("Noop"); diff --git a/packages/unplugin/src/sentry/telemetry.ts b/packages/unplugin/src/sentry/telemetry.ts index 9db7aee3..16bd7de8 100644 --- a/packages/unplugin/src/sentry/telemetry.ts +++ b/packages/unplugin/src/sentry/telemetry.ts @@ -9,6 +9,7 @@ import { import { Span } from "@sentry/tracing"; import { AxiosError } from "axios"; import { version as unpluginVersion } from "../../package.json"; +import { BuildContext } from "../types"; export function makeSentryClient( dsn: string, @@ -48,14 +49,14 @@ export function makeSentryClient( * Adds a span to the passed parentSpan or to the current transaction that's on the passed hub's scope. */ export function addSpanToTransaction( - sentryHub: Hub, - parentSpan?: Span, + ctx: BuildContext, op?: string, description?: string ): Span | undefined { - const actualSpan = parentSpan || sentryHub.getScope()?.getTransaction(); + const { hub, parentSpan } = ctx; + const actualSpan = parentSpan || hub.getScope()?.getTransaction(); const span = actualSpan?.startChild({ op, description }); - sentryHub.configureScope((scope) => scope.setSpan(span)); + hub.configureScope((scope) => scope.setSpan(span)); return span; } diff --git a/packages/unplugin/src/types.ts b/packages/unplugin/src/types.ts index e6e485d2..34c5f127 100644 --- a/packages/unplugin/src/types.ts +++ b/packages/unplugin/src/types.ts @@ -1,4 +1,8 @@ //TODO: JsDoc for all properties + +import { Hub } from "@sentry/hub"; +import { Span } from "@sentry/tracing"; + //TODO: compare types w/ webpack plugin (and sentry-cli?) export type Options = { debugLogging?: boolean; @@ -84,3 +88,12 @@ type IncludeEntry = { //TODO: what about the other entries?? }; */ + +/** + * Holds data for internal purposes + * (e.g. telemetry and logging) + */ +export type BuildContext = { + hub: Hub; + parentSpan?: Span; +};