-
-
Notifications
You must be signed in to change notification settings - Fork 358
Expand file tree
/
Copy pathwithSentry.ts
More file actions
153 lines (135 loc) · 5.94 KB
/
withSentry.ts
File metadata and controls
153 lines (135 loc) · 5.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import type { ExpoConfig } from '@expo/config-types';
import type { ConfigPlugin } from 'expo/config-plugins';
import { createRunOncePlugin, withDangerousMod } from 'expo/config-plugins';
import type { SentryAndroidGradlePluginOptions } from './withSentryAndroidGradlePlugin';
import { bold, warnOnce } from './logger';
import { writeSentryOptions } from './utils';
import { PLUGIN_NAME, PLUGIN_VERSION } from './version';
import { withSentryAndroid } from './withSentryAndroid';
import { withSentryAndroidGradlePlugin } from './withSentryAndroidGradlePlugin';
import { withSentryIOS } from './withSentryIOS';
interface PluginProps {
organization?: string;
project?: string;
authToken?: string;
url?: string;
useNativeInit?: boolean;
disableAutoUpload?: boolean;
options?: Record<string, unknown>;
experimental_android?: SentryAndroidGradlePluginOptions;
}
/**
* Store build-time properties in config._internal so they're discoverable
* by the sourcemap upload script via `expo config --json`, even when
* withSentry is used programmatically in app.config.ts.
*
* We use _internal instead of extra because _internal is stripped from the
* public config (app manifest) and not shipped in the production app, while
* extra would leak org/project metadata into the app binary.
*/
function storeBuildPropertiesInConfig(config: ExpoConfig, props: PluginProps | void): void {
if (props?.organization || props?.project) {
// ExpoConfig types don't include _internal, but it's a standard Expo field
// used by config plugins infrastructure (e.g. pluginHistory).
const configWithInternal = config as ExpoConfig & { _internal?: Record<string, unknown> };
configWithInternal._internal = configWithInternal._internal || {};
configWithInternal._internal.sentryBuildProperties = {
organization: props?.organization,
project: props?.project,
url: props?.url || 'https://sentry.io/',
};
}
}
const withSentryPlugin: ConfigPlugin<PluginProps | void> = (config, props) => {
const sentryProperties = getSentryProperties(props);
if (props?.authToken) {
// If not removed, the plugin config with the authToken will be written to the application package
delete props.authToken;
}
storeBuildPropertiesInConfig(config, props);
let cfg = config;
const pluginOptions = props?.options ? { ...props.options } : {};
// oxlint-disable-next-line typescript-eslint(no-unsafe-member-access)
const environment = process.env.SENTRY_ENVIRONMENT;
if (environment) {
pluginOptions.environment = environment;
}
if (Object.keys(pluginOptions).length > 0) {
cfg = withSentryOptionsFile(cfg, pluginOptions);
}
if (sentryProperties !== null) {
try {
cfg = withSentryAndroid(cfg, {
sentryProperties,
useNativeInit: props?.useNativeInit,
disableAutoUpload: props?.disableAutoUpload,
});
} catch (e) {
warnOnce(`There was a problem with configuring your native Android project: ${e}`);
}
// if `enableAndroidGradlePlugin` is provided configure the Sentry Android Gradle Plugin
if (props?.experimental_android?.enableAndroidGradlePlugin) {
try {
cfg = withSentryAndroidGradlePlugin(cfg, props.experimental_android);
} catch (e) {
warnOnce(`There was a problem with configuring Sentry Android Gradle Plugin: ${e}`);
}
}
try {
cfg = withSentryIOS(cfg, {
sentryProperties,
useNativeInit: props?.useNativeInit,
disableAutoUpload: props?.disableAutoUpload,
});
} catch (e) {
warnOnce(`There was a problem with configuring your native iOS project: ${e}`);
}
}
return cfg;
};
const missingProjectMessage = '# no project found, falling back to SENTRY_PROJECT environment variable';
const missingOrgMessage = '# no org found, falling back to SENTRY_ORG environment variable';
const existingAuthTokenMessage =
'# DO NOT COMMIT the auth token, use SENTRY_AUTH_TOKEN instead, see https://docs.sentry.io/platforms/react-native/manual-setup/';
const missingAuthTokenMessage = '# Using SENTRY_AUTH_TOKEN environment variable';
export function getSentryProperties(props: PluginProps | void): string | null {
const { organization, project, authToken, url = 'https://sentry.io/' } = props ?? {};
const missingProperties = ['organization', 'project'].filter(each => !props?.hasOwnProperty(each));
if (missingProperties.length) {
const missingPropertiesString = bold(missingProperties.join(', '));
const warningMessage = `Missing config for ${missingPropertiesString}. Environment variables will be used as a fallback during the build. https://docs.sentry.io/platforms/react-native/manual-setup/`;
warnOnce(warningMessage);
}
if (authToken) {
warnOnce(
`Detected unsecure use of 'authToken' in Sentry plugin configuration. To avoid exposing the token use ${bold(
'SENTRY_AUTH_TOKEN',
)} environment variable instead. https://docs.sentry.io/platforms/react-native/manual-setup/`,
);
}
return `defaults.url=${url}
${organization ? `defaults.org=${organization}` : missingOrgMessage}
${project ? `defaults.project=${project}` : missingProjectMessage}
${authToken ? `${existingAuthTokenMessage}\nauth.token=${authToken}` : missingAuthTokenMessage}`;
}
function withSentryOptionsFile(config: ExpoConfig, pluginOptions: Record<string, unknown>): ExpoConfig {
// withDangerousMod requires a platform key, but sentry.options.json is at the project root.
// We apply to both platforms so it works with `expo prebuild --platform ios` or `--platform android`.
let cfg = withDangerousMod(config, [
'android',
mod => {
writeSentryOptions(mod.modRequest.projectRoot, pluginOptions);
return mod;
},
]);
cfg = withDangerousMod(cfg, [
'ios',
mod => {
writeSentryOptions(mod.modRequest.projectRoot, pluginOptions);
return mod;
},
]);
return cfg;
}
const withSentry = createRunOncePlugin(withSentryPlugin, PLUGIN_NAME, PLUGIN_VERSION);
export { withSentry };