Add support for running create-astro
in cloned empty git repository (#4805)
This commit is contained in:
parent
f2b515d0b4
commit
c84d85ba4d
5 changed files with 64 additions and 6 deletions
5
.changeset/six-weeks-grab.md
Normal file
5
.changeset/six-weeks-grab.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'create-astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Add support for running in cloned empty git repository
|
|
@ -43,6 +43,46 @@ function isEmpty(dirPath: string) {
|
||||||
return !fs.existsSync(dirPath) || fs.readdirSync(dirPath).length === 0;
|
return !fs.existsSync(dirPath) || fs.readdirSync(dirPath).length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some existing files and directories can be safely ignored when checking if a directory is a valid project directory.
|
||||||
|
// https://github.com/facebook/create-react-app/blob/d960b9e38c062584ff6cfb1a70e1512509a966e7/packages/create-react-app/createReactApp.js#L907-L934
|
||||||
|
const VALID_PROJECT_DIRECTORY_SAFE_LIST = [
|
||||||
|
'.DS_Store',
|
||||||
|
'.git',
|
||||||
|
'.gitattributes',
|
||||||
|
'.gitignore',
|
||||||
|
'.gitlab-ci.yml',
|
||||||
|
'.hg',
|
||||||
|
'.hgcheck',
|
||||||
|
'.hgignore',
|
||||||
|
'.idea',
|
||||||
|
'.npmignore',
|
||||||
|
'.travis.yml',
|
||||||
|
'.yarn',
|
||||||
|
'.yarnrc.yml',
|
||||||
|
'docs',
|
||||||
|
'LICENSE',
|
||||||
|
'mkdocs.yml',
|
||||||
|
'Thumbs.db',
|
||||||
|
/\.iml$/,
|
||||||
|
/^npm-debug\.log/,
|
||||||
|
/^yarn-debug\.log/,
|
||||||
|
/^yarn-error\.log/,
|
||||||
|
];
|
||||||
|
|
||||||
|
function isValidProjectDirectory(dirPath: string) {
|
||||||
|
if (!fs.existsSync(dirPath)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const conflicts = fs.readdirSync(dirPath).filter((content) => {
|
||||||
|
return !VALID_PROJECT_DIRECTORY_SAFE_LIST.some((safeContent) => {
|
||||||
|
return typeof safeContent === 'string' ? content === safeContent : safeContent.test(content);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return conflicts.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
const { version } = JSON.parse(
|
const { version } = JSON.parse(
|
||||||
fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
|
fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
|
||||||
);
|
);
|
||||||
|
@ -59,7 +99,7 @@ export async function main() {
|
||||||
|
|
||||||
let cwd = args['_'][2] as string;
|
let cwd = args['_'][2] as string;
|
||||||
|
|
||||||
if (cwd && isEmpty(cwd)) {
|
if (cwd && isValidProjectDirectory(cwd)) {
|
||||||
let acknowledgeProjectDir = ora({
|
let acknowledgeProjectDir = ora({
|
||||||
color: 'green',
|
color: 'green',
|
||||||
text: `Using ${bold(cwd)} as project directory.`,
|
text: `Using ${bold(cwd)} as project directory.`,
|
||||||
|
@ -67,10 +107,10 @@ export async function main() {
|
||||||
acknowledgeProjectDir.succeed();
|
acknowledgeProjectDir.succeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cwd || !isEmpty(cwd)) {
|
if (!cwd || !isValidProjectDirectory(cwd)) {
|
||||||
const notEmptyMsg = (dirPath: string) => `"${bold(dirPath)}" is not empty!`;
|
const notEmptyMsg = (dirPath: string) => `"${bold(dirPath)}" is not empty!`;
|
||||||
|
|
||||||
if (!isEmpty(cwd)) {
|
if (!isValidProjectDirectory(cwd)) {
|
||||||
let rejectProjectDir = ora({ color: 'red', text: notEmptyMsg(cwd) });
|
let rejectProjectDir = ora({ color: 'red', text: notEmptyMsg(cwd) });
|
||||||
rejectProjectDir.fail();
|
rejectProjectDir.fail();
|
||||||
}
|
}
|
||||||
|
@ -81,7 +121,7 @@ export async function main() {
|
||||||
message: 'Where would you like to create your new project?',
|
message: 'Where would you like to create your new project?',
|
||||||
initial: './my-astro-site',
|
initial: './my-astro-site',
|
||||||
validate(value) {
|
validate(value) {
|
||||||
if (!isEmpty(value)) {
|
if (!isValidProjectDirectory(value)) {
|
||||||
return notEmptyMsg(value);
|
return notEmptyMsg(value);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -143,8 +183,10 @@ export async function main() {
|
||||||
|
|
||||||
// degit does not return an error when an invalid template is provided, as such we need to handle this manually
|
// 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
|
// It's not very pretty, but to the user eye, we just return a nice message and nothing weird happened
|
||||||
if (isEmpty(cwd)) {
|
if (isValidProjectDirectory(cwd)) {
|
||||||
fs.rmdirSync(cwd);
|
if (isEmpty(cwd)) {
|
||||||
|
fs.rmdirSync(cwd);
|
||||||
|
}
|
||||||
throw new Error(`Error: The provided template (${cyan(options.template)}) does not exist`);
|
throw new Error(`Error: The provided template (${cyan(options.template)}) does not exist`);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { PROMPT_MESSAGES, testDir, setup, promiseWithTimeout, timeout } from './
|
||||||
|
|
||||||
const inputs = {
|
const inputs = {
|
||||||
nonEmptyDir: './fixtures/select-directory/nonempty-dir',
|
nonEmptyDir: './fixtures/select-directory/nonempty-dir',
|
||||||
|
nonEmptySafeDir: './fixtures/select-directory/nonempty-safe-dir',
|
||||||
emptyDir: './fixtures/select-directory/empty-dir',
|
emptyDir: './fixtures/select-directory/empty-dir',
|
||||||
nonexistentDir: './fixtures/select-directory/banana-dir',
|
nonexistentDir: './fixtures/select-directory/banana-dir',
|
||||||
};
|
};
|
||||||
|
@ -30,6 +31,16 @@ describe('[create-astro] select directory', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('should proceed on a non-empty safe directory', function () {
|
||||||
|
return promiseWithTimeout((resolve) => {
|
||||||
|
const { stdout } = setup([inputs.nonEmptySafeDir]);
|
||||||
|
stdout.on('data', (chunk) => {
|
||||||
|
if (chunk.includes(PROMPT_MESSAGES.template)) {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
it('should proceed on an empty directory', async function () {
|
it('should proceed on an empty directory', async function () {
|
||||||
const resolvedEmptyDirPath = path.resolve(testDir, inputs.emptyDir);
|
const resolvedEmptyDirPath = path.resolve(testDir, inputs.emptyDir);
|
||||||
if (!existsSync(resolvedEmptyDirPath)) {
|
if (!existsSync(resolvedEmptyDirPath)) {
|
||||||
|
|
0
packages/create-astro/test/fixtures/select-directory/nonempty-safe-dir/.gitignore
vendored
Normal file
0
packages/create-astro/test/fixtures/select-directory/nonempty-safe-dir/.gitignore
vendored
Normal file
0
packages/create-astro/test/fixtures/select-directory/nonempty-safe-dir/module.iml
vendored
Normal file
0
packages/create-astro/test/fixtures/select-directory/nonempty-safe-dir/module.iml
vendored
Normal file
Loading…
Add table
Reference in a new issue