From efae20e2245465bbf6f9a90a7f2e537cdda659a0 Mon Sep 17 00:00:00 2001 From: Ward Peeters Date: Thu, 11 Apr 2019 22:19:27 +0200 Subject: [PATCH] fix: add tty helper to not ask for prompt in non tty/ci env (#13290) ## Description added a utility to check if isTTY is enabled so we don't ask for prompts. In future PRs we might want to move it to gatsby or gatsby-utils package so we can use it in different packages like telemetry. --- packages/gatsby-cli/package.json | 1 + packages/gatsby-cli/src/init-starter.js | 54 ++++++++--------- .../gatsby-cli/src/util/__tests__/is-tty.js | 47 +++++++++++++++ packages/gatsby-cli/src/util/configstore.js | 45 ++++++++++++++ packages/gatsby-cli/src/util/is-tty.js | 6 ++ yarn.lock | 58 ------------------- 6 files changed, 124 insertions(+), 87 deletions(-) create mode 100644 packages/gatsby-cli/src/util/__tests__/is-tty.js create mode 100644 packages/gatsby-cli/src/util/configstore.js create mode 100644 packages/gatsby-cli/src/util/is-tty.js diff --git a/packages/gatsby-cli/package.json b/packages/gatsby-cli/package.json index 39638616295ff..6d3b074c01b5e 100644 --- a/packages/gatsby-cli/package.json +++ b/packages/gatsby-cli/package.json @@ -13,6 +13,7 @@ "@babel/code-frame": "^7.0.0", "@babel/runtime": "^7.0.0", "bluebird": "^3.5.0", + "ci-info": "^2.0.0", "common-tags": "^1.4.0", "configstore": "^4.0.0", "convert-hrtime": "^2.0.0", diff --git a/packages/gatsby-cli/src/init-starter.js b/packages/gatsby-cli/src/init-starter.js index 4ddd545f3f1bb..7ae81ba8dc65d 100644 --- a/packages/gatsby-cli/src/init-starter.js +++ b/packages/gatsby-cli/src/init-starter.js @@ -1,6 +1,5 @@ /* @flow */ const { execSync } = require(`child_process`) -const Configstore = require(`configstore`) const execa = require(`execa`) const hostedGitInfo = require(`hosted-git-info`) const fs = require(`fs-extra`) @@ -9,23 +8,37 @@ const report = require(`./reporter`) const url = require(`url`) const existsSync = require(`fs-exists-cached`).sync const { trackCli, trackError } = require(`gatsby-telemetry`) -const prompts = require(`prompts`) + +const { + getPackageManager, + promptPackageManager, +} = require(`./util/configstore`) +const isTTY = require(`./util/is-tty`) const spawn = (cmd: string, options: any) => { const [file, ...args] = cmd.split(/\s+/) return execa(file, args, { stdio: `inherit`, ...options }) } -const conf = new Configstore(`gatsby`, {}, { globalConfigPath: true }) - -// Checks the existence of yarn package +// Checks the existence of yarn package and user preference if it exists // We use yarnpkg instead of yarn to avoid conflict with Hadoop yarn // Refer to https://github.com/yarnpkg/yarn/issues/673 -// -// Returns true if yarn exists, false otherwise -const shouldUseYarn = () => { +const shouldUseYarn = async () => { try { execSync(`yarnpkg --version`, { stdio: `ignore` }) - return true + + let packageManager = getPackageManager() + if (!packageManager) { + // if package manager is not set: + // - prompt user to pick package manager if in interactive console + // - default to yarn if not in interactive console + if (isTTY()) { + packageManager = (await promptPackageManager()) || `yarn` + } else { + packageManager = `yarn` + } + } + + return packageManager === `yarn` } catch (e) { return false } @@ -71,30 +84,13 @@ const install = async rootPath => { process.chdir(rootPath) try { - const npmCmd = `npm install` - let response = npmCmd - if (shouldUseYarn()) { - const promptsAnswer = await prompts([ - { - type: `select`, - name: `package_manager`, - message: `Which package manager would you like to use ?`, - choices: [ - { title: `yarn`, value: `yarnpkg` }, - { title: `npm`, value: npmCmd }, - ], - initial: 0, - }, - ]) - response = promptsAnswer.package_manager - } - conf.set(`package_manager`, response) - if (response.includes(`yarn`)) { + if (await shouldUseYarn()) { await fs.remove(`package-lock.json`) + await spawn(`yarnpkg`) } else { await fs.remove(`yarn.lock`) + await spawn(`npm install`) } - await spawn(response) } finally { process.chdir(prevDir) } diff --git a/packages/gatsby-cli/src/util/__tests__/is-tty.js b/packages/gatsby-cli/src/util/__tests__/is-tty.js new file mode 100644 index 0000000000000..aa65a14130795 --- /dev/null +++ b/packages/gatsby-cli/src/util/__tests__/is-tty.js @@ -0,0 +1,47 @@ +describe(`isTTY`, () => { + let originalTTY + beforeEach(() => { + jest.resetModules() + + originalTTY = process.stdout.isTTY + }) + afterEach(() => { + process.stdout.isTTY = originalTTY + }) + + it(`returns true if not on ci & TTY is enabled`, () => { + process.stdout.isTTY = true + jest.mock(`ci-info`, () => { + return { isCI: false } + }) + const isTTY = require(`../is-tty`) + expect(isTTY()).toBe(true) + }) + + it(`returns false if not on ci & TTY is disabled`, () => { + process.stdout.isTTY = false + jest.mock(`ci-info`, () => { + return { isCI: false } + }) + const isTTY = require(`../is-tty`) + expect(isTTY()).toBe(false) + }) + + it(`returns false if on ci & TTY is enabled`, () => { + process.stdout.isTTY = true + jest.mock(`ci-info`, () => { + return { isCI: true } + }) + const isTTY = require(`../is-tty`) + expect(isTTY()).toBe(false) + }) + + it(`returns false if on ci & TTY is disabled`, () => { + process.stdout.isTTY = false + jest.mock(`ci-info`, () => { + return { isCI: true } + }) + const isTTY = require(`../is-tty`) + expect(isTTY()).toBe(false) + }) +}) diff --git a/packages/gatsby-cli/src/util/configstore.js b/packages/gatsby-cli/src/util/configstore.js new file mode 100644 index 0000000000000..d066050279c49 --- /dev/null +++ b/packages/gatsby-cli/src/util/configstore.js @@ -0,0 +1,45 @@ +const Configstore = require(`configstore`) +const prompts = require(`prompts`) +const report = require(`../reporter`) + +let conf +try { + conf = new Configstore(`gatsby`, {}, { globalConfigPath: true }) +} catch (e) { + // This should never happen (?) + conf = { + settings: { + "cli.packageManager": undefined, + }, + get: key => conf.settings[key], + set: (key, value) => (conf.settings[key] = value), + } +} + +const packageMangerConfigKey = `cli.packageManager` +exports.getPackageManager = () => conf.get(packageMangerConfigKey) +const setPackageManager = packageManager => { + conf.set(packageMangerConfigKey, packageManager) + report.info(`Preferred package manager set to "${packageManager}"`) +} +exports.setPackageManager = setPackageManager + +exports.promptPackageManager = async () => { + const promptsAnswer = await prompts([ + { + type: `select`, + name: `package_manager`, + message: `Which package manager would you like to use ?`, + choices: [ + { title: `yarn`, value: `yarn` }, + { title: `npm`, value: `npm` }, + ], + initial: 0, + }, + ]) + const response = promptsAnswer.package_manager + if (response) { + setPackageManager(response) + } + return response +} diff --git a/packages/gatsby-cli/src/util/is-tty.js b/packages/gatsby-cli/src/util/is-tty.js new file mode 100644 index 0000000000000..45decfcedf3eb --- /dev/null +++ b/packages/gatsby-cli/src/util/is-tty.js @@ -0,0 +1,6 @@ +const isCI = require(`ci-info`).isCI + +// Some CI pipelines incorrectly report process.stdout.isTTY status, +// which causes unwanted lines in the output. An additional check for isCI helps. +// @see https://github.com/prettier/prettier/blob/36aeb4ce4f620023c8174e826d7208c0c64f1a0b/src/utils/is-tty.js +module.exports = () => process.stdout.isTTY && !isCI diff --git a/yarn.lock b/yarn.lock index 166ea7b0aa7ff..65d0f1ae45c88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4900,13 +4900,6 @@ bindings@^1.3.1: dependencies: file-uri-to-path "1.0.0" -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - bl@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" @@ -14717,11 +14710,6 @@ nan@^2.10.0, nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== -nan@^2.13.1: - version "2.13.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" - integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== - nan@^2.9.2: version "2.11.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" @@ -14819,13 +14807,6 @@ node-abi@^2.2.0: dependencies: semver "^5.4.1" -node-abi@^2.7.0: - version "2.7.1" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.7.1.tgz#a8997ae91176a5fbaa455b194976e32683cda643" - integrity sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw== - dependencies: - semver "^5.4.1" - node-dir@0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" @@ -16743,28 +16724,6 @@ prebuild-install@^5.2.2: tunnel-agent "^0.6.0" which-pm-runs "^1.0.0" -prebuild-install@^5.2.5: - version "5.2.5" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.5.tgz#c7485911fe98950b7f7cd15bb9daee11b875cc44" - integrity sha512-6uZgMVg7yDfqlP5CPurVhtq3hUKBFNufiar4J5hZrlHTo59DDBEtyxw01xCdFss9j0Zb9+qzFVf/s4niayba3w== - dependencies: - detect-libc "^1.0.3" - expand-template "^2.0.3" - github-from-package "0.0.0" - minimist "^1.2.0" - mkdirp "^0.5.1" - napi-build-utils "^1.0.1" - node-abi "^2.7.0" - noop-logger "^0.1.1" - npmlog "^4.0.1" - os-homedir "^1.0.1" - pump "^2.0.1" - rc "^1.2.7" - simple-get "^2.7.0" - tar-fs "^1.13.0" - tunnel-agent "^0.6.0" - which-pm-runs "^1.0.0" - prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -18805,23 +18764,6 @@ sharp@^0.21.3: tar "^4.4.8" tunnel-agent "^0.6.0" -sharp@^0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.22.0.tgz#cf4cfcb019941fd06ac24555d9f5bc84536d29be" - integrity sha512-yInpiWYvVbE0hJylso2Q2A7QaYFBxGdSlVVHGeUf1F9JsQNAUpmaqdnX54TImgKbSCy9mQpEAoGm1pcKCZhCsQ== - dependencies: - bindings "^1.5.0" - color "^3.1.0" - detect-libc "^1.0.3" - fs-copy-file-sync "^1.1.1" - nan "^2.13.1" - npmlog "^4.1.2" - prebuild-install "^5.2.5" - semver "^5.6.0" - simple-get "^3.0.3" - tar "^4.4.8" - tunnel-agent "^0.6.0" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"