From 5658b87e0c9f89fde11b3a04bc467fbfbdd9ba0d Mon Sep 17 00:00:00 2001 From: LB Date: Fri, 18 Sep 2020 09:21:06 -0400 Subject: [PATCH] feat(gatsby-cli): enable set packagemanager (#26856) * Address configuration issues related to package manager selection * fix linting * use the right cli * clean up yargs * change console log * missing comma * find the eslint bug * think it was this * add everything back * change logic a bit, shouldn't also set telemetry * add whitespace * ignore TS error for the moment to validate the logic * switch order of validate script commands * Update packages/gatsby-cli/src/init-starter.ts Co-authored-by: Ward Peeters * use pathExists * use pathExists * We want to keep the lock files * set package manager to yarn for gatsby new tests * fix tests and remove yarn.lock from official starters * might be a typescript issue * use positional arguments instead * adjust tests * fix plugin command top level error * run in gatsby project * make it a one off test like feedback * update links to .com and rename as options * remove unused prompt code * Allow for package-manager as key * decouple publish starters script from CLI version by keeping yarn import * Update scripts/publish-starters.sh Co-authored-by: Ward Peeters Co-authored-by: Laurie Barth Co-authored-by: Ward Peeters Co-authored-by: Laurie Barth Co-authored-by: gatsbybot --- integration-tests/gatsby-cli/__tests__/new.js | 9 +- .../gatsby-cli/__tests__/options.js | 14 ++ packages/gatsby-cli/src/create-cli.ts | 145 +++++++++++++----- packages/gatsby-cli/src/init-starter.ts | 34 ++-- .../gatsby-cli/src/util/package-manager.ts | 23 --- scripts/publish-starters.sh | 4 +- 6 files changed, 142 insertions(+), 87 deletions(-) create mode 100644 integration-tests/gatsby-cli/__tests__/options.js diff --git a/integration-tests/gatsby-cli/__tests__/new.js b/integration-tests/gatsby-cli/__tests__/new.js index 094778d46ae65..570a94f5662b1 100644 --- a/integration-tests/gatsby-cli/__tests__/new.js +++ b/integration-tests/gatsby-cli/__tests__/new.js @@ -2,6 +2,7 @@ import { GatsbyCLI } from "../test-helpers" import * as fs from "fs-extra" import execa from "execa" import { join } from "path" +import { getConfigStore } from "gatsby-core-utils" const MAX_TIMEOUT = 30000 jest.setTimeout(MAX_TIMEOUT) @@ -13,12 +14,18 @@ const clean = dir => execa(`yarn`, ["del-cli", dir]) describe(`gatsby new`, () => { // make folder for us to create sites into const dir = join(__dirname, "../execution-folder") + const originalPackageManager = getConfigStore().get("cli.packageManager") + beforeAll(async () => { await clean(dir) await fs.ensureDir(dir) + GatsbyCLI.from(cwd).invoke([`options`, `set`, `pm`, `yarn`]) }) - afterAll(() => clean(dir)) + afterAll(async () => { + GatsbyCLI.from(cwd).invoke([`options`, `set`,`pm`, originalPackageManager]) + await clean(dir) + }) it(`a default starter creates a gatsby site`, () => { const [code, logs] = GatsbyCLI.from(cwd).invoke([`new`, `gatsby-default`]) diff --git a/integration-tests/gatsby-cli/__tests__/options.js b/integration-tests/gatsby-cli/__tests__/options.js new file mode 100644 index 0000000000000..b53c22c47d176 --- /dev/null +++ b/integration-tests/gatsby-cli/__tests__/options.js @@ -0,0 +1,14 @@ +import { GatsbyCLI } from "../test-helpers" + +const MAX_TIMEOUT = 2147483647 +jest.setTimeout(MAX_TIMEOUT) + +describe(`gatsby options`, () => { + it(`Prints the options`, () => { + const [status, logs] = GatsbyCLI.from(`gatsby-sites/gatsby-build`).invoke(`options`) + + logs.should.contain(`Package Manager`) + logs.should.contain(`Telemetry enabled`) + expect(status).toBe(0) + }) +}) diff --git a/packages/gatsby-cli/src/create-cli.ts b/packages/gatsby-cli/src/create-cli.ts index 28ac7d648645f..7e1788323863d 100644 --- a/packages/gatsby-cli/src/create-cli.ts +++ b/packages/gatsby-cli/src/create-cli.ts @@ -7,10 +7,17 @@ import { getLocalGatsbyVersion } from "./util/version" import envinfo from "envinfo" import { sync as existsSync } from "fs-exists-cached" import clipboardy from "clipboardy" -import { trackCli, setDefaultTags, setTelemetryEnabled } from "gatsby-telemetry" +import { + trackCli, + setDefaultTags, + setTelemetryEnabled, + isTrackingEnabled, +} from "gatsby-telemetry" import { initStarter } from "./init-starter" import { recipesHandler } from "./recipes" import { startGraphQLServer } from "gatsby-recipes" +import { getPackageManager, setPackageManager } from "./util/package-manager" +import reporter from "../lib/reporter" const handlerP = (fn: Function) => (...args: Array): void => { Promise.resolve(fn(...args)).then( @@ -144,24 +151,24 @@ function buildLocalCommands(cli: yargs.Argv, isLocalSite: boolean): void { .option(`S`, { alias: `https`, type: `boolean`, - describe: `Use HTTPS. See https://www.gatsbyjs.org/docs/local-https/ as a guide`, + describe: `Use HTTPS. See https://www.gatsbyjs.com/docs/local-https/ as a guide`, }) .option(`c`, { alias: `cert-file`, type: `string`, default: ``, - describe: `Custom HTTPS cert file (also required: --https, --key-file). See https://www.gatsbyjs.org/docs/local-https/`, + describe: `Custom HTTPS cert file (also required: --https, --key-file). See https://www.gatsbyjs.com/docs/local-https/`, }) .option(`k`, { alias: `key-file`, type: `string`, default: ``, - describe: `Custom HTTPS key file (also required: --https, --cert-file). See https://www.gatsbyjs.org/docs/local-https/`, + describe: `Custom HTTPS key file (also required: --https, --cert-file). See https://www.gatsbyjs.com/docs/local-https/`, }) .option(`ca-file`, { type: `string`, default: ``, - describe: `Custom HTTPS CA certificate file (also required: --https, --cert-file, --key-file). See https://www.gatsbyjs.org/docs/local-https/`, + describe: `Custom HTTPS CA certificate file (also required: --https, --cert-file, --key-file). See https://www.gatsbyjs.com/docs/local-https/`, }) .option(`graphql-tracing`, { type: `boolean`, @@ -174,11 +181,11 @@ function buildLocalCommands(cli: yargs.Argv, isLocalSite: boolean): void { }) .option(`inspect`, { type: `number`, - describe: `Opens a port for debugging. See https://www.gatsbyjs.org/docs/debugging-the-build-process/`, + describe: `Opens a port for debugging. See https://www.gatsbyjs.com/docs/debugging-the-build-process/`, }) .option(`inspect-brk`, { type: `number`, - describe: `Opens a port for debugging. Will block until debugger is attached. See https://www.gatsbyjs.org/docs/debugging-the-build-process/`, + describe: `Opens a port for debugging. Will block until debugger is attached. See https://www.gatsbyjs.com/docs/debugging-the-build-process/`, }), handler: handlerP( getCommandHandler(`develop`, (args: yargs.Arguments, cmd: Function) => { @@ -347,7 +354,7 @@ function buildLocalCommands(cli: yargs.Argv, isLocalSite: boolean): void { cli.command({ command: `repl`, - describe: `Get a node repl with context of Gatsby environment, see (https://www.gatsbyjs.org/docs/gatsby-repl/)`, + describe: `Get a node repl with context of Gatsby environment, see (https://www.gatsbyjs.com/docs/gatsby-repl/)`, handler: getCommandHandler( `repl`, (args: yargs.Arguments, cmd: Function) => { @@ -481,39 +488,6 @@ export const createCli = (argv: Array): yargs.Arguments => { await initStarter(starterStr, rootPathStr) }), }) - .command(`plugin`, `Useful commands relating to Gatsby plugins`, yargs => - yargs - .command({ - command: `docs`, - describe: `Helpful info about using and creating plugins`, - handler: handlerP(() => - console.log(` -Using a plugin: -- What is a Plugin? (https://www.gatsbyjs.org/docs/what-is-a-plugin/) -- Using a Plugin in Your Site (https://www.gatsbyjs.org/docs/using-a-plugin-in-your-site/) -- What You Don't Need Plugins For (https://www.gatsbyjs.org/docs/what-you-dont-need-plugins-for/) -- Loading Plugins from Your Local Plugins Folder (https://www.gatsbyjs.org/docs/loading-plugins-from-your-local-plugins-folder/) -- Plugin Library (https://www.gatsbyjs.org/plugins/) - -Creating a plugin: -- Naming a Plugin (https://www.gatsbyjs.org/docs/naming-a-plugin/) -- Files Gatsby Looks for in a Plugin (https://www.gatsbyjs.org/docs/files-gatsby-looks-for-in-a-plugin/) -- Creating a Generic Plugin (https://www.gatsbyjs.org/docs/creating-a-generic-plugin/) -- Creating a Local Plugin (https://www.gatsbyjs.org/docs/creating-a-local-plugin/) -- Creating a Source Plugin (https://www.gatsbyjs.org/docs/creating-a-source-plugin/) -- Creating a Transformer Plugin (https://www.gatsbyjs.org/docs/creating-a-transformer-plugin/) -- Submit to Plugin Library (https://www.gatsbyjs.org/contributing/submit-to-plugin-library/) -- Source Plugin Tutorial (https://www.gatsbyjs.org/tutorial/source-plugin-tutorial/) -- Maintaining a Plugin (https://www.gatsbyjs.org/docs/maintaining-a-plugin/) -- Join Discord #plugin-authoring channel to ask questions! (https://gatsby.dev/discord/) - `) - ), - }) - .demandCommand( - 1, - `Pass --help to see all available commands and options.` - ) - ) .command({ command: `telemetry`, describe: `Enable or disable Gatsby anonymous analytics collection.`, @@ -534,6 +508,95 @@ Creating a plugin: report.log(`Telemetry collection ${enabled ? `enabled` : `disabled`}`) }), }) + .command({ + command: `plugin [cmd]`, + describe: `Useful commands relating to Gatsby plugins`, + builder: yargs => + yargs.positional(`cmd`, { + choices: [`docs`], + describe: "Valid commands include `docs`.", + type: `string`, + }), + handler: handlerP(({ cmd }) => { + if (cmd === `docs`) { + console.log(` + Using a plugin: + - What is a Plugin? (https://www.gatsbyjs.com/docs/what-is-a-plugin/) + - Using a Plugin in Your Site (https://www.gatsbyjs.com/docs/using-a-plugin-in-your-site/) + - What You Don't Need Plugins For (https://www.gatsbyjs.com/docs/what-you-dont-need-plugins-for/) + - Loading Plugins from Your Local Plugins Folder (https://www.gatsbyjs.com/docs/loading-plugins-from-your-local-plugins-folder/) + - Plugin Library (https://www.gatsbyjs.com/plugins/) + + Creating a plugin: + - Naming a Plugin (https://www.gatsbyjs.com/docs/naming-a-plugin/) + - Files Gatsby Looks for in a Plugin (https://www.gatsbyjs.com/docs/files-gatsby-looks-for-in-a-plugin/) + - Creating a Generic Plugin (https://www.gatsbyjs.com/docs/creating-a-generic-plugin/) + - Creating a Local Plugin (https://www.gatsbyjs.com/docs/creating-a-local-plugin/) + - Creating a Source Plugin (https://www.gatsbyjs.com/docs/creating-a-source-plugin/) + - Creating a Transformer Plugin (https://www.gatsbyjs.com/docs/creating-a-transformer-plugin/) + - Submit to Plugin Library (https://www.gatsbyjs.com/contributing/submit-to-plugin-library/) + - Source Plugin Tutorial (https://www.gatsbyjs.com/tutorial/source-plugin-tutorial/) + - Maintaining a Plugin (https://www.gatsbyjs.com/docs/maintaining-a-plugin/) + - Join Discord #plugin-authoring channel to ask questions! (https://gatsby.dev/discord/) + `) + } else { + console.log(`Current valid subcommands are: 'docs'`) // right now this is hardcoded because we only have a single command + } + }), + }) + .command({ + command: `options [cmd] [key] [value]`, + describe: `View or set your gatsby-cli configuration settings.`, + builder: yargs => + yargs + .positional(`cmd`, { + choices: [`set`], + type: `string`, + describe: `Configure your package manager.`, + }) + .positional(`key`, { + choices: [`pm`, `package-manager`], + type: `string`, + describe: `Set the package manager \`gatsby new\` is using.`, + }) + .positional(`value`, { + choices: [`npm`, `yarn`], + type: `string`, + describe: `Set package manager as \`npm\` or \`yarn\`.`, + }), + + handler: handlerP(({ cmd, key, value }: yargs.Arguments) => { + if (!getPackageManager()) { + setPackageManager(`npm`) + } + + if (cmd === `set`) { + if (key === `pm` || key === `package-manager`) { + if (value && value !== `yarn` && value !== `npm`) { + report.panic(`Package manager must be yarn or npm.`) + } + + if (value) { + // @ts-ignore + setPackageManager(value) + return + } else { + setPackageManager(`npm`) + } + } else { + reporter.warn( + `Please pass your desired config key and value. Currently you can only set your package manager using \`pm\`.` + ) + } + return + } + + console.log(` + Package Manager: ${getPackageManager()} + Telemetry enabled: ${isTrackingEnabled()} + `) + }), + }) .wrap(cli.terminalWidth()) .demandCommand(1, `Pass --help to see all available commands and options.`) .strict() diff --git a/packages/gatsby-cli/src/init-starter.ts b/packages/gatsby-cli/src/init-starter.ts index a61fa19c35dd5..c85548e046277 100644 --- a/packages/gatsby-cli/src/init-starter.ts +++ b/packages/gatsby-cli/src/init-starter.ts @@ -11,8 +11,7 @@ import prompts from "prompts" import url from "url" import { updateSiteMetadata } from "gatsby-core-utils" import report from "./reporter" -import { getPackageManager, promptPackageManager } from "./util/package-manager" -import { isTTY } from "./util/is-tty" +import { getPackageManager, setPackageManager } from "./util/package-manager" import reporter from "../lib/reporter" const spawnWithArgs = ( @@ -29,26 +28,13 @@ const spawn = ( const [file, ...args] = cmd.split(/\s+/) return spawnWithArgs(file, args, options) } -// Checks the existence of yarn package and user preference if it exists +// Checks the existence of yarn package // We use yarnpkg instead of yarn to avoid conflict with Hadoop yarn // Refer to https://github.com/yarnpkg/yarn/issues/673 -const shouldUseYarn = async (): Promise => { +const checkForYarn = async (): Promise => { try { execSync(`yarnpkg --version`, { stdio: `ignore` }) - - 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` + return true } catch (e) { return false } @@ -115,8 +101,16 @@ const install = async (rootPath: string): Promise => { process.chdir(rootPath) try { - if (await shouldUseYarn()) { - await fs.remove(`package-lock.json`) + if (!getPackageManager()) { + setPackageManager(`npm`) + } + if (getPackageManager() === `yarn` && checkForYarn()) { + if (await fs.pathExists(`package-lock.json`)) { + if (!(await fs.pathExists(`yarn.lock`))) { + await spawn(`yarnpkg import`) + } + await fs.remove(`package-lock.json`) + } await spawn(`yarnpkg`) } else { await fs.remove(`yarn.lock`) diff --git a/packages/gatsby-cli/src/util/package-manager.ts b/packages/gatsby-cli/src/util/package-manager.ts index 5b7a38ec90340..324af7c36c04d 100644 --- a/packages/gatsby-cli/src/util/package-manager.ts +++ b/packages/gatsby-cli/src/util/package-manager.ts @@ -1,5 +1,4 @@ import { getConfigStore } from "gatsby-core-utils" -import prompts from "prompts" import report from "../reporter" type PackageManager = "yarn" | "npm" @@ -11,25 +10,3 @@ export const setPackageManager = (packageManager: PackageManager): void => { getConfigStore().set(packageMangerConfigKey, packageManager) report.info(`Preferred package manager set to "${packageManager}"`) } - -export const promptPackageManager = async (): Promise => { - const promptsAnswer: { - package_manager: PackageManager - } = 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/scripts/publish-starters.sh b/scripts/publish-starters.sh index 21bc1d68e5298..18ff153bdf531 100755 --- a/scripts/publish-starters.sh +++ b/scripts/publish-starters.sh @@ -27,8 +27,8 @@ for folder in $GLOB; do cp -r "$BASE/$folder/." . if [ "$IS_WORKSPACE" = null ]; then - rm -rf yarn.lock - yarn import # generate a new yarn.lock file based on package-lock.json + rm -f yarn.lock + yarn import # generate a new yarn.lock file based on package-lock.json, gatsby new does this is new CLI versions but will ignore if file exists fi if [ -n "$(git status --porcelain)" ]; then