@sentry/wizard 3.39.0 → 3.41.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.
Files changed (221) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +21 -21
  3. package/bin.ts +5 -0
  4. package/codecov.yml +15 -0
  5. package/dist/bin.js +4 -0
  6. package/dist/bin.js.map +1 -1
  7. package/dist/e2e-tests/jest.config.d.ts +1 -0
  8. package/dist/e2e-tests/jest.config.js +1 -0
  9. package/dist/e2e-tests/jest.config.js.map +1 -1
  10. package/dist/e2e-tests/tests/flutter.test.d.ts +1 -0
  11. package/dist/e2e-tests/tests/flutter.test.js +190 -0
  12. package/dist/e2e-tests/tests/flutter.test.js.map +1 -0
  13. package/dist/e2e-tests/utils/index.d.ts +11 -0
  14. package/dist/e2e-tests/utils/index.js +36 -1
  15. package/dist/e2e-tests/utils/index.js.map +1 -1
  16. package/dist/lib/Constants.d.ts +1 -0
  17. package/dist/lib/Constants.js +5 -0
  18. package/dist/lib/Constants.js.map +1 -1
  19. package/dist/package.json +3 -2
  20. package/dist/src/apple/apple-wizard.js +2 -3
  21. package/dist/src/apple/apple-wizard.js.map +1 -1
  22. package/dist/src/apple/code-tools.d.ts +10 -0
  23. package/dist/src/apple/code-tools.js +16 -12
  24. package/dist/src/apple/code-tools.js.map +1 -1
  25. package/dist/src/apple/fastlane.d.ts +23 -0
  26. package/dist/src/apple/fastlane.js +11 -7
  27. package/dist/src/apple/fastlane.js.map +1 -1
  28. package/dist/src/apple/templates.d.ts +1 -1
  29. package/dist/src/apple/templates.js +0 -2
  30. package/dist/src/apple/templates.js.map +1 -1
  31. package/dist/src/apple/xcode-manager.d.ts +13 -9
  32. package/dist/src/apple/xcode-manager.js +146 -61
  33. package/dist/src/apple/xcode-manager.js.map +1 -1
  34. package/dist/src/flutter/code-tools.d.ts +17 -0
  35. package/dist/src/flutter/code-tools.js +263 -0
  36. package/dist/src/flutter/code-tools.js.map +1 -0
  37. package/dist/src/flutter/flutter-wizard.d.ts +2 -0
  38. package/dist/src/flutter/flutter-wizard.js +171 -0
  39. package/dist/src/flutter/flutter-wizard.js.map +1 -0
  40. package/dist/src/flutter/templates.d.ts +9 -0
  41. package/dist/src/flutter/templates.js +40 -0
  42. package/dist/src/flutter/templates.js.map +1 -0
  43. package/dist/src/nextjs/nextjs-wizard.js +5 -3
  44. package/dist/src/nextjs/nextjs-wizard.js.map +1 -1
  45. package/dist/src/nuxt/nuxt-wizard.js +6 -4
  46. package/dist/src/nuxt/nuxt-wizard.js.map +1 -1
  47. package/dist/src/nuxt/sdk-setup.d.ts +1 -1
  48. package/dist/src/nuxt/sdk-setup.js +2 -1
  49. package/dist/src/nuxt/sdk-setup.js.map +1 -1
  50. package/dist/src/react-native/react-native-wizard.js +5 -3
  51. package/dist/src/react-native/react-native-wizard.js.map +1 -1
  52. package/dist/src/remix/remix-wizard.js +5 -3
  53. package/dist/src/remix/remix-wizard.js.map +1 -1
  54. package/dist/src/run.d.ts +2 -1
  55. package/dist/src/run.js +40 -32
  56. package/dist/src/run.js.map +1 -1
  57. package/dist/src/sveltekit/sveltekit-wizard.js +5 -3
  58. package/dist/src/sveltekit/sveltekit-wizard.js.map +1 -1
  59. package/dist/src/utils/clack-utils.d.ts +4 -2
  60. package/dist/src/utils/clack-utils.js +18 -12
  61. package/dist/src/utils/clack-utils.js.map +1 -1
  62. package/dist/src/utils/package-manager.d.ts +1 -0
  63. package/dist/src/utils/package-manager.js +5 -0
  64. package/dist/src/utils/package-manager.js.map +1 -1
  65. package/dist/src/utils/types.d.ts +9 -0
  66. package/dist/src/utils/types.js.map +1 -1
  67. package/dist/test/apple/cocoapod.test.d.ts +1 -0
  68. package/dist/test/apple/cocoapod.test.js +409 -0
  69. package/dist/test/apple/cocoapod.test.js.map +1 -0
  70. package/dist/test/apple/code-tools.test.d.ts +1 -0
  71. package/dist/test/apple/code-tools.test.js +673 -0
  72. package/dist/test/apple/code-tools.test.js.map +1 -0
  73. package/dist/test/apple/fastfile.test.d.ts +1 -0
  74. package/dist/test/apple/fastfile.test.js +431 -0
  75. package/dist/test/apple/fastfile.test.js.map +1 -0
  76. package/dist/test/apple/templates.test.d.ts +1 -0
  77. package/dist/test/apple/templates.test.js +73 -0
  78. package/dist/test/apple/templates.test.js.map +1 -0
  79. package/dist/test/apple/xcode-manager.test.d.ts +1 -0
  80. package/dist/test/apple/xcode-manager.test.js +834 -0
  81. package/dist/test/apple/xcode-manager.test.js.map +1 -0
  82. package/dist/test/flutter/code-tools.test.d.ts +1 -0
  83. package/dist/test/flutter/code-tools.test.js +84 -0
  84. package/dist/test/flutter/code-tools.test.js.map +1 -0
  85. package/dist/test/flutter/templates.test.d.ts +1 -0
  86. package/dist/test/flutter/templates.test.js +41 -0
  87. package/dist/test/flutter/templates.test.js.map +1 -0
  88. package/dist/test/utils/clack-utils.test.js +89 -0
  89. package/dist/test/utils/clack-utils.test.js.map +1 -1
  90. package/e2e-tests/README.md +5 -1
  91. package/e2e-tests/jest.config.ts +1 -0
  92. package/e2e-tests/test-applications/apple/damaged-missing-configuration-list/Project.xcodeproj/project.pbxproj +52 -0
  93. package/e2e-tests/test-applications/apple/damaged-missing-configuration-list/Project.xcodeproj/xcshareddata/xcschemes/Project1.xcscheme +78 -0
  94. package/e2e-tests/test-applications/apple/no-targets/Project.xcodeproj/project.pbxproj +62 -0
  95. package/e2e-tests/test-applications/apple/no-targets/Project.xcodeproj/xcshareddata/xcschemes/Project1.xcscheme +78 -0
  96. package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project.xcodeproj/project.pbxproj +470 -0
  97. package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project.xcodeproj/xcshareddata/xcschemes/Project1.xcscheme +78 -0
  98. package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project1/ContentView.swift +7 -0
  99. package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project1/Project1App.swift +10 -0
  100. package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project2/ContentView.swift +7 -0
  101. package/e2e-tests/test-applications/apple/spm-swiftui-multi-targets/Project2/Project2App.swift +10 -0
  102. package/e2e-tests/test-applications/apple/spm-swiftui-single-target/Project.xcodeproj/project.pbxproj +382 -0
  103. package/e2e-tests/test-applications/apple/spm-swiftui-single-target/Project.xcodeproj/xcshareddata/xcschemes/Project.xcscheme +78 -0
  104. package/e2e-tests/test-applications/apple/spm-swiftui-single-target/Sources/ContentView.swift +7 -0
  105. package/e2e-tests/test-applications/apple/spm-swiftui-single-target/Sources/MainApp.swift +10 -0
  106. package/e2e-tests/test-applications/flutter-test-app/.metadata +45 -0
  107. package/e2e-tests/test-applications/flutter-test-app/README.md +16 -0
  108. package/e2e-tests/test-applications/flutter-test-app/analysis_options.yaml +28 -0
  109. package/e2e-tests/test-applications/flutter-test-app/android/app/build.gradle +44 -0
  110. package/e2e-tests/test-applications/flutter-test-app/android/app/src/debug/AndroidManifest.xml +7 -0
  111. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/AndroidManifest.xml +45 -0
  112. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/kotlin/com/example/flutter_magic/MainActivity.kt +5 -0
  113. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/drawable/launch_background.xml +12 -0
  114. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/drawable-v21/launch_background.xml +12 -0
  115. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  116. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  117. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  118. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  119. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  120. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/values/styles.xml +18 -0
  121. package/e2e-tests/test-applications/flutter-test-app/android/app/src/main/res/values-night/styles.xml +18 -0
  122. package/e2e-tests/test-applications/flutter-test-app/android/app/src/profile/AndroidManifest.xml +7 -0
  123. package/e2e-tests/test-applications/flutter-test-app/android/build.gradle +18 -0
  124. package/e2e-tests/test-applications/flutter-test-app/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  125. package/e2e-tests/test-applications/flutter-test-app/android/gradle.properties +3 -0
  126. package/e2e-tests/test-applications/flutter-test-app/android/settings.gradle +25 -0
  127. package/e2e-tests/test-applications/flutter-test-app/lib/main.dart +125 -0
  128. package/e2e-tests/test-applications/flutter-test-app/linux/CMakeLists.txt +145 -0
  129. package/e2e-tests/test-applications/flutter-test-app/linux/flutter/CMakeLists.txt +88 -0
  130. package/e2e-tests/test-applications/flutter-test-app/linux/flutter/generated_plugin_registrant.cc +11 -0
  131. package/e2e-tests/test-applications/flutter-test-app/linux/flutter/generated_plugin_registrant.h +15 -0
  132. package/e2e-tests/test-applications/flutter-test-app/linux/flutter/generated_plugins.cmake +23 -0
  133. package/e2e-tests/test-applications/flutter-test-app/linux/main.cc +6 -0
  134. package/e2e-tests/test-applications/flutter-test-app/linux/my_application.cc +124 -0
  135. package/e2e-tests/test-applications/flutter-test-app/linux/my_application.h +18 -0
  136. package/e2e-tests/test-applications/flutter-test-app/macos/Flutter/Flutter-Debug.xcconfig +2 -0
  137. package/e2e-tests/test-applications/flutter-test-app/macos/Flutter/Flutter-Release.xcconfig +2 -0
  138. package/e2e-tests/test-applications/flutter-test-app/macos/Flutter/GeneratedPluginRegistrant.swift +10 -0
  139. package/e2e-tests/test-applications/flutter-test-app/macos/Podfile +43 -0
  140. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/AppDelegate.swift +9 -0
  141. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +68 -0
  142. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png +0 -0
  143. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png +0 -0
  144. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png +0 -0
  145. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png +0 -0
  146. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png +0 -0
  147. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png +0 -0
  148. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png +0 -0
  149. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Base.lproj/MainMenu.xib +343 -0
  150. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Configs/AppInfo.xcconfig +14 -0
  151. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Configs/Debug.xcconfig +2 -0
  152. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Configs/Release.xcconfig +2 -0
  153. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Configs/Warnings.xcconfig +13 -0
  154. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/DebugProfile.entitlements +12 -0
  155. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Info.plist +32 -0
  156. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/MainFlutterWindow.swift +15 -0
  157. package/e2e-tests/test-applications/flutter-test-app/macos/Runner/Release.entitlements +8 -0
  158. package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcodeproj/project.pbxproj +705 -0
  159. package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  160. package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +98 -0
  161. package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcworkspace/contents.xcworkspacedata +7 -0
  162. package/e2e-tests/test-applications/flutter-test-app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  163. package/e2e-tests/test-applications/flutter-test-app/macos/RunnerTests/RunnerTests.swift +12 -0
  164. package/e2e-tests/test-applications/flutter-test-app/pubspec.lock +213 -0
  165. package/e2e-tests/test-applications/flutter-test-app/pubspec.yaml +89 -0
  166. package/e2e-tests/test-applications/flutter-test-app/test/widget_test.dart +30 -0
  167. package/e2e-tests/test-applications/flutter-test-app/web/favicon.png +0 -0
  168. package/e2e-tests/test-applications/flutter-test-app/web/icons/Icon-192.png +0 -0
  169. package/e2e-tests/test-applications/flutter-test-app/web/icons/Icon-512.png +0 -0
  170. package/e2e-tests/test-applications/flutter-test-app/web/icons/Icon-maskable-192.png +0 -0
  171. package/e2e-tests/test-applications/flutter-test-app/web/icons/Icon-maskable-512.png +0 -0
  172. package/e2e-tests/test-applications/flutter-test-app/web/index.html +38 -0
  173. package/e2e-tests/test-applications/flutter-test-app/web/manifest.json +35 -0
  174. package/e2e-tests/test-applications/flutter-test-app/windows/CMakeLists.txt +108 -0
  175. package/e2e-tests/test-applications/flutter-test-app/windows/flutter/CMakeLists.txt +109 -0
  176. package/e2e-tests/test-applications/flutter-test-app/windows/flutter/generated_plugin_registrant.cc +11 -0
  177. package/e2e-tests/test-applications/flutter-test-app/windows/flutter/generated_plugin_registrant.h +15 -0
  178. package/e2e-tests/test-applications/flutter-test-app/windows/flutter/generated_plugins.cmake +23 -0
  179. package/e2e-tests/test-applications/flutter-test-app/windows/runner/CMakeLists.txt +40 -0
  180. package/e2e-tests/test-applications/flutter-test-app/windows/runner/Runner.rc +121 -0
  181. package/e2e-tests/test-applications/flutter-test-app/windows/runner/flutter_window.cpp +71 -0
  182. package/e2e-tests/test-applications/flutter-test-app/windows/runner/flutter_window.h +33 -0
  183. package/e2e-tests/test-applications/flutter-test-app/windows/runner/main.cpp +43 -0
  184. package/e2e-tests/test-applications/flutter-test-app/windows/runner/resource.h +16 -0
  185. package/e2e-tests/test-applications/flutter-test-app/windows/runner/resources/app_icon.ico +0 -0
  186. package/e2e-tests/test-applications/flutter-test-app/windows/runner/runner.exe.manifest +14 -0
  187. package/e2e-tests/test-applications/flutter-test-app/windows/runner/utils.cpp +65 -0
  188. package/e2e-tests/test-applications/flutter-test-app/windows/runner/utils.h +19 -0
  189. package/e2e-tests/test-applications/flutter-test-app/windows/runner/win32_window.cpp +288 -0
  190. package/e2e-tests/test-applications/flutter-test-app/windows/runner/win32_window.h +102 -0
  191. package/e2e-tests/tests/flutter.test.ts +127 -0
  192. package/e2e-tests/utils/index.ts +33 -0
  193. package/lib/Constants.ts +5 -0
  194. package/package.json +3 -2
  195. package/src/apple/apple-wizard.ts +2 -3
  196. package/src/apple/code-tools.ts +21 -6
  197. package/src/apple/fastlane.ts +18 -2
  198. package/src/apple/templates.ts +2 -2
  199. package/src/apple/xcode-manager.ts +186 -99
  200. package/src/flutter/code-tools.ts +284 -0
  201. package/src/flutter/flutter-wizard.ts +164 -0
  202. package/src/flutter/templates.ts +90 -0
  203. package/src/nextjs/nextjs-wizard.ts +5 -2
  204. package/src/nuxt/nuxt-wizard.ts +6 -3
  205. package/src/nuxt/sdk-setup.ts +2 -0
  206. package/src/react-native/react-native-wizard.ts +5 -2
  207. package/src/remix/remix-wizard.ts +5 -2
  208. package/src/run.ts +9 -0
  209. package/src/sveltekit/sveltekit-wizard.ts +5 -2
  210. package/src/utils/clack-utils.ts +16 -4
  211. package/src/utils/package-manager.ts +6 -0
  212. package/src/utils/types.ts +10 -0
  213. package/test/apple/cocoapod.test.ts +306 -0
  214. package/test/apple/code-tools.test.ts +1042 -0
  215. package/test/apple/fastfile.test.ts +550 -0
  216. package/test/apple/templates.test.ts +191 -0
  217. package/test/apple/xcode-manager.test.ts +1066 -0
  218. package/test/flutter/code-tools.test.ts +212 -0
  219. package/test/flutter/templates.test.ts +100 -0
  220. package/test/utils/clack-utils.test.ts +92 -0
  221. package/types/xcode.d.ts +526 -0
@@ -1,9 +1,9 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
- import * as templates from './templates';
4
3
  import { askForItemSelection } from '../utils/clack-utils';
4
+ import * as templates from './templates';
5
5
  // @ts-ignore - clack is ESM and TS complains about that. It works though
6
- import clack from '@clack/prompts';
6
+ import * as clack from '@clack/prompts';
7
7
 
8
8
  export function fastFile(projectPath: string): string | null {
9
9
  const fastlanePath = path.join(projectPath, 'fastlane', 'Fastfile');
@@ -152,3 +152,19 @@ export async function addSentryToFastlane(
152
152
  fs.writeFileSync(fastFilePath, newFileContent, 'utf8');
153
153
  return true;
154
154
  }
155
+
156
+ /**
157
+ * Exported for testing purposes, but should not be used in other modules.
158
+ */
159
+ export let exportForTesting: {
160
+ findIOSPlatform: typeof findIOSPlatform;
161
+ findLanes: typeof findLanes;
162
+ addSentryToLane: typeof addSentryToLane;
163
+ };
164
+ if (process.env.NODE_ENV === 'test') {
165
+ exportForTesting = {
166
+ findIOSPlatform,
167
+ findLanes,
168
+ addSentryToLane,
169
+ };
170
+ }
@@ -1,8 +1,8 @@
1
1
  export function getRunScriptTemplate(
2
2
  orgSlug: string,
3
3
  projectSlug: string,
4
- uploadSource = true,
5
- includeHomebrewPath = false,
4
+ uploadSource: boolean,
5
+ includeHomebrewPath: boolean,
6
6
  ): string {
7
7
  // eslint-disable-next-line no-useless-escape
8
8
  const includeHomebrew = includeHomebrewPath
@@ -5,88 +5,146 @@
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
- import * as path from 'path';
11
- const xcode = require('xcode');
12
11
 
13
- interface ProjetFile {
12
+ import {
13
+ project as createXcodeProject,
14
+ PBXBuildFile,
15
+ PBXGroup,
16
+ PBXNativeTarget,
17
+ PBXObjects,
18
+ PBXSourcesBuildPhase,
19
+ Project,
20
+ XCConfigurationList,
21
+ } from 'xcode';
22
+
23
+ interface ProjectFile {
14
24
  key: string;
15
25
  path: string;
16
26
  }
17
27
 
18
28
  function setDebugInformationFormatAndSandbox(
19
- proj: any,
29
+ proj: Project,
20
30
  targetName: string,
21
31
  ): void {
22
32
  const xcObjects = proj.hash.project.objects;
23
- const targetKey: string = Object.keys(xcObjects.PBXNativeTarget || {}).filter(
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
- xcObjects.PBXNativeTarget[key].name === targetName
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.XCConfigurationList[
34
- target.buildConfigurationList
35
- ].buildConfigurations.forEach((buildConfig: { value: string }) => {
36
- const buildSettings =
37
- xcObjects.XCBuildConfiguration[buildConfig.value].buildSettings;
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: any, targetName: string): void {
79
+ function addSentrySPM(proj: Project, targetName: string): void {
44
80
  const xcObjects = proj.hash.project.objects;
45
81
 
46
- const sentryFrameworkUUID = proj.generateUuid() as string;
47
- const sentrySPMUUID = proj.generateUuid() as string;
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
- if (!key.endsWith('_comment')) {
53
- const frameworks = xcObjects.PBXFrameworksBuildPhase[key].files;
54
- for (const framework of frameworks) {
55
- if (framework.comment === 'Sentry in Frameworks') {
56
- return;
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 + '_comment'] =
111
+ xcObjects.PBXBuildFile[`${sentryFrameworkUUID}_comment`] =
69
112
  'Sentry in Frameworks';
70
113
 
71
- for (const key in xcObjects.PBXFrameworksBuildPhase || {}) {
72
- if (!key.endsWith('_comment')) {
73
- const frameworks = xcObjects.PBXFrameworksBuildPhase[key].files;
74
- frameworks.push({
75
- value: sentryFrameworkUUID,
76
- comment: 'Sentry in Frameworks',
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
- const targetKey: string = Object.keys(xcObjects.PBXNativeTarget || {}).filter(
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
- xcObjects.PBXNativeTarget[key].name === targetName
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() as string;
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 + '_comment'] =
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 + '_comment'] =
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: any,
198
+ xcodeProject: Project,
141
199
  sentryProject: SentryProjectData,
142
200
  targetName: string,
143
- uploadSource = true,
201
+ uploadSource: boolean,
144
202
  ): void {
145
203
  const xcObjects = xcodeProject.hash.project.objects;
146
- const targetKey: string = Object.keys(xcObjects.PBXNativeTarget || {}).filter(
147
- (key) => {
148
- return (
149
- !key.endsWith('_comment') &&
150
- xcObjects.PBXNativeTarget[key].name === targetName
151
- );
152
- },
153
- )[0];
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
- for (const scriptKey in xcObjects.PBXShellScriptBuildPhase || {}) {
156
- if (!scriptKey.endsWith('_comment')) {
157
- const script = xcObjects.PBXShellScriptBuildPhase[scriptKey].shellScript;
158
- //Sentry script already exists, update it
159
- if (script.includes('sentry-cli')) {
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: any;
192
- objects: any;
193
- files: ProjetFile[] | undefined;
194
-
259
+ project: Project;
260
+ objects: PBXObjects;
261
+ files: ProjectFile[] | undefined;
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 = xcode.project(projectPath);
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
- return Object.keys(this.objects.PBXNativeTarget || {})
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
- this.objects.PBXNativeTarget[key].productType.startsWith(
208
- '"com.apple.product-type.application',
209
- )
282
+ typeof value !== 'string' &&
283
+ value.productType.startsWith('"com.apple.product-type.application')
210
284
  );
211
285
  })
212
286
  .map((key) => {
213
- return this.objects.PBXNativeTarget[key].name as string;
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: any = {};
310
+ const fileDictionary: Record<string, string> = {};
238
311
  files.forEach((file) => {
239
312
  fileDictionary[file.key] = file.path;
240
313
  });
241
314
 
242
- const nativeTarget = Object.keys(this.objects.PBXNativeTarget || {}).filter(
243
- (key) => {
244
- return (
245
- !key.endsWith('_comment') &&
246
- this.objects.PBXNativeTarget[key].name === target
247
- );
248
- },
249
- )[0];
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 = this.objects.PBXNativeTarget[
256
- nativeTarget
257
- ].buildPhases.filter((phase: any) => {
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 buildPhases = this.objects.PBXSourcesBuildPhase[buildPhaseKey.value];
266
- if (buildPhases === undefined) {
267
- return undefined;
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 buildPhases.files
273
- .map((file: any) => {
274
- const buildFile = fileDictionary[
275
- this.objects.PBXBuildFile[file.value].fileRef
276
- ] as string;
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) as string[];
360
+ .filter((f: string) => f.length > 0);
283
361
  }
284
362
 
285
- projectFiles(): ProjetFile[] {
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: any, path = ''): ProjetFile[] {
296
- const result: ProjetFile[] = [];
297
- for (const child of group.children) {
298
- if (this.objects.PBXFileReference[child.value]) {
299
- const fileReference = this.objects.PBXFileReference[child.value];
376
+ buildGroup(group: PBXGroup, path = ''): ProjectFile[] {
377
+ const result: ProjectFile[] = [];
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 (this.objects.PBXGroup[child.value]) {
305
- const groupReference = this.objects.PBXGroup[child.value];
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