Fix misc create-astro issues (#4075)

* Add prompt to automatically fix cache issue

* Throw an error when an invalid template is used

* Use already existing util

* Add changeset
This commit is contained in:
Erika 2022-07-28 12:05:39 -04:00 committed by GitHub
parent 742eedee39
commit cc10a5c8e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 116 additions and 45 deletions

View file

@ -0,0 +1,5 @@
---
'create-astro': patch
---
Added better error handling when cancelling operations, providing bad templates and when there's a degit cache issue

View file

@ -2,6 +2,7 @@
import degit from 'degit'; import degit from 'degit';
import { execa, execaCommand } from 'execa'; import { execa, execaCommand } from 'execa';
import fs from 'fs'; import fs from 'fs';
import os from 'os';
import { bgCyan, black, bold, cyan, dim, gray, green, red, reset, yellow } from 'kleur/colors'; import { bgCyan, black, bold, cyan, dim, gray, green, red, reset, yellow } from 'kleur/colors';
import ora from 'ora'; import ora from 'ora';
import path from 'path'; import path from 'path';
@ -72,18 +73,21 @@ export async function main() {
let rejectProjectDir = ora({ color: 'red', text: notEmptyMsg(cwd) }); let rejectProjectDir = ora({ color: 'red', text: notEmptyMsg(cwd) });
rejectProjectDir.fail(); rejectProjectDir.fail();
} }
const dirResponse = await prompts({ const dirResponse = await prompts(
type: 'text', {
name: 'directory', type: 'text',
message: 'Where would you like to create your new project?', name: 'directory',
initial: './my-astro-site', message: 'Where would you like to create your new project?',
validate(value) { initial: './my-astro-site',
if (!isEmpty(value)) { validate(value) {
return notEmptyMsg(value); if (!isEmpty(value)) {
} return notEmptyMsg(value);
return true; }
return true;
},
}, },
}); { onCancel: () => ora().info(dim('Operation cancelled. See you later, astronaut!')) }
);
cwd = dirResponse.directory; cwd = dirResponse.directory;
} }
@ -91,20 +95,23 @@ export async function main() {
process.exit(1); process.exit(1);
} }
const options = await prompts([ const options = await prompts(
{ [
type: 'select', {
name: 'template', type: 'select',
message: 'Which template would you like to use?', name: 'template',
choices: TEMPLATES, message: 'Which template would you like to use?',
}, choices: TEMPLATES,
]); },
],
{ onCancel: () => ora().info(dim('Operation cancelled. See you later, astronaut!')) }
);
if (!options.template) { if (!options.template) {
process.exit(1); process.exit(1);
} }
const templateSpinner = await loadWithRocketGradient('Copying project files...'); let templateSpinner = await loadWithRocketGradient('Copying project files...');
const hash = args.commit ? `#${args.commit}` : ''; const hash = args.commit ? `#${args.commit}` : '';
@ -132,23 +139,55 @@ export async function main() {
logger.debug(info.message); logger.debug(info.message);
}); });
await emitter.clone(cwd); await emitter.clone(cwd);
// degit does not return an error when an invalid template is provided, as such we need to handle this manually
// It's not very pretty, but to the user eye, we just return a nice message and nothing weird happened
if (isEmpty(cwd)) {
fs.rmdirSync(cwd);
throw new Error(`Error: The provided template (${cyan(options.template)}) does not exist`);
}
} catch (err: any) { } catch (err: any) {
templateSpinner.fail();
// degit is compiled, so the stacktrace is pretty noisy. Only report the stacktrace when using verbose mode. // degit is compiled, so the stacktrace is pretty noisy. Only report the stacktrace when using verbose mode.
logger.debug(err); logger.debug(err);
console.error(red(err.message)); console.error(red(err.message));
// Warning for issue #655 // Warning for issue #655 and other corrupted cache issue
if (err.message === 'zlib: unexpected end of file') { if (
err.message === 'zlib: unexpected end of file' ||
err.message === 'TAR_BAD_ARCHIVE: Unrecognized archive format'
) {
console.log( console.log(
yellow( yellow(
"This seems to be a cache related problem. Remove the folder '~/.degit/github/withastro' to fix this error." 'Local degit cache seems to be corrupted. For more information check out this issue: https://github.com/withastro/astro/issues/655. '
)
);
console.log(
yellow(
'For more information check out this issue: https://github.com/withastro/astro/issues/655'
) )
); );
const cacheIssueResponse = await prompts({
type: 'confirm',
name: 'cache',
message: 'Would you like us to clear the cache and try again?',
initial: true,
});
if (cacheIssueResponse.cache) {
const homeDirectory = os.homedir();
const cacheDir = path.join(homeDirectory, '.degit', 'github', 'withastro');
fs.rmSync(cacheDir, { recursive: true, force: true, maxRetries: 3 });
templateSpinner = await loadWithRocketGradient('Copying project files...');
try {
await emitter.clone(cwd);
} catch (e: any) {
logger.debug(e);
console.error(red(e.message));
}
} else {
console.log(
"Okay, no worries! To fix this manually, remove the folder '~/.degit/github/withastro' and rerun the command."
);
}
} }
// Helpful message when encountering the "could not find commit hash for ..." error // Helpful message when encountering the "could not find commit hash for ..." error
@ -164,7 +203,7 @@ export async function main() {
) )
); );
} }
templateSpinner.fail();
process.exit(1); process.exit(1);
} }
@ -182,12 +221,26 @@ export async function main() {
templateSpinner.text = green('Template copied!'); templateSpinner.text = green('Template copied!');
templateSpinner.succeed(); templateSpinner.succeed();
const installResponse = await prompts({ const installResponse = await prompts(
type: 'confirm', {
name: 'install', type: 'confirm',
message: `Would you like to install ${pkgManager} dependencies? ${reset(dim('(recommended)'))}`, name: 'install',
initial: true, message: `Would you like to install ${pkgManager} dependencies? ${reset(
}); dim('(recommended)')
)}`,
initial: true,
},
{
onCancel: () => {
ora().info(
dim(
'Operation cancelled. Your project folder has already been created, however no dependencies have been installed'
)
);
process.exit(1);
},
}
);
if (args.dryRun) { if (args.dryRun) {
ora().info(dim(`--dry-run enabled, skipping.`)); ora().info(dim(`--dry-run enabled, skipping.`));
@ -210,12 +263,22 @@ export async function main() {
ora().info(dim(`No problem! Remember to install dependencies after setup.`)); ora().info(dim(`No problem! Remember to install dependencies after setup.`));
} }
const gitResponse = await prompts({ const gitResponse = await prompts(
type: 'confirm', {
name: 'git', type: 'confirm',
message: `Would you like to initialize a new git repository? ${reset(dim('(optional)'))}`, name: 'git',
initial: true, message: `Would you like to initialize a new git repository? ${reset(dim('(optional)'))}`,
}); initial: true,
},
{
onCancel: () => {
ora().info(
dim('Operation cancelled. No worries, your project folder has already been created')
);
process.exit(1);
},
}
);
if (args.dryRun) { if (args.dryRun) {
ora().info(dim(`--dry-run enabled, skipping.`)); ora().info(dim(`--dry-run enabled, skipping.`));
@ -234,9 +297,12 @@ export async function main() {
let projectDir = path.relative(process.cwd(), cwd); let projectDir = path.relative(process.cwd(), cwd);
const devCmd = pkgManager === 'npm' ? 'npm run dev' : `${pkgManager} dev`; const devCmd = pkgManager === 'npm' ? 'npm run dev' : `${pkgManager} dev`;
await logAndWait( // If the project dir is the current dir, no need to tell users to cd in the folder
`You can now ${bold(cyan('cd'))} into the ${bold(cyan(projectDir))} project directory.` if (projectDir !== '/') {
); await logAndWait(
`You can now ${bold(cyan('cd'))} into the ${bold(cyan(projectDir))} project directory.`
);
}
await logAndWait( await logAndWait(
`Run ${bold(cyan(devCmd))} to start the Astro dev server. ${bold(cyan('CTRL-C'))} to close.` `Run ${bold(cyan(devCmd))} to start the Astro dev server. ${bold(cyan('CTRL-C'))} to close.`
); );
@ -246,7 +312,7 @@ export async function main() {
)} to your project using ${bold(cyan('astro add'))}` )} to your project using ${bold(cyan('astro add'))}`
); );
await logAndWait(''); await logAndWait('');
await logAndWait(`Stuck? Come join us at ${bold(cyan('https://astro.build/chat'))}`, 1000); await logAndWait(`Stuck? Come join us at ${bold(cyan('https://astro.build/chat'))}`, 750);
await logAndWait(dim('Good luck out there, astronaut.')); await logAndWait(dim('Good luck out there, astronaut.'));
await logAndWait('', 300); await logAndWait('', 300);
} }