Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 32 additions & 22 deletions packages/create-next-app/create-app.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import retry from 'async-retry'
import chalk from 'chalk'
import cpy from 'cpy'
import fs from 'fs'
import makeDir from 'make-dir'
import os from 'os'
import path from 'path'

import {
hasExample,
hasRepo,
getRepoInfo,
downloadAndExtractExample,
downloadAndExtractRepo,
getRepoInfo,
hasExample,
hasRepo,
RepoInfo,
} from './helpers/examples'
import { tryGitInit } from './helpers/git'
Expand All @@ -19,6 +19,8 @@ import { isFolderEmpty } from './helpers/is-folder-empty'
import { getOnline } from './helpers/is-online'
import { shouldUseYarn } from './helpers/should-use-yarn'

export class DownloadError extends Error {}

export async function createApp({
appPath,
useNpm,
Expand Down Expand Up @@ -75,7 +77,7 @@ export async function createApp({
)
process.exit(1)
}
} else {
} else if (example !== '__internal-testing-retry') {
const found = await hasExample(example)

if (!found) {
Expand Down Expand Up @@ -109,24 +111,32 @@ export async function createApp({
process.chdir(root)

if (example) {
if (repoInfo) {
console.log(
`Downloading files from repo ${chalk.cyan(
example
)}. This might take a moment.`
)
console.log()
await downloadAndExtractRepo(root, repoInfo)
} else {
console.log(
`Downloading files for example ${chalk.cyan(
example
)}. This might take a moment.`
)
console.log()
await downloadAndExtractExample(root, example)
try {
if (repoInfo) {
const repoInfo2 = repoInfo
console.log(
`Downloading files from repo ${chalk.cyan(
example
)}. This might take a moment.`
)
console.log()
await retry(() => downloadAndExtractRepo(root, repoInfo2), {
retries: 3,
})
} else {
console.log(
`Downloading files for example ${chalk.cyan(
example
)}. This might take a moment.`
)
console.log()
await retry(() => downloadAndExtractExample(root, example), {
retries: 3,
})
}
} catch (reason) {
throw new DownloadError(reason)
}

// Copy our default `.gitignore` if the application did not provide one
const ignorePath = path.join(root, '.gitignore')
if (!fs.existsSync(ignorePath)) {
Expand Down
4 changes: 4 additions & 0 deletions packages/create-next-app/helpers/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ export async function downloadAndExtractExample(
root: string,
name: string
): Promise<void> {
if (name === '__internal-testing-retry') {
throw new Error('This is an internal example for testing the CLI.')
}

try {
return await pipeline(
got.stream('https://codeload.github.com/zeit/next.js/tar.gz/canary'),
Expand Down
39 changes: 29 additions & 10 deletions packages/create-next-app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import Commander from 'commander'
import path from 'path'
import prompts from 'prompts'
import checkForUpdate from 'update-check'

import { createApp } from './create-app'
import { createApp, DownloadError } from './create-app'
import { listExamples } from './helpers/examples'
import { shouldUseYarn } from './helpers/should-use-yarn'
import { validateNpmName } from './helpers/validate-pkg'
import packageJson from './package.json'
import { shouldUseYarn } from './helpers/should-use-yarn'
import { listExamples } from './helpers/examples'

let projectPath: string = ''

Expand Down Expand Up @@ -166,12 +165,32 @@ async function run(): Promise<void> {
}

const example = typeof program.example === 'string' && program.example.trim()
await createApp({
appPath: resolvedProjectPath,
useNpm: !!program.useNpm,
example: example && example !== 'default' ? example : undefined,
examplePath: program.examplePath,
})
try {
await createApp({
appPath: resolvedProjectPath,
useNpm: !!program.useNpm,
example: example && example !== 'default' ? example : undefined,
examplePath: program.examplePath,
})
} catch (reason) {
if (!(reason instanceof DownloadError)) {
throw reason
}

const res = await prompts({
type: 'confirm',
name: 'builtin',
message:
`Could not download "${example}" because of a connectivity issue between your machine and GitHub.\n` +
`Do you want to use the default template instead?`,
initial: true,
})
if (!res.builtin) {
throw reason
}

await createApp({ appPath: resolvedProjectPath, useNpm: !!program.useNpm })
}
}

const update = checkForUpdate(packageJson).catch(() => null)
Expand Down
2 changes: 2 additions & 0 deletions packages/create-next-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@
"prepublish": "yarn release"
},
"devDependencies": {
"@types/async-retry": "1.4.2",
"@types/node": "^12.6.8",
"@types/prompts": "2.0.1",
"@types/rimraf": "3.0.0",
"@types/tar": "4.0.3",
"@types/validate-npm-package-name": "3.0.0",
"@zeit/ncc": "^0.20.4",
"async-retry": "1.3.1",
"chalk": "2.4.2",
"commander": "2.20.0",
"cpy": "7.3.0",
Expand Down
36 changes: 33 additions & 3 deletions test/integration/create-next-app/index.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/* eslint-env jest */
import path from 'path'
import fs from 'fs-extra'
import execa from 'execa'
import fs from 'fs-extra'
import os from 'os'
import path from 'path'

const cli = require.resolve('create-next-app/dist/index.js')

jest.setTimeout(1000 * 60 * 2)
jest.setTimeout(1000 * 60 * 5)

const run = (cwd, ...args) => execa('node', [cli, ...args], { cwd })
const runStarter = (cwd, ...args) => {
Expand Down Expand Up @@ -229,6 +229,36 @@ describe('create next app', () => {
expect(res.stdout).toMatch(/Downloading files for example hello-world/)
})
})

it('should fall back to default template', async () => {
await usingTempDir(async (cwd) => {
const runExample = (...args) => {
const res = run(cwd, ...args)

function fallbackToTemplate(data) {
if (
/Do you want to use the default template instead/.test(
data.toString()
)
) {
res.stdout.removeListener('data', fallbackToTemplate)
res.stdin.write('\n')
}
}

res.stdout.on('data', fallbackToTemplate)

return res
}

const res = await runExample(
'fail-example',
'--example',
'__internal-testing-retry'
)
expect(res.exitCode).toBe(0)
})
})
}

it('should allow an example named default', async () => {
Expand Down
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2407,6 +2407,13 @@
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"

"@types/async-retry@1.4.2":
version "1.4.2"
resolved "https://registry.yarnpkg.com/@types/async-retry/-/async-retry-1.4.2.tgz#7f910188cd3893b51e32df51765ee8d5646053e3"
integrity sha512-GUDuJURF0YiJZ+CBjNQA0+vbP/VHlJbB0sFqkzsV7EcOPRfurVonXpXKAt3w8qIjM1TEzpz6hc6POocPvHOS3w==
dependencies:
"@types/retry" "*"

"@types/babel__code-frame@7.0.1":
version "7.0.1"
resolved "https://registry.yarnpkg.com/@types/babel__code-frame/-/babel__code-frame-7.0.1.tgz#baf2529c4abbfb5e4008c845efcfe39a187e2f99"
Expand Down Expand Up @@ -2778,6 +2785,11 @@
dependencies:
"@types/node" "*"

"@types/retry@*":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==

"@types/rimraf@3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.0.tgz#b9d03f090ece263671898d57bb7bb007023ac19f"
Expand Down Expand Up @@ -3585,6 +3597,13 @@ async-retry@1.2.3:
dependencies:
retry "0.12.0"

async-retry@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.1.tgz#139f31f8ddce50c0870b0ba558a6079684aaed55"
integrity sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==
dependencies:
retry "0.12.0"

async-sema@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/async-sema/-/async-sema-3.0.0.tgz#9e22d6783f0ab66a1cf330e21a905e39b3b3a975"
Expand Down