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:
parent
742eedee39
commit
cc10a5c8e0
2 changed files with 116 additions and 45 deletions
5
.changeset/large-rivers-enjoy.md
Normal file
5
.changeset/large-rivers-enjoy.md
Normal 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
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue