From b2ddd73dd74a7e91b77c11dd20c1f20e91700d16 Mon Sep 17 00:00:00 2001 From: eunjae-lee Date: Wed, 23 Jun 2021 15:05:38 +0200 Subject: [PATCH 1/4] feat(cli): make app path optional --- src/cli/index.js | 93 +++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/src/cli/index.js b/src/cli/index.js index 38cc0da3a..1b50d133f 100755 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -5,6 +5,7 @@ const program = require('commander'); const inquirer = require('inquirer'); const chalk = require('chalk'); const latestSemver = require('latest-semver'); +const os = require('os'); const createInstantSearchApp = require('../api'); const { @@ -25,14 +26,14 @@ const { } = require('./getConfiguration'); const { version } = require('../../package.json'); -let appPath; +let appPathFromArgument; let options = {}; program .version(version, '-v, --version') .arguments('') .usage(`${chalk.green('')} [options]`) - .option('--name ', 'The name of the application') + .option('--name ', 'The name of the application or widget') .option('--app-id ', 'The application ID') .option('--api-key ', 'The Algolia search API key') .option('--index-name ', 'The main index of your search') @@ -49,52 +50,18 @@ program .option('--config ', 'The configuration file to get the options from') .option('--no-installation', 'Ignore dependency installation') .action((dest, opts) => { - appPath = dest; + appPathFromArgument = dest; options = opts; }) .parse(process.argv); -if (!appPath) { - console.log('Please specify the project directory:'); - console.log(); - console.log( - ` ${chalk.cyan('create-instantsearch-app')} ${chalk.green( - '' - )}` - ); - console.log(); - console.log('For example:'); - console.log( - ` ${chalk.cyan('create-instantsearch-app')} ${chalk.green( - 'my-instantsearch-app' - )}` - ); - console.log(); - console.log( - `Run ${chalk.cyan('create-instantsearch-app --help')} to see all options.` - ); - - process.exit(1); -} - -const optionsFromArguments = getOptionsFromArguments(options.rawArgs); -const appName = optionsFromArguments.name || path.basename(appPath); +const optionsFromArguments = getOptionsFromArguments(options.rawArgs || []); const attributesToDisplay = (optionsFromArguments.attributesToDisplay || '') .split(',') .filter(Boolean) .map(x => x.trim()); -try { - checkAppPath(appPath); - checkAppName(appName); -} catch (err) { - console.error(err.message); - console.log(); - - process.exit(1); -} - -const questions = { +const getQuestions = ({ appName }) => ({ application: [ { type: 'list', @@ -212,9 +179,53 @@ const questions = { }, }, ], -}; +}); async function run() { + let appPath = appPathFromArgument; + if (!appPath) { + const answers = await inquirer.prompt([ + { + type: 'input', + name: 'appPath', + message: 'Project directory:', + }, + ]); + appPath = answers.appPath; + } + if (appPath.startsWith('~/')) { + appPath = path.join(os.homedir(), appPath.slice(2)); + } + let appName = optionsFromArguments.name || path.basename(appPath); + try { + checkAppPath(appPath); + } catch (err) { + console.error(err.message); + console.log(); + + process.exit(1); + } + + appName = ( + await inquirer.prompt([ + { + type: 'input', + name: 'appName', + message: 'The name of the application or widget: ', + default: appName, + }, + ]) + ).appName; + + try { + checkAppName(appName); + } catch (err) { + console.error(err.message); + console.log(); + + process.exit(1); + } + console.log(); console.log(`Creating a new InstantSearch app in ${chalk.green(appPath)}.`); console.log(); @@ -264,7 +275,7 @@ async function run() { templateConfig.category === 'Widget' ? 'widget' : 'application'; const answers = await inquirer.prompt( - questions[implementationType].filter(question => + getQuestions({ appName })[implementationType].filter(question => isQuestionAsked({ question, args: optionsFromArguments }) ), { ...optionsFromArguments, template } From cb20f321b0cec17859942f4c935bb5acdf35f40a Mon Sep 17 00:00:00 2001 From: eunjae-lee Date: Wed, 23 Jun 2021 15:28:57 +0200 Subject: [PATCH 2/4] fix: do not ask project name if given by argument --- e2e/installs.test.js | 7 ++++++- e2e/templates.test.js | 1 + src/cli/index.js | 24 +++++++++++++----------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/e2e/installs.test.js b/e2e/installs.test.js index 47905a942..447349fb8 100644 --- a/e2e/installs.test.js +++ b/e2e/installs.test.js @@ -4,6 +4,7 @@ const { execSync } = require('child_process'); describe('Installation', () => { let temporaryDirectory; let appPath; + const appName = 'test-app'; beforeAll(() => { temporaryDirectory = execSync( @@ -18,7 +19,7 @@ describe('Installation', () => { }); beforeEach(() => { - appPath = `${temporaryDirectory}/test-app`; + appPath = `${temporaryDirectory}/${appName}`; execSync(`mkdir ${appPath}`); }); @@ -30,6 +31,7 @@ describe('Installation', () => { test('get skipped with the `no-installation` flag', () => { execSync( `yarn start ${appPath} \ + --name ${appName} \ --template "InstantSearch.js" \ --no-installation`, { stdio: 'ignore' } @@ -43,6 +45,7 @@ describe('Installation', () => { test('without conflict generates files', () => { execSync( `yarn start ${appPath} \ + --name ${appName} \ --template "InstantSearch.js" \ --no-installation`, { stdio: 'ignore' } @@ -57,6 +60,7 @@ describe('Installation', () => { expect(() => { execSync( `yarn start ${appPath} \ + --name ${appName} \ --template "InstantSearch.js" \ --no-installation`, { stdio: 'ignore' } @@ -76,6 +80,7 @@ describe('Installation', () => { expect(() => { execSync( `yarn start ${appPath}/file \ + --name ${appName} \ --template "InstantSearch.js" \ --no-installation`, { stdio: 'ignore' } diff --git a/e2e/templates.test.js b/e2e/templates.test.js index 5a75535d9..d18cdab12 100644 --- a/e2e/templates.test.js +++ b/e2e/templates.test.js @@ -57,6 +57,7 @@ describe('Templates', () => { execSync( `yarn start ${appPath} \ + --name ${templateConfig.appName} \ --config ${configFilePath} \ --no-installation`, { stdio: 'ignore' } diff --git a/src/cli/index.js b/src/cli/index.js index 1b50d133f..af20f954a 100755 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -196,7 +196,6 @@ async function run() { if (appPath.startsWith('~/')) { appPath = path.join(os.homedir(), appPath.slice(2)); } - let appName = optionsFromArguments.name || path.basename(appPath); try { checkAppPath(appPath); } catch (err) { @@ -206,16 +205,19 @@ async function run() { process.exit(1); } - appName = ( - await inquirer.prompt([ - { - type: 'input', - name: 'appName', - message: 'The name of the application or widget: ', - default: appName, - }, - ]) - ).appName; + let appName = optionsFromArguments.name; + if (!appName) { + appName = ( + await inquirer.prompt([ + { + type: 'input', + name: 'appName', + message: 'The name of the application or widget: ', + default: path.basename(appPath), + }, + ]) + ).appName; + } try { checkAppName(appName); From 5763d5e99dc6839d5119bc79163d568f3ff8f154 Mon Sep 17 00:00:00 2001 From: eunjae-lee Date: Wed, 23 Jun 2021 16:10:41 +0200 Subject: [PATCH 3/4] fix: update build script for CI test --- scripts/build-app.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/build-app.js b/scripts/build-app.js index bb98966c6..00360bbf8 100644 --- a/scripts/build-app.js +++ b/scripts/build-app.js @@ -18,8 +18,11 @@ if (!templateName) { process.exit(1); } +const appName = path.basename(appPath); + execSync( `yarn start ${appPath} \ + --name "${appName}" \ --template "${templateName}"`, { stdio: 'inherit' } ); From 7c42b5269f7bddb74fc9a6cee783d747179bbca9 Mon Sep 17 00:00:00 2001 From: Eunjae Lee Date: Mon, 28 Jun 2021 10:32:33 +0200 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Haroen Viaene --- src/cli/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cli/index.js b/src/cli/index.js index af20f954a..212f854f2 100755 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -188,7 +188,7 @@ async function run() { { type: 'input', name: 'appPath', - message: 'Project directory:', + message: 'Project directory', }, ]); appPath = answers.appPath; @@ -212,7 +212,7 @@ async function run() { { type: 'input', name: 'appName', - message: 'The name of the application or widget: ', + message: 'The name of the application or widget', default: path.basename(appPath), }, ])