diff --git a/.changeset/lazy-ears-tap.md b/.changeset/lazy-ears-tap.md new file mode 100644 index 00000000000..a25355967f5 --- /dev/null +++ b/.changeset/lazy-ears-tap.md @@ -0,0 +1,5 @@ +--- +"create-fuels": patch +--- + +feat: auto-detect package manager in `create fuels` diff --git a/apps/docs/src/guide/creating-a-fuel-dapp/index.md b/apps/docs/src/guide/creating-a-fuel-dapp/index.md index ac9b3eb234f..1f5e6954ee6 100644 --- a/apps/docs/src/guide/creating-a-fuel-dapp/index.md +++ b/apps/docs/src/guide/creating-a-fuel-dapp/index.md @@ -20,15 +20,15 @@ The first step is to run the command: ::: code-group ```sh-vue [npm] -npm create fuels@{{fuels}} -- --npm +npm create fuels@{{fuels}} ``` ```sh-vue [pnpm] -pnpm create fuels@{{fuels}} --pnpm +pnpm create fuels@{{fuels}} ``` ```sh-vue [bun] -bunx --bun create-fuels@{{fuels}} --bun +bun create fuels@{{fuels}} ``` ::: diff --git a/apps/docs/src/guide/creating-a-fuel-dapp/options.md b/apps/docs/src/guide/creating-a-fuel-dapp/options.md index 8719900be02..0e016e8b6ac 100644 --- a/apps/docs/src/guide/creating-a-fuel-dapp/options.md +++ b/apps/docs/src/guide/creating-a-fuel-dapp/options.md @@ -10,15 +10,15 @@ The `npm create fuels` command has several command-line options that you can use ::: code-group ```sh-vue [pnpm] -pnpm create fuels@{{fuels}} --pnpm [project-name] [options] +pnpm create fuels@{{fuels}} [project-name] [options] ``` ```sh-vue [npm] -npm create fuels@{{fuels}} -- --npm [project-name] [options] +npm create fuels@{{fuels}} -- [project-name] [options] ``` ```sh-vue [bun] -bunx --bun create-fuels@{{fuels}} --bun [project-name] [options] +bun create fuels@{{fuels}} [project-name] [options] ``` ::: @@ -27,18 +27,6 @@ bunx --bun create-fuels@{{fuels}} --bun [project-name] [options] Specifies the template to use for your project. The available templates are: `vite` and `nextjs`. The default template is `vite`. -## `--pnpm` - -Notifies the tool to use pnpm as the package manager to install the necessary dependencies. - -## `--npm` - -Notifies the tool to use npm as the package manager to install the necessary dependencies. - -## `--bun` - -Notifies the tool to use bun as the package manager to install the necessary dependencies. - ## `--verbose` Enables verbose logging. Useful when debugging issues with the tool. diff --git a/packages/create-fuels/src/cli.ts b/packages/create-fuels/src/cli.ts index 6b33723e20a..2b9078f83c6 100644 --- a/packages/create-fuels/src/cli.ts +++ b/packages/create-fuels/src/cli.ts @@ -63,7 +63,7 @@ export const runScaffoldCli = async ({ let projectPath = program.args[0] ?? (await promptForProjectPath()); const verboseEnabled = opts.verbose ?? false; - const packageManager = getPackageManager(opts); + const packageManager = getPackageManager(); if (!process.env.VITEST) { await tryInstallFuelUp(verboseEnabled); diff --git a/packages/create-fuels/src/lib/getPackageManager.test.ts b/packages/create-fuels/src/lib/getPackageManager.test.ts index 9fb4b0fb780..5eab1e42f71 100644 --- a/packages/create-fuels/src/lib/getPackageManager.test.ts +++ b/packages/create-fuels/src/lib/getPackageManager.test.ts @@ -3,14 +3,6 @@ import { mockLogger } from '../../test/utils/mockLogger'; import type { PackageManager } from './getPackageManager'; import { availablePackageManagers, getPackageManager, packageMangers } from './getPackageManager'; -const mockAllDeps = () => { - const { warn } = mockLogger(); - - return { - warn, - }; -}; - const installScenarios: [PackageManager, string][] = [ ['pnpm', 'pnpm install'], ['npm', 'npm install'], @@ -24,17 +16,30 @@ const runScenarios: [PackageManager, string][] = [ ['bun', 'bun run fuels:dev'], ]; +const mockAllDeps = () => { + const { warn } = mockLogger(); + + return { + warn, + }; +}; + /** * @group node */ describe('getPackageManager', () => { + beforeEach(() => { + delete process.env.npm_config_user_agent; + }); + it.each(availablePackageManagers)( `should get the correct package manager for %s`, (packageManager: PackageManager) => { const expectedPackageManager = packageMangers[packageManager]; - const opts = { [packageManager]: true }; - const result = getPackageManager(opts); + process.env.npm_config_user_agent = packageManager; + + const result = getPackageManager(); expect(result).toEqual(expectedPackageManager); } @@ -43,7 +48,9 @@ describe('getPackageManager', () => { it.each(installScenarios)( 'should have the correct install commands', (packageManager, expectedInstallCommand) => { - const command = getPackageManager({ [packageManager]: true }); + process.env.npm_config_user_agent = packageManager; + + const command = getPackageManager(); const install = command.install; @@ -54,7 +61,9 @@ describe('getPackageManager', () => { it.each(runScenarios)( 'should have the correct run commands', (packageManager, expectedRunCommand) => { - const command = getPackageManager({ [packageManager]: true }); + process.env.npm_config_user_agent = packageManager; + + const command = getPackageManager(); const run = command.run(runCommand); @@ -62,24 +71,14 @@ describe('getPackageManager', () => { } ); - it('should warn the user if more than one package manager selected', () => { - const { warn } = mockAllDeps(); - const opts = { pnpm: true, npm: true }; - - getPackageManager(opts); - - expect(warn).toBeCalledWith('More than one package manager was selected.'); - }); - - it('should default to npm if no package manager is selected', () => { + it('should default to npm', () => { const packageManager = 'npm'; const expectedPackageManager = packageMangers[packageManager]; const { warn } = mockAllDeps(); - const opts = {}; - const result = getPackageManager(opts); + const result = getPackageManager(); - expect(warn).not.toBeCalled(); expect(result).toEqual(expectedPackageManager); + expect(warn).toHaveBeenCalledWith(`This package manager is not supported. Using npm instead.`); }); }); diff --git a/packages/create-fuels/src/lib/getPackageManager.ts b/packages/create-fuels/src/lib/getPackageManager.ts index f1982f13b84..fcbc60fc84d 100644 --- a/packages/create-fuels/src/lib/getPackageManager.ts +++ b/packages/create-fuels/src/lib/getPackageManager.ts @@ -1,7 +1,5 @@ import { warn } from '../utils/logger'; -import type { ProgramOptions } from './setupProgram'; - export const availablePackageManagers = ['pnpm', 'npm', 'bun'] as const; export type PackageManager = (typeof availablePackageManagers)[number]; @@ -10,39 +8,53 @@ const runnableApplicator = (command: string = '') => `${commandPrefix} ${command}`; -export const packageMangers = { +export const packageMangers: Record< + PackageManager, + { + install: string; + run: (command: string) => string; + name: PackageManager; + } +> = { pnpm: { install: 'pnpm install', run: runnableApplicator('pnpm'), + name: 'pnpm', }, npm: { install: 'npm install', run: runnableApplicator('npm run'), + name: 'npm', }, bun: { install: 'bun install', run: runnableApplicator('bun run'), + name: 'bun', }, } as const; -export const getPackageManager = (opts: ProgramOptions) => { - const packageMangerOpts = { - pnpm: opts.pnpm, - npm: opts.npm, - bun: opts.bun, - }; +export function getUserPkgManager(): PackageManager { + const userAgent = process.env.npm_config_user_agent || ''; - const cliChosenPackageManagerSelected = Object.entries(packageMangerOpts) - .filter(([, v]) => v) - .map(([k]) => k) as PackageManager[]; + if (userAgent.startsWith(packageMangers.pnpm.name)) { + return packageMangers.pnpm.name; + } - let packageManager: PackageManager | undefined = cliChosenPackageManagerSelected[0]; - if (cliChosenPackageManagerSelected.length > 1) { - warn('More than one package manager was selected.'); + if (userAgent.startsWith(packageMangers.bun.name)) { + return packageMangers.bun.name; } - if (!packageManager) { - packageManager = 'npm'; // default to npm if the user has not specified a package manager (eg. --pnpm, --bun) + if (userAgent.startsWith(packageMangers.npm.name)) { + return packageMangers.npm.name; } + + warn(`This package manager is not supported. Using npm instead.`); + + return packageMangers.npm.name; +} + +export const getPackageManager = () => { + const packageManager = getUserPkgManager(); + return packageMangers[packageManager]; }; diff --git a/packages/create-fuels/src/lib/setupProgram.test.ts b/packages/create-fuels/src/lib/setupProgram.test.ts index 642afdce40c..f63913dc072 100644 --- a/packages/create-fuels/src/lib/setupProgram.test.ts +++ b/packages/create-fuels/src/lib/setupProgram.test.ts @@ -6,20 +6,8 @@ import { setupProgram } from './setupProgram'; describe('setupProgram', () => { test('setupProgram takes in args properly', () => { const program = setupProgram(); - program.parse([ - '', - '', - 'test-project-name', - '--template', - 'nextjs', - '--pnpm', - '--npm', - '--bun', - ]); + program.parse(['', '', 'test-project-name', '--template', 'nextjs']); expect(program.args[0]).toBe('test-project-name'); - expect(program.opts().pnpm).toBe(true); - expect(program.opts().npm).toBe(true); - expect(program.opts().bun).toBe(true); expect(program.opts().install).toBe(true); expect(program.opts().template).toBe('nextjs'); }); diff --git a/packages/create-fuels/src/lib/setupProgram.ts b/packages/create-fuels/src/lib/setupProgram.ts index 7576240c803..009ba4ce257 100644 --- a/packages/create-fuels/src/lib/setupProgram.ts +++ b/packages/create-fuels/src/lib/setupProgram.ts @@ -10,9 +10,6 @@ export interface ProgramOptions { contract?: boolean; predicate?: boolean; script?: boolean; - pnpm?: boolean; - npm?: boolean; - bun?: boolean; verbose?: boolean; install?: boolean; template?: Template; @@ -22,9 +19,6 @@ export const setupProgram = () => { const program = new Command(packageJson.name) .version(packageJson.version) .arguments('[projectDirectory]') - .option('--pnpm', 'Use pnpm to install dependencies') - .option('--npm', 'Use npm to install dependencies') - .option('--bun', 'Use bun to install dependencies') .option('--verbose', 'Enable verbose logging') .option('--no-install', 'Do not install dependencies') .option('--template