Skip to content

Commit

Permalink
feat: auto-detect package manager in create fuels (#3503)
Browse files Browse the repository at this point in the history
* feat: auto-detect package manager in `create fuels`

* fix tests and docs

* add changeset

* fix tests

* disable pr release
  • Loading branch information
Dhaiwat10 authored Jan 2, 2025
1 parent d5a696c commit e8a8c71
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 82 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-ears-tap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-fuels": patch
---

feat: auto-detect package manager in `create fuels`
6 changes: 3 additions & 3 deletions apps/docs/src/guide/creating-a-fuel-dapp/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
```

:::
Expand Down
18 changes: 3 additions & 15 deletions apps/docs/src/guide/creating-a-fuel-dapp/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
```

:::
Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion packages/create-fuels/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
49 changes: 24 additions & 25 deletions packages/create-fuels/src/lib/getPackageManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand All @@ -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);
}
Expand All @@ -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;

Expand All @@ -54,32 +61,24 @@ 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);

expect(run).toEqual(expectedRunCommand);
}
);

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.`);
});
});
46 changes: 29 additions & 17 deletions packages/create-fuels/src/lib/getPackageManager.ts
Original file line number Diff line number Diff line change
@@ -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];

Expand All @@ -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];
};
14 changes: 1 addition & 13 deletions packages/create-fuels/src/lib/setupProgram.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});
Expand Down
6 changes: 0 additions & 6 deletions packages/create-fuels/src/lib/setupProgram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 <template>', 'Specify a template to use', defaultTemplate)
Expand Down
5 changes: 4 additions & 1 deletion packages/create-fuels/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,10 @@ describe('CLI', { timeout: 15_000 }, () => {
});

test('should rewrite for the appropriate package manager', async () => {
process.env.npm_config_user_agent = 'bun';

const args = generateArgv({
projectName: paths.projectRoot,
packageManager: 'bun',
template: paths.templateName,
});

Expand All @@ -114,6 +115,8 @@ describe('CLI', { timeout: 15_000 }, () => {
const readme = readFileSync(readmePath, 'utf-8');
expect(readme).toContain('bun run fuels:dev');
expect(readme).toContain('bun run dev');

delete process.env.npm_config_user_agent;
});

test('create-fuels reports an error if the project directory already exists', async () => {
Expand Down
1 change: 0 additions & 1 deletion packages/create-fuels/test/utils/generateArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export const generateArgs = ({
args.push(`--template`);
args.push(template);
}
args.push(`--${packageManager}`);
args.push(`--no-install`);
return args;
};
Expand Down

0 comments on commit e8a8c71

Please sign in to comment.