Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add npm to create-next-app environment package manager parser #41279

Merged
merged 10 commits into from Oct 13, 2022
24 changes: 8 additions & 16 deletions packages/create-next-app/helpers/get-pkg-manager.ts
@@ -1,25 +1,17 @@
import { execSync } from 'child_process'

export type PackageManager = 'npm' | 'pnpm' | 'yarn'

export function getPkgManager(): PackageManager {
try {
const userAgent = process.env.npm_config_user_agent
if (userAgent) {
if (userAgent.startsWith('yarn')) {
return 'yarn'
} else if (userAgent.startsWith('pnpm')) {
return 'pnpm'
}
}
try {
execSync('yarn --version', { stdio: 'ignore' })
const userAgent = process.env.npm_config_user_agent

if (userAgent) {
if (userAgent.startsWith('yarn')) {
return 'yarn'
} catch {
execSync('pnpm --version', { stdio: 'ignore' })
} else if (userAgent.startsWith('pnpm')) {
return 'pnpm'
} else {
return 'npm'
}
} catch {
} else {
return 'npm'
}
}
26 changes: 14 additions & 12 deletions packages/create-next-app/index.ts
Expand Up @@ -62,6 +62,12 @@ const program = new Commander.Command(packageJson.name)
.allowUnknownOption()
.parse(process.argv)

const packageManager = !!program.useNpm
? 'npm'
: !!program.usePnpm
? 'pnpm'
: getPkgManager()

async function run(): Promise<void> {
if (typeof projectPath === 'string') {
projectPath = projectPath.trim()
Expand Down Expand Up @@ -122,12 +128,6 @@ async function run(): Promise<void> {
process.exit(1)
}

const packageManager = !!program.useNpm
? 'npm'
: !!program.usePnpm
? 'pnpm'
: getPkgManager()

const example = typeof program.example === 'string' && program.example.trim()
try {
await createApp({
Expand Down Expand Up @@ -168,16 +168,18 @@ async function notifyUpdate(): Promise<void> {
try {
const res = await update
if (res?.latest) {
const pkgManager = getPkgManager()
const updateMessage =
packageManager === 'yarn'
? 'yarn global add create-next-app'
: packageManager === 'pnpm'
? 'pnpm add -g create-next-app'
: 'npm i -g create-next-app'

console.log(
chalk.yellow.bold('A new version of `create-next-app` is available!') +
'\n' +
'You can update by running: ' +
chalk.cyan(
pkgManager === 'yarn'
? 'yarn global add create-next-app'
: `${pkgManager} install --global create-next-app`
) +
chalk.cyan(updateMessage) +
'\n'
)
}
Expand Down
162 changes: 162 additions & 0 deletions test/integration/create-next-app/index.test.ts
Expand Up @@ -506,10 +506,172 @@ describe('create next app', () => {
'pnpm-lock.yaml',
'node_modules/next',
]
files.forEach((file) =>
expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy()
)
})
})

it('should infer npm as the package manager', async () => {
await usingTempDir(async (cwd) => {
const projectName = 'infer-package-manager-npm'
const res = await run([projectName], {
cwd,
env: { ...process.env, npm_config_user_agent: 'npm' },
})
expect(res.exitCode).toBe(0)

const files = [
'package.json',
'pages/index.js',
'.gitignore',
'.eslintrc.json',
'package-lock.json',
'node_modules/next',
]
files.forEach((file) =>
expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy()
)
})
})

it('should infer npm as the package manager with example', async () => {
await usingTempDir(async (cwd) => {
const projectName = 'infer-package-manager-npm'
const res = await run(
[projectName, '--example', `${exampleRepo}/${examplePath}`],
{ cwd, env: { ...process.env, npm_config_user_agent: 'npm' } }
)
expect(res.exitCode).toBe(0)

const files = [
'package.json',
'pages/index.tsx',
'.gitignore',
'package-lock.json',
'node_modules/next',
]
files.forEach((file) =>
expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy()
)
})
})

it('should infer yarn as the package manager', async () => {
try {
await execa('yarn', ['--version'])
} catch (_) {
// install yarn if not available
await execa('npm', ['i', '-g', 'yarn'])
}

await usingTempDir(async (cwd) => {
const projectName = 'infer-package-manager-yarn'
const res = await run([projectName], {
cwd,
env: { ...process.env, npm_config_user_agent: 'yarn' },
})
expect(res.exitCode).toBe(0)

const files = [
'package.json',
'pages/index.js',
'.gitignore',
'.eslintrc.json',
'yarn.lock',
'node_modules/next',
]
files.forEach((file) =>
expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy()
)
})
})

it('should infer yarn as the package manager with example', async () => {
try {
await execa('yarn', ['--version'])
} catch (_) {
// install yarn if not available
await execa('npm', ['i', '-g', 'yarn'])
}

await usingTempDir(async (cwd) => {
const projectName = 'infer-package-manager-npm'
const res = await run(
[projectName, '--example', `${exampleRepo}/${examplePath}`],
{ cwd, env: { ...process.env, npm_config_user_agent: 'yarn' } }
)
expect(res.exitCode).toBe(0)

const files = [
'package.json',
'pages/index.tsx',
'.gitignore',
'yarn.lock',
'node_modules/next',
]
files.forEach((file) =>
expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy()
)
})
})

it('should infer pnpm as the package manager', async () => {
try {
await execa('pnpm', ['--version'])
} catch (_) {
// install pnpm if not available
await execa('npm', ['i', '-g', 'pnpm'])
}

await usingTempDir(async (cwd) => {
const projectName = 'infer-package-manager'
const res = await run([projectName], {
cwd,
env: { ...process.env, npm_config_user_agent: 'pnpm' },
})
expect(res.exitCode).toBe(0)

const files = [
'package.json',
'pages/index.js',
'.gitignore',
'.eslintrc.json',
'pnpm-lock.yaml',
'node_modules/next',
]
files.forEach((file) =>
expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy()
)
})
})
})

it('should infer pnpm as the package manager with example', async () => {
try {
await execa('pnpm', ['--version'])
} catch (_) {
// install pnpm if not available
await execa('npm', ['i', '-g', 'pnpm'])
}

await usingTempDir(async (cwd) => {
const projectName = 'infer-package-manager-npm'
const res = await run(
[projectName, '--example', `${exampleRepo}/${examplePath}`],
{ cwd, env: { ...process.env, npm_config_user_agent: 'pnpm' } }
)
expect(res.exitCode).toBe(0)

const files = [
'package.json',
'pages/index.tsx',
'.gitignore',
'pnpm-lock.yaml',
'node_modules/next',
]
files.forEach((file) =>
expect(fs.existsSync(path.join(cwd, projectName, file))).toBeTruthy()
)
})
})