Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(astro): Add enabled option to Astro integration options #10007

Merged
merged 2 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 31 additions & 21 deletions packages/astro/src/integration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,15 @@ export const sentryAstro = (options: SentryOptions = {}): AstroIntegration => {
// Will revisit this later.
const env = process.env;

const sdkEnabled = {
client: typeof options.enabled === 'boolean' ? options.enabled : options.enabled?.client ?? true,
server: typeof options.enabled === 'boolean' ? options.enabled : options.enabled?.server ?? true,
};
const partiallyEnabled = sdkEnabled.client || sdkEnabled.server;
Lms24 marked this conversation as resolved.
Show resolved Hide resolved

const uploadOptions = options.sourceMapsUploadOptions || {};

const shouldUploadSourcemaps = uploadOptions?.enabled ?? true;
const shouldUploadSourcemaps = (partiallyEnabled && uploadOptions?.enabled) ?? true;

// We don't need to check for AUTH_TOKEN here, because the plugin will pick it up from the env
if (shouldUploadSourcemaps && command !== 'dev') {
Expand All @@ -51,31 +57,35 @@ export const sentryAstro = (options: SentryOptions = {}): AstroIntegration => {
});
}

const pathToClientInit = options.clientInitPath
? path.resolve(options.clientInitPath)
: findDefaultSdkInitFile('client');
const pathToServerInit = options.serverInitPath
? path.resolve(options.serverInitPath)
: findDefaultSdkInitFile('server');

if (pathToClientInit) {
options.debug && console.log(`[sentry-astro] Using ${pathToClientInit} for client init.`);
injectScript('page', buildSdkInitFileImportSnippet(pathToClientInit));
} else {
options.debug && console.log('[sentry-astro] Using default client init.');
injectScript('page', buildClientSnippet(options || {}));
if (sdkEnabled.client) {
const pathToClientInit = options.clientInitPath
? path.resolve(options.clientInitPath)
: findDefaultSdkInitFile('client');

if (pathToClientInit) {
options.debug && console.log(`[sentry-astro] Using ${pathToClientInit} for client init.`);
injectScript('page', buildSdkInitFileImportSnippet(pathToClientInit));
} else {
options.debug && console.log('[sentry-astro] Using default client init.');
injectScript('page', buildClientSnippet(options || {}));
}
}

if (pathToServerInit) {
options.debug && console.log(`[sentry-astro] Using ${pathToServerInit} for server init.`);
injectScript('page-ssr', buildSdkInitFileImportSnippet(pathToServerInit));
} else {
options.debug && console.log('[sentry-astro] Using default server init.');
injectScript('page-ssr', buildServerSnippet(options || {}));
if (sdkEnabled.server) {
const pathToServerInit = options.serverInitPath
? path.resolve(options.serverInitPath)
: findDefaultSdkInitFile('server');
if (pathToServerInit) {
options.debug && console.log(`[sentry-astro] Using ${pathToServerInit} for server init.`);
injectScript('page-ssr', buildSdkInitFileImportSnippet(pathToServerInit));
} else {
options.debug && console.log('[sentry-astro] Using default server init.');
injectScript('page-ssr', buildServerSnippet(options || {}));
}
}

const isSSR = config && (config.output === 'server' || config.output === 'hybrid');
const shouldAddMiddleware = options.autoInstrumentation?.requestHandler !== false;
const shouldAddMiddleware = sdkEnabled.server && options.autoInstrumentation?.requestHandler !== false;

// Guarding calling the addMiddleware function because it was only introduced in astro@3.5.0
// Users on older versions of astro will need to add the middleware manually.
Expand Down
23 changes: 22 additions & 1 deletion packages/astro/src/integration/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,26 @@ type InstrumentationOptions = {
};
};

type SdkEnabledOptions = {
/**
* Controls if the Sentry SDK is enabled or not.
*
* You can either set a boolean value to enable/disable the SDK for both client and server,
* or pass an object with `client` and `server` properties to enable/disable the SDK.
*
* If the SDK is disabled, no data will be caught or sent to Sentry. In this case, also no
* Sentry code will be added to your bundle.
*
* @default true - the SDK is enabled by default for both, client and server.
*/
enabled?:
| boolean
| {
client?: boolean;
server?: boolean;
};
};

/**
* A subset of Sentry SDK options that can be set via the `sentryAstro` integration.
* Some options (e.g. integrations) are set by default and cannot be changed here.
Expand All @@ -119,4 +139,5 @@ export type SentryOptions = SdkInitPaths &
Pick<Options, 'dsn' | 'release' | 'environment' | 'sampleRate' | 'tracesSampleRate' | 'debug'> &
Pick<BrowserOptions, 'replaysSessionSampleRate' | 'replaysOnErrorSampleRate'> &
SourceMapsOptions &
InstrumentationOptions;
InstrumentationOptions &
SdkEnabledOptions;
71 changes: 69 additions & 2 deletions packages/astro/test/integration/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,21 @@ describe('sentryAstro integration', () => {
expect(sentryVitePluginSpy).toHaveBeenCalledTimes(0);
});

it('injects client and server init scripts', async () => {
const integration = sentryAstro({});
it("doesn't add the plugin or enable source maps if the SDK is disabled", async () => {
const integration = sentryAstro({
enabled: false,
});

expect(integration.hooks['astro:config:setup']).toBeDefined();
// @ts-expect-error - the hook exists and we only need to pass what we actually use
await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config });

expect(updateConfig).toHaveBeenCalledTimes(0);
expect(sentryVitePluginSpy).toHaveBeenCalledTimes(0);
});

it.each([{}, { enabled: true }])('injects client and server init scripts', async options => {
const integration = sentryAstro(options);

expect(integration.hooks['astro:config:setup']).toBeDefined();
// @ts-expect-error - the hook exists and we only need to pass what we actually use
Expand All @@ -180,6 +193,41 @@ describe('sentryAstro integration', () => {
expect(injectScript).toHaveBeenCalledWith('page-ssr', expect.stringContaining('Sentry.init'));
});

it("doesn't inject client init script if `enabled.client` is `false`", async () => {
const integration = sentryAstro({ enabled: { client: false } });

expect(integration.hooks['astro:config:setup']).toBeDefined();
// @ts-expect-error - the hook exists and we only need to pass what we actually use
await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config });

expect(injectScript).toHaveBeenCalledTimes(1);
expect(injectScript).toHaveBeenCalledWith('page-ssr', expect.stringContaining('Sentry.init'));
});

it("doesn't inject server init script if `enabled.server` is `false`", async () => {
const integration = sentryAstro({ enabled: { server: false } });

expect(integration.hooks['astro:config:setup']).toBeDefined();
// @ts-expect-error - the hook exists and we only need to pass what we actually use
await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config });

expect(injectScript).toHaveBeenCalledTimes(1);
expect(injectScript).toHaveBeenCalledWith('page', expect.stringContaining('Sentry.init'));
});

it.each([false, { client: false, server: false }])(
"doesn't inject any init script if `enabled` is generally false (`%s`)",
async enabled => {
const integration = sentryAstro({ enabled });

expect(integration.hooks['astro:config:setup']).toBeDefined();
// @ts-expect-error - the hook exists and we only need to pass what we actually use
await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config });

expect(injectScript).toHaveBeenCalledTimes(0);
},
);

it('injects client and server init scripts from custom paths', async () => {
const integration = sentryAstro({
clientInitPath: 'my-client-init-path.js',
Expand Down Expand Up @@ -278,4 +326,23 @@ describe('sentryAstro integration', () => {
expect(updateConfig).toHaveBeenCalledTimes(1);
expect(injectScript).toHaveBeenCalledTimes(2);
});

it("doesn't add middleware if the SDK is disabled", () => {
const integration = sentryAstro({ enabled: false });
const addMiddleware = vi.fn();
const updateConfig = vi.fn();
const injectScript = vi.fn();

expect(integration.hooks['astro:config:setup']).toBeDefined();
// @ts-expect-error - the hook exists and we only need to pass what we actually use
integration.hooks['astro:config:setup']({
// @ts-expect-error - we only need to pass what we actually use
config: { output: 'server' },
addMiddleware,
updateConfig,
injectScript,
});

expect(addMiddleware).toHaveBeenCalledTimes(0);
});
});