@sentry/wizard 3.40.0 → 3.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -1
- package/README.md +19 -19
- package/bin.ts +5 -0
- package/codecov.yml +15 -0
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -1
- package/dist/e2e-tests/jest.config.d.ts +1 -0
- package/dist/e2e-tests/jest.config.js +1 -0
- package/dist/e2e-tests/jest.config.js.map +1 -1
- package/dist/e2e-tests/tests/remix.test.js +1 -1
- package/dist/e2e-tests/tests/remix.test.js.map +1 -1
- package/dist/package.json +3 -2
- package/dist/src/apple/apple-wizard.js +1 -2
- package/dist/src/apple/apple-wizard.js.map +1 -1
- package/dist/src/apple/code-tools.d.ts +10 -0
- package/dist/src/apple/code-tools.js +16 -12
- package/dist/src/apple/code-tools.js.map +1 -1
- package/dist/src/apple/fastlane.d.ts +23 -0
- package/dist/src/apple/fastlane.js +11 -7
- package/dist/src/apple/fastlane.js.map +1 -1
- package/dist/src/apple/templates.d.ts +1 -1
- package/dist/src/apple/templates.js +0 -2
- package/dist/src/apple/templates.js.map +1 -1
- package/dist/src/apple/xcode-manager.d.ts +10 -6
- package/dist/src/apple/xcode-manager.js +146 -61
- package/dist/src/apple/xcode-manager.js.map +1 -1
- package/dist/src/nextjs/nextjs-wizard.js +6 -4
- package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
- package/dist/src/nuxt/nuxt-wizard.js +7 -5
- package/dist/src/nuxt/nuxt-wizard.js.map +1 -1
- package/dist/src/nuxt/sdk-setup.d.ts +1 -1
- package/dist/src/nuxt/sdk-setup.js +2 -1
- package/dist/src/nuxt/sdk-setup.js.map +1 -1
- package/dist/src/react-native/react-native-wizard.js +5 -3
- package/dist/src/react-native/react-native-wizard.js.map +1 -1
- package/dist/src/remix/remix-wizard.js +6 -4
- package/dist/src/remix/remix-wizard.js.map +1 -1
- package/dist/src/remix/sdk-setup.js +0 -4
- package/dist/src/remix/sdk-setup.js.map +1 -1
- package/dist/src/run.d.ts +1 -0
- package/dist/src/run.js +1 -0
- package/dist/src/run.js.map +1 -1
- package/dist/src/sveltekit/sveltekit-wizard.js +6 -4
- package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
- package/dist/src/utils/clack-utils.d.ts +3 -1
- package/dist/src/utils/clack-utils.js +18 -12
- package/dist/src/utils/clack-utils.js.map +1 -1
- package/dist/src/utils/package-manager.d.ts +1 -0
- package/dist/src/utils/package-manager.js +5 -0
- package/dist/src/utils/package-manager.js.map +1 -1
- package/dist/src/utils/types.d.ts +9 -0
- package/dist/src/utils/types.js.map +1 -1
- package/dist/test/apple/cocoapod.test.d.ts +1 -0
- package/dist/test/apple/cocoapod.test.js +409 -0
- package/dist/test/apple/cocoapod.test.js.map +1 -0
- package/dist/test/apple/code-tools.test.d.ts +1 -0
- package/dist/test/apple/code-tools.test.js +673 -0
- package/dist/test/apple/code-tools.test.js.map +1 -0
- package/dist/test/apple/fastfile.test.d.ts +1 -0
- package/dist/test/apple/fastfile.test.js +431 -0
- package/dist/test/apple/fastfile.test.js.map +1 -0
- package/dist/test/apple/templates.test.d.ts +1 -0
- package/dist/test/apple/templates.test.js +73 -0
- package/dist/test/apple/templates.test.js.map +1 -0
- package/dist/test/apple/xcode-manager.test.d.ts +1 -0
- package/dist/test/apple/xcode-manager.test.js +834 -0
- package/dist/test/apple/xcode-manager.test.js.map +1 -0
- package/dist/test/remix/server-instrumentation.test.js +2 -2
- package/dist/test/remix/server-instrumentation.test.js.map +1 -1
- package/dist/test/utils/clack-utils.test.js +89 -0
- package/dist/test/utils/clack-utils.test.js.map +1 -1
- package/e2e-tests/jest.config.ts +1 -0
- package/e2e-tests/test-applications/apple/damaged-missing-configuration-list/Project.xcodeproj/project.pbxproj +52 -0
- package/e2e-tests/test-applications/apple/damaged-missing-configuration-list/Project.xcodeproj/xcshareddata/xcschemes/Project1.xcscheme +78 -0
- package/e2e-tests/test-applications/apple/no-targets/Project.xcodeproj/project.pbxproj +62 -0
- package/e2e-tests/test-applications/apple/no-targets/Project.xcodeproj/xcshareddata/xcschemes/Project1.xcscheme +78 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project.xcodeproj/project.pbxproj +470 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project.xcodeproj/xcshareddata/xcschemes/Project1.xcscheme +78 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project1/ContentView.swift +7 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project1/Project1App.swift +10 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project2/ContentView.swift +7 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project2/Project2App.swift +10 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-single-target/Project.xcodeproj/project.pbxproj +382 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-single-target/Project.xcodeproj/xcshareddata/xcschemes/Project.xcscheme +78 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-single-target/Sources/ContentView.swift +7 -0
- package/e2e-tests/test-applications/apple/spm-swiftui-single-target/Sources/MainApp.swift +10 -0
- package/e2e-tests/tests/remix.test.ts +1 -2
- package/package.json +3 -2
- package/src/apple/apple-wizard.ts +1 -2
- package/src/apple/code-tools.ts +21 -6
- package/src/apple/fastlane.ts +18 -2
- package/src/apple/templates.ts +2 -2
- package/src/apple/xcode-manager.ts +181 -94
- package/src/nextjs/nextjs-wizard.ts +6 -3
- package/src/nuxt/nuxt-wizard.ts +7 -4
- package/src/nuxt/sdk-setup.ts +2 -0
- package/src/react-native/react-native-wizard.ts +5 -2
- package/src/remix/remix-wizard.ts +6 -3
- package/src/remix/sdk-setup.ts +0 -5
- package/src/run.ts +2 -0
- package/src/sveltekit/sveltekit-wizard.ts +6 -3
- package/src/utils/clack-utils.ts +12 -2
- package/src/utils/package-manager.ts +6 -0
- package/src/utils/types.ts +10 -0
- package/test/apple/cocoapod.test.ts +306 -0
- package/test/apple/code-tools.test.ts +1042 -0
- package/test/apple/fastfile.test.ts +550 -0
- package/test/apple/templates.test.ts +191 -0
- package/test/apple/xcode-manager.test.ts +1066 -0
- package/test/remix/server-instrumentation.test.ts +2 -4
- package/test/utils/clack-utils.test.ts +92 -0
- package/types/xcode.d.ts +526 -0
|
@@ -5,10 +5,20 @@
|
|
|
5
5
|
// @ts-ignore - clack is ESM and TS complains about that. It works though
|
|
6
6
|
import clack from '@clack/prompts';
|
|
7
7
|
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
8
9
|
import { SentryProjectData } from '../utils/types';
|
|
9
10
|
import * as templates from './templates';
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
project as createXcodeProject,
|
|
14
|
+
PBXBuildFile,
|
|
15
|
+
PBXGroup,
|
|
16
|
+
PBXNativeTarget,
|
|
17
|
+
PBXObjects,
|
|
18
|
+
PBXSourcesBuildPhase,
|
|
19
|
+
Project,
|
|
20
|
+
XCConfigurationList,
|
|
21
|
+
} from 'xcode';
|
|
12
22
|
|
|
13
23
|
interface ProjectFile {
|
|
14
24
|
key: string;
|
|
@@ -16,77 +26,125 @@ interface ProjectFile {
|
|
|
16
26
|
}
|
|
17
27
|
|
|
18
28
|
function setDebugInformationFormatAndSandbox(
|
|
19
|
-
proj:
|
|
29
|
+
proj: Project,
|
|
20
30
|
targetName: string,
|
|
21
31
|
): void {
|
|
22
32
|
const xcObjects = proj.hash.project.objects;
|
|
23
|
-
|
|
33
|
+
if (!xcObjects.PBXNativeTarget) {
|
|
34
|
+
xcObjects.PBXNativeTarget = {};
|
|
35
|
+
}
|
|
36
|
+
const targetKey: string = Object.keys(xcObjects.PBXNativeTarget).filter(
|
|
24
37
|
(key) => {
|
|
38
|
+
const value = xcObjects.PBXNativeTarget?.[key];
|
|
25
39
|
return (
|
|
26
40
|
!key.endsWith('_comment') &&
|
|
27
|
-
|
|
41
|
+
typeof value !== 'string' &&
|
|
42
|
+
value?.name === targetName
|
|
28
43
|
);
|
|
29
44
|
},
|
|
30
45
|
)[0];
|
|
31
|
-
const target = xcObjects.PBXNativeTarget[targetKey]
|
|
46
|
+
const target = xcObjects.PBXNativeTarget[targetKey] as
|
|
47
|
+
| PBXNativeTarget
|
|
48
|
+
| undefined;
|
|
32
49
|
|
|
33
|
-
xcObjects.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
if (!xcObjects.XCBuildConfiguration) {
|
|
51
|
+
xcObjects.XCBuildConfiguration = {};
|
|
52
|
+
}
|
|
53
|
+
if (!xcObjects.XCConfigurationList) {
|
|
54
|
+
xcObjects.XCConfigurationList = {};
|
|
55
|
+
}
|
|
56
|
+
const buildConfigurationListId = target?.buildConfigurationList ?? '';
|
|
57
|
+
const configurationList = xcObjects.XCConfigurationList?.[
|
|
58
|
+
buildConfigurationListId
|
|
59
|
+
] as XCConfigurationList | undefined;
|
|
60
|
+
const buildListConfigurationIds =
|
|
61
|
+
configurationList?.buildConfigurations ?? [];
|
|
62
|
+
for (const buildListConfigId of buildListConfigurationIds) {
|
|
63
|
+
const config =
|
|
64
|
+
xcObjects.XCBuildConfiguration[buildListConfigId.value] ?? {};
|
|
65
|
+
if (typeof config === 'string') {
|
|
66
|
+
// Ignore comments
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const buildSettings = config.buildSettings ?? {};
|
|
38
71
|
buildSettings.DEBUG_INFORMATION_FORMAT = '"dwarf-with-dsym"';
|
|
39
72
|
buildSettings.ENABLE_USER_SCRIPT_SANDBOXING = '"NO"';
|
|
40
|
-
|
|
73
|
+
|
|
74
|
+
config.buildSettings = buildSettings;
|
|
75
|
+
xcObjects.XCBuildConfiguration[buildListConfigId.value] = config;
|
|
76
|
+
}
|
|
41
77
|
}
|
|
42
78
|
|
|
43
|
-
function addSentrySPM(proj:
|
|
79
|
+
function addSentrySPM(proj: Project, targetName: string): void {
|
|
44
80
|
const xcObjects = proj.hash.project.objects;
|
|
45
81
|
|
|
46
|
-
const sentryFrameworkUUID = proj.generateUuid()
|
|
47
|
-
const sentrySPMUUID = proj.generateUuid()
|
|
82
|
+
const sentryFrameworkUUID = proj.generateUuid();
|
|
83
|
+
const sentrySPMUUID = proj.generateUuid();
|
|
48
84
|
|
|
49
|
-
//Check whether xcObjects already have sentry framework
|
|
85
|
+
// Check whether xcObjects already have sentry framework
|
|
50
86
|
if (xcObjects.PBXFrameworksBuildPhase) {
|
|
51
87
|
for (const key in xcObjects.PBXFrameworksBuildPhase || {}) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
88
|
+
const frameworkBuildPhase = xcObjects.PBXFrameworksBuildPhase[key];
|
|
89
|
+
if (key.endsWith('_comment') || typeof frameworkBuildPhase === 'string') {
|
|
90
|
+
// Ignore comments
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
for (const framework of frameworkBuildPhase.files ?? []) {
|
|
94
|
+
// We identify the Sentry framework by the comment "Sentry in Frameworks",
|
|
95
|
+
// which is set by this manager in previous runs.
|
|
96
|
+
if (framework.comment === 'Sentry in Frameworks') {
|
|
97
|
+
return;
|
|
58
98
|
}
|
|
59
99
|
}
|
|
60
100
|
}
|
|
61
101
|
}
|
|
62
102
|
|
|
103
|
+
if (!xcObjects.PBXBuildFile) {
|
|
104
|
+
xcObjects.PBXBuildFile = {};
|
|
105
|
+
}
|
|
63
106
|
xcObjects.PBXBuildFile[sentryFrameworkUUID] = {
|
|
64
107
|
isa: 'PBXBuildFile',
|
|
65
108
|
productRef: sentrySPMUUID,
|
|
66
109
|
productRef_comment: 'Sentry',
|
|
67
110
|
};
|
|
68
|
-
xcObjects.PBXBuildFile[sentryFrameworkUUID
|
|
111
|
+
xcObjects.PBXBuildFile[`${sentryFrameworkUUID}_comment`] =
|
|
69
112
|
'Sentry in Frameworks';
|
|
70
113
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
114
|
+
if (!xcObjects.PBXFrameworksBuildPhase) {
|
|
115
|
+
xcObjects.PBXFrameworksBuildPhase = {};
|
|
116
|
+
}
|
|
117
|
+
for (const key in xcObjects.PBXFrameworksBuildPhase) {
|
|
118
|
+
const value = xcObjects.PBXFrameworksBuildPhase[key];
|
|
119
|
+
if (key.endsWith('_comment') || typeof value === 'string') {
|
|
120
|
+
// Ignore comments
|
|
121
|
+
continue;
|
|
78
122
|
}
|
|
123
|
+
|
|
124
|
+
const frameworks = value.files ?? [];
|
|
125
|
+
frameworks.push({
|
|
126
|
+
value: sentryFrameworkUUID,
|
|
127
|
+
comment: 'Sentry in Frameworks',
|
|
128
|
+
});
|
|
129
|
+
value.files = frameworks;
|
|
130
|
+
|
|
131
|
+
xcObjects.PBXFrameworksBuildPhase[key] = value;
|
|
79
132
|
}
|
|
80
133
|
|
|
81
|
-
|
|
134
|
+
if (!xcObjects.PBXNativeTarget) {
|
|
135
|
+
xcObjects.PBXNativeTarget = {};
|
|
136
|
+
}
|
|
137
|
+
const targetKey = Object.keys(xcObjects.PBXNativeTarget || {}).filter(
|
|
82
138
|
(key) => {
|
|
139
|
+
const value = xcObjects.PBXNativeTarget?.[key];
|
|
83
140
|
return (
|
|
84
141
|
!key.endsWith('_comment') &&
|
|
85
|
-
|
|
142
|
+
typeof value !== 'string' &&
|
|
143
|
+
value?.name === targetName
|
|
86
144
|
);
|
|
87
145
|
},
|
|
88
146
|
)[0];
|
|
89
|
-
const target = xcObjects.PBXNativeTarget[targetKey];
|
|
147
|
+
const target = xcObjects.PBXNativeTarget[targetKey] as PBXNativeTarget;
|
|
90
148
|
|
|
91
149
|
if (!target.packageProductDependencies) {
|
|
92
150
|
target.packageProductDependencies = [];
|
|
@@ -96,7 +154,7 @@ function addSentrySPM(proj: any, targetName: string): void {
|
|
|
96
154
|
comment: 'Sentry',
|
|
97
155
|
});
|
|
98
156
|
|
|
99
|
-
const sentrySwiftPackageUUID = proj.generateUuid()
|
|
157
|
+
const sentrySwiftPackageUUID = proj.generateUuid();
|
|
100
158
|
const xcProject = proj.getFirstProject().firstProject;
|
|
101
159
|
if (!xcProject.packageReferences) {
|
|
102
160
|
xcProject.packageReferences = [];
|
|
@@ -118,7 +176,7 @@ function addSentrySPM(proj: any, targetName: string): void {
|
|
|
118
176
|
minimumVersion: '8.0.0',
|
|
119
177
|
},
|
|
120
178
|
};
|
|
121
|
-
xcObjects.XCRemoteSwiftPackageReference[sentrySwiftPackageUUID
|
|
179
|
+
xcObjects.XCRemoteSwiftPackageReference[`${sentrySwiftPackageUUID}_comment`] =
|
|
122
180
|
'XCRemoteSwiftPackageReference "sentry-cocoa"';
|
|
123
181
|
|
|
124
182
|
if (!xcObjects.XCSwiftPackageProductDependency) {
|
|
@@ -130,38 +188,48 @@ function addSentrySPM(proj: any, targetName: string): void {
|
|
|
130
188
|
package_comment: 'XCRemoteSwiftPackageReference "sentry-cocoa"',
|
|
131
189
|
productName: 'Sentry',
|
|
132
190
|
};
|
|
133
|
-
xcObjects.XCSwiftPackageProductDependency[sentrySPMUUID
|
|
191
|
+
xcObjects.XCSwiftPackageProductDependency[`${sentrySPMUUID}_comment`] =
|
|
134
192
|
'Sentry';
|
|
135
193
|
|
|
136
194
|
clack.log.step('Added Sentry SPM dependency to your project');
|
|
137
195
|
}
|
|
138
196
|
|
|
139
197
|
function addUploadSymbolsScript(
|
|
140
|
-
xcodeProject:
|
|
198
|
+
xcodeProject: Project,
|
|
141
199
|
sentryProject: SentryProjectData,
|
|
142
200
|
targetName: string,
|
|
143
|
-
uploadSource
|
|
201
|
+
uploadSource: boolean,
|
|
144
202
|
): void {
|
|
145
203
|
const xcObjects = xcodeProject.hash.project.objects;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
204
|
+
if (!xcObjects.PBXNativeTarget) {
|
|
205
|
+
xcObjects.PBXNativeTarget = {};
|
|
206
|
+
}
|
|
207
|
+
const targetKey = Object.keys(xcObjects.PBXNativeTarget).filter((key) => {
|
|
208
|
+
const value = xcObjects.PBXNativeTarget?.[key];
|
|
209
|
+
return (
|
|
210
|
+
!key.endsWith('_comment') &&
|
|
211
|
+
typeof value !== 'string' &&
|
|
212
|
+
value?.name === targetName
|
|
213
|
+
);
|
|
214
|
+
})[0];
|
|
215
|
+
|
|
216
|
+
if (!xcObjects.PBXShellScriptBuildPhase) {
|
|
217
|
+
xcObjects.PBXShellScriptBuildPhase = {};
|
|
218
|
+
}
|
|
219
|
+
for (const key in xcObjects.PBXShellScriptBuildPhase) {
|
|
220
|
+
const value = xcObjects.PBXShellScriptBuildPhase[key] ?? {};
|
|
221
|
+
if (typeof value === 'string') {
|
|
222
|
+
// Ignore comments
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
154
225
|
|
|
155
|
-
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
delete xcObjects.PBXShellScriptBuildPhase[scriptKey];
|
|
161
|
-
delete xcObjects.PBXShellScriptBuildPhase[scriptKey + '_comment'];
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
226
|
+
// Sentry script already exists, update it
|
|
227
|
+
if (value.shellScript?.includes('sentry-cli')) {
|
|
228
|
+
delete xcObjects.PBXShellScriptBuildPhase?.[key];
|
|
229
|
+
delete xcObjects.PBXShellScriptBuildPhase?.[`${key}_comment`];
|
|
230
|
+
break;
|
|
164
231
|
}
|
|
232
|
+
xcObjects.PBXShellScriptBuildPhase[key] = value;
|
|
165
233
|
}
|
|
166
234
|
|
|
167
235
|
const isHomebrewInstalled = fs.existsSync('/opt/homebrew/bin/sentry-cli');
|
|
@@ -188,36 +256,41 @@ function addUploadSymbolsScript(
|
|
|
188
256
|
|
|
189
257
|
export class XcodeProject {
|
|
190
258
|
projectPath: string;
|
|
191
|
-
project:
|
|
192
|
-
objects:
|
|
259
|
+
project: Project;
|
|
260
|
+
objects: PBXObjects;
|
|
193
261
|
files: ProjectFile[] | undefined;
|
|
194
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Creates a new XcodeProject instance, a wrapper around the Xcode project file `<PROJECT>.xcodeproj/project.pbxproj`.
|
|
265
|
+
*
|
|
266
|
+
* @param projectPath - The path to the Xcode project file
|
|
267
|
+
*/
|
|
195
268
|
public constructor(projectPath: string) {
|
|
196
269
|
this.projectPath = projectPath;
|
|
197
|
-
this.project =
|
|
270
|
+
this.project = createXcodeProject(projectPath);
|
|
198
271
|
this.project.parseSync();
|
|
199
272
|
this.objects = this.project.hash.project.objects;
|
|
200
273
|
}
|
|
201
274
|
|
|
202
275
|
public getAllTargets(): string[] {
|
|
203
|
-
|
|
276
|
+
const targets = this.objects.PBXNativeTarget ?? {};
|
|
277
|
+
return Object.keys(targets)
|
|
204
278
|
.filter((key) => {
|
|
279
|
+
const value = targets[key];
|
|
205
280
|
return (
|
|
206
281
|
!key.endsWith('_comment') &&
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
)
|
|
282
|
+
typeof value !== 'string' &&
|
|
283
|
+
value.productType.startsWith('"com.apple.product-type.application')
|
|
210
284
|
);
|
|
211
285
|
})
|
|
212
286
|
.map((key) => {
|
|
213
|
-
return
|
|
287
|
+
return (targets[key] as PBXNativeTarget).name;
|
|
214
288
|
});
|
|
215
289
|
}
|
|
216
290
|
|
|
217
291
|
public updateXcodeProject(
|
|
218
292
|
sentryProject: SentryProjectData,
|
|
219
293
|
target: string,
|
|
220
|
-
apiKeys: { token: string },
|
|
221
294
|
addSPMReference: boolean,
|
|
222
295
|
uploadSource = true,
|
|
223
296
|
): void {
|
|
@@ -234,75 +307,89 @@ export class XcodeProject {
|
|
|
234
307
|
|
|
235
308
|
public filesForTarget(target: string): string[] | undefined {
|
|
236
309
|
const files = this.projectFiles();
|
|
237
|
-
const fileDictionary:
|
|
310
|
+
const fileDictionary: Record<string, string> = {};
|
|
238
311
|
files.forEach((file) => {
|
|
239
312
|
fileDictionary[file.key] = file.path;
|
|
240
313
|
});
|
|
241
314
|
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
315
|
+
const targets = this.objects.PBXNativeTarget || {};
|
|
316
|
+
const nativeTarget = Object.keys(targets).filter((key) => {
|
|
317
|
+
const value = targets[key];
|
|
318
|
+
return (
|
|
319
|
+
!key.endsWith('_comment') &&
|
|
320
|
+
typeof value !== 'string' &&
|
|
321
|
+
value.name === target
|
|
322
|
+
);
|
|
323
|
+
})[0];
|
|
250
324
|
|
|
251
325
|
if (nativeTarget === undefined) {
|
|
252
326
|
return undefined;
|
|
253
327
|
}
|
|
254
328
|
|
|
255
|
-
const buildPhaseKey =
|
|
256
|
-
nativeTarget
|
|
257
|
-
|
|
258
|
-
return this.objects.PBXSourcesBuildPhase[phase.value] !== undefined;
|
|
329
|
+
const buildPhaseKey = (
|
|
330
|
+
targets[nativeTarget] as PBXNativeTarget
|
|
331
|
+
).buildPhases?.filter((phase) => {
|
|
332
|
+
return this.objects.PBXSourcesBuildPhase?.[phase.value] !== undefined;
|
|
259
333
|
})[0];
|
|
260
334
|
|
|
261
335
|
if (buildPhaseKey === undefined) {
|
|
262
336
|
return undefined;
|
|
263
337
|
}
|
|
264
338
|
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
339
|
+
const buildPhase = this.objects.PBXSourcesBuildPhase?.[
|
|
340
|
+
buildPhaseKey.value
|
|
341
|
+
] as PBXSourcesBuildPhase;
|
|
342
|
+
const buildPhaseFiles = buildPhase?.files ?? [];
|
|
269
343
|
|
|
270
344
|
const baseDir = path.dirname(path.dirname(this.projectPath));
|
|
271
345
|
|
|
272
|
-
return
|
|
273
|
-
.map((file
|
|
274
|
-
const
|
|
275
|
-
this.objects.PBXBuildFile[file.value]
|
|
276
|
-
|
|
346
|
+
return buildPhaseFiles
|
|
347
|
+
.map((file) => {
|
|
348
|
+
const fileRef = (
|
|
349
|
+
this.objects.PBXBuildFile?.[file.value] as PBXBuildFile
|
|
350
|
+
)?.fileRef;
|
|
351
|
+
if (!fileRef) {
|
|
352
|
+
return '';
|
|
353
|
+
}
|
|
354
|
+
const buildFile = fileDictionary[fileRef];
|
|
277
355
|
if (!buildFile) {
|
|
278
356
|
return '';
|
|
279
357
|
}
|
|
280
358
|
return path.join(baseDir, buildFile);
|
|
281
359
|
})
|
|
282
|
-
.filter((f: string) => f.length > 0)
|
|
360
|
+
.filter((f: string) => f.length > 0);
|
|
283
361
|
}
|
|
284
362
|
|
|
285
363
|
projectFiles(): ProjectFile[] {
|
|
286
364
|
if (this.files === undefined) {
|
|
287
365
|
const proj = this.project.getFirstProject();
|
|
288
366
|
const mainGroupKey = proj.firstProject.mainGroup;
|
|
289
|
-
const mainGroup = this.objects.PBXGroup[mainGroupKey];
|
|
367
|
+
const mainGroup = this.objects.PBXGroup?.[mainGroupKey];
|
|
368
|
+
if (!mainGroup || typeof mainGroup === 'string') {
|
|
369
|
+
return [];
|
|
370
|
+
}
|
|
290
371
|
this.files = this.buildGroup(mainGroup);
|
|
291
372
|
}
|
|
292
373
|
return this.files;
|
|
293
374
|
}
|
|
294
375
|
|
|
295
|
-
buildGroup(group:
|
|
376
|
+
buildGroup(group: PBXGroup, path = ''): ProjectFile[] {
|
|
296
377
|
const result: ProjectFile[] = [];
|
|
297
|
-
for (const child of group.children) {
|
|
298
|
-
|
|
299
|
-
|
|
378
|
+
for (const child of group.children ?? []) {
|
|
379
|
+
const fileReference = this.objects.PBXFileReference?.[child.value];
|
|
380
|
+
const groupReference = this.objects.PBXGroup?.[child.value];
|
|
381
|
+
if (fileReference) {
|
|
382
|
+
if (typeof fileReference === 'string') {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
300
385
|
result.push({
|
|
301
386
|
key: child.value,
|
|
302
387
|
path: `${path}${fileReference.path.replace(/"/g, '')}`,
|
|
303
388
|
});
|
|
304
|
-
} else if (
|
|
305
|
-
|
|
389
|
+
} else if (groupReference) {
|
|
390
|
+
if (typeof groupReference === 'string') {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
306
393
|
const groupChildren = this.buildGroup(
|
|
307
394
|
groupReference,
|
|
308
395
|
groupReference.path
|
|
@@ -65,10 +65,12 @@ export function runNextjsWizard(options: WizardOptions) {
|
|
|
65
65
|
export async function runNextjsWizardWithTelemetry(
|
|
66
66
|
options: WizardOptions,
|
|
67
67
|
): Promise<void> {
|
|
68
|
+
const { promoCode, telemetryEnabled, forceInstall } = options;
|
|
69
|
+
|
|
68
70
|
printWelcome({
|
|
69
71
|
wizardName: 'Sentry Next.js Wizard',
|
|
70
|
-
promoCode
|
|
71
|
-
telemetryEnabled
|
|
72
|
+
promoCode,
|
|
73
|
+
telemetryEnabled,
|
|
72
74
|
});
|
|
73
75
|
|
|
74
76
|
const typeScriptDetected = isUsingTypeScript();
|
|
@@ -93,9 +95,10 @@ export async function runNextjsWizardWithTelemetry(
|
|
|
93
95
|
|
|
94
96
|
const { packageManager: packageManagerFromInstallStep } =
|
|
95
97
|
await installPackage({
|
|
96
|
-
packageName: '@sentry/nextjs@^
|
|
98
|
+
packageName: '@sentry/nextjs@^9',
|
|
97
99
|
packageNameDisplayLabel: '@sentry/nextjs',
|
|
98
100
|
alreadyInstalled: !!packageJson?.dependencies?.['@sentry/nextjs'],
|
|
101
|
+
forceInstall,
|
|
99
102
|
});
|
|
100
103
|
|
|
101
104
|
await traceStep('configure-sdk', async () => {
|
package/src/nuxt/nuxt-wizard.ts
CHANGED
|
@@ -50,10 +50,12 @@ export function runNuxtWizard(options: WizardOptions) {
|
|
|
50
50
|
export async function runNuxtWizardWithTelemetry(
|
|
51
51
|
options: WizardOptions,
|
|
52
52
|
): Promise<void> {
|
|
53
|
+
const { promoCode, telemetryEnabled, forceInstall } = options;
|
|
54
|
+
|
|
53
55
|
printWelcome({
|
|
54
56
|
wizardName: 'Sentry Nuxt Wizard',
|
|
55
|
-
promoCode
|
|
56
|
-
telemetryEnabled
|
|
57
|
+
promoCode,
|
|
58
|
+
telemetryEnabled,
|
|
57
59
|
});
|
|
58
60
|
|
|
59
61
|
await confirmContinueIfNoOrDirtyGitRepo();
|
|
@@ -95,15 +97,16 @@ export async function runNuxtWizardWithTelemetry(
|
|
|
95
97
|
|
|
96
98
|
const packageManager = await getPackageManager();
|
|
97
99
|
|
|
98
|
-
await addNuxtOverrides(packageJson, packageManager, minVer);
|
|
100
|
+
await addNuxtOverrides(packageJson, packageManager, minVer, forceInstall);
|
|
99
101
|
|
|
100
102
|
const sdkAlreadyInstalled = hasPackageInstalled('@sentry/nuxt', packageJson);
|
|
101
103
|
Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled);
|
|
102
104
|
|
|
103
105
|
await installPackage({
|
|
104
|
-
packageName: '@sentry/nuxt',
|
|
106
|
+
packageName: '@sentry/nuxt@^9',
|
|
105
107
|
alreadyInstalled: sdkAlreadyInstalled,
|
|
106
108
|
packageManager,
|
|
109
|
+
forceInstall,
|
|
107
110
|
});
|
|
108
111
|
|
|
109
112
|
await addDotEnvSentryBuildPluginFile(authToken);
|
package/src/nuxt/sdk-setup.ts
CHANGED
|
@@ -250,6 +250,7 @@ export async function addNuxtOverrides(
|
|
|
250
250
|
packageJson: PackageDotJson,
|
|
251
251
|
packageManager: PackageManager,
|
|
252
252
|
nuxtMinVer: SemVer | null,
|
|
253
|
+
forceInstall?: boolean,
|
|
253
254
|
) {
|
|
254
255
|
const isPNPM = PNPM.detect();
|
|
255
256
|
|
|
@@ -306,6 +307,7 @@ export async function addNuxtOverrides(
|
|
|
306
307
|
packageName: 'import-in-the-middle',
|
|
307
308
|
alreadyInstalled: iitmAlreadyInstalled,
|
|
308
309
|
packageManager,
|
|
310
|
+
forceInstall,
|
|
309
311
|
});
|
|
310
312
|
}
|
|
311
313
|
}
|
|
@@ -111,10 +111,12 @@ export async function runReactNativeWizardWithTelemetry(
|
|
|
111
111
|
return runReactNativeUninstall(options);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
const { promoCode, telemetryEnabled, forceInstall } = options;
|
|
115
|
+
|
|
114
116
|
printWelcome({
|
|
115
117
|
wizardName: 'Sentry React Native Wizard',
|
|
116
|
-
promoCode
|
|
117
|
-
telemetryEnabled
|
|
118
|
+
promoCode,
|
|
119
|
+
telemetryEnabled,
|
|
118
120
|
});
|
|
119
121
|
|
|
120
122
|
await confirmContinueIfNoOrDirtyGitRepo();
|
|
@@ -147,6 +149,7 @@ Or setup using ${chalk.cyan(
|
|
|
147
149
|
await installPackage({
|
|
148
150
|
packageName: RN_SDK_PACKAGE,
|
|
149
151
|
alreadyInstalled: hasPackageInstalled(RN_SDK_PACKAGE, packageJson),
|
|
152
|
+
forceInstall,
|
|
150
153
|
});
|
|
151
154
|
const sdkVersion = getPackageVersion(
|
|
152
155
|
RN_SDK_PACKAGE,
|
|
@@ -52,10 +52,12 @@ export async function runRemixWizard(options: WizardOptions): Promise<void> {
|
|
|
52
52
|
async function runRemixWizardWithTelemetry(
|
|
53
53
|
options: WizardOptions,
|
|
54
54
|
): Promise<void> {
|
|
55
|
+
const { promoCode, telemetryEnabled, forceInstall } = options;
|
|
56
|
+
|
|
55
57
|
printWelcome({
|
|
56
58
|
wizardName: 'Sentry Remix Wizard',
|
|
57
|
-
promoCode
|
|
58
|
-
telemetryEnabled
|
|
59
|
+
promoCode,
|
|
60
|
+
telemetryEnabled,
|
|
59
61
|
});
|
|
60
62
|
|
|
61
63
|
await confirmContinueIfNoOrDirtyGitRepo();
|
|
@@ -70,9 +72,10 @@ async function runRemixWizardWithTelemetry(
|
|
|
70
72
|
await getOrAskForProjectData(options, 'javascript-remix');
|
|
71
73
|
|
|
72
74
|
await installPackage({
|
|
73
|
-
packageName: '@sentry/remix@^
|
|
75
|
+
packageName: '@sentry/remix@^9',
|
|
74
76
|
packageNameDisplayLabel: '@sentry/remix',
|
|
75
77
|
alreadyInstalled: hasPackageInstalled('@sentry/remix', packageJson),
|
|
78
|
+
forceInstall,
|
|
76
79
|
});
|
|
77
80
|
|
|
78
81
|
const dsn = selectedProject.keys[0].dsn.public;
|
package/src/remix/sdk-setup.ts
CHANGED
package/src/run.ts
CHANGED
|
@@ -56,6 +56,7 @@ type Args = {
|
|
|
56
56
|
org?: string;
|
|
57
57
|
project?: string;
|
|
58
58
|
saas?: boolean;
|
|
59
|
+
forceInstall?: boolean;
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
function preSelectedProjectArgsToObject(
|
|
@@ -132,6 +133,7 @@ export async function run(argv: Args) {
|
|
|
132
133
|
projectSlug: finalArgs.project,
|
|
133
134
|
saas: finalArgs.saas,
|
|
134
135
|
preSelectedProject: preSelectedProjectArgsToObject(finalArgs),
|
|
136
|
+
forceInstall: finalArgs.forceInstall,
|
|
135
137
|
};
|
|
136
138
|
|
|
137
139
|
switch (integration) {
|
|
@@ -41,10 +41,12 @@ export async function runSvelteKitWizard(
|
|
|
41
41
|
export async function runSvelteKitWizardWithTelemetry(
|
|
42
42
|
options: WizardOptions,
|
|
43
43
|
): Promise<void> {
|
|
44
|
+
const { promoCode, telemetryEnabled, forceInstall } = options;
|
|
45
|
+
|
|
44
46
|
printWelcome({
|
|
45
47
|
wizardName: 'Sentry SvelteKit Wizard',
|
|
46
|
-
promoCode
|
|
47
|
-
telemetryEnabled
|
|
48
|
+
promoCode,
|
|
49
|
+
telemetryEnabled,
|
|
48
50
|
});
|
|
49
51
|
|
|
50
52
|
await confirmContinueIfNoOrDirtyGitRepo();
|
|
@@ -95,9 +97,10 @@ export async function runSvelteKitWizardWithTelemetry(
|
|
|
95
97
|
Sentry.setTag('sdk-already-installed', sdkAlreadyInstalled);
|
|
96
98
|
|
|
97
99
|
await installPackage({
|
|
98
|
-
packageName: '@sentry/sveltekit@^
|
|
100
|
+
packageName: '@sentry/sveltekit@^9',
|
|
99
101
|
packageNameDisplayLabel: '@sentry/sveltekit',
|
|
100
102
|
alreadyInstalled: sdkAlreadyInstalled,
|
|
103
|
+
forceInstall,
|
|
101
104
|
});
|
|
102
105
|
|
|
103
106
|
await addDotEnvSentryBuildPluginFile(authToken);
|
package/src/utils/clack-utils.ts
CHANGED
|
@@ -207,6 +207,8 @@ export async function confirmContinueIfNoOrDirtyGitRepo(): Promise<void> {
|
|
|
207
207
|
if (!continueWithoutGit) {
|
|
208
208
|
await abort(undefined, 0);
|
|
209
209
|
}
|
|
210
|
+
// return early to avoid checking for uncommitted files
|
|
211
|
+
return;
|
|
210
212
|
}
|
|
211
213
|
|
|
212
214
|
const uncommittedOrUntrackedFiles = getUncommittedOrUntrackedFiles();
|
|
@@ -247,7 +249,10 @@ export function isInGitRepo() {
|
|
|
247
249
|
export function getUncommittedOrUntrackedFiles(): string[] {
|
|
248
250
|
try {
|
|
249
251
|
const gitStatus = childProcess
|
|
250
|
-
.execSync('git status --porcelain=v1'
|
|
252
|
+
.execSync('git status --porcelain=v1', {
|
|
253
|
+
// we only care about stdout
|
|
254
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
255
|
+
})
|
|
251
256
|
.toString();
|
|
252
257
|
|
|
253
258
|
const files = gitStatus
|
|
@@ -356,6 +361,7 @@ export async function installPackage({
|
|
|
356
361
|
askBeforeUpdating = true,
|
|
357
362
|
packageNameDisplayLabel,
|
|
358
363
|
packageManager,
|
|
364
|
+
forceInstall = false,
|
|
359
365
|
}: {
|
|
360
366
|
/** The string that is passed to the package manager CLI as identifier to install (e.g. `@sentry/nextjs`, or `@sentry/nextjs@^8`) */
|
|
361
367
|
packageName: string;
|
|
@@ -364,6 +370,8 @@ export async function installPackage({
|
|
|
364
370
|
/** Overrides what is shown in the installation logs in place of the `packageName` option. Useful if the `packageName` is ugly (e.g. `@sentry/nextjs@^8`) */
|
|
365
371
|
packageNameDisplayLabel?: string;
|
|
366
372
|
packageManager?: PackageManager;
|
|
373
|
+
/** Add force install flag to command to skip install precondition fails */
|
|
374
|
+
forceInstall?: boolean;
|
|
367
375
|
}): Promise<{ packageManager?: PackageManager }> {
|
|
368
376
|
return traceStep('install-package', async () => {
|
|
369
377
|
if (alreadyInstalled && askBeforeUpdating) {
|
|
@@ -393,7 +401,9 @@ export async function installPackage({
|
|
|
393
401
|
try {
|
|
394
402
|
await new Promise<void>((resolve, reject) => {
|
|
395
403
|
childProcess.exec(
|
|
396
|
-
`${pkgManager.installCommand} ${packageName} ${pkgManager.flags}
|
|
404
|
+
`${pkgManager.installCommand} ${packageName} ${pkgManager.flags} ${
|
|
405
|
+
forceInstall ? pkgManager.forceInstallFlag : ''
|
|
406
|
+
}`,
|
|
397
407
|
(err, stdout, stderr) => {
|
|
398
408
|
if (err) {
|
|
399
409
|
// Write a log file so we can better troubleshoot issues
|