-
Notifications
You must be signed in to change notification settings - Fork 85
refactor(cli): only install and start project after all questions #77
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
Changes from all commits
bb4cc58
25ff4ad
b89b705
9843bea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,15 +3,17 @@ import chalk from 'chalk'; | |
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
import yargs from 'yargs-parser'; | ||
import { execa } from 'execa'; | ||
import { pkg } from '../../pkg.js'; | ||
import { errorLabel, primaryLabel, printHelp } from '../../utils/messages.js'; | ||
import { errorLabel, primaryLabel, printHelp, warnLabel } from '../../utils/messages.js'; | ||
import { generateProjectName } from '../../utils/project.js'; | ||
import { assertNotCanceled } from '../../utils/tasks.js'; | ||
import { installDependencies, type PackageManager } from './dependencies.js'; | ||
import { initGitRepo } from './git.js'; | ||
import { DEFAULT_VALUES, type CreateOptions } from './options.js'; | ||
import { setupEnterpriseConfig } from './enterprise.js'; | ||
import { copyTemplate } from './template.js'; | ||
import { selectPackageManager, type PackageManager } from './package-manager.js'; | ||
import { installAndStart } from './install-start.js'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Late to the party, but should we call the file |
||
|
||
const TUTORIALKIT_VERSION = pkg.version; | ||
|
||
|
@@ -24,6 +26,7 @@ export async function createTutorial(flags: yargs.Arguments) { | |
Options: [ | ||
['--dir, -d', 'The folder in which the tutorial gets created'], | ||
['--install, --no-install', `Install dependencies (default ${chalk.yellow(DEFAULT_VALUES.install)})`], | ||
['--start, --no-start', `Start project (default ${chalk.yellow(DEFAULT_VALUES.start)})`], | ||
['--git, --no-git', `Initialize a local git repository (default ${chalk.yellow(DEFAULT_VALUES.git)})`], | ||
['--dry-run', `Walk through steps without executing (default ${chalk.yellow(DEFAULT_VALUES.dryRun)})`], | ||
[ | ||
|
@@ -46,6 +49,16 @@ export async function createTutorial(flags: yargs.Arguments) { | |
return 0; | ||
} | ||
|
||
applyAliases(flags); | ||
|
||
try { | ||
verifyFlags(flags); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not possible to do |
||
} catch (error) { | ||
console.error(`${errorLabel()} ${error.message}`); | ||
|
||
process.exit(1); | ||
} | ||
|
||
try { | ||
return _createTutorial(flags); | ||
} catch (error) { | ||
|
@@ -60,8 +73,6 @@ export async function createTutorial(flags: yargs.Arguments) { | |
} | ||
|
||
async function _createTutorial(flags: CreateOptions) { | ||
applyAliases(flags); | ||
|
||
prompts.intro(primaryLabel(pkg.name)); | ||
|
||
let tutorialName = flags._[1] !== undefined ? String(flags._[1]) : undefined; | ||
|
@@ -131,21 +142,55 @@ async function _createTutorial(flags: CreateOptions) { | |
|
||
updatePackageJson(resolvedDest, tutorialName, flags); | ||
|
||
const { selectedPackageManager, dependenciesInstalled } = await installDependencies(resolvedDest, flags); | ||
const selectedPackageManager = await selectPackageManager(flags); | ||
|
||
updateReadme(resolvedDest, selectedPackageManager, flags); | ||
|
||
await setupEnterpriseConfig(resolvedDest, flags); | ||
|
||
await initGitRepo(resolvedDest, flags); | ||
|
||
const { install, start } = await installAndStart(flags); | ||
|
||
prompts.log.success(chalk.green('Tutorial successfully created!')); | ||
|
||
printNextSteps(dest, selectedPackageManager, dependenciesInstalled); | ||
if (install || start) { | ||
let message = 'Please wait while we install the dependencies and start your project...'; | ||
|
||
prompts.outro(`You're all set!`); | ||
if (install && !start) { | ||
// change the message if we're only installing dependencies | ||
message = 'Please wait while we install the dependencies...'; | ||
|
||
console.log('Until next time 👋'); | ||
// print the next steps without the install step in case we only install dependencies | ||
printNextSteps(dest, selectedPackageManager, true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we install the dependencies, but we don't start the project, we still print the next steps without the
|
||
} | ||
|
||
prompts.outro(message); | ||
|
||
await startProject(resolvedDest, selectedPackageManager, flags, start); | ||
} else { | ||
printNextSteps(dest, selectedPackageManager, false); | ||
|
||
prompts.outro(`You're all set!`); | ||
|
||
console.log('Until next time 👋'); | ||
} | ||
} | ||
|
||
async function startProject(cwd: string, packageManager: PackageManager, flags: CreateOptions, startProject: boolean) { | ||
if (flags.dryRun) { | ||
const message = startProject | ||
? 'Skipped dependency installation and project start' | ||
: 'Skipped dependency installation'; | ||
|
||
console.warn(`${warnLabel('DRY RUN')} ${message}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't do anything in case of a dry run.
|
||
} else { | ||
await execa(packageManager, ['install'], { cwd, stdio: 'inherit' }); | ||
|
||
if (startProject) { | ||
await execa(packageManager, ['run', 'dev'], { cwd, stdio: 'inherit' }); | ||
} | ||
} | ||
} | ||
|
||
async function getTutorialDirectory(tutorialName: string, flags: CreateOptions) { | ||
|
@@ -264,3 +309,9 @@ function applyAliases(flags: CreateOptions & Record<string, any>) { | |
flags.enterprise = flags.e; | ||
} | ||
} | ||
|
||
function verifyFlags(flags: CreateOptions) { | ||
if (flags.install === false && flags.start) { | ||
throw new Error('Cannot start project without installing dependencies.'); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import * as prompts from '@clack/prompts'; | ||
import { DEFAULT_VALUES, readFlag, type CreateOptions } from './options.js'; | ||
import { assertNotCanceled } from '../../utils/tasks.js'; | ||
|
||
export async function installAndStart(flags: CreateOptions) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function combines both the |
||
let installDeps = readFlag(flags, 'install'); | ||
let startProject = readFlag(flags, 'start'); | ||
|
||
if (installDeps === false) { | ||
// the user doesn't want to install the dependencies, which means we can't start the project either | ||
return { install: false, start: false }; | ||
} | ||
|
||
if (startProject) { | ||
// the user wants to start the project, so we also have to install the dependencies | ||
return { install: true, start: true }; | ||
} | ||
|
||
if (installDeps) { | ||
if (startProject === false) { | ||
// the user wants to install the dependencies but expicitly not start the project | ||
return { install: true, start: false }; | ||
} else { | ||
// the user explicitly wants to install the dependencies, but we don't know if they want to start the project | ||
const answer = await prompts.confirm({ | ||
message: 'Start project?', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
initialValue: DEFAULT_VALUES.install, | ||
}); | ||
|
||
assertNotCanceled(answer); | ||
|
||
return { install: true, start: answer }; | ||
} | ||
} | ||
|
||
const answer = await prompts.confirm({ | ||
message: 'Install dependencies and start project?', | ||
initialValue: DEFAULT_VALUES.install, | ||
}); | ||
|
||
assertNotCanceled(answer); | ||
|
||
return { install: answer, start: answer }; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a small
readFlag()
utility which returns the value of the flag, or if the flag doesn't have a value, it will return the default ONLY ifflags.default
istrue
. It makes the logic a bit easier because you know that if the value isundefined
, you can prompt the user for the question because it also means--defaults
was not provided.