Skip to content

Commit

Permalink
[CRWA]: Switch to using enquirer, add engine compatibility override o…
Browse files Browse the repository at this point in the history
…ption (#6723)

* Add engine check and prompt

* Language tweak

* Add link and additional text to error

* Migrate to Listr2

* WIP

* Complete engine checks

* Typo, concurrent, simpler output

* Fix broken quit process, add quit install message

* Remove ToDo, update code comments

* Make suggested visual changes

* Collapse Listr
  • Loading branch information
ehowey authored and github-actions committed Nov 7, 2022
1 parent e889042 commit 88581e1
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 77 deletions.
3 changes: 2 additions & 1 deletion packages/create-redwood-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@
"chalk": "4.1.2",
"check-node-version": "4.2.1",
"core-js": "3.25.5",
"enquirer": "2.3.6",
"execa": "5.1.1",
"fs-extra": "10.1.0",
"listr2": "5.0.5",
"prompts": "2.4.2",
"terminal-link": "2.1.1",
"yargs": "17.6.0"
},
"devDependencies": {
Expand Down
181 changes: 106 additions & 75 deletions packages/create-redwood-app/src/create-redwood-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import path from 'path'

import chalk from 'chalk'
import checkNodeVersion from 'check-node-version'
import { prompt } from 'enquirer'
import execa from 'execa'
import fs from 'fs-extra'
import { Listr } from 'listr2'
import prompts from 'prompts'
import { Listr, figures } from 'listr2'
import terminalLink from 'terminal-link'
import { hideBin } from 'yargs/helpers'
import yargs from 'yargs/yargs'

Expand Down Expand Up @@ -104,38 +105,6 @@ import { name, version } from '../package'
.version(version)
.parse()

// Variable to hold the user args as an object that can be used for prompt overides
// This gets more useful as there are more prompts to override
let userArgs = {}

// Handle if typescript is selected via --ts
if (typescript === true) {
Object.assign(userArgs, { typescript: true })
}
// Handle if typescript is skipped via --no-ts
if (typescript === false) {
Object.assign(userArgs, { typescript: false })
}

// User prompts
// See https://github.com/terkelg/prompts
const questions = [
{
type: 'confirm',
name: 'typescript',
message: 'Use TypeScript?',
initial: true,
active: 'Yes',
inactive: 'No',
},
]

// Override prompts based on initial args from user
prompts.override(userArgs)

// Get the answers from the user
const answers = await prompts(questions)

// Get the directory for installation from the args
const targetDir = String(args).replace(/,/g, '-')

Expand Down Expand Up @@ -163,44 +132,6 @@ import { name, version } from '../package'

const createProjectTasks = ({ newAppDir, overwrite }) => {
return [
{
title: 'Checking node and yarn compatibility',
skip: () => {
if (yarnInstall === false) {
return 'Warning: skipping check on request'
}
},
task: () => {
return new Promise((resolve, reject) => {
const { engines } = require(path.join(templateDir, 'package.json'))

// this checks all engine requirements, including Node.js and Yarn
checkNodeVersion(engines, (_error, result) => {
if (result.isSatisfied) {
return resolve()
}

const logStatements = Object.keys(result.versions)
.filter((name) => !result.versions[name].isSatisfied)
.map((name) => {
const { version, wanted } = result.versions[name]
return style.error(
`${name} ${wanted} required, but you have ${version}`
)
})
logStatements.push(
style.header(`\nVisit requirements documentation:`)
)
logStatements.push(
style.warning(
`/docs/tutorial/chapter1/prerequisites/#nodejs-and-yarn-versions\n`
)
)
return reject(new Error(logStatements.join('\n')))
})
})
},
},
{
title: `${
appDirExists ? 'Using' : 'Creating'
Expand Down Expand Up @@ -315,8 +246,105 @@ import { name, version } from '../package'

const startTime = Date.now()

// Engine check Listr. Separate Listr to avoid https://github.com/cenk1cenk2/listr2/issues/296
// Boolean flag
let hasPassedEngineCheck = null
// Array of strings
let engineErrorLog = []
// Docs link for engine errors
const engineErrorDocsLink = terminalLink(
'Tutorial - Prerequisites',
'https://redwoodjs.com/docs/tutorial/chapter1/prerequisites'
)

await new Listr(
[
{
title: 'Checking node and yarn compatibility',
skip: () => {
if (yarnInstall === false) {
return 'Warning: skipping check on request'
}
},
task: () => {
return new Promise((resolve) => {
const { engines } = require(path.join(templateDir, 'package.json'))

// this checks all engine requirements, including Node.js and Yarn
checkNodeVersion(engines, (_error, result) => {
if (result.isSatisfied) {
hasPassedEngineCheck = true
return resolve()
}
const logStatements = Object.keys(result.versions)
.filter((name) => !result.versions[name].isSatisfied)
.map((name) => {
const { version, wanted } = result.versions[name]
return `${name} ${wanted} required, but you have ${version}`
})
engineErrorLog = logStatements
hasPassedEngineCheck = false
return resolve()
})
})
},
},
],
{ rendererOptions: { clearOutput: true } }
).run()

// Show a success message if required engines are present
if (hasPassedEngineCheck === true) {
console.log(`${style.success(figures.tick)} Compatibility checks passed`)
}

// Show an error and prompt if failed engines check
if (hasPassedEngineCheck === false) {
console.log(`${style.error(figures.cross)} Compatibility checks failed`)
console.log(
[
` ${style.warning(figures.warning)} ${engineErrorLog.join('\n')}`,
'',
` This may make your project incompatible with some deploy targets.`,
` See: ${engineErrorDocsLink}`,
'',
].join('\n')
)
// Prompt user for how to proceed
const response = await prompt({
type: 'select',
name: 'override-engine-error',
message: 'How would you like to proceed?',
choices: ['Override error and continue install', 'Quit install'],
initial: 0,
onCancel: () => process.exit(1),
})
// Quit the install if user selects this option, otherwise it will proceed
if (response['override-engine-error'] === 'Quit install') {
process.exit(1)
}
}

// Main install Listr
new Listr(
[
{
title: 'Language preference',
skip: () => typescript !== null,
task: async (ctx, task) => {
ctx.language = await task.prompt({
type: 'Select',
choices: ['TypeScript', 'JavaScript'],
message: 'Select your preferred coding language',
initial: 'TypeScript',
})

task.output = ctx.language
},
options: {
persistentOutput: true,
},
},
{
title: 'Creating Redwood app',
task: () => new Listr(createProjectTasks({ newAppDir, overwrite })),
Expand All @@ -329,9 +357,9 @@ import { name, version } from '../package'
title: 'Convert TypeScript files to JavaScript',
// Enabled if user selects no to typescript prompt
// Enabled if user specified --no-ts via command line
enabled: () =>
enabled: (ctx) =>
yarnInstall === true &&
(typescript === false || answers.typescript === false),
(typescript === false || ctx.language === 'JavaScript'),
task: () => {
return execa('yarn rw ts-to-js', {
shell: true,
Expand All @@ -350,7 +378,10 @@ import { name, version } from '../package'
},
},
],
{ rendererOptions: { collapse: false }, exitOnError: true }
{
rendererOptions: { collapse: false },
exitOnError: true,
}
)
.run()
.then(() => {
Expand Down
3 changes: 2 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13785,11 +13785,12 @@ __metadata:
chalk: 4.1.2
check-node-version: 4.2.1
core-js: 3.25.5
enquirer: 2.3.6
execa: 5.1.1
fs-extra: 10.1.0
jest: 29.2.2
listr2: 5.0.5
prompts: 2.4.2
terminal-link: 2.1.1
typescript: 4.7.4
yargs: 17.6.0
bin:
Expand Down

0 comments on commit 88581e1

Please sign in to comment.