diff --git a/CHANGELOG.md b/CHANGELOG.md index bed89bbf4..d515f4e04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Breaking Changes + +- feat(apple)!: Remove CocoaPods as an installation option ([#1299](https://github.com/getsentry/sentry-wizard/pull/1299)) + ## 6.13.0 ### Fixes diff --git a/src/apple/apple-wizard.ts b/src/apple/apple-wizard.ts index 27d7016e6..3a3e26710 100644 --- a/src/apple/apple-wizard.ts +++ b/src/apple/apple-wizard.ts @@ -10,9 +10,10 @@ import { printWelcome, } from '../utils/clack'; import { offerProjectScopedMcpConfig } from '../utils/clack/mcp-config'; +import * as Sentry from '@sentry/node'; + import { checkInstalledCLI } from './check-installed-cli'; import { configureFastlane } from './configure-fastlane'; -import { configurePackageManager } from './configure-package-manager'; import { configureSentryCLI } from './configure-sentry-cli'; import { configureXcodeProject } from './configure-xcode-project'; import { injectCodeSnippet } from './inject-code-snippet'; @@ -75,17 +76,13 @@ async function runAppleWizardWithTelementry( authToken: authToken, }); - // Step - Set up Package Manager - const { shouldUseSPM } = await configurePackageManager({ - projectDir, - }); + Sentry.setTag('package-manager', 'SPM'); // Step - Configure Xcode Project configureXcodeProject({ xcProject, project: selectedProject, target, - shouldUseSPM, }); // Step - Feature Selection diff --git a/src/apple/configure-package-manager.ts b/src/apple/configure-package-manager.ts deleted file mode 100644 index 23ee351eb..000000000 --- a/src/apple/configure-package-manager.ts +++ /dev/null @@ -1,79 +0,0 @@ -// @ts-expect-error - clack is ESM and TS complains about that. It works though -import clack from '@clack/prompts'; -import * as Sentry from '@sentry/node'; -import chalk from 'chalk'; - -import { traceStep } from '../telemetry'; -import { abortIfCancelled } from '../utils/clack'; -import { debug } from '../utils/debug'; -import * as cocoapod from './cocoapod'; - -export async function configurePackageManager({ - projectDir, -}: { - projectDir: string; -}) { - debug( - `Checking if CocoaPods is installed at path: ${chalk.cyan(projectDir)}`, - ); - - // Xcode ships with the Swift Package Manager and potentially using CocoaPods. - // We need to check if the user has CocoaPods set up. - let shouldUseSPM = true; - - const isCocoaPodsAvailable = cocoapod.usesCocoaPod(projectDir); - Sentry.setTag('cocoapod-exists', isCocoaPodsAvailable); - debug(`CocoaPods is ${isCocoaPodsAvailable ? 'installed' : 'not installed'}`); - - if (isCocoaPodsAvailable) { - clack.log.warn( - 'CocoaPods is being deprecated. No new updates will be released after June 2026.\nWe recommend migrating to Swift Package Manager (SPM).', - ); - - debug('Asking user to choose a package manager'); - const pm: 'SPM' | 'CocoaPods' = await traceStep( - 'Choose a package manager', - () => - abortIfCancelled( - clack.select({ - message: - 'Which package manager would you like to use to add Sentry?', - options: [ - { - value: 'SPM', - label: 'Swift Package Manager', - hint: 'Recommended', - }, - { - value: 'CocoaPods', - label: 'CocoaPods', - hint: 'Deprecated - no updates after June 2026', - }, - ], - }), - ), - ); - debug(`User chose package manager: ${chalk.cyan(pm)}`); - - shouldUseSPM = pm === 'SPM'; - - if (!shouldUseSPM) { - debug('Adding CocoaPods reference'); - const podAdded = await traceStep('Add CocoaPods reference', () => - cocoapod.addCocoaPods(projectDir), - ); - Sentry.setTag('cocoapod-added', podAdded); - debug(`CocoaPods reference added: ${chalk.cyan(podAdded.toString())}`); - - if (!podAdded) { - clack.log.warn( - "Could not add Sentry pod to your Podfile. You'll have to add it manually.\nPlease follow the instructions at https://docs.sentry.io/platforms/apple/guides/ios/#install", - ); - } - } - } - debug(`Should use SPM: ${chalk.cyan(shouldUseSPM.toString())}`); - Sentry.setTag('package-manager', shouldUseSPM ? 'SPM' : 'CocoaPods'); - - return { shouldUseSPM }; -} diff --git a/src/apple/configure-xcode-project.ts b/src/apple/configure-xcode-project.ts index 4a826e35f..d28d31442 100644 --- a/src/apple/configure-xcode-project.ts +++ b/src/apple/configure-xcode-project.ts @@ -10,25 +10,20 @@ export function configureXcodeProject({ xcProject, project, target, - shouldUseSPM, }: { xcProject: XcodeProject; project: SentryProjectData; target: string; - shouldUseSPM: boolean; }) { traceStep('Update Xcode project', () => { xcProject.updateXcodeProject( project, target, - shouldUseSPM - ? { - product: sentrySwiftPackageProductSpec, - existingFrameworkComment: - SENTRY_SPM_ALREADY_LINKED_FRAMEWORK_COMMENT, - successMessage: 'Added Sentry SPM dependency to your project', - } - : undefined, + { + product: sentrySwiftPackageProductSpec, + existingFrameworkComment: SENTRY_SPM_ALREADY_LINKED_FRAMEWORK_COMMENT, + successMessage: 'Added Sentry SPM dependency to your project', + }, true, ); }); diff --git a/src/apple/cocoapod.ts b/src/react-native/cocoapod.ts similarity index 100% rename from src/apple/cocoapod.ts rename to src/react-native/cocoapod.ts diff --git a/src/react-native/react-native-wizard.ts b/src/react-native/react-native-wizard.ts index cf3851436..c3efee308 100644 --- a/src/react-native/react-native-wizard.ts +++ b/src/react-native/react-native-wizard.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import * as Sentry from '@sentry/node'; import { platform } from 'os'; -import { podInstall } from '../apple/cocoapod'; +import { podInstall } from './cocoapod'; import { traceStep, withTelemetry } from '../telemetry'; import { offerProjectScopedMcpConfig } from '../utils/clack/mcp-config'; import { diff --git a/test/apple/configure-package-manager.test.ts b/test/apple/configure-package-manager.test.ts deleted file mode 100644 index 1c71d692a..000000000 --- a/test/apple/configure-package-manager.test.ts +++ /dev/null @@ -1,171 +0,0 @@ -import * as Sentry from '@sentry/node'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import * as cocoapod from '../../src/apple/cocoapod'; -import { configurePackageManager } from '../../src/apple/configure-package-manager'; -// @ts-expect-error - clack is ESM and TS complains about that. It works though -import clack from '@clack/prompts'; -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; - -vi.mock('@clack/prompts', () => ({ - __esModule: true, - default: { - log: { - warn: vi.fn(), - step: vi.fn(), - }, - select: vi.fn(), - }, -})); - -vi.mock('../../src/apple/cocoapod'); -vi.mock('../../src/utils/clack', () => ({ - abortIfCancelled: vi.fn((value: unknown) => Promise.resolve(value)), -})); - -vi.mock('../../src/telemetry', () => ({ - traceStep: vi.fn( - async (_name: string, fn: () => Promise) => await fn(), - ), -})); - -vi.mock('../../src/utils/debug', () => ({ - debug: vi.fn(), -})); - -vi.mock('@sentry/node', async () => { - const actual = await vi.importActual( - '@sentry/node', - ); - return { - ...actual, - setTag: vi.fn(), - captureException: vi.fn(() => 'id'), - }; -}); - -describe('configurePackageManager', () => { - let projectDir: string; - - beforeEach(() => { - projectDir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-project')); - vi.clearAllMocks(); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - describe('when CocoaPods is not available', () => { - it('should default to SPM and not prompt user', async () => { - // -- Arrange -- - vi.spyOn(cocoapod, 'usesCocoaPod').mockReturnValue(false); - - // -- Act -- - const result = await configurePackageManager({ projectDir }); - - // -- Assert -- - expect(result.shouldUseSPM).toBe(true); - expect(clack.select).not.toHaveBeenCalled(); - expect(clack.log.warn).not.toHaveBeenCalled(); - expect(Sentry.setTag).toHaveBeenCalledWith('cocoapod-exists', false); - expect(Sentry.setTag).toHaveBeenCalledWith('package-manager', 'SPM'); - }); - }); - - describe('when CocoaPods is available', () => { - beforeEach(() => { - vi.spyOn(cocoapod, 'usesCocoaPod').mockReturnValue(true); - }); - - it('should show deprecation warning', async () => { - // -- Arrange -- - vi.mocked(clack.select).mockResolvedValue('SPM' as never); - - // -- Act -- - await configurePackageManager({ projectDir }); - - // -- Assert -- - expect(clack.log.warn).toHaveBeenCalledWith( - 'CocoaPods is being deprecated. No new updates will be released after June 2026.\nWe recommend migrating to Swift Package Manager (SPM).', - ); - }); - - it('should prompt user to choose package manager', async () => { - // -- Arrange -- - vi.mocked(clack.select).mockResolvedValue('SPM' as never); - - // -- Act -- - await configurePackageManager({ projectDir }); - - // -- Assert -- - expect(clack.select).toHaveBeenCalledWith({ - message: 'Which package manager would you like to use to add Sentry?', - options: [ - { - value: 'SPM', - label: 'Swift Package Manager', - hint: 'Recommended', - }, - { - value: 'CocoaPods', - label: 'CocoaPods', - hint: 'Deprecated - no updates after June 2026', - }, - ], - }); - }); - - it('should use SPM when user selects SPM', async () => { - // -- Arrange -- - vi.mocked(clack.select).mockResolvedValue('SPM' as never); - - // -- Act -- - const result = await configurePackageManager({ projectDir }); - - // -- Assert -- - expect(result.shouldUseSPM).toBe(true); - expect(cocoapod.addCocoaPods).not.toHaveBeenCalled(); - expect(Sentry.setTag).toHaveBeenCalledWith('cocoapod-exists', true); - expect(Sentry.setTag).toHaveBeenCalledWith('package-manager', 'SPM'); - }); - - it('should use CocoaPods when user selects CocoaPods', async () => { - // -- Arrange -- - vi.mocked(clack.select).mockResolvedValue('CocoaPods' as never); - vi.spyOn(cocoapod, 'addCocoaPods').mockResolvedValue(true); - - // -- Act -- - const result = await configurePackageManager({ projectDir }); - - // -- Assert -- - expect(result.shouldUseSPM).toBe(false); - expect(cocoapod.addCocoaPods).toHaveBeenCalledWith(projectDir); - expect(Sentry.setTag).toHaveBeenCalledWith('cocoapod-exists', true); - expect(Sentry.setTag).toHaveBeenCalledWith('cocoapod-added', true); - expect(Sentry.setTag).toHaveBeenCalledWith( - 'package-manager', - 'CocoaPods', - ); - }); - - it('should handle CocoaPods addition failure', async () => { - // -- Arrange -- - vi.mocked(clack.select).mockResolvedValue('CocoaPods' as never); - vi.spyOn(cocoapod, 'addCocoaPods').mockResolvedValue(false); - - // -- Act -- - const result = await configurePackageManager({ projectDir }); - - // -- Assert -- - expect(result.shouldUseSPM).toBe(false); - expect(cocoapod.addCocoaPods).toHaveBeenCalledWith(projectDir); - expect(Sentry.setTag).toHaveBeenCalledWith('cocoapod-added', false); - expect(Sentry.setTag).toHaveBeenCalledWith( - 'package-manager', - 'CocoaPods', - ); - }); - }); -}); diff --git a/test/apple/cocoapod.test.ts b/test/react-native/cocoapod.test.ts similarity index 99% rename from test/apple/cocoapod.test.ts rename to test/react-native/cocoapod.test.ts index 0164bfc6c..f79705663 100644 --- a/test/apple/cocoapod.test.ts +++ b/test/react-native/cocoapod.test.ts @@ -6,7 +6,7 @@ import { addCocoaPods, podInstall, usesCocoaPod, -} from '../../src/apple/cocoapod'; +} from '../../src/react-native/cocoapod'; import * as bash from '../../src/utils/bash'; // @ts-expect-error - clack is ESM and TS complains about that. It works though import * as clack from '@clack/prompts';