├── .babelrc ├── .flowconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── bin.js ├── code-of-conduct.md ├── example ├── package.json ├── packages │ ├── bar │ │ ├── bar.js │ │ └── package.json │ └── foo │ │ ├── package.json │ │ └── packages │ │ └── baz │ │ └── package.json └── yarn.lock ├── flow-typed └── npm │ ├── chalk_v1.x.x.js │ ├── jest_v20.x.x.js │ └── meow_v3.x.x.js ├── index.js ├── package.json ├── src ├── Config.js ├── GlobalOptions.js ├── Package.js ├── Project.js ├── Repository.js ├── __fixtures__ │ ├── dependent-workspaces-with-cycle │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── dependent-workspaces │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── dev-dependent-workspaces-only │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── independent-workspaces │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── invalid-project-root-dependency-on-ws │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── nested-workspaces-transitive-dependents │ │ ├── package.json │ │ └── packages │ │ │ ├── pkg-a │ │ │ └── package.json │ │ │ └── workspace-a │ │ │ ├── package.json │ │ │ └── packages │ │ │ ├── pkg-b │ │ │ └── package.json │ │ │ └── pkg-c │ │ │ └── package.json │ ├── nested-workspaces-with-muliple-binaries │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ ├── bin │ │ │ │ ├── anotherBar.js │ │ │ │ └── bar1.js │ │ │ └── package.json │ │ │ ├── foo │ │ │ ├── package.json │ │ │ └── packages │ │ │ │ └── baz │ │ │ │ ├── baz.js │ │ │ │ └── package.json │ │ │ └── zee │ │ │ ├── package.json │ │ │ └── zee.js │ ├── nested-workspaces-with-root-dependencies-installed │ │ ├── node_modules │ │ │ ├── .bin │ │ │ │ ├── external-dep-two-bins-1 │ │ │ │ ├── external-dep-two-bins-2 │ │ │ │ └── external-dep-with-bin │ │ │ ├── external-dep-alt-version │ │ │ │ └── package.json │ │ │ ├── external-dep-with-bin │ │ │ │ ├── external-bin.js │ │ │ │ └── package.json │ │ │ ├── external-dep-with-two-bins │ │ │ │ ├── external-bin-1.js │ │ │ │ ├── external-bin-2.js │ │ │ │ └── package.json │ │ │ └── external-dep │ │ │ │ └── package.json │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ ├── bar.js │ │ │ └── package.json │ │ │ └── foo │ │ │ ├── package.json │ │ │ └── packages │ │ │ ├── baz │ │ │ ├── baz-bin-1.js │ │ │ ├── baz-bin-2.js │ │ │ └── package.json │ │ │ └── zee │ │ │ └── package.json │ ├── nested-workspaces-with-scoped-package-names │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ ├── node_modules │ │ │ │ └── react │ │ │ └── package.json │ │ │ └── foo │ │ │ ├── node_modules │ │ │ ├── @scope │ │ │ │ └── bar │ │ │ ├── @scoped │ │ │ │ └── bar │ │ │ └── react │ │ │ ├── package.json │ │ │ └── packages │ │ │ └── baz │ │ │ ├── node_modules │ │ │ ├── @scope │ │ │ │ └── bar │ │ │ ├── @scoped │ │ │ │ └── bar │ │ │ └── react │ │ │ └── package.json │ ├── nested-workspaces │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ ├── package.json │ │ │ └── packages │ │ │ └── baz │ │ │ └── package.json │ ├── no-package-json-workspace │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── .gitkeep │ │ │ └── foo │ │ │ └── package.json │ ├── package-with-external-deps-installed │ │ ├── node_modules │ │ │ ├── foo-dep │ │ │ │ └── package.json │ │ │ ├── global-dep │ │ │ │ └── package.json │ │ │ ├── project-only-dep-with-beta-tag │ │ │ │ └── package.json │ │ │ └── project-only-dep │ │ │ │ └── package.json │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ ├── node_modules │ │ │ │ └── global-dep │ │ │ └── package.json │ │ │ └── foo │ │ │ ├── node_modules │ │ │ ├── foo-dep │ │ │ └── global-dep │ │ │ └── package.json │ ├── package-with-four-spaces-json │ │ └── package.json │ ├── package-with-invalid-json │ │ └── package.json │ ├── package-with-uncertain-indentation-json │ │ └── package.json │ ├── project-with-bins │ │ ├── node_modules │ │ │ ├── .bin │ │ │ │ └── dep-with-bin │ │ │ └── dep-with-bin │ │ │ │ ├── bin.js │ │ │ │ └── package.json │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ ├── node_modules │ │ │ ├── .bin │ │ │ │ └── dep-with-bin │ │ │ └── dep-with-bin │ │ │ └── package.json │ ├── simple-package │ │ └── package.json │ ├── simple-project-with-excluded-package │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── simple-project-with-multiple-depTypes │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── simple-project-with-private-package │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── simple-project │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── simple-repo │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ └── workspace-with-bin │ │ ├── package.json │ │ └── packages │ │ ├── bar │ │ ├── bin.js │ │ └── package.json │ │ └── foo │ │ └── package.json ├── __tests__ │ ├── Config.test.js │ ├── Package.test.js │ ├── Project.test.js │ ├── Repository.test.js │ └── cli.test.js ├── cli.js ├── commands │ ├── __tests__ │ │ ├── add.test.js │ │ ├── autoclean.test.js │ │ ├── bin.test.js │ │ ├── build.test.js │ │ ├── check.test.js │ │ ├── create.test.js │ │ ├── doc.test.js │ │ ├── exec.test.js │ │ ├── format.test.js │ │ ├── generate.test.js │ │ ├── help.test.js │ │ ├── import.test.js │ │ ├── info.test.js │ │ ├── init.test.js │ │ ├── install.test.js │ │ ├── link.test.js │ │ ├── lint.test.js │ │ ├── list.test.js │ │ ├── login.test.js │ │ ├── logout.test.js │ │ ├── normalize.test.js │ │ ├── outdated.test.js │ │ ├── pack.test.js │ │ ├── publish.test.js │ │ ├── publishLock.test.js │ │ ├── publishUnlock.test.js │ │ ├── remove.test.js │ │ ├── run.test.js │ │ ├── test.test.js │ │ ├── unlink.test.js │ │ ├── upgrade.test.js │ │ ├── upgradeInteractive.test.js │ │ ├── version.test.js │ │ ├── versions.test.js │ │ └── why.test.js │ ├── add.js │ ├── autoclean.js │ ├── bin.js │ ├── build.js │ ├── cache │ │ ├── __tests__ │ │ │ ├── clean.test.js │ │ │ ├── dir.test.js │ │ │ └── list.test.js │ │ ├── clean.js │ │ ├── dir.js │ │ ├── index.js │ │ └── list.js │ ├── check.js │ ├── config │ │ ├── __tests__ │ │ │ ├── current.test.js │ │ │ ├── delete.test.js │ │ │ ├── get.test.js │ │ │ ├── list.test.js │ │ │ └── set.test.js │ │ ├── current.js │ │ ├── delete.js │ │ ├── get.js │ │ ├── index.js │ │ ├── list.js │ │ └── set.js │ ├── create.js │ ├── doc.js │ ├── exec.js │ ├── format.js │ ├── generate.js │ ├── global │ │ ├── __tests__ │ │ │ ├── add.test.js │ │ │ ├── bin.test.js │ │ │ ├── list.test.js │ │ │ ├── remove.test.js │ │ │ └── upgrade.test.js │ │ ├── add.js │ │ ├── bin.js │ │ ├── index.js │ │ ├── list.js │ │ ├── remove.js │ │ └── upgrade.js │ ├── help.js │ ├── import.js │ ├── index.js │ ├── info.js │ ├── init.js │ ├── install.js │ ├── licenses │ │ ├── __tests__ │ │ │ ├── generateDisclaimer.test.js │ │ │ └── list.test.js │ │ ├── generateDisclaimer.js │ │ ├── index.js │ │ └── list.js │ ├── link.js │ ├── lint.js │ ├── list.js │ ├── login.js │ ├── logout.js │ ├── normalize.js │ ├── outdated.js │ ├── owner │ │ ├── __tests__ │ │ │ ├── add.test.js │ │ │ ├── list.test.js │ │ │ └── remove.test.js │ │ ├── add.js │ │ ├── index.js │ │ ├── list.js │ │ └── remove.js │ ├── pack.js │ ├── project │ │ ├── __tests__ │ │ │ ├── add.test.js │ │ │ ├── exec.test.js │ │ │ ├── remove.test.js │ │ │ ├── run.test.js │ │ │ └── upgrade.test.js │ │ ├── add.js │ │ ├── exec.js │ │ ├── index.js │ │ ├── remove.js │ │ ├── run.js │ │ └── upgrade.js │ ├── publish.js │ ├── publishLock.js │ ├── publishUnlock.js │ ├── remove.js │ ├── run.js │ ├── tag │ │ ├── __tests__ │ │ │ ├── add.test.js │ │ │ ├── list.test.js │ │ │ └── remove.test.js │ │ ├── add.js │ │ ├── index.js │ │ ├── list.js │ │ └── remove.js │ ├── team │ │ ├── __tests__ │ │ │ ├── add.test.js │ │ │ ├── create.test.js │ │ │ ├── destroy.test.js │ │ │ ├── list.test.js │ │ │ └── remove.test.js │ │ ├── add.js │ │ ├── create.js │ │ ├── destroy.js │ │ ├── index.js │ │ ├── list.js │ │ └── remove.js │ ├── test.js │ ├── unlink.js │ ├── upgrade.js │ ├── upgradeInteractive.js │ ├── version.js │ ├── versions.js │ ├── why.js │ ├── workspace │ │ ├── __tests__ │ │ │ ├── add.test.js │ │ │ ├── exec.test.js │ │ │ ├── link.test.js │ │ │ ├── remove.test.js │ │ │ ├── run.test.js │ │ │ ├── unlink.test.js │ │ │ └── upgrade.test.js │ │ ├── add.js │ │ ├── exec.js │ │ ├── index.js │ │ ├── link.js │ │ ├── remove.js │ │ ├── run.js │ │ ├── unlink.js │ │ └── upgrade.js │ └── workspaces │ │ ├── __tests__ │ │ ├── add.test.js │ │ ├── exec.test.js │ │ ├── remove.test.js │ │ ├── run.test.js │ │ └── upgrade.test.js │ │ ├── add.js │ │ ├── exec.js │ │ ├── index.js │ │ ├── remove.js │ │ ├── run.js │ │ └── upgrade.js ├── constants.js ├── functions │ ├── __fixtures__ │ │ └── lots-of-internally-linked-deps │ │ │ ├── package.json │ │ │ └── packages │ │ │ ├── caret-dep │ │ │ └── package.json │ │ │ ├── has-all-deps-with-peers │ │ │ └── package.json │ │ │ ├── has-all-deps │ │ │ └── package.json │ │ │ ├── pinned-dep │ │ │ └── package.json │ │ │ └── tilde-dep │ │ │ └── package.json │ ├── __tests__ │ │ ├── getDependentsGraph.test.js │ │ ├── getProject.test.js │ │ ├── runWorkspaceTasks.test.js │ │ └── updatePackageVersions.test.js │ ├── getDependencyGraph.js │ ├── getDependentsGraph.js │ ├── getProject.js │ ├── getWorkspaces.js │ ├── index.js │ ├── publishPackages.js │ ├── runWorkspaceTasks.js │ ├── updatePackageVersions.js │ └── updateWorkspaceDependencies.js ├── generators │ ├── __tests__ │ │ └── license.test.js │ └── license.js ├── index.js ├── types.js └── utils │ ├── __fixtures__ │ ├── project-with-missing-version-field │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ ├── simple-project-with-bolt-version-check │ │ ├── package.json │ │ └── packages │ │ │ ├── bar │ │ │ └── package.json │ │ │ └── foo │ │ │ └── package.json │ └── symlinks │ │ ├── executable.sh │ │ ├── file.txt │ │ ├── file2.txt │ │ ├── shim.cmd │ │ └── shim_target.js │ ├── __mocks__ │ ├── npm.js │ └── spawn.js │ ├── __tests__ │ ├── addDependenciesToPackages.test.js │ ├── changes.test.js │ ├── fs.test.js │ ├── git.test.js │ ├── jsonModifier.test.js │ ├── locks.test.js │ ├── logger.test.js │ ├── npm.test.js │ ├── options.test.js │ ├── processes.test.js │ ├── promises.test.js │ ├── prompts.test.js │ ├── publish.test.js │ ├── symlinkPackageDependencies.test.js │ ├── symlinkPackagesBinariesToProject.test.js │ ├── upgradeDependenciesInPackages.test.js │ ├── validateProject.test.js │ └── yarn.test.js │ ├── addDependenciesToPackages.js │ ├── changes.js │ ├── cleanUp.js │ ├── env.js │ ├── errors.js │ ├── execCommand.js │ ├── fs.js │ ├── git.js │ ├── globs.js │ ├── jsonModifier.js │ ├── locks.js │ ├── logger.js │ ├── messages.js │ ├── npm.js │ ├── options.js │ ├── processes.js │ ├── promiseWrapper.js │ ├── promises.js │ ├── prompts.js │ ├── publish.js │ ├── removeDependenciesFromPackages.js │ ├── symlinkPackageDependencies.js │ ├── symlinkPackagesBinariesToProject.js │ ├── upgradeDependenciesInPackages.js │ ├── validateProject.js │ └── yarn.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "test": { 4 | "presets": [ 5 | "flow", ["env", { 6 | "loose": true, 7 | "targets": { 8 | "node": "current" 9 | } 10 | }] 11 | ], 12 | "plugins": [ 13 | "transform-class-properties", 14 | "transform-object-rest-spread", 15 | "transform-runtime" 16 | ] 17 | }, 18 | "legacy": { 19 | "presets": [ 20 | "flow", ["env", { 21 | "loose": true, 22 | "targets": { 23 | "node": 4 24 | } 25 | }] 26 | ], 27 | "plugins": [ 28 | "transform-class-properties", 29 | "transform-object-rest-spread", 30 | "transform-runtime" 31 | ], 32 | "ignore": [ 33 | "__mocks__", 34 | "__tests__", 35 | "__fixtures__", 36 | "node_modules" 37 | ] 38 | }, 39 | "modern": { 40 | "presets": [ 41 | "flow", ["env", { 42 | "loose": true, 43 | "targets": { 44 | "node": 8 45 | } 46 | }] 47 | ], 48 | "plugins": [ 49 | "transform-class-properties", 50 | "transform-object-rest-spread", 51 | "transform-runtime" 52 | ], 53 | "ignore": [ 54 | "__mocks__", 55 | "__tests__", 56 | "__fixtures__", 57 | "node_modules" 58 | ] 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/__fixtures__/.* 3 | 4 | [include] 5 | 6 | [libs] 7 | 8 | [options] 9 | 10 | [lints] 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | dist 4 | coverage/ 5 | !**/__fixtures__/**/node_modules/ 6 | example-2 7 | .vscode/ 8 | **/.DS_Store 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | git: 2 | depth: 1 3 | sudo: false 4 | language: node_js 5 | node_js: 6 | - '6' 7 | - '8' 8 | - '10' 9 | cache: 10 | yarn: true 11 | directories: 12 | - node_modules 13 | script: yarn test --maxWorkers=4 && yarn flow 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Bolt 2 | 3 | Join the boltpkg community slack room at https://boltpkg.slack.com 4 | 5 | **Note:** Recommended to use Node > 8.5, (*Node < 4 is not supported*) 6 | 7 | > Please make sure you have latest [yarn](https://yarnpkg.com/en/docs/install) installed 8 | 9 | ## Folder Structure: 10 | 11 | ```yml 12 | - bin.js # node executable, this where bolt starts 13 | - src 14 | - cli.js # taking in user args, and converting them to command map, - also calls the command as per argv 15 | - Package.js # exports function to initialise a package 16 | - Project.js # exports function to initialise a project 17 | - types.js # flow types 18 | - commands # all the commands are here 19 | - workspace # workspace related commands 20 | - workspaces # workspaces related commands 21 | : : : : : : : 22 | - add.js # bolt add command 23 | - bin.js # bolt bin command 24 | : : : : : : : 25 | - utils 26 | - messages.js # log messages 27 | - yarn.js # yarn related commands 28 | : : : : : : : 29 | ``` 30 | 31 | ## SetUp: 32 | 33 | - Clone the repo - `git clone https://github.com/boltpkg/bolt.git` 34 | - cd into the repo, `cd bolt` 35 | - install dependencies - `yarn install` 36 | 37 | ## Develop: 38 | 39 | Running the build in watch mode: 40 | 41 | ```sh 42 | yarn build:modern --watch 43 | ``` 44 | 45 | ## Testing: 46 | 47 | Running test in watch mode: 48 | 49 | ```sh 50 | yarn run test --watch 51 | ``` 52 | 53 | > Please note that this project is released with a [Contributor Code of Conduct](code-of-conduct.md). By participating in this project you agree to its terms. 54 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | | Title | Description 4 | | --------------------|------------ 5 | | Version | 6 | | Type | 7 | | node | 8 | | Operating System | 9 | | Short Description | 10 | | Detailed description| 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-present James Kyle 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var ver = process.versions.node; 5 | var majorVer = parseInt(ver.split('.')[0], 10); 6 | var cli; 7 | 8 | if (majorVer < 6) { 9 | throw new Error( 10 | 'Node version ' + 11 | ver + 12 | ' is not supported in Bolt, please use Node.js 6.0 or higher.' 13 | ); 14 | } else if (majorVer < 8) { 15 | cli = require('./dist/legacy/cli').default; 16 | } else { 17 | cli = require('./dist/modern/cli').default; 18 | } 19 | 20 | cli(process.argv.slice(2), true); 21 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "fixture-project", 4 | "bolt": { 5 | "workspaces": ["packages/*"] 6 | }, 7 | "dependencies": { 8 | "react": "^15.6.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/packages/bar/bar.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/example/packages/bar/bar.js -------------------------------------------------------------------------------- /example/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar-workspace-package", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "preinstall": "echo preinstall", 7 | "postinstall": "echo postinstall", 8 | "prepublish": "echo prepublish" 9 | }, 10 | "dependencies": { 11 | "react": "^15.6.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo-workspace-package", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "preinstall": "echo preinstall", 7 | "postinstall": "echo postinstall", 8 | "prepublish": "echo prepublish" 9 | }, 10 | "bolt": { 11 | "workspaces": ["packages/*"] 12 | }, 13 | "dependencies": { 14 | "react": "^15.6.1", 15 | "bar-workspace-package": "^1.0.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/packages/foo/packages/baz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baz-workspace-package", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "preinstall": "echo preinstall", 7 | "postinstall": "echo postinstall", 8 | "prepublish": "echo prepublish" 9 | }, 10 | "dependencies": { 11 | "react": "^15.6.1", 12 | "bar-workspace-package": "^1.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /flow-typed/npm/meow_v3.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 43c4544830c615dbbf641316eedc12f1 2 | // flow-typed version: b43dff3e0e/meow_v3.x.x/flow_>=v0.25.x 3 | 4 | declare module 'meow' { 5 | declare type options = 6 | | string 7 | | Array 8 | | { 9 | description?: string, 10 | help: string, 11 | version?: string | boolean, 12 | pkg?: string | Object, 13 | argv?: Array, 14 | inferType?: boolean 15 | }; 16 | 17 | declare type minimistOptions = { 18 | string?: string | Array, 19 | boolean?: boolean | string | Array, 20 | alias?: { [arg: string]: string | Array }, 21 | default?: { [arg: string]: any }, 22 | stopEarly?: boolean, 23 | '--'?: boolean, 24 | unknown?: (param: string) => boolean 25 | }; 26 | 27 | declare type Flags = { 28 | '--'?: Array, 29 | [flag: string]: string | boolean 30 | }; 31 | 32 | declare module.exports: ( 33 | options: options, 34 | minimistOptions?: minimistOptions 35 | ) => { 36 | input: Array, 37 | flags: Flags, 38 | pkg: Object, 39 | help: string, 40 | showHelp: Function 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var ver = process.versions.node; 4 | var majorVer = parseInt(ver.split('.')[0], 10); 5 | 6 | if (majorVer < 4) { 7 | console.error( 8 | 'Node version ' + 9 | ver + 10 | ' is not supported in Bolt, please use Node.js 4.0 or higher.' 11 | ); 12 | process.exit(1); 13 | } else if (majorVer < 8) { 14 | module.exports = require('./dist/legacy/index'); 15 | } else { 16 | module.exports = require('./dist/modern/index'); 17 | } 18 | -------------------------------------------------------------------------------- /src/GlobalOptions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Singleton that manages global bolt options. 3 | */ 4 | 5 | import * as options from './utils/options'; 6 | 7 | export type GlobalOptions = { 8 | disableCmdPrefix?: boolean 9 | }; 10 | class GlobalOptionsStore { 11 | store = { 12 | disableCmdPrefix: undefined 13 | }; 14 | set(key: $Keys, value: $PropertyType) { 15 | this.store[key] = value; 16 | } 17 | get(key: $Keys): $PropertyType { 18 | return this.store[key]; 19 | } 20 | getAll(): GlobalOptions { 21 | return this.store; 22 | } 23 | setFromFlags(flags: options.Flags) { 24 | if (flags.prefix === false) { 25 | this.set('disableCmdPrefix', true); 26 | } 27 | } 28 | } 29 | 30 | export const globalOptions = new GlobalOptionsStore(); 31 | -------------------------------------------------------------------------------- /src/Repository.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as git from './utils/git'; 3 | import { BoltError } from './utils/errors'; 4 | 5 | export default class Repository { 6 | dir: string; 7 | 8 | constructor(dir: string) { 9 | this.dir = dir; 10 | } 11 | 12 | static async init(cwd: string) { 13 | let dir = await git.getRootDirectory({ cwd }); 14 | 15 | if (!dir) { 16 | throw new BoltError( 17 | `There is no git repository in the current working directory` 18 | ); 19 | } 20 | 21 | return new Repository(dir); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/__fixtures__/dependent-workspaces-with-cycle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "dependent-workspaces-with-cycle", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/dependent-workspaces-with-cycle/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0", 4 | "devDependencies": { 5 | "foo": "^1.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__fixtures__/dependent-workspaces-with-cycle/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "bar": "^1.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__fixtures__/dependent-workspaces/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "dependent-workspaces", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/dependent-workspaces/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/dependent-workspaces/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "bar": "^1.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__fixtures__/dev-dependent-workspaces-only/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "description": "Contains two workspaces that are only dependent as a devDependency.", 4 | "name": "dev-dependent-workspaces-only", 5 | "version": "1.0.0", 6 | "bolt": { 7 | "workspaces": [ 8 | "packages/*" 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/__fixtures__/dev-dependent-workspaces-only/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/dev-dependent-workspaces-only/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "devDependencies": { 5 | "bar": "^1.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__fixtures__/independent-workspaces/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "independent-workspaces", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/independent-workspaces/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/independent-workspaces/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/invalid-project-root-dependency-on-ws/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "invalid-project-root-dependency-on-ws", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "foo": "^1.0.0" 7 | }, 8 | "bolt": { 9 | "workspaces": [ 10 | "packages/*" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/__fixtures__/invalid-project-root-dependency-on-ws/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/invalid-project-root-dependency-on-ws/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-transitive-dependents/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "version": "1.0.0", 4 | "name": "nested-workspaces-transitive-dependents", 5 | "description": "pkg-a is a leaf node, pkg-b and pkg-c exist under a nested workspace", 6 | "description2": "pkg-b depends on pkg-a directly, and pkg-c depends on pkg-b, thus transitively depends on pkg-a", 7 | "bolt": { 8 | "workspaces": ["packages/*"] 9 | }, 10 | "dependencies": { 11 | "react": "^15.6.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-transitive-dependents/packages/pkg-a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pkg-a", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "react": "^15.6.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-transitive-dependents/packages/workspace-a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workspace-a", 3 | "private": true, 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": ["packages/*"] 7 | }, 8 | "dependencies": { 9 | "react": "^15.6.1", 10 | "pkg-a": "^1.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-transitive-dependents/packages/workspace-a/packages/pkg-b/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pkg-b", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "react": "^15.6.1", 6 | "pkg-a": "^1.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-transitive-dependents/packages/workspace-a/packages/pkg-c/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pkg-c", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "react": "^15.6.1", 6 | "pkg-b": "^1.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nested-workspaces-with-muliple-binaries", 3 | "description": "A collection of packages with different types of binaries", 4 | "private": true, 5 | "version": "1.0.0", 6 | "bolt": { 7 | "workspaces": ["packages/*"] 8 | }, 9 | "dependencies": { 10 | "react": "^15.6.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/bar/bin/anotherBar.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/bar/bin/anotherBar.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/bar/bin/bar1.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/bar/bin/bar1.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scope/bar", 3 | "private": true, 4 | "version": "1.0.0", 5 | "bin": { 6 | "bar1": "bin/bar1.js", 7 | "bar2": "bin/anotherBar.js" 8 | }, 9 | "dependencies": { 10 | "react": "^15.6.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scope/foo", 3 | "version": "1.0.0", 4 | "bolt": { 5 | "workspaces": ["packages/*"] 6 | }, 7 | "dependencies": { 8 | "react": "^15.6.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/foo/packages/baz/baz.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/foo/packages/baz/baz.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/foo/packages/baz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scope/baz", 3 | "version": "1.0.0", 4 | "bin": "baz.js", 5 | "dependencies": { 6 | "react": "^15.6.1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/zee/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zee", 3 | "private": true, 4 | "version": "1.0.0", 5 | "bin": "zee.js", 6 | "dependencies": { 7 | "react": "^15.6.1" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/zee/zee.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-muliple-binaries/packages/zee/zee.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/.bin/external-dep-two-bins-1: -------------------------------------------------------------------------------- 1 | ../external-dep-with-two-bins/external-bin-1.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/.bin/external-dep-two-bins-2: -------------------------------------------------------------------------------- 1 | ../external-dep-with-two-bins/external-bin-2.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/.bin/external-dep-with-bin: -------------------------------------------------------------------------------- 1 | ../external-dep-with-bin/external-bin.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-alt-version/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "external-dep-alt-version", 3 | "version": "1.1.4" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-with-bin/external-bin.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-with-bin/external-bin.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-with-bin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "external-dep-with-bin", 3 | "version": "1.0.0", 4 | "bin": "./external-bin.js" 5 | } 6 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-with-two-bins/external-bin-1.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-with-two-bins/external-bin-1.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-with-two-bins/external-bin-2.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-with-two-bins/external-bin-2.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep-with-two-bins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "external-dep-with-two-bins", 3 | "version": "1.0.0", 4 | "bin": { 5 | "external-dep-two-bins-1": "./external-bin-1.js", 6 | "external-dep-two-bins-2": "./external-bin-2.js" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/node_modules/external-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "external-dep", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "version": "1.0.0", 4 | "name": "fixture-project-nested-workspaces-with-root-dependencies-installed", 5 | "description": "A project with only the root node_modules and symlinks already set up", 6 | "description2": "Packages: foo, bar, baz, zee", 7 | "description3": "bar has a single bin file, baz has two", 8 | "description4": "foo and baz depend on bar, zee depends on baz", 9 | "bolt": { 10 | "workspaces": [ 11 | "packages/*" 12 | ] 13 | }, 14 | "dependencies": { 15 | "external-dep": "^1.0.0", 16 | "external-dep-with-bin": "^1.0.0", 17 | "external-dep-with-two-bins": "^1.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/bar/bar.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/bar/bar.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "external-dep": "^1.0.0" 6 | }, 7 | "bin": "./bar.js" 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "bar": "^1.0.0", 6 | "external-dep": "^1.0.0", 7 | "external-dep-with-bin": "^1.0.0" 8 | }, 9 | "bolt": { 10 | "workspaces": ["packages/*"] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/foo/packages/baz/baz-bin-1.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/foo/packages/baz/baz-bin-1.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/foo/packages/baz/baz-bin-2.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/foo/packages/baz/baz-bin-2.js -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/foo/packages/baz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baz", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "bar": "^1.0.0" 6 | }, 7 | "bin": { 8 | "baz-1": "./baz-bin-1.js", 9 | "baz-2": "./baz-bin-2.js" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-root-dependencies-installed/packages/foo/packages/zee/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zee", 3 | "version": "1.0.0", 4 | "description": "We use the zee package to test all bin symlinking", 5 | "description2": "bar and external-dep-with-bin both have one bin", 6 | "description3": "baz and external-dep... both have two", 7 | "dependencies": { 8 | "bar": "^1.0.0", 9 | "baz": "^1.0.0", 10 | "external-dep-with-bin": "^1.0.0", 11 | "external-dep-with-two-bins": "^1.0.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fixture-project-nested-workspaces-with-scoped-packages", 3 | "description": "Same as scoped-workspaces but packages all have scoped names", 4 | "private": true, 5 | "version": "1.0.0", 6 | "bolt": { 7 | "workspaces": ["packages/*"] 8 | }, 9 | "dependencies": { 10 | "react": "^15.6.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/bar/node_modules/react: -------------------------------------------------------------------------------- 1 | ../../../node_modules/react -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scope/bar", 3 | "private": true, 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "react": "^15.6.1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/foo/node_modules/@scope/bar: -------------------------------------------------------------------------------- 1 | ../../../bar -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/foo/node_modules/@scoped/bar: -------------------------------------------------------------------------------- 1 | ../../../bar -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/foo/node_modules/react: -------------------------------------------------------------------------------- 1 | ../../../node_modules/react -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scope/foo", 3 | "version": "1.0.0", 4 | "bolt": { 5 | "workspaces": ["packages/*"] 6 | }, 7 | "dependencies": { 8 | "react": "^15.6.1", 9 | "@scope/bar": "^1.0.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/foo/packages/baz/node_modules/@scope/bar: -------------------------------------------------------------------------------- 1 | ../../../../../bar -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/foo/packages/baz/node_modules/@scoped/bar: -------------------------------------------------------------------------------- 1 | ../../../../../bar -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/foo/packages/baz/node_modules/react: -------------------------------------------------------------------------------- 1 | ../../../../../node_modules/react -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces-with-scoped-package-names/packages/foo/packages/baz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scope/baz", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "react": "^15.6.1", 6 | "@scope/bar": "^1.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "version": "1.0.0", 4 | "name": "fixture-project-nested-workspaces", 5 | "bolt": { 6 | "workspaces": ["packages/*"] 7 | }, 8 | "dependencies": { 9 | "react": "^15.6.1", 10 | "left-pad": "^1.1.3" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "react": "^15.6.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "test": "echo 'running test script in foo package'" 6 | }, 7 | "bolt": { 8 | "workspaces": ["packages/*"] 9 | }, 10 | "dependencies": { 11 | "react": "^15.6.1", 12 | "bar": "^1.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/__fixtures__/nested-workspaces/packages/foo/packages/baz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baz", 3 | "version": "1.0.1", 4 | "dependencies": { 5 | "react": "^15.6.1", 6 | "bar": "^1.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/no-package-json-workspace/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple-project", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/no-package-json-workspace/packages/bar/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/__fixtures__/no-package-json-workspace/packages/bar/.gitkeep -------------------------------------------------------------------------------- /src/__fixtures__/no-package-json-workspace/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/node_modules/foo-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo-dep", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/node_modules/global-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "global-dep", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/node_modules/project-only-dep-with-beta-tag/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "project-only-dep-with-beta-tag", 3 | "version": "1.0.1-beta" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/node_modules/project-only-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "project-only-dep", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "package-with-external-deps-installed", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | }, 10 | "devDependencies": { 11 | "foo-dep": "^1.0.0", 12 | "global-dep": "^1.0.0", 13 | "project-only-dep": "^1.0.0", 14 | "project-only-dep-with-beta-tag": "1.0.0-beta" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/packages/bar/node_modules/global-dep: -------------------------------------------------------------------------------- 1 | ../../../node_modules/global-dep -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0", 4 | "devDependencies": { 5 | "global-dep": "^1.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/packages/foo/node_modules/foo-dep: -------------------------------------------------------------------------------- 1 | ../../../node_modules/foo-dep -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/packages/foo/node_modules/global-dep: -------------------------------------------------------------------------------- 1 | ../../../node_modules/global-dep -------------------------------------------------------------------------------- /src/__fixtures__/package-with-external-deps-installed/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "foo-dep": "^1.0.0", 6 | "global-dep": "^1.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-four-spaces-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "four-spaces" 3 | } 4 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-invalid-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "invalid 3 | } 4 | -------------------------------------------------------------------------------- /src/__fixtures__/package-with-uncertain-indentation-json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uncertain-indentation" 3 | } 4 | -------------------------------------------------------------------------------- /src/__fixtures__/project-with-bins/node_modules/.bin/dep-with-bin: -------------------------------------------------------------------------------- 1 | ../dep-with-bin/bin.js -------------------------------------------------------------------------------- /src/__fixtures__/project-with-bins/node_modules/dep-with-bin/bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | console.log('Hello from dep-with-bin'); 4 | -------------------------------------------------------------------------------- /src/__fixtures__/project-with-bins/node_modules/dep-with-bin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dep-with-bin", 3 | "version": "1.0.0", 4 | "bin": "bin.js" 5 | } 6 | -------------------------------------------------------------------------------- /src/__fixtures__/project-with-bins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "project-with-bins", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | }, 10 | "dependencies": { 11 | "dep-with-bin": "^1.0.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/__fixtures__/project-with-bins/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/project-with-bins/packages/foo/node_modules/.bin/dep-with-bin: -------------------------------------------------------------------------------- 1 | ../../../../node_modules/.bin/dep-with-bin -------------------------------------------------------------------------------- /src/__fixtures__/project-with-bins/packages/foo/node_modules/dep-with-bin: -------------------------------------------------------------------------------- 1 | ../../../node_modules/dep-with-bin -------------------------------------------------------------------------------- /src/__fixtures__/project-with-bins/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "dep-with-bin": "^1.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fixture-basic" 3 | } 4 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-excluded-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple-project", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*", 8 | "!packages/bar" 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-excluded-package/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-excluded-package/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-multiple-depTypes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple-project-with-multiple-dep-types", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "depOnly": "^1.0.0" 7 | }, 8 | "devDependencies": { 9 | "devDepOnly": "^1.0.0", 10 | "react": "^16.0.0" 11 | }, 12 | "peerDependencies": { 13 | "peerDepOnly": "^1.0.0", 14 | "react": "^16.0.0" 15 | }, 16 | "bolt": { 17 | "workspaces": [ 18 | "packages/*" 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-multiple-depTypes/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-multiple-depTypes/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "devDependencies": { 5 | "react": "^16.0.0" 6 | }, 7 | "peerDependencies": { 8 | "react": "^16.0.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-private-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple-project", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-private-package/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0", 4 | "private": true 5 | } 6 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project-with-private-package/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple-project", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-project/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-repo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple-repo", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-repo/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/simple-repo/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/__fixtures__/workspace-with-bin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple-repo", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "workspaces": [ 7 | "packages/*" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__fixtures__/workspace-with-bin/packages/bar/bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | -------------------------------------------------------------------------------- /src/__fixtures__/workspace-with-bin/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0", 4 | "bin": "bin.js" 5 | } 6 | -------------------------------------------------------------------------------- /src/__fixtures__/workspace-with-bin/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "bar": "^1.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__tests__/Repository.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Repository from '../Repository'; 3 | import * as git from '../utils/git'; 4 | import * as fs from '../utils/fs'; 5 | import fixtures from 'fixturez'; 6 | 7 | const f = fixtures(__dirname); 8 | 9 | describe('Repository', () => { 10 | test('Repository.init()', async () => { 11 | let cwd = f.copy('simple-repo'); 12 | await expect(Repository.init(cwd)).rejects.toBeInstanceOf(Error); 13 | await git.initRepository({ cwd }); 14 | let repo = await Repository.init(cwd); 15 | expect(repo.dir).toBe(cwd); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/__tests__/autoclean.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { toAutocleanOptions, autoclean } from '../autoclean'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | jest.mock('../../utils/yarn'); 7 | 8 | const projectDirMock = 'dummyPattern/dummyPath'; 9 | 10 | describe('bolt autoclean', () => { 11 | it('should call yarn cliCommand with autoClean and path to project', async () => { 12 | await autoclean(toAutocleanOptions([], { cwd: projectDirMock })); 13 | expect(yarn.cliCommand).toHaveBeenCalledWith(projectDirMock, 'autoclean'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/commands/__tests__/bin.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { bin, toBinOptions } from '../bin'; 3 | 4 | test('bolt bin'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/build.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { build, toBuildOptions } from '../build'; 3 | 4 | test('bolt build'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/check.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { check, toCheckOptions } from '../check'; 3 | 4 | test('bolt check'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/create.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { create, toCreateOptions } from '../create'; 3 | import * as yarn from '../../utils/yarn'; 4 | 5 | jest.mock('../../utils/yarn'); 6 | 7 | describe('bolt create', () => { 8 | it('should be able to pass down arguments down to yarn create', async () => { 9 | await create( 10 | toCreateOptions(['react-app', 'my-app'], { 11 | cwd: 'dummyPattern/dummyPath' 12 | }) 13 | ); 14 | expect(yarn.cliCommand).toHaveBeenCalledWith( 15 | 'dummyPattern/dummyPath', 16 | 'create', 17 | ['react-app', 'my-app'] 18 | ); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/commands/__tests__/doc.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { doc, toDocOptions } from '../doc'; 3 | 4 | test('bolt doc'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/exec.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { exec, toExecOptions } from '../exec'; 3 | import * as path from 'path'; 4 | import * as processes from '../../utils/processes'; 5 | import containDeep from 'jest-expect-contain-deep'; 6 | import fixtures from 'fixturez'; 7 | 8 | const f = fixtures(__dirname); 9 | 10 | jest.mock('../../utils/processes'); 11 | const unsafeProcesses: any & typeof processes = processes; 12 | const binDir = path.join('node_modules', '.bin'); 13 | 14 | describe('bolt exec', () => { 15 | test('running in a project', async () => { 16 | let projectDir = f.copy('project-with-bins'); 17 | let projectBinDir = path.join(projectDir, binDir); 18 | 19 | await exec( 20 | toExecOptions([], { 21 | cwd: projectDir, 22 | '--': ['dep-with-bin'] 23 | }) 24 | ); 25 | 26 | expect(unsafeProcesses.spawn).toHaveBeenCalledTimes(1); 27 | expect(unsafeProcesses.spawn).toHaveBeenCalledWith( 28 | 'dep-with-bin', 29 | [], 30 | containDeep({ 31 | cwd: projectDir, 32 | env: { 33 | PATH: expect.stringContaining(projectBinDir) 34 | } 35 | }) 36 | ); 37 | }); 38 | 39 | test('running in a workspace', async () => { 40 | let projectDir = f.copy('project-with-bins'); 41 | let fooWorkspaceDir = path.join(projectDir, 'packages', 'foo'); 42 | let projectBinDir = path.join(projectDir, binDir); 43 | let fooBinDir = path.join(fooWorkspaceDir, binDir); 44 | 45 | await exec( 46 | toExecOptions([], { 47 | cwd: fooWorkspaceDir, 48 | '--': ['dep-with-bin'] 49 | }) 50 | ); 51 | 52 | expect(unsafeProcesses.spawn).toHaveBeenCalledTimes(1); 53 | expect(unsafeProcesses.spawn).toHaveBeenCalledWith( 54 | 'dep-with-bin', 55 | [], 56 | containDeep({ 57 | cwd: fooWorkspaceDir, 58 | env: { 59 | PATH: expect.stringContaining(fooBinDir + ':' + projectBinDir) 60 | } 61 | }) 62 | ); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /src/commands/__tests__/format.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { format, toFormatOptions } from '../format'; 3 | 4 | test('bolt format'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/generate.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { generate, toGenerateOptions } from '../generate'; 3 | 4 | test('bolt generate'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/help.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { help, toHelpOptions } from '../help'; 3 | import * as messages from '../../utils/messages'; 4 | 5 | describe('bolt help', () => { 6 | let consoleLogSpy; 7 | beforeEach(() => { 8 | consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); 9 | }); 10 | afterEach(() => { 11 | consoleLogSpy.mockRestore(); 12 | }); 13 | 14 | it('should return the default help message when no subcommand is passed', async () => { 15 | await help(toHelpOptions([], {})); 16 | expect(consoleLogSpy).toHaveBeenCalledTimes(1); 17 | expect(consoleLogSpy).toHaveBeenCalledWith(messages.helpContent()); 18 | }); 19 | 20 | it('should throw an error when called with a subcommand', async () => { 21 | await expect(help(toHelpOptions(['install'], {}))).rejects.toBeInstanceOf( 22 | Error 23 | ); 24 | expect(consoleLogSpy).toHaveBeenCalledTimes(0); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/commands/__tests__/import.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { import_, toImportOptions } from '../import'; 3 | import * as yarn from '../../utils/yarn'; 4 | 5 | jest.mock('../../utils/yarn'); 6 | 7 | const projectDirMock = 'dummyPattern/dummyPath'; 8 | 9 | describe('bolt import', () => { 10 | it('should call yarn cliCommand with autoClean and path to project', async () => { 11 | await import_(toImportOptions([], { cwd: projectDirMock })); 12 | expect(yarn.cliCommand).toHaveBeenCalledWith(projectDirMock, 'import'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/commands/__tests__/info.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { info, toInfoOptions } from '../info'; 3 | 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | jest.mock('../../utils/yarn'); 7 | 8 | const cwd = 'dummy/path/to/dir'; 9 | const args = ['react']; 10 | const flags = { cwd, json: true }; 11 | const opt = { flags, args }; 12 | 13 | describe('bolt info', () => { 14 | test('should return the expected cwd', () => { 15 | let result = toInfoOptions(args, flags); 16 | expect(result.cwd).toBe(cwd); 17 | }); 18 | 19 | test('should return the expected argument', () => { 20 | let result = toInfoOptions(args, flags); 21 | expect(result.args).toBe(args); 22 | }); 23 | 24 | test('should return the expected flags', () => { 25 | let result = toInfoOptions(args, flags); 26 | expect(result.flags).toBe(flags); 27 | }); 28 | 29 | test('should call npm login once', async () => { 30 | await info(opt); 31 | expect(yarn.info).toHaveBeenCalledTimes(1); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/commands/__tests__/init.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { init, toInitOptions } from '../init'; 3 | import * as yarn from '../../utils/yarn'; 4 | import * as prompts from '../../utils/prompts'; 5 | import Package from '../../Package'; 6 | 7 | jest.mock('../../utils/yarn'); 8 | jest.mock('../../utils/prompts'); 9 | 10 | const dummyPath = '/dummyPattern/dummyPath'; 11 | describe('bolt init', () => { 12 | it('should be able to pass yes to yarn when y flag is passed', async () => { 13 | await init(toInitOptions([], { cwd: dummyPath, y: true })); 14 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'init', [ 15 | '-s', 16 | '-y' 17 | ]); 18 | }); 19 | 20 | it('should be able to pass yes to yarn when yes flag is passes', async () => { 21 | await init(toInitOptions([], { cwd: dummyPath, yes: true })); 22 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'init', [ 23 | '-s', 24 | '-y' 25 | ]); 26 | }); 27 | 28 | it('should be able to pass private to yarn when p flag is passed', async () => { 29 | await init(toInitOptions([], { cwd: dummyPath, p: true })); 30 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'init', [ 31 | '-s', 32 | '-p' 33 | ]); 34 | }); 35 | 36 | it('should be able to pass private to yarn when private flag is passes', async () => { 37 | await init(toInitOptions([], { cwd: dummyPath, private: true })); 38 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'init', [ 39 | '-s', 40 | '-p' 41 | ]); 42 | }); 43 | 44 | it('should be able to pass yes and private to yarn when private and yes flag is passes', async () => { 45 | await init(toInitOptions([], { cwd: dummyPath, private: true, yes: true })); 46 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'init', [ 47 | '-s', 48 | '-p', 49 | '-y' 50 | ]); 51 | }); 52 | 53 | it('should be able to add workspaces', async () => { 54 | await init(toInitOptions([], { cwd: dummyPath })); 55 | expect(prompts.isWorkspaceNeeded).toHaveBeenCalledTimes(1); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/commands/__tests__/link.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { link, toLinkOptions } from '../link'; 3 | import * as yarn from '../../utils/yarn'; 4 | import * as logger from '../../utils/logger'; 5 | import fixtures from 'fixturez'; 6 | 7 | const f = fixtures(__dirname); 8 | 9 | jest.mock('../../utils/yarn'); 10 | jest.mock('../../utils/logger'); 11 | 12 | describe('bolt link', () => { 13 | let projectDir; 14 | 15 | beforeEach(() => { 16 | projectDir = f.copy('package-with-external-deps-installed'); 17 | }); 18 | 19 | it('should show warning on linking internal dependency', async () => { 20 | await link(toLinkOptions(['foo'], { cwd: projectDir })); 21 | expect(logger.warn).toHaveBeenCalled(); 22 | }); 23 | 24 | it('should call yarn link for extenal package', async () => { 25 | await link(toLinkOptions(['some-external-package'], { cwd: projectDir })); 26 | expect(yarn.cliCommand).toHaveBeenCalled(); 27 | }); 28 | 29 | it('should call yarn link for all extenal package and show warning for all internal dependency', async () => { 30 | await link( 31 | toLinkOptions( 32 | [ 33 | 'some-external-package', 34 | 'foo', 35 | 'bar', 36 | 'someother-external-dependency' 37 | ], 38 | { cwd: projectDir } 39 | ) 40 | ); 41 | expect(yarn.cliCommand).toHaveBeenCalledTimes(2); 42 | expect(logger.warn).toHaveBeenCalledTimes(2); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /src/commands/__tests__/lint.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { lint, toLintOptions } from '../lint'; 3 | 4 | test('bolt lint'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/list.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { list, toListOptions } from '../list'; 3 | 4 | test('bolt list'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/login.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { login, toLoginOptions } from '../login'; 3 | import * as npm from '../../utils/npm'; 4 | 5 | jest.mock('../../utils/npm'); 6 | 7 | describe('bolt login', () => { 8 | test('should return the expected cwd', () => { 9 | let commandArgs = []; 10 | let expectedCwd = 'dummy/path/to/dir'; 11 | let flags = { cwd: expectedCwd }; 12 | let result = toLoginOptions(commandArgs, flags); 13 | expect(result.cwd).toBe(expectedCwd); 14 | }); 15 | 16 | test('should call npm login once', async () => { 17 | let cwd = 'dummy/path/to/dir'; 18 | let opt = { cwd }; 19 | await login(opt); 20 | expect(npm.login).toHaveBeenCalledTimes(1); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/commands/__tests__/logout.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { logout, toLogoutOptions } from '../logout'; 3 | import * as npm from '../../utils/npm'; 4 | 5 | jest.mock('../../utils/npm'); 6 | 7 | describe('bolt logout', () => { 8 | test('should return the expected cwd', () => { 9 | let commandArgs = []; 10 | let expectedCwd = 'dummy/path/to/dir'; 11 | let flags = { cwd: expectedCwd }; 12 | let result = toLogoutOptions(commandArgs, flags); 13 | expect(result.cwd).toBe(expectedCwd); 14 | }); 15 | 16 | test('should call npm logout once', async () => { 17 | let cwd = 'dummy/path/to/dir'; 18 | let opt = { cwd }; 19 | await logout(opt); 20 | expect(npm.logout).toHaveBeenCalledTimes(1); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/commands/__tests__/normalize.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { normalize, toNormalizeOptions } from '../normalize'; 3 | 4 | test('bolt normalize'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/outdated.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { outdated, toOutdatedOptions } from '../outdated'; 3 | import * as yarn from '../../utils/yarn'; 4 | 5 | jest.mock('../../utils/yarn'); 6 | 7 | describe('bolt outdated', () => { 8 | it('should be able to pass arguments to yarn outdated', async () => { 9 | await outdated( 10 | toOutdatedOptions(['jest'], { 11 | cwd: 'dummyPattern/dummyPath' 12 | }) 13 | ); 14 | expect(yarn.cliCommand).toHaveBeenCalledWith( 15 | 'dummyPattern/dummyPath', 16 | 'outdated', 17 | ['jest'] 18 | ); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/commands/__tests__/pack.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { pack, toPackOptions } from '../pack'; 3 | import * as yarn from '../../utils/yarn'; 4 | 5 | jest.mock('../../utils/yarn'); 6 | 7 | describe('bolt pack', () => { 8 | it('should be able to handle filename flag', async () => { 9 | await pack( 10 | toPackOptions([], { 11 | cwd: 'dummyPattern/dummyPath', 12 | filename: 'my-app' 13 | }) 14 | ); 15 | expect(yarn.cliCommand).toHaveBeenCalledWith( 16 | 'dummyPattern/dummyPath', 17 | 'pack', 18 | ['--filename=my-app'] 19 | ); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/commands/__tests__/publishLock.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { publishLock, toPublishLockOptions } from '../publishLock'; 3 | 4 | test('bolt publish-lock'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/publishUnlock.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { publishUnlock, toPublishUnlockOptions } from '../publishUnlock'; 3 | 4 | test('bolt publish-unlock'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/run.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { run, toRunOptions } from '../run'; 3 | 4 | test('bolt run'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/test.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { test as test_, toTestOptions } from '../test'; 3 | 4 | test('bolt test'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/unlink.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { unlink, toUnlinkOptions } from '../unlink'; 3 | import * as yarn from '../../utils/yarn'; 4 | import * as logger from '../../utils/logger'; 5 | import fixtures from 'fixturez'; 6 | 7 | const f = fixtures(__dirname); 8 | 9 | jest.mock('../../utils/yarn'); 10 | jest.mock('../../utils/logger'); 11 | 12 | describe('bolt unlink', () => { 13 | let projectDir; 14 | 15 | beforeEach(() => { 16 | projectDir = f.copy('package-with-external-deps-installed'); 17 | }); 18 | 19 | it('should warn if unlink a internal package', async () => { 20 | await unlink(toUnlinkOptions(['foo'], { cwd: projectDir })); 21 | expect(logger.warn).toHaveBeenCalled(); 22 | }); 23 | 24 | it('should call yarn unlink if unlinking an external internal package', async () => { 25 | await unlink(toUnlinkOptions(['external-package'], { cwd: projectDir })); 26 | expect(yarn.cliCommand).toHaveBeenCalled(); 27 | }); 28 | 29 | it('should call yarn unlink for all external packages and warn for internal packages', async () => { 30 | await unlink( 31 | toUnlinkOptions( 32 | ['external-package', 'foo', 'bar', 'someother-external-package'], 33 | { cwd: projectDir } 34 | ) 35 | ); 36 | expect(logger.warn).toHaveBeenCalledTimes(2); 37 | expect(yarn.cliCommand).toHaveBeenCalledTimes(2); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/commands/__tests__/upgradeInteractive.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | upgradeInteractive, 4 | toUpgradeInteractiveOptions 5 | } from '../upgradeInteractive'; 6 | 7 | test('bolt upgrade-interactive'); 8 | -------------------------------------------------------------------------------- /src/commands/__tests__/version.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { version, toVersionOptions } from '../version'; 3 | 4 | test('bolt version'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/versions.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { versions, toVersionsOptions } from '../versions'; 3 | 4 | test('bolt versions'); 5 | -------------------------------------------------------------------------------- /src/commands/__tests__/why.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { why, toWhyOptions } from '../why'; 3 | import * as yarn from '../../utils/yarn'; 4 | 5 | jest.mock('../../utils/yarn'); 6 | 7 | describe('bolt why', () => { 8 | it('should be able to handle arguments', async () => { 9 | await why( 10 | toWhyOptions(['jest'], { 11 | cwd: 'dummyPattern/dummyPath' 12 | }) 13 | ); 14 | expect(yarn.cliCommand).toHaveBeenCalledWith( 15 | 'dummyPattern/dummyPath', 16 | 'why', 17 | ['jest'] 18 | ); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/commands/add.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import Package from '../Package'; 4 | import * as options from '../utils/options'; 5 | import * as logger from '../utils/logger'; 6 | import addDependenciesToPackage from '../utils/addDependenciesToPackages'; 7 | import type { Dependency, configDependencyType } from '../types'; 8 | import { DEPENDENCY_TYPE_FLAGS_MAP } from '../constants'; 9 | import type { ProjectAddOptions } from './project/add'; 10 | 11 | export type AddOptions = { 12 | cwd?: string, 13 | deps: Array, 14 | type: configDependencyType 15 | }; 16 | 17 | export function toAddOptions( 18 | args: options.Args, 19 | flags: options.Flags 20 | ): AddOptions { 21 | let depsArgs = []; 22 | let type = 'dependencies'; 23 | 24 | // args is each of our dependencies we are adding which may have "@version" parts to them 25 | args.forEach(dep => { 26 | depsArgs.push(options.toDependency(dep)); 27 | }); 28 | 29 | Object.keys(DEPENDENCY_TYPE_FLAGS_MAP).forEach(depTypeFlag => { 30 | if (flags[depTypeFlag]) { 31 | type = DEPENDENCY_TYPE_FLAGS_MAP[depTypeFlag]; 32 | // check if value of dependency flag is a package name and then push to dependency arguments 33 | if (typeof flags[depTypeFlag] === 'string') { 34 | depsArgs.push(options.toDependency(flags[depTypeFlag])); 35 | } 36 | } 37 | }); 38 | 39 | return { 40 | cwd: options.string(flags.cwd, 'cwd'), 41 | deps: depsArgs, 42 | type 43 | }; 44 | } 45 | 46 | export async function add(opts: AddOptions | ProjectAddOptions) { 47 | let cwd = opts.cwd || process.cwd(); 48 | let project = await Project.init(cwd); 49 | let pkg = await Package.closest(cwd); 50 | await addDependenciesToPackage(project, pkg, opts.deps, opts.type); 51 | } 52 | -------------------------------------------------------------------------------- /src/commands/autoclean.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as yarn from '../utils/yarn'; 5 | 6 | export type AutocleanOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toAutocleanOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): AutocleanOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function autoclean(opts: AutocleanOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | 22 | try { 23 | await yarn.cliCommand(cwd, 'autoclean'); 24 | } catch (err) { 25 | throw new BoltError(err); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/bin.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as yarn from '../utils/yarn'; 3 | import * as options from '../utils/options'; 4 | import { BoltError } from '../utils/errors'; 5 | 6 | export type BinOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toBinOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): BinOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function bin(opts: BinOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | 22 | try { 23 | await yarn.cliCommand(cwd, 'bin'); 24 | } catch (err) { 25 | throw new BoltError(err); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/build.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import { run } from './run'; 5 | 6 | export type BuildOptions = {| 7 | cwd?: string, 8 | args: options.Args 9 | |}; 10 | 11 | export function toBuildOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): BuildOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args: args 18 | }; 19 | } 20 | 21 | export async function build(opts: BuildOptions) { 22 | await run({ 23 | cwd: opts.cwd, 24 | script: 'build', 25 | scriptArgs: opts.args 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/cache/__tests__/clean.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { cacheClean, toCacheCleanOptions } from '../clean'; 3 | import * as yarn from '../../../utils/yarn'; 4 | 5 | jest.mock('../../../utils/yarn'); 6 | 7 | describe('bolt cache clean', () => { 8 | it('should handle situation where no arguments are passed', async () => { 9 | await cacheClean( 10 | toCacheCleanOptions([], { 11 | cwd: 'dummyPattern/dummyPath' 12 | }) 13 | ); 14 | expect(yarn.cliCommand).toHaveBeenCalledWith( 15 | 'dummyPattern/dummyPath', 16 | 'cache', 17 | ['clean'] 18 | ); 19 | }); 20 | 21 | it('should handle passing the arguments down to yarn clean', async () => { 22 | await cacheClean( 23 | toCacheCleanOptions(['jest'], { 24 | cwd: 'dummyPattern/dummyPath' 25 | }) 26 | ); 27 | expect(yarn.cliCommand).toHaveBeenCalledWith( 28 | 'dummyPattern/dummyPath', 29 | 'cache', 30 | ['clean', 'jest'] 31 | ); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/commands/cache/__tests__/dir.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { cacheDir, toCacheDirOptions } from '../dir'; 3 | import * as yarn from '../../../utils/yarn'; 4 | 5 | jest.mock('../../../utils/yarn'); 6 | 7 | describe('bolt cache dir', () => { 8 | it('should call yarn cache with dir command', async () => { 9 | await cacheDir( 10 | toCacheDirOptions([], { 11 | cwd: 'dummyPattern/dummyPath' 12 | }) 13 | ); 14 | expect(yarn.cliCommand).toHaveBeenCalledWith( 15 | 'dummyPattern/dummyPath', 16 | 'cache', 17 | ['dir'] 18 | ); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/commands/cache/__tests__/list.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { cacheList, toCacheListOptions } from '../list'; 3 | import * as yarn from '../../../utils/yarn'; 4 | 5 | jest.mock('../../../utils/yarn'); 6 | 7 | describe('bolt cache list', () => { 8 | it('should handle situation where no arguments are passed', async () => { 9 | await cacheList( 10 | toCacheListOptions([], { 11 | cwd: 'dummyPattern/dummyPath' 12 | }) 13 | ); 14 | expect(yarn.cliCommand).toHaveBeenCalledWith( 15 | 'dummyPattern/dummyPath', 16 | 'cache', 17 | ['list'] 18 | ); 19 | }); 20 | 21 | it('should handle --pattern flag', async () => { 22 | await cacheList( 23 | toCacheListOptions([], { 24 | cwd: 'dummyPattern/dummyPath', 25 | pattern: 'jest' 26 | }) 27 | ); 28 | expect(yarn.cliCommand).toHaveBeenCalledWith( 29 | 'dummyPattern/dummyPath', 30 | 'cache', 31 | ['list', '--pattern=jest'] 32 | ); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/commands/cache/clean.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type CacheCleanOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toCacheCleanOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): CacheCleanOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args: args || [] 18 | }; 19 | } 20 | 21 | export async function cacheClean(opts: CacheCleanOptions) { 22 | let cwd = opts.cwd || process.cwd(); 23 | let args = ['clean']; 24 | 25 | if (opts.args.length) { 26 | args = args.concat(opts.args); 27 | } 28 | try { 29 | await yarn.cliCommand(cwd, 'cache', args); 30 | } catch (err) { 31 | throw new BoltError(err); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/cache/dir.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type CacheDirOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toCacheDirOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): CacheDirOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function cacheDir(opts: CacheDirOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | 22 | try { 23 | await yarn.cliCommand(cwd, 'cache', ['dir']); 24 | } catch (err) { 25 | throw new BoltError(err); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/cache/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./clean'), 4 | ...require('./dir'), 5 | ...require('./list') 6 | }; 7 | -------------------------------------------------------------------------------- /src/commands/cache/list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type CacheListOptions = { 7 | cwd?: string, 8 | pattern?: string 9 | }; 10 | 11 | export function toCacheListOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): CacheListOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | pattern: options.string(flags.pattern, 'pattern') || '' 18 | }; 19 | } 20 | 21 | export async function cacheList(opts: CacheListOptions) { 22 | let cwd = opts.cwd || process.cwd(); 23 | let args = ['list']; 24 | if (opts.pattern) { 25 | args = args.concat([`--pattern=${opts.pattern}`]); 26 | } 27 | 28 | try { 29 | await yarn.cliCommand(cwd, 'cache', args); 30 | } catch (err) { 31 | throw new BoltError(err); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/check.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import { run } from './run'; 5 | 6 | export type CheckOptions = {| 7 | cwd?: string, 8 | args: options.Args 9 | |}; 10 | 11 | export function toCheckOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): CheckOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args: args 18 | }; 19 | } 20 | 21 | export async function check(opts: CheckOptions) { 22 | await run({ 23 | cwd: opts.cwd, 24 | script: 'check', 25 | scriptArgs: opts.args 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/config/__tests__/current.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { configCurrent, toConfigCurrentOptions } from '../current'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt config current', async () => { 10 | let config = await configCurrent({ cwd: dummyPath }); 11 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'config', [ 12 | 'current' 13 | ]); 14 | }); 15 | -------------------------------------------------------------------------------- /src/commands/config/__tests__/delete.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { configDelete, toConfigDeleteOptions } from '../delete'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt config delete', async () => { 10 | let config = await configDelete( 11 | toConfigDeleteOptions(['user-agent'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'config', [ 14 | 'delete', 15 | 'user-agent' 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/config/__tests__/get.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { configGet, toConfigGetOptions } from '../get'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt config get', async () => { 10 | let config = await configGet( 11 | toConfigGetOptions(['user-agent'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'config', [ 14 | 'get', 15 | 'user-agent' 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/config/__tests__/list.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { configList, toConfigListOptions } from '../list'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt config list', async () => { 10 | let config = await configList({ cwd: dummyPath }); 11 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'config', ['list']); 12 | }); 13 | -------------------------------------------------------------------------------- /src/commands/config/__tests__/set.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { configSet, toConfigSetOptions } from '../set'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt config set', async () => { 10 | let config = await configSet( 11 | toConfigSetOptions(['user.email', 'test@example.com'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'config', [ 14 | 'set', 15 | 'user.email', 16 | 'test@example.com' 17 | ]); 18 | }); 19 | -------------------------------------------------------------------------------- /src/commands/config/current.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type ConfigCurrentOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toConfigCurrentOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): ConfigCurrentOptions { 14 | return { cwd: options.string(flags.cwd, 'cwd') }; 15 | } 16 | 17 | export async function configCurrent(opts: ConfigCurrentOptions) { 18 | let cwd = opts.cwd || process.cwd(); 19 | try { 20 | await yarn.cliCommand(cwd, 'config', ['current']); 21 | } catch (err) { 22 | throw new BoltError(err); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/commands/config/delete.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type ConfigDeleteOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toConfigDeleteOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): ConfigDeleteOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function configDelete(opts: ConfigDeleteOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await yarn.cliCommand(cwd, 'config', ['delete', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/config/get.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type ConfigGetOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toConfigGetOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): ConfigGetOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function configGet(opts: ConfigGetOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await yarn.cliCommand(cwd, 'config', ['get', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/config/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./current'), 4 | ...require('./delete'), 5 | ...require('./get'), 6 | ...require('./list'), 7 | ...require('./set') 8 | }; 9 | -------------------------------------------------------------------------------- /src/commands/config/list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type ConfigListOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toConfigListOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): ConfigListOptions { 14 | if (args.length !== 0) { 15 | throw new BoltError('Invalid subcommand, try bolt config list'); 16 | } 17 | return { cwd: options.string(flags.cwd, 'cwd') }; 18 | } 19 | 20 | export async function configList(opts: ConfigListOptions) { 21 | let cwd = opts.cwd || process.cwd(); 22 | try { 23 | await yarn.cliCommand(cwd, 'config', ['list']); 24 | } catch (err) { 25 | throw new BoltError(err); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/config/set.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type ConfigSetOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toConfigSetOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): ConfigSetOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function configSet(opts: ConfigSetOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await yarn.cliCommand(cwd, 'config', ['set', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/create.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as yarn from '../utils/yarn'; 5 | 6 | export type CreateOptions = { 7 | cwd?: string, 8 | args?: Array 9 | }; 10 | 11 | export function toCreateOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): CreateOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args 18 | }; 19 | } 20 | 21 | export async function create(opts: CreateOptions) { 22 | let cwd = opts.cwd || process.cwd(); 23 | 24 | try { 25 | await yarn.cliCommand(cwd, 'create', opts.args); 26 | } catch (err) { 27 | throw new BoltError(err); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/commands/doc.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import { run } from './run'; 5 | 6 | export type DocOptions = {| 7 | cwd?: string, 8 | args: options.Args 9 | |}; 10 | 11 | export function toDocOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): DocOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args: args 18 | }; 19 | } 20 | 21 | export async function doc(opts: DocOptions) { 22 | await run({ 23 | cwd: opts.cwd, 24 | script: 'doc', 25 | scriptArgs: opts.args 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/exec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import Package from '../Package'; 4 | import * as options from '../utils/options'; 5 | import execCommand from '../utils/execCommand'; 6 | 7 | export type ExecOptions = {| 8 | cwd?: string, 9 | command: string, 10 | commandArgs: options.Args 11 | |}; 12 | 13 | export function toExecOptions( 14 | args: options.Args, 15 | flags: options.Flags 16 | ): ExecOptions { 17 | let [command, ...commandArgs] = flags['--'] || []; 18 | return { 19 | cwd: options.string(flags.cwd, 'cwd'), 20 | command, 21 | commandArgs 22 | }; 23 | } 24 | 25 | export async function exec(opts: ExecOptions) { 26 | let cwd = opts.cwd || process.cwd(); 27 | let project = await Project.init(cwd); 28 | let pkg = await Package.closest(cwd); 29 | return await execCommand(project, pkg, opts.command, opts.commandArgs); 30 | } 31 | -------------------------------------------------------------------------------- /src/commands/format.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import { run } from './run'; 5 | 6 | export type FormatOptions = {| 7 | cwd?: string, 8 | args: options.Args 9 | |}; 10 | 11 | export function toFormatOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): FormatOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args: args 18 | }; 19 | } 20 | 21 | export async function format(opts: FormatOptions) { 22 | await run({ 23 | cwd: opts.cwd, 24 | script: 'format', 25 | scriptArgs: opts.args 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/generate.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | 5 | export type GenerateOptions = {}; 6 | 7 | export function toGenerateOptions( 8 | args: options.Args, 9 | flags: options.Flags 10 | ): GenerateOptions { 11 | return {}; 12 | } 13 | 14 | export async function generate(opts: GenerateOptions) { 15 | throw new BoltError('Unimplemented command "generate"'); 16 | } 17 | -------------------------------------------------------------------------------- /src/commands/global/__tests__/add.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { globalAdd, toGlobalAddOptions } from '../add'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt global add', async () => { 10 | let tag = await globalAdd( 11 | toGlobalAddOptions(['test-tag'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.globalCli).toHaveBeenCalledWith('add', [{ name: 'test-tag' }]); 14 | }); 15 | -------------------------------------------------------------------------------- /src/commands/global/__tests__/bin.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { globalBin, toGlobalBinOptions } from '../bin'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt global bin', async () => { 10 | let tag = await globalBin(toGlobalBinOptions([], { cwd: dummyPath })); 11 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'global', ['bin']); 12 | }); 13 | -------------------------------------------------------------------------------- /src/commands/global/__tests__/list.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { globalList, toGlobalListOptions } from '../list'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt global list', async () => { 10 | let tag = await globalList( 11 | toGlobalListOptions(['test-tag'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'global', [ 14 | 'list', 15 | 'test-tag' 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/global/__tests__/remove.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { globalRemove, toGlobalRemoveOptions } from '../remove'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt global remove', async () => { 10 | let tag = await globalRemove( 11 | toGlobalRemoveOptions(['test-tag'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.globalCli).toHaveBeenCalledWith('remove', [{ name: 'test-tag' }]); 14 | }); 15 | -------------------------------------------------------------------------------- /src/commands/global/__tests__/upgrade.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { globalUpgrade, toGlobalUpgradeOptions } from '../upgrade'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt global upgrade', async () => { 10 | let tag = await globalUpgrade( 11 | toGlobalUpgradeOptions(['test-tag'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.globalCli).toHaveBeenCalledWith('upgrade', [ 14 | { name: 'test-tag' } 15 | ]); 16 | }); 17 | -------------------------------------------------------------------------------- /src/commands/global/add.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import type { Dependency } from '../../types'; 5 | import { BoltError } from '../../utils/errors'; 6 | 7 | export type GlobalAddOptions = { 8 | deps: Array 9 | }; 10 | 11 | export function toGlobalAddOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): GlobalAddOptions { 15 | let depsArgs = []; 16 | 17 | // args is each of our dependencies we are adding which may have "@version" parts to them 18 | args.forEach(dep => { 19 | depsArgs.push(options.toDependency(dep)); 20 | }); 21 | 22 | return { 23 | deps: depsArgs 24 | }; 25 | } 26 | 27 | export async function globalAdd(opts: GlobalAddOptions) { 28 | try { 29 | await yarn.globalCli('add', opts.deps); 30 | } catch (err) { 31 | throw new BoltError(err); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/global/bin.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type GlobalBinOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toGlobalBinOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): GlobalBinOptions { 14 | return { cwd: options.string(flags.cwd, 'cwd') }; 15 | } 16 | 17 | export async function globalBin(opts: GlobalBinOptions) { 18 | let cwd = opts.cwd || process.cwd(); 19 | try { 20 | await yarn.cliCommand(cwd, 'global', ['bin']); 21 | } catch (err) { 22 | throw new BoltError(err); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/commands/global/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./add'), 4 | ...require('./bin'), 5 | ...require('./list'), 6 | ...require('./remove'), 7 | ...require('./upgrade') 8 | }; 9 | -------------------------------------------------------------------------------- /src/commands/global/list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type GlobalListOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toGlobalListOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): GlobalListOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function globalList(opts: GlobalListOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | let args = opts.args || []; 21 | try { 22 | await yarn.cliCommand(cwd, 'global', ['list', ...opts.args]); 23 | } catch (err) { 24 | throw new BoltError(err); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/commands/global/remove.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import type { Dependency } from '../../types'; 5 | import { BoltError } from '../../utils/errors'; 6 | 7 | export type GlobalRemoveOptions = { 8 | deps: Array 9 | }; 10 | 11 | export function toGlobalRemoveOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): GlobalRemoveOptions { 15 | let depsArgs = []; 16 | 17 | // args is each of our dependencies we are adding which may have "@version" parts to them 18 | args.forEach(dep => { 19 | depsArgs.push(options.toDependency(dep)); 20 | }); 21 | 22 | return { 23 | deps: depsArgs 24 | }; 25 | } 26 | 27 | export async function globalRemove(opts: GlobalRemoveOptions) { 28 | try { 29 | await yarn.globalCli('remove', opts.deps); 30 | } catch (err) { 31 | throw new BoltError(err); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/global/upgrade.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import type { Dependency } from '../../types'; 5 | import { BoltError } from '../../utils/errors'; 6 | 7 | export type GlobalUpgradeOptions = { 8 | deps: Array 9 | }; 10 | 11 | export function toGlobalUpgradeOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): GlobalUpgradeOptions { 15 | let depsArgs = []; 16 | 17 | // args is each of our dependencies we are adding which may have "@version" parts to them 18 | args.forEach(dep => { 19 | depsArgs.push(options.toDependency(dep)); 20 | }); 21 | 22 | return { 23 | deps: depsArgs 24 | }; 25 | } 26 | 27 | export async function globalUpgrade(opts: GlobalUpgradeOptions) { 28 | try { 29 | await yarn.globalCli('upgrade', opts.deps); 30 | } catch (err) { 31 | throw new BoltError(err); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/commands/help.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as messages from '../utils/messages'; 5 | 6 | export type HelpOptions = { 7 | command?: string 8 | }; 9 | 10 | export function toHelpOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): HelpOptions { 14 | return { 15 | command: args.length > 0 ? args[0] : undefined 16 | }; 17 | } 18 | 19 | export async function help(opts: HelpOptions) { 20 | if (opts.command) { 21 | throw new BoltError('Subcommand help information is not available yet.'); 22 | } else { 23 | console.log(messages.helpContent()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/import.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as yarn from '../utils/yarn'; 5 | 6 | export type ImportOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toImportOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): ImportOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function import_(opts: ImportOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | 22 | try { 23 | await yarn.cliCommand(cwd, 'import'); 24 | } catch (err) { 25 | throw new BoltError(err); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./add'), 4 | ...require('./autoclean'), 5 | ...require('./bin'), 6 | ...require('./build'), 7 | ...require('./cache'), 8 | ...require('./check'), 9 | ...require('./config'), 10 | ...require('./create'), 11 | ...require('./doc'), 12 | ...require('./exec'), 13 | ...require('./format'), 14 | ...require('./generate'), 15 | ...require('./global'), 16 | ...require('./help'), 17 | ...require('./import'), 18 | ...require('./info'), 19 | ...require('./init'), 20 | ...require('./install'), 21 | ...require('./licenses'), 22 | ...require('./link'), 23 | ...require('./lint'), 24 | ...require('./list'), 25 | ...require('./login'), 26 | ...require('./logout'), 27 | ...require('./normalize'), 28 | ...require('./outdated'), 29 | ...require('./owner'), 30 | ...require('./pack'), 31 | ...require('./project'), 32 | ...require('./publish'), 33 | ...require('./publishLock'), 34 | ...require('./publishUnlock'), 35 | ...require('./remove'), 36 | ...require('./run'), 37 | ...require('./tag'), 38 | ...require('./team'), 39 | ...require('./test'), 40 | ...require('./unlink'), 41 | ...require('./upgrade'), 42 | ...require('./upgradeInteractive'), 43 | ...require('./version'), 44 | ...require('./versions'), 45 | ...require('./why'), 46 | ...require('./workspace'), 47 | ...require('./workspaces') 48 | }; 49 | -------------------------------------------------------------------------------- /src/commands/info.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as yarn from '../utils/yarn'; 5 | 6 | export type InfoOptions = {| 7 | cwd?: string, 8 | args: options.Args, 9 | flags: options.Flags 10 | |}; 11 | 12 | export function toInfoOptions( 13 | args: options.Args, 14 | flags: options.Flags 15 | ): InfoOptions { 16 | return { 17 | cwd: options.string(flags.cwd, 'cwd'), 18 | args, 19 | flags 20 | }; 21 | } 22 | 23 | export async function info(opts: InfoOptions) { 24 | let cwd = opts.cwd || process.cwd(); 25 | let spawnArgs = Array.prototype.concat([], opts.args); 26 | if (opts.flags && opts.flags.json) { 27 | spawnArgs.push('--json'); 28 | } 29 | try { 30 | await yarn.info(cwd, spawnArgs); 31 | } catch (err) { 32 | throw new BoltError(err); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/commands/init.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { BoltError } from '../utils/errors'; 3 | import * as options from '../utils/options'; 4 | import * as yarn from '../utils/yarn'; 5 | import Package from '../Package'; 6 | import { isWorkspaceNeeded } from '../utils/prompts'; 7 | import addWorkspacesToJson from '../utils/jsonModifier'; 8 | 9 | export type InitOptions = {| 10 | cwd?: string, 11 | args: { 12 | private?: boolean, 13 | yes?: boolean 14 | } 15 | |}; 16 | 17 | export function toInitOptions( 18 | args: options.Args, 19 | flags: options.Flags 20 | ): InitOptions { 21 | return { 22 | cwd: options.string(flags.cwd, 'cwd'), 23 | args: options.toYarnInit(flags) 24 | }; 25 | } 26 | 27 | export async function init(opts: InitOptions) { 28 | let cwd = opts.cwd || process.cwd(); 29 | let spawnArgs = ['-s']; 30 | 31 | if (opts.args.private) spawnArgs.push('-p'); 32 | if (opts.args.yes) spawnArgs.push('-y'); 33 | 34 | try { 35 | await yarn.cliCommand(cwd, 'init', spawnArgs); 36 | 37 | if (spawnArgs.indexOf('-y') === -1) { 38 | let addWorkspace = await isWorkspaceNeeded(); 39 | 40 | if (addWorkspace) { 41 | let pkg = await Package.closest(cwd); 42 | let config = pkg.config; 43 | let json = await addWorkspacesToJson(config.json); 44 | config.write(json); 45 | } 46 | } 47 | } catch (err) { 48 | throw new BoltError(`Unable to create new package due to: ${err}`); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/commands/licenses/__tests__/generateDisclaimer.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { 3 | licensesGenerateDisclaimer, 4 | toLicensesGenerateDisclaimerOptions 5 | } from '../generateDisclaimer'; 6 | import * as yarn from '../../../utils/yarn'; 7 | 8 | jest.mock('../../../utils/yarn'); 9 | 10 | describe('bolt licenses generate-disclaimer', () => { 11 | it('calls yarn licenses with generate-disclaimer script', async () => { 12 | await licensesGenerateDisclaimer( 13 | toLicensesGenerateDisclaimerOptions([], { cwd: 'dummyPattern/dummyPath' }) 14 | ); 15 | 16 | expect(yarn.cliCommand).toHaveBeenCalledWith( 17 | 'dummyPattern/dummyPath', 18 | 'licenses', 19 | ['generate-disclaimer'] 20 | ); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/commands/licenses/__tests__/list.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { licensesList, toLicensesListOptions } from '../list'; 3 | import * as yarn from '../../../utils/yarn'; 4 | 5 | jest.mock('../../../utils/yarn'); 6 | 7 | describe('bolt licenses list', () => { 8 | it('calls yarn licenses with list script', async () => { 9 | await licensesList( 10 | toLicensesListOptions([], { cwd: 'dummyPattern/dummyPath' }) 11 | ); 12 | expect(yarn.cliCommand).toHaveBeenCalledWith( 13 | 'dummyPattern/dummyPath', 14 | 'licenses', 15 | ['list'] 16 | ); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/commands/licenses/generateDisclaimer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type LicensesGenerateDisclaimerOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toLicensesGenerateDisclaimerOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): LicensesGenerateDisclaimerOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function licensesGenerateDisclaimer( 20 | opts: LicensesGenerateDisclaimerOptions 21 | ) { 22 | let cwd = opts.cwd || process.cwd(); 23 | try { 24 | await yarn.cliCommand(cwd, 'licenses', ['generate-disclaimer']); 25 | } catch (err) { 26 | throw new BoltError(err); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/commands/licenses/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./generateDisclaimer'), 4 | ...require('./list') 5 | }; 6 | -------------------------------------------------------------------------------- /src/commands/licenses/list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type LicensesListOptions = { 7 | cwd?: string 8 | }; 9 | 10 | export function toLicensesListOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): LicensesListOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function licensesList(opts: LicensesListOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | 22 | try { 23 | await yarn.cliCommand(cwd, 'licenses', ['list']); 24 | } catch (err) { 25 | throw new BoltError(err); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/link.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import * as yarn from '../utils/yarn'; 4 | import * as logger from '../utils/logger'; 5 | import * as options from '../utils/options'; 6 | import { BoltError } from '../utils/errors'; 7 | import * as messages from '../utils/messages'; 8 | 9 | function getPackageMap(packages) { 10 | let packageMap = new Map(); 11 | 12 | for (let pkg of packages) { 13 | packageMap.set(pkg.getName(), pkg); 14 | } 15 | 16 | return packageMap; 17 | } 18 | 19 | export type LinkOptions = {| 20 | cwd?: string, 21 | packagesToLink: ?Array 22 | |}; 23 | 24 | export function toLinkOptions( 25 | args: options.Args, 26 | flags: options.Flags 27 | ): LinkOptions { 28 | return { 29 | cwd: options.string(flags.cwd, 'cwd'), 30 | packagesToLink: args 31 | }; 32 | } 33 | 34 | export async function link(opts: LinkOptions) { 35 | let cwd = opts.cwd || process.cwd(); 36 | let packagesToLink = opts.packagesToLink; 37 | let project = await Project.init(cwd); 38 | let packages = await project.getPackages(); 39 | let packageMap = getPackageMap(packages); 40 | 41 | if (packagesToLink && packagesToLink.length) { 42 | await Promise.all( 43 | packagesToLink.map(async packageToLink => { 44 | if (packageMap.has(packageToLink)) { 45 | logger.warn(messages.linkInternalPackage(packageToLink)); 46 | } else { 47 | await yarn.cliCommand(cwd, 'link', [packageToLink]); 48 | } 49 | }) 50 | ); 51 | } else { 52 | throw new BoltError( 53 | `Cannot create a link to entire workspace. Please specify package to link.` 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/commands/lint.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import { run } from './run'; 5 | 6 | export type LintOptions = {| 7 | cwd?: string, 8 | args: options.Args 9 | |}; 10 | 11 | export function toLintOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): LintOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args: args 18 | }; 19 | } 20 | 21 | export async function lint(opts: LintOptions) { 22 | await run({ 23 | cwd: opts.cwd, 24 | script: 'lint', 25 | scriptArgs: opts.args 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as yarn from '../utils/yarn'; 5 | 6 | export type ListOptions = { 7 | cwd?: string, 8 | pattern?: string, 9 | depth?: number | string 10 | }; 11 | 12 | export function toListOptions( 13 | args: options.Args, 14 | flags: options.Flags 15 | ): ListOptions { 16 | return { 17 | cwd: options.string(flags.cwd, 'cwd'), 18 | pattern: options.string(flags.pattern, 'pattern') || '', 19 | depth: options.number(flags.depth, 'depth') || '' 20 | }; 21 | } 22 | 23 | export async function list(opts: ListOptions) { 24 | let cwd = opts.cwd || process.cwd(); 25 | let args = opts.pattern ? [`--pattern=${opts.pattern}`] : []; 26 | if (opts.depth) { 27 | args = args.concat([`--depth=${opts.depth}`]); 28 | } 29 | try { 30 | yarn.cliCommand(cwd, 'list', args); 31 | } catch (err) { 32 | throw new BoltError(err); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/commands/login.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import * as npm from '../utils/npm'; 4 | import { BoltError } from '../utils/errors'; 5 | 6 | export type LoginOptions = {| 7 | cwd?: string 8 | |}; 9 | 10 | export function toLoginOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): LoginOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function login(opts: LoginOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | try { 22 | await npm.login(cwd); 23 | } catch (err) { 24 | throw new BoltError(err); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/commands/logout.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import * as npm from '../utils/npm'; 4 | import { BoltError } from '../utils/errors'; 5 | 6 | export type LogoutOptions = {| 7 | cwd?: string 8 | |}; 9 | 10 | export function toLogoutOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): LogoutOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function logout(opts: LogoutOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | try { 22 | await npm.logout(cwd); 23 | } catch (err) { 24 | throw new BoltError(err); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/commands/outdated.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as yarn from '../utils/yarn'; 5 | 6 | export type OutdatedOptions = { 7 | cwd?: string, 8 | args?: Array 9 | }; 10 | 11 | export function toOutdatedOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): OutdatedOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args 18 | }; 19 | } 20 | 21 | export async function outdated(opts: OutdatedOptions) { 22 | let cwd = opts.cwd || process.cwd(); 23 | try { 24 | await yarn.cliCommand(cwd, 'outdated', opts.args); 25 | } catch (err) { 26 | throw new BoltError(err); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/commands/owner/__tests__/add.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { ownerAdd, toOwnerAddOptions } from '../add'; 3 | import * as yarn from '../../../utils/yarn'; 4 | 5 | jest.mock('../../../utils/yarn'); 6 | 7 | const dummyPath = '/dummyPattern/dummyPath'; 8 | test('bolt owner add', async () => { 9 | await ownerAdd( 10 | toOwnerAddOptions(['test-owner@1.0.0', 'stable'], { cwd: dummyPath }) 11 | ); 12 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'owner', [ 13 | 'add', 14 | 'test-owner@1.0.0', 15 | 'stable' 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/owner/__tests__/list.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { ownerList, toOwnerListOptions } from '../list'; 3 | import * as yarn from '../../../utils/yarn'; 4 | 5 | jest.mock('../../../utils/yarn'); 6 | 7 | const dummyPath = '/dummyPattern/dummyPath'; 8 | test('bolt owner list', async () => { 9 | await ownerList(toOwnerListOptions(['react'], { cwd: dummyPath })); 10 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'owner', [ 11 | 'list', 12 | 'react' 13 | ]); 14 | }); 15 | -------------------------------------------------------------------------------- /src/commands/owner/__tests__/remove.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { ownerRemove, toOwnerRemoveOptions } from '../remove'; 3 | import * as yarn from '../../../utils/yarn'; 4 | 5 | jest.mock('../../../utils/yarn'); 6 | 7 | const dummyPath = '/dummyPattern/dummyPath'; 8 | test('bolt owner remove', async () => { 9 | await ownerRemove( 10 | toOwnerRemoveOptions(['test-owner', 'stable'], { cwd: dummyPath }) 11 | ); 12 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'owner', [ 13 | 'remove', 14 | 'test-owner', 15 | 'stable' 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/owner/add.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type OwnerAddOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toOwnerAddOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): OwnerAddOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function ownerAdd(opts: OwnerAddOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await yarn.cliCommand(cwd, 'owner', ['add', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/owner/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./add'), 4 | ...require('./list'), 5 | ...require('./remove') 6 | }; 7 | -------------------------------------------------------------------------------- /src/commands/owner/list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type OwnerListOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toOwnerListOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): OwnerListOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function ownerList(opts: OwnerListOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | let args = opts.args || []; 21 | 22 | try { 23 | await yarn.cliCommand(cwd, 'owner', ['list', ...args]); 24 | } catch (err) { 25 | throw new BoltError(err); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/owner/remove.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type OwnerRemoveOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toOwnerRemoveOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): OwnerRemoveOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function ownerRemove(opts: OwnerRemoveOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await yarn.cliCommand(cwd, 'owner', ['remove', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/pack.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as yarn from '../utils/yarn'; 5 | 6 | export type PackOptions = { 7 | cwd?: string, 8 | fileName?: string 9 | }; 10 | 11 | export function toPackOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): PackOptions { 15 | let fileName = 16 | options.string(flags.filename, 'filename') || options.string(flags.f, 'f'); 17 | return { 18 | cwd: options.string(flags.cwd, 'cwd'), 19 | fileName: fileName || '' 20 | }; 21 | } 22 | 23 | export async function pack(opts: PackOptions) { 24 | let cwd = opts.cwd || process.cwd(); 25 | let fileName = opts.fileName ? [`--filename=${opts.fileName}`] : []; 26 | 27 | try { 28 | await yarn.cliCommand(cwd, 'pack', fileName); 29 | } catch (err) { 30 | throw new BoltError(err); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/commands/project/__tests__/add.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { projectAdd, toProjectAddOptions } from '../add'; 3 | import * as fs from 'fs'; 4 | import * as path from 'path'; 5 | import * as yarn from '../../../utils/yarn'; 6 | import fixtures from 'fixturez'; 7 | import addDependenciesToPackage from '../../../utils/addDependenciesToPackages'; 8 | 9 | const f = fixtures(__dirname); 10 | 11 | jest.mock('../../../utils/addDependenciesToPackages'); 12 | 13 | describe('bolt project add', () => { 14 | test('adding a project dependency only used by the project', async () => { 15 | let tempDir = f.copy('package-with-external-deps-installed'); 16 | 17 | await projectAdd( 18 | toProjectAddOptions(['project-new-dep'], { cwd: tempDir }) 19 | ); 20 | 21 | expect(addDependenciesToPackage).toHaveBeenCalledTimes(1); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/commands/project/__tests__/exec.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { projectExec, toProjectExecOptions } from '../exec'; 3 | import * as path from 'path'; 4 | import * as processes from '../../../utils/processes'; 5 | import containDeep from 'jest-expect-contain-deep'; 6 | import fixtures from 'fixturez'; 7 | 8 | const f = fixtures(__dirname); 9 | 10 | jest.mock('../../../utils/processes'); 11 | const unsafeProcesses: any & typeof processes = processes; 12 | const binDir = path.join('node_modules', '.bin'); 13 | 14 | describe('bolt project exec', () => { 15 | test('running in a project', async () => { 16 | let projectDir = f.copy('project-with-bins'); 17 | let projectBinDir = path.join(projectDir, binDir); 18 | 19 | await projectExec( 20 | toProjectExecOptions([], { 21 | cwd: projectDir, 22 | '--': ['dep-with-bin'] 23 | }) 24 | ); 25 | 26 | expect(unsafeProcesses.spawn).toHaveBeenCalledTimes(1); 27 | expect(unsafeProcesses.spawn).toHaveBeenCalledWith( 28 | 'dep-with-bin', 29 | [], 30 | containDeep({ 31 | cwd: projectDir, 32 | env: { 33 | PATH: expect.stringContaining(projectBinDir) 34 | } 35 | }) 36 | ); 37 | }); 38 | 39 | test('running from inside a workspace', async () => { 40 | let projectDir = f.copy('project-with-bins'); 41 | let fooWorkspaceDir = path.join(projectDir, 'packages', 'foo'); 42 | let projectBinDir = path.join(projectDir, binDir); 43 | 44 | await projectExec( 45 | toProjectExecOptions([], { 46 | cwd: fooWorkspaceDir, 47 | '--': ['dep-with-bin'] 48 | }) 49 | ); 50 | 51 | expect(unsafeProcesses.spawn).toHaveBeenCalledTimes(1); 52 | expect(unsafeProcesses.spawn).toHaveBeenCalledWith( 53 | 'dep-with-bin', 54 | [], 55 | containDeep({ 56 | cwd: projectDir, 57 | env: { 58 | PATH: expect.stringContaining(projectBinDir) 59 | } 60 | }) 61 | ); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /src/commands/project/__tests__/remove.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { projectRemove, toProjectRemoveOptions } from '../remove'; 3 | import * as fs from 'fs'; 4 | import * as path from 'path'; 5 | import * as yarn from '../../../utils/yarn'; 6 | import fixtures from 'fixturez'; 7 | 8 | const f = fixtures(__dirname); 9 | 10 | jest.mock('../../../utils/logger'); 11 | jest.mock('../../../utils/yarn'); 12 | 13 | describe('bolt project remove', () => { 14 | test('removing a project dependency only used by the project', async () => { 15 | let tempDir = f.copy('package-with-external-deps-installed'); 16 | 17 | await projectRemove( 18 | toProjectRemoveOptions(['project-only-dep'], { cwd: tempDir }) 19 | ); 20 | 21 | expect(yarn.remove).toHaveBeenCalledTimes(1); 22 | expect(yarn.remove).toHaveBeenCalledWith(['project-only-dep'], tempDir); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/commands/project/__tests__/run.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { projectRun, toProjectRunOptions } from '../run'; 3 | 4 | test('bolt project run'); 5 | -------------------------------------------------------------------------------- /src/commands/project/__tests__/upgrade.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as fs from 'fs'; 3 | import * as path from 'path'; 4 | import fixtures from 'fixturez'; 5 | import { projectUpgrade, toProjectUpgradeOptions } from '../upgrade'; 6 | import upgradeDependenciesInPackage from '../../../utils/upgradeDependenciesInPackages'; 7 | 8 | const f = fixtures(__dirname); 9 | 10 | jest.mock('../../../utils/upgradeDependenciesInPackages'); 11 | 12 | describe('bolt project add', () => { 13 | test('upgrading a project dependency only used by the project', async () => { 14 | let tempDir = f.copy('package-with-external-deps-installed'); 15 | 16 | await projectUpgrade( 17 | toProjectUpgradeOptions(['project-new-dep'], { cwd: tempDir }) 18 | ); 19 | 20 | expect(upgradeDependenciesInPackage).toHaveBeenCalledTimes(1); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/commands/project/add.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import addDependenciesToPackage from '../../utils/addDependenciesToPackages'; 3 | import Project from '../../Project'; 4 | import * as options from '../../utils/options'; 5 | import * as logger from '../../utils/logger'; 6 | import type { Dependency, configDependencyType } from '../../types'; 7 | import { DEPENDENCY_TYPE_FLAGS_MAP } from '../../constants'; 8 | import { add } from '../add'; 9 | 10 | export type ProjectAddOptions = { 11 | cwd?: string, 12 | deps: Array, 13 | type: configDependencyType 14 | }; 15 | 16 | export function toProjectAddOptions( 17 | args: options.Args, 18 | flags: options.Flags 19 | ): ProjectAddOptions { 20 | let depsArgs = []; 21 | let type = 'dependencies'; 22 | 23 | // args is each of our dependencies we are adding which may have "@version" parts to them 24 | args.forEach(dep => { 25 | depsArgs.push(options.toDependency(dep)); 26 | }); 27 | 28 | Object.keys(DEPENDENCY_TYPE_FLAGS_MAP).forEach(depTypeFlag => { 29 | if (flags[depTypeFlag]) { 30 | type = DEPENDENCY_TYPE_FLAGS_MAP[depTypeFlag]; 31 | // check if value of dependency flag is a package name and then push to dependency arguments 32 | if (typeof flags[depTypeFlag] === 'string') { 33 | depsArgs.push(options.toDependency(flags[depTypeFlag])); 34 | } 35 | } 36 | }); 37 | 38 | return { 39 | cwd: options.string(flags.cwd, 'cwd'), 40 | deps: depsArgs, 41 | type 42 | }; 43 | } 44 | 45 | export async function projectAdd(opts: ProjectAddOptions) { 46 | await add(opts); 47 | } 48 | -------------------------------------------------------------------------------- /src/commands/project/exec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../../Project'; 3 | import * as options from '../../utils/options'; 4 | import execCommand from '../../utils/execCommand'; 5 | 6 | export type ProjectExecOptions = { 7 | cwd?: string, 8 | command: string, 9 | commandArgs: options.Args 10 | }; 11 | 12 | export function toProjectExecOptions( 13 | args: options.Args, 14 | flags: options.Flags 15 | ): ProjectExecOptions { 16 | let [command, ...commandArgs] = flags['--'] || []; 17 | return { 18 | cwd: options.string(flags.cwd, 'cwd'), 19 | command, 20 | commandArgs 21 | }; 22 | } 23 | 24 | export async function projectExec(opts: ProjectExecOptions) { 25 | let cwd = opts.cwd || process.cwd(); 26 | let project = await Project.init(cwd); 27 | await execCommand(project, project.pkg, opts.command, opts.commandArgs); 28 | } 29 | -------------------------------------------------------------------------------- /src/commands/project/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./add'), 4 | ...require('./exec'), 5 | ...require('./remove'), 6 | ...require('./run'), 7 | ...require('./upgrade') 8 | }; 9 | -------------------------------------------------------------------------------- /src/commands/project/remove.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../../Project'; 3 | import Package from '../../Package'; 4 | import * as options from '../../utils/options'; 5 | import { type SpawnOpts } from '../../types'; 6 | import * as logger from '../../utils/logger'; 7 | import removeDependenciesFromPackages from '../../utils/removeDependenciesFromPackages'; 8 | 9 | export type ProjectRemoveOptions = {| 10 | cwd?: string, 11 | deps: Array, 12 | spawnOpts: SpawnOpts 13 | |}; 14 | 15 | export function toProjectRemoveOptions( 16 | args: options.Args, 17 | flags: options.Flags 18 | ): ProjectRemoveOptions { 19 | return { 20 | cwd: options.string(flags.cwd, 'cwd'), 21 | deps: args, 22 | spawnOpts: options.toSpawnOpts(flags) 23 | }; 24 | } 25 | 26 | export async function projectRemove(opts: ProjectRemoveOptions) { 27 | let cwd = opts.cwd || process.cwd(); 28 | let project = await Project.init(cwd); 29 | let packages = await project.getPackages(); 30 | 31 | await removeDependenciesFromPackages( 32 | project, 33 | packages, 34 | [project.pkg], 35 | opts.deps, 36 | opts.spawnOpts 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/commands/project/run.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../../Project'; 3 | import * as options from '../../utils/options'; 4 | import * as yarn from '../../utils/yarn'; 5 | import * as logger from '../../utils/logger'; 6 | import { BoltError } from '../../utils/errors'; 7 | 8 | export type ProjectRunOptions = { 9 | cwd?: string, 10 | script: string, 11 | scriptArgs: options.Args 12 | }; 13 | 14 | export function toProjectRunOptions( 15 | args: options.Args, 16 | flags: options.Flags 17 | ): ProjectRunOptions { 18 | /** 19 | * Unfortunately, in run commands, we are unable to use meow's parsed flags and args as we really 20 | * want to be able to pass all args and flags to yarn without modification. For example, we could 21 | * get a flag called `t` and we wont know if `t` was passed in with `--t` or `-t` and could pass it in 22 | * incorrectly. The only other alternative would be to pass in all flags using the `--` separator 23 | * and args on the other side e.g `bolt run test src/* -- --watch --bail` which is further away from 24 | * how yarn handles things and is more complicated for the consumer. 25 | */ 26 | let [script] = args; 27 | const scriptArgIdx = process.argv.indexOf(script); 28 | // the flags that we'll be passing in as args start after the script name, and we'll pass them all directly 29 | const scriptArgs = process.argv.slice(scriptArgIdx + 1); 30 | return { 31 | cwd: options.string(flags.cwd, 'cwd'), 32 | script, 33 | scriptArgs 34 | }; 35 | } 36 | 37 | export async function projectRun(opts: ProjectRunOptions) { 38 | let cwd = opts.cwd || process.cwd(); 39 | let project = await Project.init(cwd); 40 | let script = await yarn.getScript(project.pkg, opts.script); 41 | 42 | if (script) { 43 | logger.cmd(script, opts.scriptArgs); 44 | await yarn.run(project.pkg, opts.script, opts.scriptArgs); 45 | } else { 46 | throw new BoltError( 47 | `Package at "${project.pkg.dir}" does not have a script named "${opts.script}"` 48 | ); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/commands/project/upgrade.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import Project from '../../Project'; 5 | import type { Dependency } from '../../types'; 6 | import upgradeDependenciesInPackage from '../../utils/upgradeDependenciesInPackages'; 7 | 8 | // TODO: pass flags individially, upgrade has many flags this is here for testing 9 | function toScriptFlags(flags: options.Flags) { 10 | let scriptFlags = []; 11 | 12 | Object.keys(flags).map(flag => { 13 | if (flag === '--') return; 14 | if (typeof flags[flag] === 'string') { 15 | scriptFlags.push(`--${flag}=${flags[flag]}`); 16 | } else { 17 | scriptFlags.push(`--${flag}`); 18 | } 19 | }); 20 | 21 | return scriptFlags; 22 | } 23 | 24 | export type ProjectUpgradeOptions = { 25 | cwd?: string, 26 | deps: Array, 27 | flags: Array 28 | }; 29 | 30 | export function toProjectUpgradeOptions( 31 | args: options.Args, 32 | flags: options.Flags 33 | ): ProjectUpgradeOptions { 34 | let depsArgs = []; 35 | 36 | args.forEach(dep => { 37 | depsArgs.push(options.toDependency(dep)); 38 | }); 39 | 40 | return { 41 | cwd: options.string(flags.cwd, 'cwd'), 42 | deps: depsArgs, 43 | flags: toScriptFlags(flags) 44 | }; 45 | } 46 | 47 | export async function projectUpgrade(opts: ProjectUpgradeOptions) { 48 | let cwd = opts.cwd || process.cwd(); 49 | let project = await Project.init(cwd); 50 | 51 | try { 52 | await upgradeDependenciesInPackage( 53 | project, 54 | project.pkg, 55 | opts.deps, 56 | opts.flags 57 | ); 58 | } catch (err) { 59 | throw new BoltError(`upgrading dependencies failed due to ${err}`); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/commands/publish.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import * as logger from '../utils/logger'; 4 | import * as messages from '../utils/messages'; 5 | import { 6 | publish as publishUtil, 7 | type PublishOptions, 8 | type PackageMeta 9 | } from '../utils/publish'; 10 | import { BoltError } from '../utils/errors'; 11 | 12 | export function toPublishOptions( 13 | args: options.Args, 14 | flags: options.Flags 15 | ): PublishOptions { 16 | return { 17 | cwd: options.string(flags.cwd, 'cwd'), 18 | access: options.string(flags.access, 'access') 19 | }; 20 | } 21 | 22 | function partition(collection, predicate = x => x): PackageMeta[][] { 23 | return collection.reduce( 24 | ([a, b], value) => { 25 | (predicate(value) ? a : b).push(value); 26 | return [a, b]; 27 | }, 28 | [[], []] 29 | ); 30 | } 31 | 32 | export async function publish(opts: PublishOptions) { 33 | const response: PackageMeta[] = await publishUtil(opts); 34 | 35 | const [successful, unsuccessful] = partition(response, p => p.published); 36 | 37 | for (const pkg of successful) { 38 | logger.success( 39 | messages.successfullyPublishedPackage(pkg.name, pkg.newVersion) 40 | ); 41 | } 42 | 43 | for (const pkg of unsuccessful) { 44 | logger.error(messages.failedToPublishPackage(pkg.name)); 45 | } 46 | 47 | if (unsuccessful.length > 0) { 48 | throw new BoltError( 49 | `Failed to publish ${unsuccessful.length} ${ 50 | unsuccessful.length === 1 ? 'package' : 'packages' 51 | }` 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/commands/publishLock.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import * as options from '../utils/options'; 4 | import * as locks from '../utils/locks'; 5 | 6 | export type PublishLockOptions = {| 7 | cwd?: string 8 | |}; 9 | 10 | export function toPublishLockOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): PublishLockOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function publishLock(opts: PublishLockOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | let project = await Project.init(cwd); 22 | let packages = await project.getPackages(); 23 | let publicPackages = packages.filter(pkg => !pkg.config.getPrivate()); 24 | await locks.lock(publicPackages); 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/publishUnlock.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import * as options from '../utils/options'; 4 | import * as locks from '../utils/locks'; 5 | 6 | export type PublishUnlockOptions = {| 7 | cwd?: string 8 | |}; 9 | 10 | export function toPublishUnlockOptions( 11 | args: options.Args, 12 | flags: options.Flags 13 | ): PublishUnlockOptions { 14 | return { 15 | cwd: options.string(flags.cwd, 'cwd') 16 | }; 17 | } 18 | 19 | export async function publishUnlock(opts: PublishUnlockOptions) { 20 | let cwd = opts.cwd || process.cwd(); 21 | let project = await Project.init(cwd); 22 | let packages = await project.getPackages(); 23 | let publicPackages = packages.filter(pkg => !pkg.config.getPrivate()); 24 | await locks.unlock(publicPackages); 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/remove.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import Package from '../Package'; 4 | import * as options from '../utils/options'; 5 | import * as logger from '../utils/logger'; 6 | import removeDependenciesFromPackages from '../utils/removeDependenciesFromPackages'; 7 | import type { SpawnOpts } from '../types'; 8 | 9 | export type RemoveOptions = {| 10 | cwd?: string, 11 | deps: Array, 12 | spawnOpts: SpawnOpts 13 | |}; 14 | 15 | export function toRemoveOptions( 16 | args: options.Args, 17 | flags: options.Flags 18 | ): RemoveOptions { 19 | return { 20 | cwd: options.string(flags.cwd, 'cwd'), 21 | deps: args, 22 | spawnOpts: options.toSpawnOpts(flags) 23 | }; 24 | } 25 | 26 | export async function remove(opts: RemoveOptions) { 27 | let cwd = opts.cwd || process.cwd(); 28 | let project = await Project.init(cwd); 29 | let packages = await project.getPackages(); 30 | let pkg = await Package.closest(cwd); 31 | await removeDependenciesFromPackages( 32 | project, 33 | packages, 34 | [pkg], 35 | opts.deps, 36 | opts.spawnOpts 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /src/commands/run.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Package from '../Package'; 3 | import * as options from '../utils/options'; 4 | import * as yarn from '../utils/yarn'; 5 | import * as logger from '../utils/logger'; 6 | import { BoltError } from '../utils/errors'; 7 | 8 | export type RunOptions = {| 9 | cwd?: string, 10 | script: string, 11 | scriptArgs: options.Args 12 | |}; 13 | 14 | export function toRunOptions( 15 | args: options.Args, 16 | flags: options.Flags 17 | ): RunOptions { 18 | /** 19 | * Unfortunately, in run commands, we are unable to use meow's parsed flags and args as we really 20 | * want to be able to pass all args and flags to yarn without modification. For example, we could 21 | * get a flag called `t` and we wont know if `t` was passed in with `--t` or `-t` and could pass it in 22 | * incorrectly. The only other alternative would be to pass in all flags using the `--` separator 23 | * and args on the other side e.g `bolt run test src/* -- --watch --bail` which is further away from 24 | * how yarn handles things and is more complicated for the consumer. 25 | */ 26 | let [script] = args; 27 | const scriptArgIdx = process.argv.indexOf(script); 28 | // the flags that we'll be passing in as args start after the script name, and we'll pass them all directly 29 | const scriptArgs = process.argv.slice(scriptArgIdx + 1); 30 | 31 | return { 32 | cwd: options.string(flags.cwd, 'cwd'), 33 | script, 34 | scriptArgs 35 | }; 36 | } 37 | 38 | export async function run(opts: RunOptions) { 39 | let cwd = opts.cwd || process.cwd(); 40 | let pkg = await Package.closest(cwd); 41 | let script = await yarn.getScript(pkg, opts.script); 42 | 43 | if (script) { 44 | logger.cmd(script, opts.scriptArgs); 45 | await yarn.run(pkg, opts.script, opts.scriptArgs); 46 | } else { 47 | throw new BoltError( 48 | `Package at "${pkg.dir}" does not have a script named "${opts.script}"` 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/commands/tag/__tests__/add.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { tagAdd, toTagAddOptions } from '../add'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt tag add', async () => { 10 | let tag = await tagAdd( 11 | toTagAddOptions(['test-tag@1.0.0', 'stable'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'tag', [ 14 | 'add', 15 | 'test-tag@1.0.0', 16 | 'stable' 17 | ]); 18 | }); 19 | -------------------------------------------------------------------------------- /src/commands/tag/__tests__/list.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { tagList, toTagListOptions } from '../list'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt tag list', async () => { 10 | let tag = await tagList(toTagListOptions(['react'], { cwd: dummyPath })); 11 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'tag', [ 12 | 'list', 13 | 'react' 14 | ]); 15 | }); 16 | -------------------------------------------------------------------------------- /src/commands/tag/__tests__/remove.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { tagRemove, toTagRemoveOptions } from '../remove'; 3 | import * as yarn from '../../../utils/yarn'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/yarn'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt tag remove', async () => { 10 | let tag = await tagRemove( 11 | toTagRemoveOptions(['test-tag', 'stable'], { cwd: dummyPath }) 12 | ); 13 | expect(yarn.cliCommand).toHaveBeenCalledWith(dummyPath, 'tag', [ 14 | 'remove', 15 | 'test-tag', 16 | 'stable' 17 | ]); 18 | }); 19 | -------------------------------------------------------------------------------- /src/commands/tag/add.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type TagAddOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toTagAddOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TagAddOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function tagAdd(opts: TagAddOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await yarn.cliCommand(cwd, 'tag', ['add', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/tag/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./add'), 4 | ...require('./list'), 5 | ...require('./remove') 6 | }; 7 | -------------------------------------------------------------------------------- /src/commands/tag/list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | import * as yarn from '../../utils/yarn'; 5 | 6 | export type TagListOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toTagListOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TagListOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function tagList(opts: TagListOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | let args = opts.args || []; 21 | 22 | try { 23 | await yarn.cliCommand(cwd, 'tag', ['list', ...args]); 24 | } catch (err) { 25 | throw new BoltError(err); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/tag/remove.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as yarn from '../../utils/yarn'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type TagRemoveOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toTagRemoveOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TagRemoveOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function tagRemove(opts: TagRemoveOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await yarn.cliCommand(cwd, 'tag', ['remove', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/team/__tests__/add.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { teamAdd, toTeamAddOptions } from '../add'; 3 | import * as npm from '../../../utils/npm'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/npm'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt team add', async () => { 10 | let team = await teamAdd( 11 | toTeamAddOptions(['test-tag', 'user1'], { cwd: dummyPath }) 12 | ); 13 | expect(npm.cliCommand).toHaveBeenCalledWith(dummyPath, 'team', [ 14 | 'add', 15 | 'test-tag', 16 | 'user1' 17 | ]); 18 | }); 19 | -------------------------------------------------------------------------------- /src/commands/team/__tests__/create.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { teamCreate, toTeamCreateOptions } from '../create'; 3 | import * as npm from '../../../utils/npm'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/npm'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt team create', async () => { 10 | let team = await teamCreate( 11 | toTeamCreateOptions(['test-tag'], { cwd: dummyPath }) 12 | ); 13 | expect(npm.cliCommand).toHaveBeenCalledWith(dummyPath, 'team', [ 14 | 'create', 15 | 'test-tag' 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/team/__tests__/destroy.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { teamDestroy, toTeamDestroyOptions } from '../destroy'; 3 | import * as npm from '../../../utils/npm'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/npm'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt team destroy', async () => { 10 | let team = await teamDestroy( 11 | toTeamDestroyOptions(['test-tag'], { cwd: dummyPath }) 12 | ); 13 | expect(npm.cliCommand).toHaveBeenCalledWith(dummyPath, 'team', [ 14 | 'destroy', 15 | 'test-tag' 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/team/__tests__/list.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { teamList, toTeamListOptions } from '../list'; 3 | import * as npm from '../../../utils/npm'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/npm'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt team list', async () => { 10 | let team = await teamList( 11 | toTeamListOptions(['test-tag'], { cwd: dummyPath }) 12 | ); 13 | expect(npm.cliCommand).toHaveBeenCalledWith(dummyPath, 'team', [ 14 | 'ls', 15 | 'test-tag' 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /src/commands/team/__tests__/remove.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { teamRemove, toTeamRemoveOptions } from '../remove'; 3 | import * as npm from '../../../utils/npm'; 4 | import { BoltError } from '../../../utils/errors'; 5 | 6 | jest.mock('../../../utils/npm'); 7 | 8 | const dummyPath = '/dummyPattern/dummyPath'; 9 | test('bolt team remove', async () => { 10 | let team = await teamRemove( 11 | toTeamRemoveOptions(['test-tag', 'user1'], { cwd: dummyPath }) 12 | ); 13 | expect(npm.cliCommand).toHaveBeenCalledWith(dummyPath, 'team', [ 14 | 'rm', 15 | 'test-tag', 16 | 'user1' 17 | ]); 18 | }); 19 | -------------------------------------------------------------------------------- /src/commands/team/add.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as npm from '../../utils/npm'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type TeamAddOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toTeamAddOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TeamAddOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function teamAdd(opts: TeamAddOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await npm.cliCommand(cwd, 'team', ['add', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/team/create.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as npm from '../../utils/npm'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type TeamCreateOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toTeamCreateOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TeamCreateOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function teamCreate(opts: TeamCreateOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await npm.cliCommand(cwd, 'team', ['create', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/team/destroy.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as npm from '../../utils/npm'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type TeamDestroyOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toTeamDestroyOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TeamDestroyOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function teamDestroy(opts: TeamDestroyOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await npm.cliCommand(cwd, 'team', ['destroy', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/team/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./add'), 4 | ...require('./create'), 5 | ...require('./destroy'), 6 | ...require('./list'), 7 | ...require('./remove') 8 | }; 9 | -------------------------------------------------------------------------------- /src/commands/team/list.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as npm from '../../utils/npm'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type TeamListOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toTeamListOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TeamListOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function teamList(opts: TeamListOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await npm.cliCommand(cwd, 'team', ['ls', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/team/remove.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as npm from '../../utils/npm'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type TeamRemoveOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toTeamRemoveOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TeamRemoveOptions { 15 | return { cwd: options.string(flags.cwd, 'cwd'), args }; 16 | } 17 | 18 | export async function teamRemove(opts: TeamRemoveOptions) { 19 | let cwd = opts.cwd || process.cwd(); 20 | try { 21 | await npm.cliCommand(cwd, 'team', ['rm', ...opts.args]); 22 | } catch (err) { 23 | throw new BoltError(err); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/commands/test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import { run } from './run'; 5 | 6 | export type TestOptions = {| 7 | cwd?: string, 8 | args: options.Args 9 | |}; 10 | 11 | export function toTestOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): TestOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args: args 18 | }; 19 | } 20 | 21 | export async function test(opts: TestOptions) { 22 | await run({ 23 | cwd: opts.cwd, 24 | script: 'test', 25 | scriptArgs: opts.args 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/commands/unlink.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import * as yarn from '../utils/yarn'; 4 | import * as logger from '../utils/logger'; 5 | import * as options from '../utils/options'; 6 | import { BoltError } from '../utils/errors'; 7 | import * as messages from '../utils/messages'; 8 | 9 | function getPackageMap(packages) { 10 | let packageMap = new Map(); 11 | 12 | for (let pkg of packages) { 13 | packageMap.set(pkg.getName(), pkg); 14 | } 15 | 16 | return packageMap; 17 | } 18 | 19 | export type UnlinkOptions = { 20 | cwd?: string, 21 | packagesToUnlink: ?Array 22 | }; 23 | 24 | export function toUnlinkOptions( 25 | args: options.Args, 26 | flags: options.Flags 27 | ): UnlinkOptions { 28 | return { 29 | cwd: options.string(flags.cwd, 'cwd'), 30 | packagesToUnlink: args 31 | }; 32 | } 33 | 34 | export async function unlink(opts: UnlinkOptions) { 35 | let cwd = opts.cwd || process.cwd(); 36 | let packagesToUnlink = opts.packagesToUnlink; 37 | let project = await Project.init(cwd); 38 | let packages = await project.getPackages(); 39 | let packageMap = getPackageMap(packages); 40 | 41 | // guard to check if there are packages to unlink 42 | if (packagesToUnlink && packagesToUnlink.length) { 43 | await Promise.all( 44 | packagesToUnlink.map(async packageToUnlink => { 45 | if (packageMap.has(packageToUnlink)) { 46 | logger.warn(messages.unlinkInternalPackage(packageToUnlink)); 47 | } else { 48 | await yarn.cliCommand(cwd, 'unlink', [packageToUnlink]); 49 | } 50 | }) 51 | ); 52 | } else { 53 | throw new BoltError( 54 | 'Please specify package to unlink. Try: bolt w [packageToUnlink] unlink' 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/commands/upgrade.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import Project from '../Project'; 5 | import Package from '../Package'; 6 | import type { Dependency } from '../types'; 7 | import upgradeDependenciesInPackage from '../utils/upgradeDependenciesInPackages'; 8 | 9 | // TODO: pass flags individially, upgrade has many flags this is here for testing 10 | function toScriptFlags(flags: options.Flags) { 11 | let scriptFlags = []; 12 | 13 | Object.keys(flags).map(flag => { 14 | if (flag === '--') return; 15 | if (typeof flags[flag] === 'string') { 16 | scriptFlags.push(`--${flag}=${flags[flag]}`); 17 | } else { 18 | scriptFlags.push(`--${flag}`); 19 | } 20 | }); 21 | 22 | return scriptFlags; 23 | } 24 | 25 | export type UpgradeOptions = { 26 | cwd?: string, 27 | deps: Array, 28 | flags: Array 29 | }; 30 | 31 | export function toUpgradeOptions( 32 | args: options.Args, 33 | flags: options.Flags 34 | ): UpgradeOptions { 35 | let depsArgs = []; 36 | 37 | args.forEach(dep => { 38 | depsArgs.push(options.toDependency(dep)); 39 | }); 40 | 41 | return { 42 | cwd: options.string(flags.cwd, 'cwd'), 43 | deps: depsArgs, 44 | flags: toScriptFlags(flags) 45 | }; 46 | } 47 | 48 | export async function upgrade(opts: UpgradeOptions) { 49 | let cwd = opts.cwd || process.cwd(); 50 | let project = await Project.init(cwd); 51 | let pkg = await Package.closest(cwd); 52 | 53 | try { 54 | await upgradeDependenciesInPackage(project, pkg, opts.deps, opts.flags); 55 | } catch (err) { 56 | throw new BoltError(`upgrading dependencies failed due to ${err}`); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/commands/upgradeInteractive.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | 5 | export type UpgradeInteractiveOptions = {}; 6 | 7 | export function toUpgradeInteractiveOptions( 8 | args: options.Args, 9 | flags: options.Flags 10 | ): UpgradeInteractiveOptions { 11 | return {}; 12 | } 13 | 14 | export async function upgradeInteractive(opts: UpgradeInteractiveOptions) { 15 | throw new BoltError('Unimplemented command "upgrade-interactive"'); 16 | } 17 | -------------------------------------------------------------------------------- /src/commands/version.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | 5 | export type VersionOptions = {}; 6 | 7 | export function toVersionOptions( 8 | args: options.Args, 9 | flags: options.Flags 10 | ): VersionOptions { 11 | return {}; 12 | } 13 | 14 | export async function version(opts: VersionOptions) { 15 | throw new BoltError('Unimplemented command "version"'); 16 | } 17 | -------------------------------------------------------------------------------- /src/commands/versions.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | 5 | export type VersionsOptions = {}; 6 | 7 | export function toVersionsOptions( 8 | args: options.Args, 9 | flags: options.Flags 10 | ): VersionsOptions { 11 | return {}; 12 | } 13 | 14 | export async function versions(opts: VersionsOptions) { 15 | throw new BoltError('Unimplemented command "versions"'); 16 | } 17 | -------------------------------------------------------------------------------- /src/commands/why.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../utils/options'; 3 | import { BoltError } from '../utils/errors'; 4 | import * as yarn from '../utils/yarn'; 5 | 6 | export type WhyOptions = { 7 | cwd?: string, 8 | args: Array 9 | }; 10 | 11 | export function toWhyOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): WhyOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd'), 17 | args 18 | }; 19 | } 20 | 21 | export async function why(opts: WhyOptions) { 22 | let cwd = opts.cwd || process.cwd(); 23 | try { 24 | await yarn.cliCommand(cwd, 'why', opts.args); 25 | } catch (err) { 26 | throw new BoltError(err); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/commands/workspace/__tests__/link.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { toWorkspacelinkOptions, workspacelink } from '../link'; 4 | import * as path from 'path'; 5 | import * as PackageLink from '../../link'; 6 | import * as yarn from '../../../utils/yarn'; 7 | import fixtures from 'fixturez'; 8 | 9 | const f = fixtures(__dirname); 10 | 11 | jest.mock('../../../utils/yarn'); 12 | jest.mock('../../link'); 13 | 14 | describe('workspace link', () => { 15 | let projectDir; 16 | beforeEach(async () => { 17 | projectDir = f.copy('package-with-external-deps-installed'); 18 | }); 19 | 20 | it('should create link to package if there are no packages to link in args', async () => { 21 | let pathToFooWorksapce = path.join(projectDir, 'packages', 'foo'); 22 | await workspacelink(toWorkspacelinkOptions(['foo'], { cwd: projectDir })); 23 | expect(yarn.cliCommand).toHaveBeenCalledWith(pathToFooWorksapce, 'link'); 24 | }); 25 | 26 | it('should link packages to root of project', async () => { 27 | await workspacelink( 28 | toWorkspacelinkOptions(['foo', 'some-external-package'], { 29 | cwd: projectDir 30 | }) 31 | ); 32 | expect(PackageLink.toLinkOptions).toHaveBeenCalledWith( 33 | ['some-external-package'], 34 | { '--': [] } 35 | ); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/commands/workspace/__tests__/unlink.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { toWorkspaceUnlinkOptions, workspaceUnlink } from '../unlink'; 3 | import * as path from 'path'; 4 | import * as yarn from '../../../utils/yarn'; 5 | import * as PackageUnlink from '../../unlink'; 6 | import fixtures from 'fixturez'; 7 | 8 | const f = fixtures(__dirname); 9 | 10 | jest.mock('../../../utils/yarn'); 11 | jest.mock('../../unlink'); 12 | 13 | describe('workspace unlink', () => { 14 | let projectDir; 15 | 16 | beforeEach(() => { 17 | projectDir = f.copy('package-with-external-deps-installed'); 18 | }); 19 | 20 | it('should unlink the package if there are no packages to unlink in args', async () => { 21 | let pathToFooWorksapce = path.join(projectDir, 'packages', 'foo'); 22 | await workspaceUnlink( 23 | toWorkspaceUnlinkOptions(['foo'], { cwd: projectDir }) 24 | ); 25 | expect(yarn.cliCommand).toHaveBeenCalledWith(pathToFooWorksapce, 'unlink'); 26 | }); 27 | 28 | it('should link packages to root of project', async () => { 29 | await workspaceUnlink( 30 | toWorkspaceUnlinkOptions(['foo', 'some-external-package'], { 31 | cwd: projectDir 32 | }) 33 | ); 34 | expect(PackageUnlink.toUnlinkOptions).toHaveBeenCalledWith( 35 | ['some-external-package'], 36 | { '--': [] } 37 | ); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/commands/workspace/__tests__/upgrade.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { workspaceUpgrade, toWorkspaceUpgradeOptions } from '../upgrade'; 3 | 4 | test('bolt workspace upgrade'); 5 | -------------------------------------------------------------------------------- /src/commands/workspace/add.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../../Project'; 3 | import Package from '../../Package'; 4 | import * as options from '../../utils/options'; 5 | import * as logger from '../../utils/logger'; 6 | import addDependenciesToPackage from '../../utils/addDependenciesToPackages'; 7 | import { BoltError } from '../../utils/errors'; 8 | import type { Dependency, configDependencyType } from '../../types'; 9 | import { DEPENDENCY_TYPE_FLAGS_MAP } from '../../constants'; 10 | 11 | export type WorkspaceAddOptions = { 12 | cwd?: string, 13 | pkgName: string, 14 | deps: Array, 15 | type: configDependencyType 16 | }; 17 | 18 | export function toWorkspaceAddOptions( 19 | args: options.Args, 20 | flags: options.Flags 21 | ): WorkspaceAddOptions { 22 | let [pkgName, ...deps] = args; 23 | let depsArgs = []; 24 | let type = 'dependencies'; 25 | 26 | deps.forEach(dep => { 27 | depsArgs.push(options.toDependency(dep)); 28 | }); 29 | 30 | Object.keys(DEPENDENCY_TYPE_FLAGS_MAP).forEach(depTypeFlag => { 31 | if (flags[depTypeFlag]) { 32 | type = DEPENDENCY_TYPE_FLAGS_MAP[depTypeFlag]; 33 | // check if value of dependency flag is a package name and then push to dependency arguments 34 | if (typeof flags[depTypeFlag] === 'string') { 35 | depsArgs.push(options.toDependency(flags[depTypeFlag])); 36 | } 37 | } 38 | }); 39 | 40 | return { 41 | cwd: options.string(flags.cwd, 'cwd'), 42 | pkgName, 43 | deps: depsArgs, 44 | type 45 | }; 46 | } 47 | 48 | export async function workspaceAdd(opts: WorkspaceAddOptions) { 49 | let cwd = opts.cwd || process.cwd(); 50 | let project = await Project.init(cwd); 51 | let packages = await project.getPackages(); 52 | let pkg = await project.getPackageByName(packages, opts.pkgName); 53 | 54 | if (!pkg) { 55 | throw new BoltError( 56 | `Could not find a workspace named "${opts.pkgName}" from "${cwd}"` 57 | ); 58 | } 59 | 60 | await addDependenciesToPackage(project, pkg, opts.deps, opts.type); 61 | } 62 | -------------------------------------------------------------------------------- /src/commands/workspace/exec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../../Project'; 3 | import * as options from '../../utils/options'; 4 | import { BoltError } from '../../utils/errors'; 5 | import execCommand from '../../utils/execCommand'; 6 | 7 | export type WorkspaceExecOptions = { 8 | cwd?: string, 9 | pkgName: string, 10 | command: string, 11 | commandArgs: options.Args 12 | }; 13 | 14 | export function toWorkspaceExecOptions( 15 | args: options.Args, 16 | flags: options.Flags 17 | ): WorkspaceExecOptions { 18 | let [pkgName] = args; 19 | let [command, ...commandArgs] = flags['--'] || []; 20 | return { 21 | cwd: options.string(flags.cwd, 'cwd'), 22 | pkgName, 23 | command, 24 | commandArgs 25 | }; 26 | } 27 | 28 | export async function workspaceExec(opts: WorkspaceExecOptions) { 29 | let cwd = opts.cwd || process.cwd(); 30 | let project = await Project.init(cwd); 31 | let packages = await project.getPackages(); 32 | let pkg = await project.getPackageByName(packages, opts.pkgName); 33 | 34 | if (!pkg) { 35 | throw new BoltError( 36 | `Could not find a workspace named "${opts.pkgName}" from "${cwd}"` 37 | ); 38 | } 39 | 40 | await execCommand(project, pkg, opts.command, opts.commandArgs); 41 | } 42 | -------------------------------------------------------------------------------- /src/commands/workspace/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./add'), 4 | ...require('./exec'), 5 | ...require('./link'), 6 | ...require('./remove'), 7 | ...require('./run'), 8 | ...require('./unlink'), 9 | ...require('./upgrade') 10 | }; 11 | -------------------------------------------------------------------------------- /src/commands/workspace/link.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as link from '../link'; 3 | import Project from '../../Project'; 4 | import * as yarn from '../../utils/yarn'; 5 | import * as options from '../../utils/options'; 6 | import { BoltError } from '../../utils/errors'; 7 | 8 | export type WorkspaceLinkOptions = {| 9 | cwd?: string, 10 | pkgName: string, 11 | packagesToLink?: Array 12 | |}; 13 | 14 | export function toWorkspacelinkOptions( 15 | args: options.Args, 16 | flags: options.Flags 17 | ): WorkspaceLinkOptions { 18 | let [pkgName, ...packagesToLink] = args; 19 | return { 20 | cwd: options.string(flags.cwd, 'cwd'), 21 | pkgName, 22 | packagesToLink 23 | }; 24 | } 25 | 26 | export async function workspacelink(opts: WorkspaceLinkOptions) { 27 | let cwd = opts.cwd || process.cwd(); 28 | let packagesToLink = opts.packagesToLink; 29 | let pkgName = opts.pkgName; 30 | let project = await Project.init(cwd); 31 | let packages = await project.getPackages(); 32 | let pkg = await project.getPackageByName(packages, opts.pkgName); 33 | 34 | if (!pkg) { 35 | throw new BoltError( 36 | `Could not find a workspace named "${opts.pkgName}" from "${cwd}"` 37 | ); 38 | } 39 | 40 | // If there are packages to link then we can link then in the Project 41 | // as dependencies are symlinked 42 | if (packagesToLink && packagesToLink.length) { 43 | await link.link(await link.toLinkOptions(packagesToLink, { '--': [] })); 44 | } else { 45 | await yarn.cliCommand(pkg.dir, 'link'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/commands/workspace/remove.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../../Project'; 3 | import Package from '../../Package'; 4 | import * as options from '../../utils/options'; 5 | import * as logger from '../../utils/logger'; 6 | import removeDependenciesFromPackages from '../../utils/removeDependenciesFromPackages'; 7 | import { BoltError } from '../../utils/errors'; 8 | import type { SpawnOpts } from '../../types'; 9 | 10 | export type WorkspaceRemoveOptions = { 11 | cwd?: string, 12 | pkgName: string, 13 | deps: Array, 14 | spawnOpts: SpawnOpts 15 | }; 16 | 17 | export function toWorkspaceRemoveOptions( 18 | args: options.Args, 19 | flags: options.Flags 20 | ): WorkspaceRemoveOptions { 21 | let [pkgName, ...deps] = args; 22 | return { 23 | cwd: options.string(flags.cwd, 'cwd'), 24 | pkgName, 25 | deps, 26 | spawnOpts: options.toSpawnOpts(flags) 27 | }; 28 | } 29 | 30 | export async function workspaceRemove(opts: WorkspaceRemoveOptions) { 31 | let cwd = opts.cwd || process.cwd(); 32 | let project = await Project.init(cwd); 33 | let packages = await project.getPackages(); 34 | let pkg = await project.getPackageByName(packages, opts.pkgName); 35 | 36 | if (!pkg) { 37 | throw new BoltError( 38 | `Could not find a workspace named "${opts.pkgName}" from "${cwd}"` 39 | ); 40 | } 41 | 42 | await removeDependenciesFromPackages( 43 | project, 44 | packages, 45 | [pkg], 46 | opts.deps, 47 | opts.spawnOpts 48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /src/commands/workspace/unlink.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as unlink from '../unlink'; 3 | import Project from '../../Project'; 4 | import * as yarn from '../../utils/yarn'; 5 | import * as options from '../../utils/options'; 6 | import { BoltError } from '../../utils/errors'; 7 | 8 | export type WorkspaceUnlinkOptions = {| 9 | cwd?: string, 10 | pkgName: string, 11 | packagesToUnlink?: Array 12 | |}; 13 | 14 | export function toWorkspaceUnlinkOptions( 15 | args: options.Args, 16 | flags: options.Flags 17 | ): WorkspaceUnlinkOptions { 18 | let [pkgName, ...packagesToUnlink] = args; 19 | return { 20 | cwd: options.string(flags.cwd, 'cwd'), 21 | pkgName, 22 | packagesToUnlink 23 | }; 24 | } 25 | 26 | export async function workspaceUnlink(opts: WorkspaceUnlinkOptions) { 27 | let cwd = opts.cwd || process.cwd(); 28 | let packagesToUnlink = opts.packagesToUnlink; 29 | let pkgName = opts.pkgName; 30 | let project = await Project.init(cwd); 31 | let packages = await project.getPackages(); 32 | let pkg = await project.getPackageByName(packages, opts.pkgName); 33 | 34 | if (!pkg) { 35 | throw new BoltError( 36 | `Could not find a workspace named "${opts.pkgName}" from "${cwd}"` 37 | ); 38 | } 39 | 40 | // If there are packages to link then we can link then in the Project 41 | // as dependencies are symlinked 42 | if (packagesToUnlink && packagesToUnlink.length) { 43 | await unlink.unlink( 44 | await unlink.toUnlinkOptions(packagesToUnlink, { '--': [] }) 45 | ); 46 | } else { 47 | await yarn.cliCommand(pkg.dir, 'unlink'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/commands/workspace/upgrade.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import * as messages from '../../utils/messages'; 4 | import { BoltError } from '../../utils/errors'; 5 | 6 | export type WorkspaceUpgradeOptions = { 7 | cwd?: string, 8 | args?: Array 9 | }; 10 | 11 | export function toWorkspaceUpgradeOptions( 12 | args: options.Args, 13 | flags: options.Flags 14 | ): WorkspaceUpgradeOptions { 15 | return { 16 | cwd: options.string(flags.cwd, 'cwd') 17 | }; 18 | } 19 | 20 | export async function workspaceUpgrade(opts: WorkspaceUpgradeOptions) { 21 | throw new BoltError(messages.errorWorkspaceUpgrade()); 22 | } 23 | -------------------------------------------------------------------------------- /src/commands/workspaces/__tests__/add.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { workspacesAdd, toWorkspacesAddOptions } from '../add'; 3 | 4 | test('bolt workspaces add'); 5 | -------------------------------------------------------------------------------- /src/commands/workspaces/__tests__/run.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { workspacesRun, toWorkspacesRunOptions } from '../run'; 3 | 4 | test('bolt workspaces run'); 5 | -------------------------------------------------------------------------------- /src/commands/workspaces/__tests__/upgrade.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { workspacesUpgrade, toWorkspacesUpgradeOptions } from '../upgrade'; 3 | 4 | test('bolt workspaces upgrade'); 5 | -------------------------------------------------------------------------------- /src/commands/workspaces/add.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as options from '../../utils/options'; 3 | import { BoltError } from '../../utils/errors'; 4 | 5 | export type WorkspacesAddOptions = { 6 | cwd?: string 7 | }; 8 | 9 | export function toWorkspacesAddOptions( 10 | args: options.Args, 11 | flags: options.Flags 12 | ): WorkspacesAddOptions { 13 | return { 14 | cwd: options.string(flags.cwd, 'cwd') 15 | }; 16 | } 17 | 18 | export async function workspacesAdd(opts: WorkspacesAddOptions) { 19 | throw new BoltError('Unimplemented command "workspaces add"'); 20 | } 21 | -------------------------------------------------------------------------------- /src/commands/workspaces/exec.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { FilterOpts, SpawnOpts } from '../../types'; 3 | import Project from '../../Project'; 4 | import * as options from '../../utils/options'; 5 | import execCommand from '../../utils/execCommand'; 6 | 7 | export type WorkspacesExecOptions = {| 8 | cwd?: string, 9 | command: string, 10 | commandArgs: options.Args, 11 | spawnOpts: SpawnOpts, 12 | filterOpts: FilterOpts 13 | |}; 14 | 15 | export function toWorkspacesExecOptions( 16 | args: options.Args, 17 | flags: options.Flags 18 | ): WorkspacesExecOptions { 19 | let [command, ...commandArgs] = flags['--'] || []; 20 | return { 21 | cwd: options.string(flags.cwd, 'cwd'), 22 | command, 23 | commandArgs, 24 | spawnOpts: options.toSpawnOpts(flags), 25 | filterOpts: options.toFilterOpts(flags) 26 | }; 27 | } 28 | 29 | export async function workspacesExec(opts: WorkspacesExecOptions) { 30 | let cwd = opts.cwd || process.cwd(); 31 | let project = await Project.init(cwd); 32 | let packages = await project.getPackages(); 33 | let filteredPackages = project.filterPackages(packages, opts.filterOpts); 34 | 35 | await project.runPackageTasks( 36 | filteredPackages, 37 | opts.spawnOpts, 38 | async pkg => await execCommand(project, pkg, opts.command, opts.commandArgs) 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /src/commands/workspaces/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./add'), 4 | ...require('./exec'), 5 | ...require('./remove'), 6 | ...require('./run'), 7 | ...require('./upgrade') 8 | }; 9 | -------------------------------------------------------------------------------- /src/commands/workspaces/remove.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { SpawnOpts, FilterOpts } from '../../types'; 3 | import * as options from '../../utils/options'; 4 | import Project from '../../Project'; 5 | import removeDependenciesFromPackages from '../../utils/removeDependenciesFromPackages'; 6 | 7 | export type WorkspacesRemoveOptions = { 8 | cwd?: string, 9 | deps: Array, 10 | spawnOpts: SpawnOpts, 11 | filterOpts: FilterOpts 12 | }; 13 | 14 | export function toWorkspacesRemoveOptions( 15 | args: options.Args, 16 | flags: options.Flags 17 | ): WorkspacesRemoveOptions { 18 | return { 19 | cwd: options.string(flags.cwd, 'cwd'), 20 | deps: args, 21 | spawnOpts: options.toSpawnOpts(flags), 22 | filterOpts: options.toFilterOpts(flags) 23 | }; 24 | } 25 | 26 | export async function workspacesRemove(opts: WorkspacesRemoveOptions) { 27 | let cwd = opts.cwd || process.cwd(); 28 | let project = await Project.init(cwd); 29 | let packages = await project.getPackages(); 30 | let filteredPackages = project.filterPackages(packages, opts.filterOpts); 31 | 32 | await removeDependenciesFromPackages( 33 | project, 34 | packages, 35 | filteredPackages, 36 | opts.deps, 37 | opts.spawnOpts 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src/commands/workspaces/run.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { SpawnOpts, FilterOpts } from '../../types'; 3 | import * as options from '../../utils/options'; 4 | import Project from '../../Project'; 5 | import * as yarn from '../../utils/yarn'; 6 | 7 | export type WorkspacesRunOptions = { 8 | cwd?: string, 9 | script: string, 10 | scriptArgs: options.Args, 11 | spawnOpts: SpawnOpts, 12 | filterOpts: FilterOpts 13 | }; 14 | 15 | export function toWorkspacesRunOptions( 16 | args: options.Args, 17 | flags: options.Flags 18 | ): WorkspacesRunOptions { 19 | let [script, ...scriptArgs] = args; 20 | const flagArgs = flags['--'] || []; 21 | 22 | return { 23 | cwd: options.string(flags.cwd, 'cwd'), 24 | script, 25 | // for ws run commands we pass in all flags that are added after the `--` 26 | scriptArgs: [...scriptArgs, ...flagArgs], 27 | spawnOpts: options.toSpawnOpts(flags), 28 | filterOpts: options.toFilterOpts(flags) 29 | }; 30 | } 31 | 32 | export async function workspacesRun(opts: WorkspacesRunOptions) { 33 | let cwd = opts.cwd || process.cwd(); 34 | let project = await Project.init(cwd); 35 | let packages = await project.getPackages(); 36 | let filteredPackages = project.filterPackages(packages, opts.filterOpts); 37 | 38 | await project.runPackageTasks( 39 | filteredPackages, 40 | opts.spawnOpts, 41 | // no need to error if script doesn't exist 42 | async pkg => await yarn.runIfExists(pkg, opts.script, opts.scriptArgs) 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /src/commands/workspaces/upgrade.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { FilterOpts } from '../../types'; 3 | import * as options from '../../utils/options'; 4 | import * as messages from '../../utils/messages'; 5 | import { BoltError } from '../../utils/errors'; 6 | import * as Upgrade from '../upgrade'; 7 | 8 | export type WorkspacesUpgradeOptions = { 9 | cwd?: string, 10 | deps: Array, 11 | filterOpts: FilterOpts, 12 | flags: options.Flags 13 | }; 14 | 15 | export function toWorkspacesUpgradeOptions( 16 | args: options.Args, 17 | flags: options.Flags 18 | ): WorkspacesUpgradeOptions { 19 | return { 20 | deps: args, 21 | filterOpts: options.toFilterOpts(flags), 22 | flags 23 | }; 24 | } 25 | 26 | export async function workspacesUpgrade(opts: WorkspacesUpgradeOptions) { 27 | let cwd = opts.cwd || process.cwd(); 28 | let filterOpts = Object.keys(opts.filterOpts); 29 | 30 | if (filterOpts.length) { 31 | throw new BoltError(messages.errorWorkspacesUpgrade(filterOpts)); 32 | } 33 | 34 | // Calling upgrade on project 35 | await Upgrade.upgrade(Upgrade.toUpgradeOptions(opts.deps, opts.flags)); 36 | } 37 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import pkgUp from 'pkg-up'; 3 | const boltPkgPath = pkgUp.sync(__dirname); 4 | 5 | // $FlowFixMe 6 | const boltPkg = require(boltPkgPath); 7 | 8 | export const DEPENDENCY_TYPES = [ 9 | 'dependencies', 10 | 'devDependencies', 11 | 'peerDependencies', 12 | 'bundledDependencies', 13 | 'optionalDependencies' 14 | ]; 15 | 16 | export const DEPENDENCY_TYPE_FLAGS_MAP = { 17 | dev: 'devDependencies', 18 | peer: 'peerDependencies', 19 | optional: 'optionalDependencies', 20 | D: 'devDependencies', 21 | P: 'peerDependencies', 22 | O: 'optionalDependencies' 23 | }; 24 | 25 | export const BOLT_VERSION = boltPkg.version; 26 | -------------------------------------------------------------------------------- /src/functions/__fixtures__/lots-of-internally-linked-deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "version": "1.0.0", 4 | "name": "lots-of-internally-linked-deps", 5 | "description": "all packages are at 1.1.1, each named package is depended on according to that name", 6 | "description-2": "i.e caret-dep will always dep depended on with a caret range", 7 | "bolt": { 8 | "workspaces": ["packages/*"] 9 | }, 10 | "dependencies": { 11 | "react": "^15.6.1", 12 | "left-pad": "^1.1.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/functions/__fixtures__/lots-of-internally-linked-deps/packages/caret-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "caret-dep", 3 | "version": "1.1.1", 4 | "dependencies": { 5 | "react": "^15.6.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/functions/__fixtures__/lots-of-internally-linked-deps/packages/has-all-deps-with-peers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "has-all-deps-with-peers", 3 | "version": "1.1.1", 4 | "peerDependencies": { 5 | "caret-dep": "^1.1.1" 6 | }, 7 | "devDependencies": { 8 | "caret-dep": "^1.1.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/functions/__fixtures__/lots-of-internally-linked-deps/packages/has-all-deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "has-all-deps", 3 | "version": "1.1.1", 4 | "dependencies": { 5 | "react": "^15.6.1", 6 | "pinned-dep": "1.1.1", 7 | "caret-dep": "^1.1.1", 8 | "tilde-dep": "~1.1.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/functions/__fixtures__/lots-of-internally-linked-deps/packages/pinned-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pinned-dep", 3 | "version": "1.1.1", 4 | "dependencies": { 5 | "react": "^15.6.1", 6 | "caret-dep": "^1.1.1" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/functions/__fixtures__/lots-of-internally-linked-deps/packages/tilde-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tilde-dep", 3 | "version": "1.1.1", 4 | "dependencies": { 5 | "react": "^15.6.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/functions/__tests__/getDependentsGraph.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import path from 'path'; 3 | import getDependentsGraph from '../getDependentsGraph'; 4 | import fixtures from 'fixturez'; 5 | 6 | const f = fixtures(__dirname); 7 | 8 | describe('function/getDependentsGraph', () => { 9 | describe('A project with nested workspaces', () => { 10 | it('should return a simplified dependents graph', async () => { 11 | let cwd = f.find('nested-workspaces'); 12 | let dependentsGraph = await getDependentsGraph({ cwd }); 13 | let expectedDependents = { 14 | bar: ['foo', 'baz'], 15 | foo: [], 16 | baz: [] 17 | }; 18 | 19 | expect(dependentsGraph.size).toEqual( 20 | Object.keys(expectedDependents).length 21 | ); 22 | Object.entries(expectedDependents).forEach(([pkg, dependents]) => { 23 | expect(dependentsGraph.get(pkg)).toEqual(dependents); 24 | }); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/functions/__tests__/getProject.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import path from 'path'; 3 | import getProject from '../getProject'; 4 | import fixtures from 'fixturez'; 5 | 6 | const f = fixtures(__dirname); 7 | 8 | describe('function/getProject', () => { 9 | describe('A simple project', () => { 10 | it('should return path to a project root folder from a workspace', async () => { 11 | let projectRoot = f.find('simple-project'); 12 | let workspacePath = path.join(projectRoot, 'packages', 'bar'); 13 | return getProject({ cwd: workspacePath }).then(pr => 14 | expect(pr.dir).toBe(projectRoot) 15 | ); 16 | }); 17 | }); 18 | 19 | describe('A project with nested workspaces', () => { 20 | it('should return path to a project root folder from a workspace', async () => { 21 | let projectRoot = f.find('nested-workspaces'); 22 | let workspacePath = path.join(projectRoot, 'packages', 'foo'); 23 | return getProject({ cwd: workspacePath }).then(pr => 24 | expect(pr.dir).toBe(projectRoot) 25 | ); 26 | }); 27 | 28 | it('should return path to a project root folder from a nested workspace', async () => { 29 | let projectRoot = f.find('nested-workspaces'); 30 | let workspacePath = path.join( 31 | projectRoot, 32 | 'packages', 33 | 'foo', 34 | 'packages', 35 | 'baz' 36 | ); 37 | return getProject({ cwd: workspacePath }).then(pr => 38 | expect(pr.dir).toBe(projectRoot) 39 | ); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/functions/getDependencyGraph.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import * as yarn from '../utils/yarn'; 4 | import type { configDependencyType } from '../types'; 5 | 6 | type Options = { 7 | cwd?: string, 8 | excludedTypes?: Array 9 | }; 10 | 11 | type DependencyGraph = Map>; 12 | 13 | export default async function getDependencyGraph( 14 | opts: Options = {} 15 | ): Promise { 16 | let cwd = opts.cwd || process.cwd(); 17 | let project = await Project.init(cwd); 18 | let packages = await project.getPackages(); 19 | 20 | let { 21 | graph: dependencyGraph, 22 | valid: graphIsValid 23 | } = await project.getDependencyGraph(packages, opts.excludedTypes); 24 | 25 | if (!graphIsValid) { 26 | throw new Error('Dependency graph is not valid'); 27 | } 28 | 29 | let simplifiedDependencyGraph = new Map(); 30 | 31 | dependencyGraph.forEach((pkgInfo, pkgName) => { 32 | simplifiedDependencyGraph.set(pkgName, pkgInfo.dependencies); 33 | }); 34 | 35 | return simplifiedDependencyGraph; 36 | } 37 | -------------------------------------------------------------------------------- /src/functions/getDependentsGraph.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import * as yarn from '../utils/yarn'; 4 | import type { configDependencyType } from '../types'; 5 | 6 | type Options = { 7 | cwd?: string, 8 | excludedTypes?: Array 9 | }; 10 | 11 | type DependentsGraph = Map>; 12 | 13 | export default async function getDependentsGraph( 14 | opts: Options = {} 15 | ): Promise { 16 | let cwd = opts.cwd || process.cwd(); 17 | let project = await Project.init(cwd); 18 | let packages = await project.getPackages(); 19 | 20 | let { 21 | graph: dependentsGraph, 22 | valid: graphIsValid 23 | } = await project.getDependentsGraph(packages, opts.excludedTypes); 24 | 25 | if (!graphIsValid) { 26 | throw new Error('Dependents graph is not valid'); 27 | } 28 | 29 | let simplifiedDependentsGraph = new Map(); 30 | 31 | dependentsGraph.forEach((pkgInfo, pkgName) => { 32 | simplifiedDependentsGraph.set(pkgName, pkgInfo.dependents); 33 | }); 34 | 35 | return simplifiedDependentsGraph; 36 | } 37 | -------------------------------------------------------------------------------- /src/functions/getProject.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as path from 'path'; 3 | import Project from '../Project'; 4 | import type { JSONValue } from '../types'; 5 | 6 | type Options = { 7 | cwd?: string 8 | }; 9 | 10 | type Package = { 11 | dir: string, 12 | name: string, 13 | config: JSONValue 14 | }; 15 | 16 | export default async function getProject(opts: Options = {}): Promise { 17 | let cwd = opts.cwd || process.cwd(); 18 | let project = await Project.init(cwd); 19 | 20 | return { 21 | dir: project.pkg.dir, 22 | name: project.pkg.config.getName(), 23 | config: project.pkg.config.json 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/functions/getWorkspaces.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import type { JSONValue } from '../types'; 4 | 5 | type Options = { 6 | cwd?: string, 7 | only?: string, 8 | ignore?: string, 9 | onlyFs?: string, 10 | ignoreFs?: string 11 | }; 12 | 13 | type Packages = Array<{ 14 | dir: string, 15 | name: string, 16 | config: JSONValue 17 | }>; 18 | 19 | export default async function getWorkspaces( 20 | opts: Options = {} 21 | ): Promise { 22 | let cwd = opts.cwd || process.cwd(); 23 | let project = await Project.init(cwd); 24 | let packages = await project.getPackages(); 25 | 26 | let filtered = project.filterPackages(packages, { 27 | only: opts.only, 28 | ignore: opts.ignore, 29 | onlyFs: opts.onlyFs, 30 | ignoreFs: opts.ignoreFs 31 | }); 32 | 33 | return filtered.map(pkg => ({ 34 | dir: pkg.dir, 35 | name: pkg.getName(), 36 | config: pkg.config.json 37 | })); 38 | } 39 | -------------------------------------------------------------------------------- /src/functions/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | export { default as getProject } from './getProject'; 3 | export { default as getWorkspaces } from './getWorkspaces'; 4 | export { default as getDependencyGraph } from './getDependencyGraph'; 5 | export { default as getDependentsGraph } from './getDependentsGraph'; 6 | export { default as publishPackages } from './publishPackages'; 7 | export { default as runWorkspaceTasks } from './runWorkspaceTasks'; 8 | export { default as updatePackageVersions } from './updatePackageVersions'; 9 | -------------------------------------------------------------------------------- /src/functions/publishPackages.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { publish, type PublishOptions } from '../utils/publish'; 3 | 4 | export default async function publishPackages(opts: PublishOptions) { 5 | return publish(opts); 6 | } 7 | -------------------------------------------------------------------------------- /src/functions/runWorkspaceTasks.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | import type { FilterOpts, JSONValue, SpawnOpts } from '../types'; 4 | 5 | type WorkspaceInfo = { 6 | dir: string, 7 | config: JSONValue 8 | }; 9 | 10 | type Task = (workspace: WorkspaceInfo) => Promise; 11 | 12 | type Options = { 13 | cwd?: string, 14 | spawnOpts?: SpawnOpts, 15 | filterOpts?: FilterOpts 16 | }; 17 | 18 | export default async function runWorkspaceTasks( 19 | task: Task, 20 | opts: Options = {} 21 | ): Promise { 22 | let cwd = opts.cwd || process.cwd(); 23 | let spawnOpts = opts.spawnOpts || {}; 24 | let filterOpts = opts.filterOpts || {}; 25 | let project = await Project.init(cwd); 26 | let packages = await project.getPackages(); 27 | let filteredPackages = project.filterPackages(packages, filterOpts); 28 | 29 | await project.runPackageTasks(filteredPackages, spawnOpts, pkg => { 30 | return task({ 31 | dir: pkg.dir, 32 | config: pkg.config.json 33 | }); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /src/functions/updateWorkspaceDependencies.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Project from '../Project'; 3 | 4 | type VersionMap = { 5 | [x: string]: any 6 | }; 7 | 8 | type Options = { 9 | cwd?: string 10 | }; 11 | 12 | function versionRangeToRangeType(versionRange: string) { 13 | if (versionRange.charAt(0) === '^') return '^'; 14 | if (versionRange.charAt(0) === '~') return '~'; 15 | return ''; 16 | } 17 | 18 | export default async function updateWorkspaceDependencies( 19 | dependencyToUpgrade: VersionMap, 20 | opts: Options = {} 21 | ) { 22 | let cwd = opts.cwd || process.cwd(); 23 | let project = await Project.init(cwd); 24 | let packages = await project.getPackages(); 25 | let { graph } = await project.getDependencyGraph(packages); 26 | let editedPackages = new Set(); 27 | 28 | // Note: all dependencyToUpgrade are external dependencies 29 | 30 | for (let pkg of packages) { 31 | let pkgDependencies = pkg.getAllDependencies(); 32 | let name = pkg.getName(); 33 | 34 | for (let depName in dependencyToUpgrade) { 35 | if (pkgDependencies.has(depName)) { 36 | let depTypes = pkg.getDependencyTypes(depName); 37 | editedPackages.add(name); 38 | for (let depType of depTypes) { 39 | await pkg.setDependencyVersionRange( 40 | depName, 41 | depType, 42 | dependencyToUpgrade[depName] 43 | ); 44 | } 45 | } 46 | } 47 | } 48 | 49 | return editedPackages; 50 | } 51 | -------------------------------------------------------------------------------- /src/generators/__tests__/license.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | test('generate license'); 3 | -------------------------------------------------------------------------------- /src/generators/license.js: -------------------------------------------------------------------------------- 1 | // TODO 2 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | module.exports = { 3 | ...require('./commands'), 4 | ...require('./functions') 5 | }; 6 | -------------------------------------------------------------------------------- /src/types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export type DependencySet = { 4 | [key: string]: string 5 | }; 6 | 7 | export type Scripts = { 8 | [script: string]: string 9 | }; 10 | 11 | export type JSONValue = 12 | | null 13 | | string 14 | | boolean 15 | | number 16 | | Array 17 | | { [key: string]: JSONValue }; 18 | 19 | export type SpawnOpts = { 20 | orderMode?: 'serial' | 'parallel' | 'parallel-nodes', 21 | bail?: boolean, 22 | // Exclude certain dependency types from being included in the dependency graph used to 23 | // execute package tasks in a certain order 24 | excludeFromGraph?: Array 25 | // maxConcurrent?: number, 26 | }; 27 | 28 | export type FilterOpts = { 29 | only?: string, 30 | ignore?: string, 31 | onlyFs?: string, 32 | ignoreFs?: string 33 | }; 34 | 35 | export type Dependency = { 36 | name: string, 37 | version?: string 38 | }; 39 | 40 | export type configDependencyType = 41 | | 'dependencies' 42 | | 'devDependencies' 43 | | 'peerDependencies' 44 | | 'optionalDependencies'; 45 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/project-with-missing-version-field/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-project", 3 | "description": "The bar config is invalid as it is missing a version field", 4 | "private": true, 5 | "version": "1.0.0", 6 | "bolt": { 7 | "workspaces": ["packages/*"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/project-with-missing-version-field/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "description": "const is better than let" 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/project-with-missing-version-field/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/simple-project-with-bolt-version-check/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "simple-project-with-bolt-version-check", 4 | "version": "1.0.0", 5 | "bolt": { 6 | "version": "0.14.x", 7 | "workspaces": [ 8 | "packages/*" 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/simple-project-with-bolt-version-check/packages/bar/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bar", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/simple-project-with-bolt-version-check/packages/foo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foo", 3 | "version": "1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/symlinks/executable.sh: -------------------------------------------------------------------------------- 1 | echo "hello" 2 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/symlinks/file.txt: -------------------------------------------------------------------------------- 1 | hi 2 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/symlinks/file2.txt: -------------------------------------------------------------------------------- 1 | bye 2 | -------------------------------------------------------------------------------- /src/utils/__fixtures__/symlinks/shim.cmd: -------------------------------------------------------------------------------- 1 | @IF EXIST "%~dp0\node.exe" ( 2 | "%~dp0\node.exe" "%~dp0\shim_target.js" %* 3 | ) ELSE ( 4 | @SETLOCAL 5 | @SET PATHEXT=%PATHEXT:;.JS;=;% 6 | node "%~dp0\shim_target.js" %* 7 | ) -------------------------------------------------------------------------------- /src/utils/__fixtures__/symlinks/shim_target.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boltpkg/bolt/f26c036e69e82253056534e159e0fd0dceb9c21b/src/utils/__fixtures__/symlinks/shim_target.js -------------------------------------------------------------------------------- /src/utils/__mocks__/npm.js: -------------------------------------------------------------------------------- 1 | const actualSpawn = require.requireActual('../npm'); 2 | const npm = jest.genMockFromModule('../npm'); 3 | 4 | let mockInfoResponses = []; 5 | 6 | npm.info = async function(pkgName) { 7 | return Promise.resolve({ 8 | name: pkgName, 9 | version: '1.0.0' 10 | }); 11 | }; 12 | 13 | npm.infoAllow404 = function(pkgName) { 14 | let mockResponse = mockInfoResponses.find(mock => mock.pkgName === pkgName); 15 | 16 | if (mockResponse) return Promise.resolve(mockResponse.mockResponse); 17 | 18 | return Promise.resolve({ 19 | published: true, 20 | pkgInfo: { 21 | name: pkgName, 22 | version: '1.0.0' 23 | } 24 | }); 25 | }; 26 | 27 | /** Causes npm.infoAllow404 to return a specified mock response for a packageName */ 28 | npm.__mockInfoAllow404 = (pkgName, mockResponse) => { 29 | mockInfoResponses.push({ pkgName, mockResponse }); 30 | }; 31 | 32 | npm.__clearMockInfoAllow404 = () => { 33 | mockInfoResponses = []; 34 | }; 35 | 36 | module.exports = npm; 37 | -------------------------------------------------------------------------------- /src/utils/__mocks__/spawn.js: -------------------------------------------------------------------------------- 1 | const actualSpawn = require.requireActual('../spawn'); 2 | const spawn = jest.genMockFromModule('../spawn'); 3 | 4 | function isArrayShape(actual, expected) { 5 | return !expected.find((value, index) => { 6 | return value !== actual[index]; 7 | }); 8 | } 9 | 10 | function isObjectShape(actual, expected) { 11 | return !Object.keys(expected).find(key => { 12 | return expected[key] === actual[key]; 13 | }); 14 | } 15 | 16 | const mocks = []; 17 | 18 | spawn.default = async function mockSpawn(cmd, args, opts) { 19 | let found = mocks.find(mock => { 20 | if (cmd !== mock.cmd) return false; 21 | if (!isArrayShape(args, mock.args)) return false; 22 | if (!isObjectShape(opts, mock.opts)) return false; 23 | return true; 24 | }); 25 | 26 | let result = { code: 0, stdout: '', stderr: '' }; 27 | 28 | if (!found) { 29 | return Promise.resolve(); 30 | } 31 | }; 32 | 33 | // __mock('echo', ['test'], {}, { code: 0, stdout: '', stderr: '' }); 34 | spawn.__mock = ({ cmd, args, opts }, { stdout, stderr, code }) => { 35 | mocks.push({ cmd, args, opts, stdout, stderr, code }); 36 | }; 37 | 38 | module.exports = spawn; 39 | -------------------------------------------------------------------------------- /src/utils/__tests__/jsonModifier.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import addWorkspacesToJson from '../jsonModifier'; 3 | 4 | describe('Json Modifier', () => { 5 | test('addWorkspacesToJson()', async () => { 6 | let json = await addWorkspacesToJson({}); 7 | expect(JSON.stringify(json)).toBe('{"bolt":{"workspaces":["packages/*"]}}'); 8 | }); 9 | 10 | test('addWorkspacesToJson() appends workspace information correctly', async () => { 11 | let json = await addWorkspacesToJson({ name: 'simple-project' }); 12 | expect(JSON.stringify(json)).toBe( 13 | `{"name":"simple-project","bolt":{"workspaces":["packages/*"]}}` 14 | ); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/utils/__tests__/locks.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as locks from '../locks'; 3 | 4 | describe('locks', () => { 5 | test('lock()'); 6 | test('unlock()'); 7 | }); 8 | -------------------------------------------------------------------------------- /src/utils/__tests__/logger.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as logger from '../logger'; 3 | 4 | describe('logger', () => { 5 | test('prefix()'); 6 | test('log()'); 7 | test('title()'); 8 | test('info()'); 9 | test('warn()'); 10 | test('error()'); 11 | test('success()'); 12 | test('stdout()'); 13 | test('stderr()'); 14 | }); 15 | -------------------------------------------------------------------------------- /src/utils/__tests__/npm.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import * as npm from '../npm'; 4 | import Project from '../../Project'; 5 | import * as processes from '../processes'; 6 | import fixtures from 'fixturez'; 7 | import containDeep from 'jest-expect-contain-deep'; 8 | 9 | const f = fixtures(__dirname); 10 | 11 | jest.mock('../logger'); 12 | jest.mock('../processes'); 13 | 14 | let REAL_ENV = process.env; 15 | 16 | const unsafeProcesses: any & typeof processes = processes; 17 | 18 | describe('npm', () => { 19 | describe('publish', () => { 20 | let cwd; 21 | let result; 22 | 23 | beforeEach(async () => { 24 | cwd = f.find('simple-project'); 25 | }); 26 | 27 | afterEach(async () => { 28 | process.env = REAL_ENV; 29 | }); 30 | 31 | test('returns published true when npm publish is successesful', async () => { 32 | unsafeProcesses.spawn.mockImplementation(() => Promise.resolve()); 33 | result = await npm.publish('simple-project', { 34 | cwd 35 | }); 36 | expect(result).toEqual({ published: true }); 37 | }); 38 | 39 | test('returns published false when npm publish is unsuccessesful', async () => { 40 | unsafeProcesses.spawn.mockImplementation(() => Promise.reject()); 41 | result = await npm.publish('simple-project', { 42 | cwd 43 | }); 44 | expect(result).toEqual({ published: false }); 45 | }); 46 | 47 | test('Overrides the npm_config_registry env variable correctly', async () => { 48 | process.env = { npm_config_registry: 'https://registry.yarnpkg.com' }; 49 | unsafeProcesses.spawn.mockImplementation(() => Promise.resolve()); 50 | result = await npm.publish('simple-project', { 51 | cwd 52 | }); 53 | 54 | expect(unsafeProcesses.spawn).toHaveBeenCalledWith( 55 | 'npm', 56 | ['publish'], 57 | containDeep({ 58 | cwd, 59 | env: {} 60 | }) 61 | ); 62 | }); 63 | }); 64 | 65 | test('info()'); 66 | test('addTag()'); 67 | test('removeTag()'); 68 | }); 69 | -------------------------------------------------------------------------------- /src/utils/__tests__/processes.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as processes from '../processes'; 3 | 4 | describe('processes', () => { 5 | test('spawn()'); 6 | test('handleSignals()'); 7 | }); 8 | -------------------------------------------------------------------------------- /src/utils/__tests__/promises.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as promises from '../promises'; 3 | 4 | describe('promises', () => { 5 | test('settleAll()'); 6 | }); 7 | -------------------------------------------------------------------------------- /src/utils/__tests__/prompts.test.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import * as prompts from '../prompts'; 3 | import inquirer from 'inquirer'; 4 | 5 | jest.mock('inquirer'); 6 | 7 | describe('Prompts', () => { 8 | test('isWorkspaceNeeded', async () => { 9 | inquirer.prompt.mockReturnValueOnce({ workspaces: true }); 10 | let workspaceNeeded = await prompts.isWorkspaceNeeded(); 11 | expect(workspaceNeeded).toBe(true); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/utils/changes.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import Repository from '../Repository'; 3 | import Package from '../Package'; 4 | import * as git from '../utils/git'; 5 | 6 | async function getLastVersionCommitForPackage(repo: Repository, pkg: Package) { 7 | let cwd = repo.dir; 8 | let filePath = pkg.config.filePath; 9 | let commits = await git.getCommitsToFile(filePath, { cwd }); 10 | let matchedCommit = null; 11 | 12 | for (let commit of commits) { 13 | let parentCommit = await git.getCommitParent(commit.hash, { cwd }); 14 | if (!parentCommit) continue; 15 | 16 | let before = await git.showFileAtCommit(filePath, parentCommit, { 17 | cwd 18 | }); 19 | let after = await git.showFileAtCommit(filePath, commit.hash, { cwd }); 20 | 21 | let jsonBefore = JSON.parse(before); 22 | let jsonAfter = JSON.parse(after); 23 | 24 | if (jsonAfter.version !== jsonBefore.version) { 25 | matchedCommit = commit; 26 | break; 27 | } 28 | } 29 | 30 | return matchedCommit; 31 | } 32 | 33 | export async function getPackageVersionCommits( 34 | repo: Repository, 35 | packages: Array 36 | ) { 37 | let versionCommits = new Map(); 38 | 39 | for (let pkg of packages) { 40 | let commit = await getLastVersionCommitForPackage(repo, pkg); 41 | versionCommits.set(pkg, commit); 42 | } 43 | 44 | return versionCommits; 45 | } 46 | -------------------------------------------------------------------------------- /src/utils/cleanUp.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | // cleanUp function must be synchronus 4 | export function handleAllSignals(cleanUp: () => void) { 5 | process.on('exit', code => { 6 | cleanUp(); 7 | }); 8 | process.on('SIGTERM', code => { 9 | cleanUp(); 10 | process.exit(code); 11 | }); 12 | process.on('SIGINT', code => { 13 | cleanUp(); 14 | process.exit(code); 15 | }); 16 | process.on('unhandledRejection', err => { 17 | cleanUp(); 18 | process.exit(1); 19 | }); 20 | process.on('uncaughtException', err => { 21 | cleanUp(); 22 | process.exit(1); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/env.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import ciParallelVars from 'ci-parallel-vars'; 3 | 4 | const VARS = { 5 | CI_NODE_TOTAL: ciParallelVars ? ciParallelVars.total : null, 6 | CI_NODE_INDEX: ciParallelVars ? ciParallelVars.index : null 7 | }; 8 | 9 | const OVERRIDES = new Map(); 10 | 11 | export function get(name: $Keys) { 12 | return OVERRIDES.has(name) ? OVERRIDES.get(name) : VARS[name]; 13 | } 14 | 15 | export function __override>(name: Name, value: any) { 16 | OVERRIDES.set(name, value); 17 | } 18 | 19 | export function __reset() { 20 | OVERRIDES.clear(); 21 | } 22 | -------------------------------------------------------------------------------- /src/utils/errors.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export class BoltError extends Error {} 4 | -------------------------------------------------------------------------------- /src/utils/execCommand.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type Project from '../Project'; 3 | import type Package from '../Package'; 4 | import * as processes from './processes'; 5 | import * as options from './options'; 6 | 7 | export default function execCommand( 8 | project: Project, 9 | pkg: Package, 10 | command: string, 11 | commandArgs: options.Args 12 | ) { 13 | let PATH_PARTS = []; 14 | 15 | // We don't want to add the project package to the PATH twice 16 | if (!pkg.isSamePackage(project.pkg)) { 17 | PATH_PARTS.push(pkg.nodeModulesBin); 18 | } 19 | 20 | PATH_PARTS.push(project.pkg.nodeModulesBin); 21 | 22 | if (process.env.PATH) { 23 | PATH_PARTS.push(process.env.PATH); 24 | } 25 | 26 | let PATH = PATH_PARTS.join(':'); 27 | 28 | return processes.spawn(command, commandArgs, { 29 | pkg, 30 | cwd: pkg.dir, 31 | tty: false, 32 | env: { ...process.env, PATH } 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /src/utils/globs.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import multimatch from 'multimatch'; 3 | import globby from 'globby'; 4 | import * as path from 'path'; 5 | 6 | function matchGlobs(paths: Array, patterns: Array) { 7 | return multimatch(paths, patterns); 8 | } 9 | 10 | function findGlobs(cwd: string, patterns: Array) { 11 | return globby(patterns, { cwd }); 12 | } 13 | 14 | export function matchWorkspaces(paths: Array, patterns: Array) { 15 | return matchGlobs(paths, patterns); 16 | } 17 | 18 | export function findWorkspaces(cwd: string, patterns: Array) { 19 | return findGlobs(cwd, patterns); 20 | } 21 | 22 | export function matchOnlyAndIgnore( 23 | paths: Array, 24 | only: string | void, 25 | ignore: string | void 26 | ) { 27 | let onlyPattern = only || '**'; 28 | let ignorePattern = ignore ? `!${ignore}` : ''; 29 | return matchGlobs(paths, [onlyPattern, ignorePattern]); 30 | } 31 | -------------------------------------------------------------------------------- /src/utils/jsonModifier.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import type { JSONValue } from '../types'; 3 | 4 | export default async function addWorkspacesToJson(json: { 5 | [key: string]: JSONValue 6 | }) { 7 | let workspaces = ['packages/*']; 8 | json.bolt = { 9 | workspaces 10 | }; 11 | return json; 12 | } 13 | -------------------------------------------------------------------------------- /src/utils/promiseWrapper.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | export type PromiseSuccess = { 4 | result: T, 5 | status: 'success', 6 | args: Array 7 | }; 8 | 9 | export type PromiseFailure = { 10 | error: any, 11 | status: 'error', 12 | args: Array 13 | }; 14 | 15 | export type PromiseResult = PromiseSuccess | PromiseFailure; 16 | 17 | type PromiseFunction = (...args: Array) => Promise; 18 | 19 | export function promiseWrapper( 20 | promiseFunc: PromiseFunction 21 | ): PromiseFunction> { 22 | return (...args: Array): Promise> => { 23 | return promiseFunc(...args).then( 24 | result => ({ result, status: 'success', args }), 25 | error => ({ error, status: 'error', args }) 26 | ); 27 | }; 28 | } 29 | 30 | export function promiseWrapperSuccess( 31 | promiseFunc: PromiseFunction 32 | ): PromiseFunction> { 33 | return (...args: Array): Promise> => { 34 | return promiseFunc(...args).then(result => ({ 35 | result, 36 | status: 'success', 37 | args 38 | })); 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /src/utils/promises.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /** 3 | * This ensures that all promises have finished before throwing any errors. Useful when you need to 4 | * be able to clean up after yourself, but have many async operations happening at once 5 | * 6 | * try { 7 | * let promises = []; 8 | * let locksHeld = []; 9 | * 10 | * files.forEach(file => { 11 | * promises.push(getLockForFile(f) 12 | * .then(lock => { locksHeld.push(lock) }) 13 | * ); 14 | * }); 15 | * 16 | * await Promise.all(promises); // BAD: leaves us with locks that hadnt resolved yet 17 | * await settleAll(locksHeld); // GOOD: We dont throw until after all promises have resolved 18 | * } catch(err) { 19 | * // need to release the locks we have 20 | * releaseLocksForFiles(locksHeld); 21 | * } 22 | * */ 23 | export async function settleAll( 24 | promises: Array> 25 | ): Promise> { 26 | let error: any; 27 | let results: Array = []; 28 | 29 | for (let promise of promises) { 30 | try { 31 | results.push(await promise); 32 | } catch (err) { 33 | error = err; 34 | } 35 | } 36 | 37 | if (error) { 38 | throw error; 39 | } else { 40 | return results; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/utils/prompts.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import inquirer from 'inquirer'; 4 | 5 | export async function isWorkspaceNeeded() { 6 | let question = await inquirer.prompt([ 7 | { 8 | type: 'confirm', 9 | name: 'workspaces', 10 | message: 'create workspaces?', 11 | default: false, 12 | prefix: 'question' 13 | } 14 | ]); 15 | 16 | return question.workspaces; 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/symlinkPackagesBinariesToProject.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import path from 'path'; 3 | import pathIsInside from 'path-is-inside'; 4 | import includes from 'array-includes'; 5 | 6 | import Project from '../Project'; 7 | import Package from '../Package'; 8 | import { BoltError } from './errors'; 9 | import * as fs from './fs'; 10 | import * as logger from './logger'; 11 | import * as messages from './messages'; 12 | import * as yarn from './yarn'; 13 | 14 | export default async function symlinkPackagesBinaries(project: Project) { 15 | let projectBinPath = project.pkg.nodeModulesBin; 16 | let packages = await project.getPackages(); 17 | let { graph: dependencyGraph } = await project.getDependencyGraph(packages); 18 | 19 | let symlinksToCreate = []; 20 | 21 | for (let pkg of packages) { 22 | const pkgBins = await pkg.getBins(); 23 | 24 | if (pkgBins.length === 0) { 25 | continue; 26 | } 27 | 28 | for (let pkgBin of pkgBins) { 29 | let binName = pkgBin.name.split('/').pop(); 30 | let src = pkgBin.filePath; 31 | let dest = path.join(projectBinPath, binName); 32 | 33 | symlinksToCreate.push({ src, dest, type: 'exec' }); 34 | } 35 | } 36 | 37 | await Promise.all( 38 | symlinksToCreate.map(({ src, dest, type }) => fs.symlink(src, dest, type)) 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /src/utils/upgradeDependenciesInPackages.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import Project from '../Project'; 4 | import Package from '../Package'; 5 | import type { Dependency } from '../types'; 6 | import * as messages from './messages'; 7 | import { BoltError } from './errors'; 8 | import * as logger from './logger'; 9 | import * as yarn from './yarn'; 10 | import updatePackageVersions from '../functions/updatePackageVersions'; 11 | import updateWorkspaceDependencies from '../functions/updateWorkspaceDependencies'; 12 | 13 | export default async function upgradeDependenciesInPackage( 14 | project: Project, 15 | pkg: Package, 16 | dependencies: Array, 17 | flags?: Array 18 | ) { 19 | let packages = await project.getPackages(); 20 | let pkgDependencies = pkg.getAllDependencies(); 21 | let { graph: depGraph } = await project.getDependencyGraph(packages); 22 | 23 | let externalDeps = dependencies.filter(dep => !depGraph.has(dep.name)); 24 | let internalDeps = dependencies.filter(dep => depGraph.has(dep.name)); 25 | let projectDependencies = project.pkg.getAllDependencies(); 26 | 27 | if (project.pkg.isSamePackage(pkg)) { 28 | if (internalDeps.length > 0) { 29 | let internalDepNames = internalDeps.map(dep => dep.name); 30 | internalDeps.forEach(dep => { 31 | logger.error( 32 | messages.cannotUpgradeWorkspaceDependencyInProject(dep.name) 33 | ); 34 | }); 35 | throw new BoltError(messages.noNeedToSymlinkInternalDependency()); 36 | } 37 | } 38 | 39 | await yarn.upgrade(project.pkg, externalDeps, flags); 40 | 41 | // we reinitialise the project config because it may be modified externally by yarn 42 | let newProject = await Project.init(project.pkg.dir); 43 | // get the new versions of everything from the project config 44 | let newProjectDependencies = newProject.pkg.getAllDependencies(); 45 | let depsToUpgrade = {}; 46 | 47 | newProjectDependencies.forEach((value, key) => { 48 | depsToUpgrade[key] = value; 49 | }); 50 | 51 | return await updateWorkspaceDependencies(depsToUpgrade, { 52 | cwd: project.pkg.dir 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /src/utils/validateProject.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import semver from 'semver'; 3 | import Project from '../Project'; 4 | import Config from '../Config'; 5 | import Package from '../Package'; 6 | import * as messages from './messages'; 7 | import { BoltError } from './errors'; 8 | import * as logger from './logger'; 9 | import { BOLT_VERSION } from '../constants'; 10 | 11 | export default async function validateProject(project: Project) { 12 | let packages = await project.getPackages(); 13 | let projectDependencies = project.pkg.getAllDependencies(); 14 | let projectConfig = project.pkg.config; 15 | let { graph: depGraph } = await project.getDependencyGraph(packages); 16 | 17 | let projectIsValid = true; 18 | 19 | // If the project has an engines.bolt field we must respect it 20 | let boltConfigVersion = projectConfig.getBoltConfigVersion(); 21 | if (boltConfigVersion) { 22 | if (!semver.satisfies(BOLT_VERSION, boltConfigVersion)) { 23 | logger.error( 24 | messages.invalidBoltVersion(BOLT_VERSION, boltConfigVersion) 25 | ); 26 | projectIsValid = false; 27 | } 28 | } 29 | 30 | // Workspaces always have a name and a version in their configs 31 | for (let pkg of packages) { 32 | try { 33 | pkg.getName(); 34 | } catch (err) { 35 | logger.error(err.message); 36 | projectIsValid = false; 37 | } 38 | 39 | try { 40 | pkg.getVersion(); 41 | } catch (err) { 42 | logger.error(err.message); 43 | projectIsValid = false; 44 | } 45 | } 46 | 47 | // Workspaces should never appear as dependencies in the Project config 48 | for (let pkg of packages) { 49 | let depName = pkg.getName(); 50 | if (projectDependencies.has(depName)) { 51 | logger.error(messages.projectCannotDependOnWorkspace(depName)); 52 | projectIsValid = false; 53 | } 54 | } 55 | 56 | /** 57 | * 58 | */ 59 | 60 | return projectIsValid; 61 | } 62 | --------------------------------------------------------------------------------