diff --git a/CHANGELOG.md b/CHANGELOG.md index e5343048a0..9a408b211d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ This is the log of notable changes to EAS CLI and related packages. ### 🎉 New features +- Allow selecting package manager when doing onboarding. ([#2402](https://github.com/expo/eas-cli/pull/2402) by [@szdziedzic](https://github.com/szdziedzic)) + ### 🐛 Bug fixes - Use the correct app config for no GitHub flow in `init:onboarding`. ([#2397](https://github.com/expo/eas-cli/pull/2397) by [@szdziedzic](https://github.com/szdziedzic)) diff --git a/packages/eas-cli/src/commands/project/onboarding.ts b/packages/eas-cli/src/commands/project/onboarding.ts index 6a89c207cc..e0098111f8 100644 --- a/packages/eas-cli/src/commands/project/onboarding.ts +++ b/packages/eas-cli/src/commands/project/onboarding.ts @@ -29,6 +29,11 @@ import { runGitPushAsync, } from '../../onboarding/git'; import { installDependenciesAsync } from '../../onboarding/installDependencies'; +import { + PackageManager, + getAvailablePackageManagersAsync, + getLockfileForPackageManager, +} from '../../onboarding/packageManagers'; import { runCommandAsync } from '../../onboarding/runCommand'; import { RequestedPlatform } from '../../platform'; import { ExpoConfigOptions, getPrivateExpoConfig } from '../../project/expoConfig'; @@ -178,9 +183,12 @@ export default class Onboarding extends EasCommand { }); } + const packageManager = await selectPackageManagerAsync(); await installDependenciesAsync({ projectDir: finalTargetProjectDirectory, + packageManager, }); + const exp = await getPrivateExpoConfigWithProjectIdAsync({ projectDir: finalTargetProjectDirectory, graphqlClient, @@ -212,7 +220,7 @@ export default class Onboarding extends EasCommand { }); Log.log(); } - await vcsClient.trackFileAsync('package-lock.json'); + await vcsClient.trackFileAsync(getLockfileForPackageManager(packageManager)); const shouldSetupCredentials = ((platform === Platform.IOS && @@ -492,3 +500,25 @@ async function configureProjectFromBareDefaultExpoTemplateAsync({ function stripInvalidCharactersForBundleIdentifier(string: string): string { return string.replaceAll(/[^A-Za-z0-9]/g, ''); } + +async function selectPackageManagerAsync(): Promise { + const avilablePackageManagers = await getAvailablePackageManagersAsync(); + + let packageManager: PackageManager; + if (avilablePackageManagers.length === 1) { + packageManager = avilablePackageManagers[0]; + } else { + const { selectedPackageManager } = await promptAsync({ + type: 'select', + name: 'selectedPackageManager', + message: '📦 Which package manager would you like to use?', + choices: avilablePackageManagers.map(pm => ({ + title: pm, + value: pm, + })), + }); + Log.log(); + packageManager = selectedPackageManager; + } + return packageManager; +} diff --git a/packages/eas-cli/src/onboarding/installDependencies.ts b/packages/eas-cli/src/onboarding/installDependencies.ts index 475d90e1fe..226bdefdb8 100644 --- a/packages/eas-cli/src/onboarding/installDependencies.ts +++ b/packages/eas-cli/src/onboarding/installDependencies.ts @@ -1,13 +1,16 @@ +import { PackageManager } from './packageManagers'; import { runCommandAsync } from './runCommand'; export async function installDependenciesAsync({ projectDir, + packageManager, }: { projectDir: string; + packageManager: PackageManager; }): Promise { // TODO: add support for other package managers await runCommandAsync({ - command: 'npm', + command: packageManager, args: ['install'], cwd: projectDir, shouldShowStderrLine: line => { diff --git a/packages/eas-cli/src/onboarding/packageManagers.ts b/packages/eas-cli/src/onboarding/packageManagers.ts new file mode 100644 index 0000000000..aecb2afe6d --- /dev/null +++ b/packages/eas-cli/src/onboarding/packageManagers.ts @@ -0,0 +1,58 @@ +import spawnAsync from '@expo/spawn-async'; + +export type PackageManager = 'bun' | 'yarn' | 'pnpm' | 'npm'; + +export function getLockfileForPackageManager(packageManager: PackageManager): string { + switch (packageManager) { + case 'bun': + return 'bun.lockb'; + case 'yarn': + return 'yarn.lock'; + case 'pnpm': + return 'pnpm-lock.yaml'; + case 'npm': + return 'package-lock.json'; + } +} + +export async function getAvailablePackageManagersAsync(): Promise { + const availablePackageManagers: PackageManager[] = []; + if (await isBunAvailableAsync()) { + availablePackageManagers.push('bun'); + } + if (await isYarnAvailableAsync()) { + availablePackageManagers.push('yarn'); + } + if (await isPnpmAvailableAsync()) { + availablePackageManagers.push('pnpm'); + } + availablePackageManagers.push('npm'); + return availablePackageManagers; +} + +async function isBunAvailableAsync(): Promise { + try { + await spawnAsync('bun', ['--version']); + return true; + } catch { + return false; + } +} + +async function isYarnAvailableAsync(): Promise { + try { + await spawnAsync('yarn', ['--version']); + return true; + } catch { + return false; + } +} + +async function isPnpmAvailableAsync(): Promise { + try { + await spawnAsync('pnpm', ['--version']); + return true; + } catch { + return false; + } +}