diff --git a/.eslintignore b/.eslintignore index be7ad4b4..69933d2d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,6 +4,7 @@ !/**/.eslintrc.js /test.js /scripts/build/shims +/scripts/release/node_modules /coverage/ /dist/ **/node_modules/** diff --git a/.gitignore b/.gitignore index 6f35f106..aaa9b1e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /node_modules +/scripts/release/node_modules *.log /errors /test.js diff --git a/scripts/.eslintrc.yml b/scripts/.eslintrc.yml index d68c539d..63b77a22 100644 --- a/scripts/.eslintrc.yml +++ b/scripts/.eslintrc.yml @@ -1,2 +1,9 @@ +parserOptions: + ecmaVersion: 2017 rules: no-console: off +overrides: + files: + - test-dist.js + parserOptions: + ecmaVersion: 6 diff --git a/scripts/build/build.js b/scripts/build/build.js index 60ddf16a..a41a1eda 100644 --- a/scripts/build/build.js +++ b/scripts/build/build.js @@ -5,23 +5,22 @@ const stringWidth = require("string-width"); const bundler = require("./bundler"); const bundleConfigs = require("./config"); const util = require("./util"); -const formatMarkdown = require("../../website/playground/markdown"); // Errors in promises should be fatal. const loggedErrors = new Set(); process.on("unhandledRejection", err => { - if (loggedErrors.has(err)) { - // No need to print it twice. - process.exit(1); + // No need to print it twice. + if (!loggedErrors.has(err)) { + console.error(err); } - throw err; + process.exit(1); }); const OK = chalk.reset.inverse.bold.green(" DONE "); const FAIL = chalk.reset.inverse.bold.red(" FAIL "); function fitTerminal(input) { - const columns = process.stdout.columns || 80; + const columns = Math.min(process.stdout.columns, 80); const WIDTH = columns - stringWidth(OK) + 1; if (input.length < WIDTH) { input += Array(WIDTH - input.length).join(chalk.dim(".")); @@ -65,30 +64,6 @@ async function preparePackage() { await util.copyFile("./README.md", "./dist/README.md"); } -async function updateIssueTemplate() { - const filename = ".github/ISSUE_TEMPLATE.md"; - const issueTemplate = await util.readFile(filename, "utf8"); - - const pkg = await util.readJson("package.json"); - await util.writeFile( - filename, - issueTemplate.replace( - /-->[^]*$/, - "-->\n\n" + - formatMarkdown( - "// code snippet", - "// code snippet", - "", - pkg.version, - "https://prettier.io/playground/#.....", - { parser: "babylon" }, - [["# Options (if any):", true], ["--single-quote", true]], - true - ) - ) - ); -} - async function run() { await util.asyncRimRaf("dist"); @@ -98,7 +73,6 @@ async function run() { } await preparePackage(); - await updateIssueTemplate(); } run(); diff --git a/scripts/release/README.md b/scripts/release/README.md new file mode 100644 index 00000000..f4dab40b --- /dev/null +++ b/scripts/release/README.md @@ -0,0 +1,13 @@ +# Release script + +## Usage + +``` +./scripts/release/release.js --version NEW_VERSION +``` + +The script its own `package.json` so we can reinstall the root's `node_modules/` while making the release. + +## Credits + +This script was inspired by [React's release script](https://github.com/facebook/react/tree/001f9ef/scripts/release). diff --git a/scripts/release/package.json b/scripts/release/package.json new file mode 100644 index 00000000..587e5d47 --- /dev/null +++ b/scripts/release/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "dependencies": { + "chalk": "2.4.1", + "child-process-promise": "2.2.1", + "dedent": "0.7.0", + "minimist": "1.2.0", + "node-fetch": "2.1.2", + "prs-merged-since": "1.0.1", + "semver": "5.5.0", + "string-width": "2.1.1" + } +} diff --git a/scripts/release/release.js b/scripts/release/release.js new file mode 100644 index 00000000..bbb978c9 --- /dev/null +++ b/scripts/release/release.js @@ -0,0 +1,54 @@ +#!/usr/bin/env node + +"use strict"; + +async function run() { + const chalk = require("chalk"); + const dedent = require("dedent"); + const minimist = require("minimist"); + + const { readJson } = require("./utils"); + + const params = minimist(process.argv.slice(2), { + string: ["version"], + boolean: ["dry"], + alias: { v: "version" } + }); + params.previousVersion = (await readJson("package.json")).version; + + const steps = [ + require("./steps/validate-new-version"), + require("./steps/check-git-status"), + require("./steps/install-dependencies"), + require("./steps/run-tests"), + require("./steps/update-version"), + require("./steps/generate-bundles"), + require("./steps/update-changelog"), + require("./steps/push-to-git"), + require("./steps/publish-to-npm"), + require("./steps/bump-prettier"), + require("./steps/post-publish-steps") + ]; + + try { + for (const step of steps) { + await step(params); + } + } catch (error) { + const message = dedent(error.message.trim()); + const stack = error.stack.replace(message, ""); + console.error(`${chalk.red("error")} ${message}\n${stack}`); + process.exit(1); + } +} + +// Install script's dependencies before any require +const { exec } = require("child_process"); +exec("yarn install", { cwd: __dirname }, error => { + if (error) { + console.error(error); + process.exit(1); + } else { + run(); + } +}); diff --git a/scripts/release/steps/bump-prettier.js b/scripts/release/steps/bump-prettier.js new file mode 100644 index 00000000..1395e7fa --- /dev/null +++ b/scripts/release/steps/bump-prettier.js @@ -0,0 +1,32 @@ +"use strict"; + +const { exec, spawn } = require("child-process-promise"); +const { logPromise } = require("../utils"); + +async function format() { + await exec("yarn lint --fix"); + await exec("yarn lint-docs --fix"); +} + +async function commit(version) { + await spawn("git", [ + "commit", + "-am", + `Bump Prettier dependency to ${version}` + ]); + await exec("git push"); +} + +module.exports = async function({ dry, version }) { + if (dry) { + return; + } + + await logPromise( + "Installing Prettier", + spawn("yarn", ["add", "--dev", `prettier@${version}`]) + ); + + await logPromise("Updating files", format()); + await logPromise("Committing changed files", commit(version)); +}; diff --git a/scripts/release/steps/check-git-status.js b/scripts/release/steps/check-git-status.js new file mode 100644 index 00000000..15e1bb71 --- /dev/null +++ b/scripts/release/steps/check-git-status.js @@ -0,0 +1,14 @@ +"use strict"; + +const { exec } = require("child-process-promise"); + +module.exports = async function() { + const status = (await exec("git status --porcelain")).stdout; + + if (status) { + throw Error( + "Uncommited local changes. " + + "Please revert or commit all local changes before making a release." + ); + } +}; diff --git a/scripts/release/steps/generate-bundles.js b/scripts/release/steps/generate-bundles.js new file mode 100644 index 00000000..87b6534a --- /dev/null +++ b/scripts/release/steps/generate-bundles.js @@ -0,0 +1,19 @@ +"use strict"; + +const chalk = require("chalk"); +const { runYarn, logPromise, readJson } = require("../utils"); + +module.exports = async function({ version }) { + await logPromise("Generating bundles", runYarn("build")); + + const builtPkg = await readJson("dist/package.json"); + if (builtPkg.version !== version) { + throw Error( + `Expected ${version} in dist/package.json but found ${builtPkg.version}` + ); + } + + await logPromise("Running tests on generated bundles", runYarn("test:dist")); + + console.log(chalk.green.bold("Build successful!\n")); +}; diff --git a/scripts/release/steps/install-dependencies.js b/scripts/release/steps/install-dependencies.js new file mode 100644 index 00000000..e41aa207 --- /dev/null +++ b/scripts/release/steps/install-dependencies.js @@ -0,0 +1,20 @@ +"use strict"; + +const { exec } = require("child-process-promise"); +const { logPromise } = require("../utils"); + +async function install() { + await exec("rm -rf node_modules"); + await exec("yarn install"); + + const status = (await exec("git ls-files -m")).stdout.trim(); + if (status) { + throw Error( + "The lockfile needs to be updated, commit it before making the release." + ); + } +} + +module.exports = function() { + return logPromise("Installing NPM dependencies", install()); +}; diff --git a/scripts/release/steps/post-publish-steps.js b/scripts/release/steps/post-publish-steps.js new file mode 100644 index 00000000..4355e0c2 --- /dev/null +++ b/scripts/release/steps/post-publish-steps.js @@ -0,0 +1,65 @@ +"use strict"; + +const chalk = require("chalk"); +const dedent = require("dedent"); +const fetch = require("node-fetch"); +const { exec } = require("child-process-promise"); +const { logPromise, waitForEnter } = require("../utils"); + +const SCHEMA_REPO = "SchemaStore/schemastore"; +const SCHEMA_PATH = "src/schemas/json/prettierrc.json"; +const RAW_URL = `https://raw.githubusercontent.com/${SCHEMA_REPO}/master/${SCHEMA_PATH}`; +const EDIT_URL = `https://github.com/${SCHEMA_REPO}/edit/master/${SCHEMA_PATH}`; + +// Any optional or manual step can be warned in this script. + +async function checkSchema() { + const schema = (await exec("node scripts/generate-schema.js")).stdout.trim(); + const remoteSchema = await logPromise( + "Checking current schema in SchemaStore", + fetch(RAW_URL) + .then(r => r.text()) + .then(t => t.trim()) + ); + + if (schema === remoteSchema) { + return; + } + + return dedent(chalk` + {bold.underline The schema in {yellow SchemaStore} needs an update.} + - Open {cyan.underline ${EDIT_URL}} + - Run {yellow node scripts/generate-schema.js} and copy the new schema + - Paste it on GitHub interface + - Open a PR + `); +} + +function twitterAnnouncement() { + return dedent(chalk` + {bold.underline Announce on Twitter} + - Open {cyan.underline https://tweetdeck.twitter.com} + - Make sure you are tweeting from the {yellow @PrettierCode} account. + - Tweet about the release, including the blog post URL. + `); +} + +module.exports = async function() { + const steps = [await checkSchema(), twitterAnnouncement()].filter(Boolean); + + console.log(chalk.bold.green("The script has finished!\n")); + + if (steps.length === 0) { + return; + } + + console.log( + dedent(chalk` + {yellow.bold The following ${ + steps.length === 1 ? "step is" : "steps are" + } optional.} + + ${steps.join("\n\n")} + `) + ); +}; diff --git a/scripts/release/steps/publish-to-npm.js b/scripts/release/steps/publish-to-npm.js new file mode 100644 index 00000000..3e2e9d08 --- /dev/null +++ b/scripts/release/steps/publish-to-npm.js @@ -0,0 +1,36 @@ +"use strict"; + +const chalk = require("chalk"); +const dedent = require("dedent"); +const { exec } = require("child-process-promise"); +const { logPromise, waitForEnter } = require("../utils"); + +module.exports = async function({ dry, version }) { + if (dry) { + return; + } + + await logPromise("Publishing to npm", exec("npm publish", { cwd: "./dist" })); + + console.log( + dedent(chalk` + {green.bold Prettier ${version} published!} + + {yellow.bold Some manual steps are necessary.} + + {bold.underline Create a GitHub Release} + - Go to {cyan.underline https://github.com/prettier/prettier/releases/new?tag=${version}} + - Copy release notes from {yellow CHANGELOG.md} + - Attach all files in {yellow dist/} folder. + - Press {bgGreen.black Publish release } + + {bold.underline Test the new releae} + - In a new session, run {yellow npm i prettier@latest} in another directory + - Test the API and CLI + + After that, we can proceed to bump this repo's Prettier dependency. + Press any key to continue. + `) + ); + await waitForEnter(); +}; diff --git a/scripts/release/steps/push-to-git.js b/scripts/release/steps/push-to-git.js new file mode 100644 index 00000000..63122917 --- /dev/null +++ b/scripts/release/steps/push-to-git.js @@ -0,0 +1,19 @@ +"use strict"; + +const { exec, spawn } = require("child-process-promise"); +const { logPromise } = require("../utils"); + +async function pushGit({ version }) { + await spawn("git", ["commit", "-am", `Release ${version}`]); + await spawn("git", ["tag", "-a", version, "-m", `Release ${version}`]); + await exec("git push"); + await exec("git push --tags"); +} + +module.exports = function(params) { + if (params.dry) { + return; + } + + return logPromise("Committing and pushing to remote", pushGit(params)); +}; diff --git a/scripts/release/steps/run-tests.js b/scripts/release/steps/run-tests.js new file mode 100644 index 00000000..970f5f78 --- /dev/null +++ b/scripts/release/steps/run-tests.js @@ -0,0 +1,9 @@ +"use strict"; + +const { runYarn, logPromise } = require("../utils"); + +module.exports = async function() { + await logPromise("Running linter", runYarn("lint")); + await logPromise("Running linter on docs", runYarn("lint-docs")); + await logPromise("Running tests", runYarn("test")); +}; diff --git a/scripts/release/steps/update-changelog.js b/scripts/release/steps/update-changelog.js new file mode 100644 index 00000000..1d77fc99 --- /dev/null +++ b/scripts/release/steps/update-changelog.js @@ -0,0 +1,100 @@ +"use strict"; + +const chalk = require("chalk"); +const dedent = require("dedent"); +const fs = require("fs"); +const prsMergedSince = require("prs-merged-since"); +const semver = require("semver"); +const { logPromise, waitForEnter } = require("../utils"); + +function getBlogPostInfo(version) { + const date = new Date(); + const year = date.getFullYear(); + const month = new String(date.getMonth() + 1).padStart(2, "0"); + const day = new String(date.getDate()).padStart(2, "0"); + + return { + file: `website/blog/${year}-${month}-${day}-${version}.md`, + path: `blog/${year}/${month}/${day}/${version}.html` + }; +} + +async function getMergedPrs(previousVersion) { + const prs = await prsMergedSince({ + repo: "prettier/prettier", + tag: previousVersion, + githubApiToken: process.env.GITHUB_API_TOKEN + }); + return prs + .map(pr => `- ${pr.title} ([#${pr.number}](${pr.html_url}))`) + .join("\n"); +} + +function writeChangelog({ version, previousVersion, releaseNotes }) { + const changelog = fs.readFileSync("CHANGELOG.md", "utf-8"); + const newEntry = dedent` + # ${version} + + [link](https://github.com/prettier/prettier/compare/${previousVersion}...${version}) + + ${releaseNotes} + `; + fs.writeFileSync("CHANGELOG.md", newEntry + "\n\n" + changelog); +} + +module.exports = async function({ version, previousVersion }) { + const semverDiff = semver.diff(version, previousVersion); + + if (semverDiff !== "patch") { + const blogPost = getBlogPostInfo(version); + writeChangelog({ + version, + previousVersion, + releaseNotes: `- [Release Notes](https://prettier.io/${blogPost.path})` + }); + if (fs.existsSync(blogPost.file)) { + // Everything is fine, this step is finished + return; + } + console.warn( + dedent(chalk` + {yellow warning} The file {bold ${ + blogPost.file + }} doesn't exist, but it will be referenced in {bold CHANGELOG.md}. Make sure to create it later. + + Press ENTER to continue. + `) + ); + } else { + if (!process.env.GITHUB_API_TOKEN) { + console.log( + chalk`{yellow warning} GitHub API access token missing. You can expose a token via {bold GITHUB_API_TOKEN} environment variable.` + ); + } + + const releaseNotes = await logPromise( + "Fetching merged PRs", + getMergedPrs(previousVersion) + ); + writeChangelog({ + version, + previousVersion, + releaseNotes + }); + console.log(); + console.log( + dedent(chalk` + {yellow.bold A manual step is necessary.} + + The script has updated the file {bold CHANGELOG.md} with all the merged PRs since the last release. + You must edit it to focus only on relevant changes and make sure they have meaningful titles. + + You don't need to commit the file, the script will take care of that. + + When you're finished, press ENTER to continue. + `) + ); + } + + await waitForEnter(); +}; diff --git a/scripts/release/steps/update-version.js b/scripts/release/steps/update-version.js new file mode 100644 index 00000000..c10c95b6 --- /dev/null +++ b/scripts/release/steps/update-version.js @@ -0,0 +1,27 @@ +"use strict"; + +const { exec } = require("child-process-promise"); +const { readFileSync, writeFileSync } = require("fs"); +const { logPromise, readJson, writeJson } = require("../utils"); + +async function bump({ version }) { + const pkg = await readJson("package.json"); + pkg.version = version; + await writeJson("package.json", pkg, { spaces: 2 }); + + // Update .github/ISSUE_TEMPLATE.MD + const issueFile = ".github/ISSUE_TEMPLATE.md"; + const issueTempl = readFileSync(issueFile, "utf-8"); + writeFileSync( + issueFile, + issueTempl.replace(/^\*\*Prettier .*?\*\*$/m, `**Prettier ${version}**`) + ); +} + +module.exports = async function(params) { + await logPromise("Bumping version", bump(params)); + await logPromise( + "Updating integration snapshots", + exec("yarn test-integration -u") + ); +}; diff --git a/scripts/release/steps/validate-new-version.js b/scripts/release/steps/validate-new-version.js new file mode 100644 index 00000000..3f529c0b --- /dev/null +++ b/scripts/release/steps/validate-new-version.js @@ -0,0 +1,14 @@ +"use strict"; + +const chalk = require("chalk"); +const semver = require("semver"); + +module.exports = async function({ version, previousVersion }) { + if (!semver.valid(version)) { + throw Error(`Invalid version specified`); + } + + if (!semver.gt(version, previousVersion)) { + throw Error(`Version ${chalk.yellow(version)} has already been published`); + } +}; diff --git a/scripts/release/utils.js b/scripts/release/utils.js new file mode 100644 index 00000000..1c5a8a3c --- /dev/null +++ b/scripts/release/utils.js @@ -0,0 +1,78 @@ +"use strict"; + +require("readline").emitKeypressEvents(process.stdin); + +const chalk = require("chalk"); +const fs = require("fs"); +const { spawn } = require("child-process-promise"); +const stringWidth = require("string-width"); + +const OK = chalk.bgGreen.black(" DONE "); +const FAIL = chalk.bgRed.black(" FAIL "); + +function fitTerminal(input) { + const columns = Math.min(process.stdout.columns, 80); + const WIDTH = columns - stringWidth(OK) + 1; + if (input.length < WIDTH) { + input += Array(WIDTH - input.length).join(chalk.dim(".")); + } + return input; +} + +function logPromise(name, promise) { + process.stdout.write(fitTerminal(name)); + + return promise + .then(result => { + process.stdout.write(`${OK}\n`); + return result; + }) + .catch(err => { + process.stdout.write(`${FAIL}\n`); + throw err; + }); +} + +function runYarn(script) { + return spawn("yarn", ["--silent", script], { + capture: ["stdout", "stderr"] + }).catch(error => { + throw Error(`\`yarn ${script}\` failed\n${error.stdout}`); + }); +} + +function waitForEnter() { + process.stdin.setRawMode(true); + + return new Promise((resolve, reject) => { + process.stdin.on("keypress", listener); + process.stdin.resume(); + + function listener(ch, key) { + if (key.name === "return") { + process.stdin.setRawMode(false); + process.stdin.removeListener("keypress", listener); + process.stdin.pause(); + resolve(); + } else if (key.ctrl && key.name === "c") { + reject(Error("Process terminated by the user")); + } + } + }); +} + +function readJson(filename) { + return JSON.parse(fs.readFileSync(filename, "utf-8")); +} + +function writeJson(filename, content) { + fs.writeFileSync(filename, JSON.stringify(content, null, 2) + "\n"); +} + +module.exports = { + runYarn, + logPromise, + readJson, + writeJson, + waitForEnter +}; diff --git a/scripts/release/yarn.lock b/scripts/release/yarn.lock new file mode 100644 index 00000000..c5fb117a --- /dev/null +++ b/scripts/release/yarn.lock @@ -0,0 +1,482 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@octokit/rest@^15.2.6": + version "15.8.1" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-15.8.1.tgz#8bcdece90026d3af5edd73bd49a8732cb3801d29" + dependencies: + before-after-hook "^1.1.0" + btoa-lite "^1.0.0" + debug "^3.1.0" + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.0" + lodash "^4.17.4" + node-fetch "^2.1.1" + url-template "^2.0.8" + +agent-base@4, agent-base@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce" + dependencies: + es6-promisify "^5.0.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +before-after-hook@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.1.0.tgz#83165e15a59460d13702cb8febd6a1807896db5a" + +btoa-lite@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + +chalk@2.4.1, chalk@^2.0.1, chalk@^2.3.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +child-process-promise@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/child-process-promise/-/child-process-promise-2.2.1.tgz#4730a11ef610fad450b8f223c79d31d7bdad8074" + dependencies: + cross-spawn "^4.0.2" + node-version "^1.0.0" + promise-polyfill "^6.0.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^1.1.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +cross-spawn@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@3.1.0, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +dedent@0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + +es6-promise@^4.0.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + dependencies: + es6-promise "^4.0.3" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + dependencies: + agent-base "4" + debug "3.1.0" + +https-proxy-agent@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash@^4.17.4: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + dependencies: + chalk "^2.0.1" + +lru-cache@^4.0.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +mem@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" + dependencies: + mimic-fn "^1.0.0" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + +minimist@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +node-fetch@2.1.2, node-fetch@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" + +node-version@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/node-version/-/node-version-1.1.3.tgz#1081c87cce6d2dbbd61d0e51e28c287782678496" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +ora@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" + dependencies: + chalk "^2.3.1" + cli-cursor "^2.1.0" + cli-spinners "^1.1.0" + log-symbols "^2.2.0" + strip-ansi "^4.0.0" + wcwidth "^1.0.1" + +os-locale@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" + dependencies: + execa "^0.7.0" + lcid "^1.0.0" + mem "^1.1.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +promise-polyfill@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-6.1.0.tgz#dfa96943ea9c121fca4de9b5868cb39d3472e057" + +prs-merged-since@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prs-merged-since/-/prs-merged-since-1.0.1.tgz#2e9905f0843ec0189c3168a6eb31087982ac47fb" + dependencies: + "@octokit/rest" "^15.2.6" + ora "^2.0.0" + yargs "^11.0.0" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +semver@5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +string-width@2.1.1, string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +supports-color@^5.3.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + +url-template@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + dependencies: + defaults "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + +yargs@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2"