summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ben Holmes <hey@bholmes.dev> 2022-04-21 16:36:48 -0400
committerGravatar GitHub <noreply@github.com> 2022-04-21 16:36:48 -0400
commit7c49194ca2161a09cc304ba8327533f8176ae0da (patch)
tree7664bf80f0963b73b93e44036bae073b35154106
parent908fffb5ec2de4efb55d03a69381e3aa376e4c42 (diff)
downloadastro-7c49194ca2161a09cc304ba8327533f8176ae0da.tar.gz
astro-7c49194ca2161a09cc304ba8327533f8176ae0da.tar.zst
astro-7c49194ca2161a09cc304ba8327533f8176ae0da.zip
Feat: [create astro] add directory prompt (#3168)
* wip: add prompt for directory with validation * feat: wire up dir response to cwd * feat: improve error handling on non-empty dirs * fix: update test helpers to execaSync * chore: add .skipped to old tests for clarity * deps: add mocha and chai to create-astro * feat: add directory step test with fixture * feat: update turbo to run create-astro tests again 🥳 * chore: changeset
-rw-r--r--.changeset/soft-berries-admire.md5
-rw-r--r--package.json2
-rw-r--r--packages/create-astro/package.json6
-rw-r--r--packages/create-astro/src/index.ts53
-rw-r--r--packages/create-astro/test/.gitignore1
-rw-r--r--packages/create-astro/test/create-astro.test.js.skipped (renamed from packages/create-astro/test/create-astro.test.js)0
-rw-r--r--packages/create-astro/test/directory-step.test.js102
-rw-r--r--packages/create-astro/test/external.test.js.skipped (renamed from packages/create-astro/test/external.test.js)0
-rw-r--r--packages/create-astro/test/fixtures/select-directory/nonempty-dir/astro-origin-story.php0
-rw-r--r--packages/create-astro/test/helpers.js4
-rw-r--r--pnpm-lock.yaml8
11 files changed, 161 insertions, 20 deletions
diff --git a/.changeset/soft-berries-admire.md b/.changeset/soft-berries-admire.md
new file mode 100644
index 000000000..a0d2957ad
--- /dev/null
+++ b/.changeset/soft-berries-admire.md
@@ -0,0 +1,5 @@
+---
+'create-astro': minor
+---
+
+Add prompt to choose a directory, now defaulting to a separate "./my-astro-site" instead of "." (current directory)
diff --git a/package.json b/package.json
index badc19ad0..5a9b6e267 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
"build:ci": "turbo run build:ci --no-deps --scope=astro --scope=create-astro --scope=\"@astrojs/*\"",
"build:examples": "turbo run build --scope=\"@example/*\"",
"dev": "turbo run dev --no-deps --no-cache --parallel --scope=astro --scope=create-astro --scope=\"@astrojs/*\"",
- "test": "turbo run test --filter=!create-astro --concurrency=1",
+ "test": "turbo run test --concurrency=1",
"test:match": "cd packages/astro && pnpm run test:match",
"test:templates": "turbo run test --filter=create-astro --concurrency=1",
"test:smoke": "node scripts/smoke/index.js",
diff --git a/packages/create-astro/package.json b/packages/create-astro/package.json
index 3714ddbdd..b28997d3a 100644
--- a/packages/create-astro/package.json
+++ b/packages/create-astro/package.json
@@ -21,7 +21,7 @@
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"dev": "astro-scripts dev \"src/**/*.ts\"",
- "test": "rm -rf test/fixtures && mkdir test/fixtures && node --unhandled-rejections=strict test/create-astro.test.js"
+ "test": "mocha --exit --timeout 20000"
},
"files": [
"dist",
@@ -38,8 +38,12 @@
"yargs-parser": "^21.0.1"
},
"devDependencies": {
+ "@types/chai": "^4.3.1",
+ "@types/mocha": "^9.1.0",
"@types/yargs-parser": "^21.0.0",
"astro-scripts": "workspace:*",
+ "chai": "^4.3.6",
+ "mocha": "^9.2.2",
"uvu": "^0.5.3"
},
"engines": {
diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts
index ec54d250c..2286c13f5 100644
--- a/packages/create-astro/src/index.ts
+++ b/packages/create-astro/src/index.ts
@@ -28,6 +28,10 @@ export function mkdirp(dir: string) {
}
}
+function isEmpty(dirPath: string) {
+ return !fs.existsSync(dirPath) || fs.readdirSync(dirPath).length === 0;
+}
+
const { version } = JSON.parse(
fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')
);
@@ -47,22 +51,41 @@ export async function main() {
spinner.succeed();
- const cwd = (args['_'][2] as string) || '.';
- if (fs.existsSync(cwd)) {
- if (fs.readdirSync(cwd).length > 0) {
- const response = await prompts({
- type: 'confirm',
- name: 'forceOverwrite',
- message: 'Directory not empty. Continue [force overwrite]?',
- initial: false,
- });
- if (!response.forceOverwrite) {
- process.exit(1);
- }
- mkdirp(cwd);
+ let cwd = args['_'][2] as string;
+
+ if (cwd && isEmpty(cwd)) {
+ let acknowledgeProjectDir = ora({
+ color: 'green',
+ text: `Using ${bold(cwd)} as project directory.`,
+ });
+ acknowledgeProjectDir.succeed();
+ }
+
+ if (!cwd || !isEmpty(cwd)) {
+ const notEmptyMsg = (dirPath: string) =>
+ `"${bold(dirPath)}" is not empty. Please clear contents or choose a different path.`;
+
+ if (!isEmpty(cwd)) {
+ let rejectProjectDir = ora({ color: 'red', text: notEmptyMsg(cwd) });
+ rejectProjectDir.fail();
}
- } else {
- mkdirp(cwd);
+ const dirResponse = await prompts({
+ type: 'text',
+ name: 'directory',
+ message: 'Where would you like to create your app?',
+ initial: './my-astro-site',
+ validate(value) {
+ if (!isEmpty(value)) {
+ return notEmptyMsg(value);
+ }
+ return true;
+ },
+ });
+ cwd = dirResponse.directory;
+ }
+
+ if (!cwd) {
+ process.exit(1);
}
const options = await prompts([
diff --git a/packages/create-astro/test/.gitignore b/packages/create-astro/test/.gitignore
deleted file mode 100644
index 116caa127..000000000
--- a/packages/create-astro/test/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-fixtures
diff --git a/packages/create-astro/test/create-astro.test.js b/packages/create-astro/test/create-astro.test.js.skipped
index 86a64e1f5..86a64e1f5 100644
--- a/packages/create-astro/test/create-astro.test.js
+++ b/packages/create-astro/test/create-astro.test.js.skipped
diff --git a/packages/create-astro/test/directory-step.test.js b/packages/create-astro/test/directory-step.test.js
new file mode 100644
index 000000000..843b8cf92
--- /dev/null
+++ b/packages/create-astro/test/directory-step.test.js
@@ -0,0 +1,102 @@
+import { execa} from 'execa';
+import { fileURLToPath } from 'url';
+import { dirname, resolve } from 'path';
+import {promises, existsSync} from 'fs'
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = dirname(__filename);
+
+const createAstroError = new Error('Timed out waiting for create-astro to respond with expected output.')
+const timeout = 5000;
+
+const instructions = {
+ directory: 'Where would you like to create your app?',
+ template: 'Which app template would you like to use?',
+};
+const inputs = {
+ nonEmptyDir: './fixtures/select-directory/nonempty-dir',
+ emptyDir: './fixtures/select-directory/empty-dir',
+ nonexistentDir: './fixtures/select-directory/banana-dir',
+};
+
+function promiseWithTimeout(testFn) {
+ return new Promise((resolve, reject) => {
+ const timeoutEvent = setTimeout(() => {
+ reject(createAstroError);
+ }, timeout);
+ function resolver() {
+ clearTimeout(timeoutEvent);
+ resolve();
+ }
+ testFn(resolver);
+ })
+}
+
+function setup(args = []) {
+ const {stdout, stdin} = execa('../create-astro.mjs', args, { cwd: __dirname })
+ return {
+ stdin,
+ stdout,
+ }
+}
+
+describe('[create-astro] select directory', function() {
+ this.timeout(timeout);
+ it ('should prompt for directory when none is provided', function () {
+ return promiseWithTimeout(resolve => {
+ const {stdout} = setup()
+ stdout.on('data', chunk => {
+ if (chunk.includes(instructions.directory)) {
+ resolve()
+ }
+ })
+ })
+ })
+ it ('should NOT proceed on a non-empty directory', function () {
+ return promiseWithTimeout(resolve => {
+ const {stdout} = setup([inputs.nonEmptyDir])
+ stdout.on('data', chunk => {
+ if (chunk.includes(instructions.directory)) {
+ resolve()
+ }
+ })
+ })
+ })
+ it ('should proceed on an empty directory', async function () {
+ const resolvedEmptyDirPath = resolve(__dirname, inputs.emptyDir)
+ if (!existsSync(resolvedEmptyDirPath)) {
+ await promises.mkdir(resolvedEmptyDirPath)
+ }
+ return promiseWithTimeout(resolve => {
+ const {stdout} = setup([inputs.emptyDir])
+ stdout.on('data', chunk => {
+ if (chunk.includes(instructions.template)) {
+ resolve()
+ }
+ })
+ })
+ })
+ it ('should proceed when directory does not exist', function () {
+ return promiseWithTimeout(resolve => {
+ const {stdout} = setup([inputs.nonexistentDir])
+ stdout.on('data', chunk => {
+ if (chunk.includes(instructions.template)) {
+ resolve()
+ }
+ })
+ })
+ })
+ it ('should error on bad directory selection in prompt', function () {
+ return promiseWithTimeout(resolve => {
+ const {stdout, stdin} = setup()
+ stdout.on('data', chunk => {
+ if (chunk.includes('Please clear contents or choose a different path.')) {
+ resolve()
+ }
+ if (chunk.includes(instructions.directory)) {
+ stdin.write(`${inputs.nonEmptyDir}\x0D`)
+ }
+ })
+ })
+ })
+})
diff --git a/packages/create-astro/test/external.test.js b/packages/create-astro/test/external.test.js.skipped
index 277e498e0..277e498e0 100644
--- a/packages/create-astro/test/external.test.js
+++ b/packages/create-astro/test/external.test.js.skipped
diff --git a/packages/create-astro/test/fixtures/select-directory/nonempty-dir/astro-origin-story.php b/packages/create-astro/test/fixtures/select-directory/nonempty-dir/astro-origin-story.php
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/packages/create-astro/test/fixtures/select-directory/nonempty-dir/astro-origin-story.php
diff --git a/packages/create-astro/test/helpers.js b/packages/create-astro/test/helpers.js
index 6e4445045..4f0b6ec3e 100644
--- a/packages/create-astro/test/helpers.js
+++ b/packages/create-astro/test/helpers.js
@@ -1,8 +1,8 @@
-import { execa } from 'execa';
+import { execaSync } from 'execa';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
-const GITHUB_SHA = process.env.GITHUB_SHA || execa.sync('git', ['rev-parse', 'HEAD']).stdout; // process.env.GITHUB_SHA will be set in CI; if testing locally execa() will gather this
+const GITHUB_SHA = process.env.GITHUB_SHA || execaSync('git', ['rev-parse', 'HEAD']).stdout; // process.env.GITHUB_SHA will be set in CI; if testing locally execa() will gather this
const FIXTURES_DIR = path.join(fileURLToPath(path.dirname(import.meta.url)), 'fixtures');
const FIXTURES_URL = pathToFileURL(FIXTURES_DIR + '/');
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b6c860568..ca2cdee4f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1202,12 +1202,16 @@ importers:
packages/create-astro:
specifiers:
+ '@types/chai': ^4.3.1
'@types/degit': ^2.8.3
+ '@types/mocha': ^9.1.0
'@types/prompts': ^2.0.14
'@types/yargs-parser': ^21.0.0
astro-scripts: workspace:*
+ chai: ^4.3.6
degit: ^2.8.4
kleur: ^4.1.4
+ mocha: ^9.2.2
node-fetch: ^3.2.3
ora: ^6.1.0
prompts: ^2.4.2
@@ -1223,8 +1227,12 @@ importers:
prompts: 2.4.2
yargs-parser: 21.0.1
devDependencies:
+ '@types/chai': 4.3.1
+ '@types/mocha': 9.1.0
'@types/yargs-parser': 21.0.0
astro-scripts: link:../../scripts
+ chai: 4.3.6
+ mocha: 9.2.2
uvu: 0.5.3
packages/integrations/deno: