diff --git a/.env.example b/.env.example new file mode 100644 index 00000000000..8f6506e0da4 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +# GitHub token with "public_repo" scope required for --create-release=github +# @see https://github.com/settings/tokens +GH_TOKEN=REPLACEME diff --git a/.eslintrc.yaml b/.eslintrc.yaml index b3f86633a39..30e4b93cbc9 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -61,11 +61,6 @@ overrides: max-classes-per-file: "off" node/no-extraneous-require: "off" node/no-unpublished-require: "off" - node/no-unsupported-features/es-syntax: - - error - - ignores: - - asyncFunctions - # jest transpiles fast-async no-console: "off" - files: - "test/fixtures/**" @@ -74,6 +69,7 @@ overrides: global-require: "off" import/no-extraneous-dependencies: "off" import/no-unresolved: "off" + import/no-useless-path-segments: "off" node/no-extraneous-require: "off" node/no-missing-require: - error diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 323536bddba..1f7c59759ca 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,6 +22,7 @@ jobs: key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} restore-keys: | ${{ runner.os }}-node- + - run: npm -g i npm@next-7 - run: npm ci - run: npm run ci:lint @@ -31,7 +32,7 @@ jobs: strategy: fail-fast: true matrix: - node: [ 12, 10, 8 ] + node: [ 12, 10 ] script: [ 'ci:test:unit', 'ci:test:integration' ] steps: - uses: actions/checkout@v2 @@ -48,6 +49,7 @@ jobs: run: | git config --global user.email test@example.com git config --global user.name "Tester McPerson" + - run: npm -g i npm@next-7 - run: npm ci - run: npm run ${{ matrix.script }} @@ -80,6 +82,7 @@ jobs: run: | git config --global user.email test@example.com git config --global user.name "Tester McPerson" + - run: npm -g i npm@next-7 - run: npm ci - env: LERNA_CI_TYPE: ${{ matrix.subset }} diff --git a/.gitignore b/.gitignore index ca0105c35e2..9ae5b4665ca 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ tmp coverage/ .nyc_output/ .eslintcache +.env diff --git a/.travis.yml b/.travis.yml index 70d62834320..76ead582a5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ language: node_js node_js: - "12" - "10" - - "8" os: - linux diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a67c2e6176..a7f8fce32fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,125 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Bug Fixes + +* **version:** Ensure --create-release environment variables are present during initialization ([2d0a97a](https://github.com/lerna/lerna/commit/2d0a97aade2b17cb58ce8c0afdbfd950033f46db)) +* Improve accuracy of JSDoc type annotations ([1ec69f0](https://github.com/lerna/lerna/commit/1ec69f0e0f7a3f1e0c74dbacb17fab2d7b7a8a44)) +* **create:** Use main as default Github branch ([1a951e9](https://github.com/lerna/lerna/commit/1a951e92376b2aff2e1866791a0ae0b03f19515d)) +* **import:** Better handling of "Patch is empty" ([#2588](https://github.com/lerna/lerna/issues/2588)) ([0497bc7](https://github.com/lerna/lerna/commit/0497bc73043b2b646cc614f54187b68ba007000e)) + + +### Code Refactoring + +* **describe-ref:** Add JSDoc types, remove test-only export ([e5cf30c](https://github.com/lerna/lerna/commit/e5cf30cb66f9b85f13afb475ea0c9e59c8fabba3)) +* **package:** Move Package.lazy() to static method ([e52108e](https://github.com/lerna/lerna/commit/e52108e308192150e1d5e21f3a23c9e91f87d4b7)) + + +### Features + +* **child-process:** Add JSDoc types ([1840492](https://github.com/lerna/lerna/commit/1840492a6b9e832dafe7046157798e3157c2a13b)) +* **collect-uncommitted:** Remove figgy-pudding ([621b382](https://github.com/lerna/lerna/commit/621b3821cf0ce4921a0815e0ce33a8222c7b172b)) +* **collect-updates:** Add JSDoc type annotations to primary export ([a4e7c78](https://github.com/lerna/lerna/commit/a4e7c7884f8c278f705824684a25a717327cda06)) +* **conventional-commits:** Add JSDoc types to named exports ([81a591c](https://github.com/lerna/lerna/commit/81a591ccf1b0ca32f7f4638bab4f84b5743a3ca6)) +* **deps:** @evocateur/libnpmaccess -> libnpmaccess@^4.0.1 ([7974b35](https://github.com/lerna/lerna/commit/7974b351e53575503dd881c639b53d820e4f525e)) +* **deps:** @evocateur/libnpmpublish -> libnpmpublish@^4.0.0 ([341146e](https://github.com/lerna/lerna/commit/341146ef6c9111607f99d2f1663f973ab16c755e)) +* **deps:** @evocateur/npm-registry-fetch -> npm-registry-fetch@^9.0.0 ([6df42f2](https://github.com/lerna/lerna/commit/6df42f2caf0887c38870c07a9f850dae0e9c4253)) +* **deps:** @evocateur/pacote -> pacote@^11.1.13 ([99b4217](https://github.com/lerna/lerna/commit/99b4217ed143527a45969f3a46f1bd9b84999d68)) +* **deps:** @octokit/rest@^18.0.9 ([f064a55](https://github.com/lerna/lerna/commit/f064a55627994a08f5ba9f735fcd5b2c3491e431)) +* **deps:** @zkochan/cmd-shim -> cmd-shim@^4.0.2 ([179e2c3](https://github.com/lerna/lerna/commit/179e2c30b5734bb95f8f4005169987231992a525)) +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* **deps:** byte-size@^7.0.0 ([a1b2555](https://github.com/lerna/lerna/commit/a1b255504b52d83455de7bed32bf5e4d63cc7538)) +* **deps:** camelcase -> yargs-parser/camelCase ([d966e8b](https://github.com/lerna/lerna/commit/d966e8b3d36ad9eb02f656b73d9b41882ca7b208)) +* **deps:** chalk@^4.1.0 ([d2a9ed5](https://github.com/lerna/lerna/commit/d2a9ed537139f49561a7e29b3ebf624c97f48c77)) +* **deps:** conventional-changelog-core@^4.2.1 ([54e2b98](https://github.com/lerna/lerna/commit/54e2b98a815cc003981a807f0a167c7dd305523a)) +* **deps:** conventional-recommended-bump@^6.0.11 ([4ff481c](https://github.com/lerna/lerna/commit/4ff481c9d7ee3495471d5d1eeb1b72738d7c5410)) +* **deps:** cosmiconfig@^7.0.0 ([2958fe6](https://github.com/lerna/lerna/commit/2958fe6b3e586adb27da6643d1c215b73c8afa7b)) +* **deps:** dot-prop@^6.0.0 ([5f31d3b](https://github.com/lerna/lerna/commit/5f31d3b46f8d1d84d264b90be38f57887d2e4969)) +* **deps:** execa@^4.1.0 ([9051dca](https://github.com/lerna/lerna/commit/9051dcab1a68b56db09b82ab0345c5f36bcfee2d)) +* **deps:** execa@^5.0.0 ([d8100fd](https://github.com/lerna/lerna/commit/d8100fd9e0742b049ed16ac77e976ce34234ebfc)) +* **deps:** fs-extra@^9.0.1 ([2f6f4e0](https://github.com/lerna/lerna/commit/2f6f4e066d5a41b4cd508b3405ac1d0a342932dc)) +* **deps:** get-port@^5.1.1 ([b1b2275](https://github.com/lerna/lerna/commit/b1b2275237f16a26e6f96deffee8b0f72d8ce17d)) +* **deps:** get-stream@^6.0.0 ([ddf2ab5](https://github.com/lerna/lerna/commit/ddf2ab5512704f17d31773f82fb180e659c461a6)) +* **deps:** globby@^11.0.1 ([6cb5bbe](https://github.com/lerna/lerna/commit/6cb5bbec5599cdd93d314ffdc4abea8822e48075)) +* **deps:** import-local@^3.0.2 ([e0e74d4](https://github.com/lerna/lerna/commit/e0e74d46c61ae884c1a27627c6e77e488061c9ba)) +* **deps:** init-package-json@^2.0.1 ([4042e8e](https://github.com/lerna/lerna/commit/4042e8e0a73427d1f9585ff285554e2a954b7be6)) +* **deps:** inquirer@^7.3.3 ([0b37795](https://github.com/lerna/lerna/commit/0b377959d76ad354f384ff3addb42e3855eec379)) +* **deps:** load-json-file@^6.2.0 ([239f54b](https://github.com/lerna/lerna/commit/239f54b070691106dd9b31f2a279d726744651f8)) +* **deps:** multimatch@^5.0.0 ([0172526](https://github.com/lerna/lerna/commit/017252644cfd2394e77680673bae0e31ffa58d5e)) +* **deps:** npm-package-arg@^8.1.0 ([12c8923](https://github.com/lerna/lerna/commit/12c892342d33b86a00ee2cf9079f9b26fe316dc6)) +* **deps:** npm-packlist@^2.1.4 ([c63fabd](https://github.com/lerna/lerna/commit/c63fabdc09bae34d8f8d907e5d21a996ac01daef)) +* **deps:** p-finally -> Promise.prototype.finally() ([028db04](https://github.com/lerna/lerna/commit/028db045b1221df000a2b98c5dceb1e4915a7806)) +* **deps:** p-finally@^2.0.1 ([165e47e](https://github.com/lerna/lerna/commit/165e47e722acf6462cf0b4e3a7d0e14d3971e7fb)) +* **deps:** p-map-series@^2.1.0 ([7f68076](https://github.com/lerna/lerna/commit/7f680767e0b3c7a15f951c51d4975150fb6e9112)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* **deps:** p-pipe@^3.1.0 ([489f59e](https://github.com/lerna/lerna/commit/489f59e28657a039becb4cdba5a1955043c73cf1)) +* **deps:** p-queue@^6.6.2 ([ed76cdd](https://github.com/lerna/lerna/commit/ed76cdddf57963e7aa3dfbff1f37fe361c9e2769)) +* **deps:** p-reduce@^2.1.0 ([fd4289a](https://github.com/lerna/lerna/commit/fd4289ad20fd9ce5921b83d97f82984abf4f65b0)) +* **deps:** p-waterfall@^2.1.0 ([7b7ea50](https://github.com/lerna/lerna/commit/7b7ea503e8371e7f663fd604bff51aebfe9e7b33)) +* **deps:** path-exists@^4.0.0 ([3fb6304](https://github.com/lerna/lerna/commit/3fb6304a31b4c92cf7eac6f7ab4fc725a22dc68f)) +* **deps:** pify@^5.0.0 ([6b34452](https://github.com/lerna/lerna/commit/6b3445219f0f022411a7cb282b0ba39a072e2ef2)) +* **deps:** read-cmd-shim@^2.0.0 ([9f78eee](https://github.com/lerna/lerna/commit/9f78eee7c148bbe0a623af193478573c4373f5a8)) +* **deps:** read-package-json@^3.0.0 ([2a02865](https://github.com/lerna/lerna/commit/2a02865a70a0b9ea60220a98bfff745128c90c6f)) +* **deps:** read-package-tree@^5.3.1 ([3311780](https://github.com/lerna/lerna/commit/331178049e61f3c401a074d27e84d12856e3494e)) +* **deps:** resolve-from@^5.0.0 ([d414462](https://github.com/lerna/lerna/commit/d4144623f3069fda62b324186c46050f4f7e1c77)) +* **deps:** rimraf@^3.0.2 ([cda2e18](https://github.com/lerna/lerna/commit/cda2e1838ea75eb668249b7a61d6a2828061b188)) +* **deps:** semver@^7.3.2 ([003ad66](https://github.com/lerna/lerna/commit/003ad6641fab8b4e3a82251ebffd27061bd6a31b)) +* **deps:** slash@^3.0.0 ([5dec383](https://github.com/lerna/lerna/commit/5dec383109bcd1cce9abbc80796369db9314acc9)) +* **deps:** ssri@^8.0.0 ([41729b4](https://github.com/lerna/lerna/commit/41729b4f9a2301a5e96cb7850c3bfd211f21006d)) +* **deps:** tar@^6.0.5 ([fce3e77](https://github.com/lerna/lerna/commit/fce3e778276cbab99301b6caba414efd3b4a78ea)) +* **deps:** temp-write@^4.0.0 ([7bbfb70](https://github.com/lerna/lerna/commit/7bbfb7020fbbf1fd7f2ebea38ac2718bea5a0646)) +* **deps:** upath@^2.0.1 ([28ecc48](https://github.com/lerna/lerna/commit/28ecc48aa9f0de6073f0bc534071e2697d8bef98)) +* **deps:** whatwg-url@^8.4.0 ([5dfb7f0](https://github.com/lerna/lerna/commit/5dfb7f0ee196a0c9b9010339d512a5b5b9b75a47)) +* **deps:** write-file-atomic@^3.0.3 ([61f341b](https://github.com/lerna/lerna/commit/61f341b0078a4ef89bdd667389ed892aa080272f)) +* **deps:** write-json-file@^4.3.0 ([d552c53](https://github.com/lerna/lerna/commit/d552c533c45489a1774f3c3b9ae8d15fc5d3b2a8)) +* **deps:** write-pkg@^4.0.0 ([34db21c](https://github.com/lerna/lerna/commit/34db21c8e344928d9ade36e191b337b74783c566)) +* **deps:** yargs@^16.1.1 ([53d432b](https://github.com/lerna/lerna/commit/53d432bd4cc5ff86345c6ca5cf601a6ff2d3e814)) +* **filter-options:** Remove figgy-pudding ([7d90289](https://github.com/lerna/lerna/commit/7d9028906098cf20c287c460da7d236bdb29007e)) +* **has-npm-version:** Remove unused makePredicate() export ([56cba2f](https://github.com/lerna/lerna/commit/56cba2ffc4dccf3380548567a36a35345fb7c747)) +* **npm-dist-tag:** Remove figgy-pudding ([1158f8e](https://github.com/lerna/lerna/commit/1158f8eea49dc3e59860886421bd8ec40a6205df)) +* **npm-publish:** Remove figgy-pudding ([bdc162d](https://github.com/lerna/lerna/commit/bdc162d2719fee38d6189daeb37fe4e22338fda7)) +* **otplease:** Remove figgy-pudding ([45ee52e](https://github.com/lerna/lerna/commit/45ee52e010cfd98fdcddf43f6bfc9cd11b4a3aa0)) +* **pack-directory:** Remove figgy-pudding ([640faa5](https://github.com/lerna/lerna/commit/640faa54cbbc5faeb6b13322c8d4f48bf035a1f7)) +* **package:** Improve JSDoc-inferred types, encapsulation ([4d80c38](https://github.com/lerna/lerna/commit/4d80c3832cf2a1cceb31e535fa841db4c68a7346)) +* **package-graph:** Improve JSDoc-inferred types, encapsulation ([fae9e8d](https://github.com/lerna/lerna/commit/fae9e8dc8d80df57b7bd34f429ea579e0529de30)) +* **prerelease-id-from-version:** Add JSDoc types ([53cdad9](https://github.com/lerna/lerna/commit/53cdad917ba6ca6a3ce350d44c3854248e0ea933)) +* **profiler:** Remove figgy-pudding ([69d4704](https://github.com/lerna/lerna/commit/69d47041e83138869404c131adda3fc3122bf2d9)) +* **project:** Add JSDoc type annotations to primary export ([8443ad3](https://github.com/lerna/lerna/commit/8443ad396b2e4d11df2d0a85b456037ca2cc87c0)) +* **prompt:** Add JSDoc types ([0406568](https://github.com/lerna/lerna/commit/0406568c51bef818b7894f6ade959caf550a378a)) +* **prompt:** Add unambiguous exports ([46fa111](https://github.com/lerna/lerna/commit/46fa11177c433482ba41e6d43765a0d9eaddc89a)) +* **prompt:** Remove ambiguous exports ([42ab453](https://github.com/lerna/lerna/commit/42ab4533d6643c5bb3ceca8eeff7358421235bf6)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* Expose named export ([c1303f1](https://github.com/lerna/lerna/commit/c1303f13adc4cf15f96ff25889b52149f8224c0e)) +* Remove default export ([e2f1ec3](https://github.com/lerna/lerna/commit/e2f1ec3dd049d2a89880029908a2aa7c66f15082)) +* **publish:** Remove figgy-pudding ([caf823e](https://github.com/lerna/lerna/commit/caf823e01e9eb5463b452b929a74dbc83ffc5df7)) +* **query-graph:** Remove figgy-pudding ([3b0e2fe](https://github.com/lerna/lerna/commit/3b0e2fec7c274bc93627404295b51638cb7d7e60)) +* **run-lifecycle:** Remove figgy-pudding ([1093f87](https://github.com/lerna/lerna/commit/1093f87d867ddcdf0d7b56f21ad9786a7fb8d6c1)) +* **run-topologically:** Remove figgy-pudding ([f3a73db](https://github.com/lerna/lerna/commit/f3a73db0f083a77fc14bdff2e4da4b2decfa8c8a)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* **prompt:** The ambiguous 'confirm', 'select', and 'input' exports have been removed. Please use the renamed exports 'promptConfirmation', 'promptSelectOne', and 'promptTextInput' (respectively). +* **has-npm-version:** The makePredicate() export has been removed, memoization is now the responsibility of the caller. +* The default export has been removed, please use a named export instead. +* **describe-ref:** The test-only 'parse()' export has been removed. +* **package:** The `lazy` named export is now a proper static method of `Package`. +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + ## [3.22.1](https://github.com/lerna/lerna/compare/v3.22.0...v3.22.1) (2020-06-09) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b8275304b6a..dc72fd89add 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,3 +110,17 @@ $ xdg-open coverage/lcov-report/index.html ### Submitting Pull Requests This project follows [GitHub's standard forking model](https://guides.github.com/activities/forking/). Please fork the project to submit pull requests. + +### Releasing + +If you are a member of Lerna's [GitHub org](https://github.com/orgs/lerna/people) and have read-write privileges in Lerna's [npm org](https://www.npmjs.com/org/lerna) _with 2-factor auth enabled_, congratulations, you can cut a release! + +You'll need to set up a local `.env` file in the repo root to provide the required environment variables. +The `.env.example` file is available in the root as a template. +The root `.env` file is _never_ placed under version control. + +Once that's done, run the release script and await glory: + +```sh +npm run release +``` diff --git a/README.md b/README.md index 514496e5c3b..adcda3d0c9e 100644 --- a/README.md +++ b/README.md @@ -227,7 +227,7 @@ The above command will automatically hoist things and use relative `file:` speci Hoisting has a few benefits: - All packages use the same version of a given dependency -- Can keep dependencies at the root up-to-date with an automated tool such as [GreenKeeper](https://greenkeeper.io/) +- Can keep dependencies at the root up-to-date with an automated tool such as [Snyk](https://snyk.io/) - Dependency installation time is reduced - Less storage is needed diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index af5ad357bb9..00000000000 --- a/babel.config.js +++ /dev/null @@ -1,15 +0,0 @@ -"use strict"; - -module.exports = { - plugins: [ - [ - "module:fast-async", - { - compiler: { - es6target: true, - noRuntime: true, - }, - }, - ], - ], -}; diff --git a/commands/__mocks__/@lerna/check-working-tree.js b/commands/__mocks__/@lerna/check-working-tree.js index 1278479bdc8..5c51bdec283 100644 --- a/commands/__mocks__/@lerna/check-working-tree.js +++ b/commands/__mocks__/@lerna/check-working-tree.js @@ -4,6 +4,6 @@ const mockCheckWorkingTree = jest.fn(() => Promise.resolve()); const mockThrowIfReleased = jest.fn(() => Promise.resolve()); const mockThrowIfUncommitted = jest.fn(() => Promise.resolve()); -module.exports = mockCheckWorkingTree; +module.exports.checkWorkingTree = mockCheckWorkingTree; module.exports.throwIfReleased = mockThrowIfReleased; module.exports.throwIfUncommitted = mockThrowIfUncommitted; diff --git a/commands/__mocks__/@lerna/collect-updates.js b/commands/__mocks__/@lerna/collect-updates.js index ba2665c56b3..99eff0d5601 100644 --- a/commands/__mocks__/@lerna/collect-updates.js +++ b/commands/__mocks__/@lerna/collect-updates.js @@ -8,7 +8,7 @@ const updated = new Map(); const mockCollectUpdates = jest.fn((filteredPackages, packageGraph, { cwd }) => { const targets = updated.get(cwd); - const updates = targets ? new Map(targets.map(name => [name, packageGraph.get(name)])) : packageGraph; + const updates = targets ? new Map(targets.map((name) => [name, packageGraph.get(name)])) : packageGraph; return Array.from(updates.values()); }); @@ -20,7 +20,7 @@ afterEach(() => { updated.clear(); }); -module.exports = mockCollectUpdates; -module.exports.setUpdated = setUpdated; +module.exports.collectUpdates = mockCollectUpdates; +module.exports.collectUpdates.setUpdated = setUpdated; module.exports.collectPackages = collectPackages; module.exports.getPackagesForOption = getPackagesForOption; diff --git a/commands/__mocks__/@lerna/conventional-commits.js b/commands/__mocks__/@lerna/conventional-commits.js index b93129aea26..6d9e672b1f5 100644 --- a/commands/__mocks__/@lerna/conventional-commits.js +++ b/commands/__mocks__/@lerna/conventional-commits.js @@ -1,15 +1,15 @@ "use strict"; -const fs = require.requireActual("fs-extra"); +const fs = jest.requireActual("fs-extra"); const path = require("path"); const semver = require("semver"); const mockRecommendVersion = jest.fn().mockName("recommendVersion"); const mockUpdateChangelog = jest.fn().mockName("updateChangelog"); -mockRecommendVersion.mockImplementation(node => semver.inc(node.version, "patch")); +mockRecommendVersion.mockImplementation((node) => semver.inc(node.version, "patch")); -mockUpdateChangelog.mockImplementation(pkg => { +mockUpdateChangelog.mockImplementation((pkg) => { const filePath = path.join(pkg.location, "CHANGELOG.md"); // grumble grumble re-implementing the implementation diff --git a/commands/__mocks__/@lerna/github-client.js b/commands/__mocks__/@lerna/github-client.js index 5a9e358a1df..3645e97b02b 100644 --- a/commands/__mocks__/@lerna/github-client.js +++ b/commands/__mocks__/@lerna/github-client.js @@ -1,13 +1,23 @@ "use strict"; +const releases = new Map(); + +// keep test data isolated +afterEach(() => { + releases.clear(); +}); + const client = { repos: { - createRelease: jest.fn(), + createRelease: jest.fn((opts) => { + releases.set(opts.name, opts); + return Promise.resolve(); + }), }, }; -module.exports.client = client; -module.exports.createGitHubClient = () => client; +module.exports.createGitHubClient = jest.fn(() => client); +module.exports.createGitHubClient.releases = releases; module.exports.parseGitRepo = () => ({ owner: "lerna", name: "lerna", diff --git a/commands/__mocks__/@lerna/gitlab-client.js b/commands/__mocks__/@lerna/gitlab-client.js index dacc557a439..3899c3c1834 100644 --- a/commands/__mocks__/@lerna/gitlab-client.js +++ b/commands/__mocks__/@lerna/gitlab-client.js @@ -1,9 +1,20 @@ "use strict"; +const releases = new Map(); + +// keep test data isolated +afterEach(() => { + releases.clear(); +}); + const client = { repos: { - createRelease: jest.fn(), + createRelease: jest.fn((opts) => { + releases.set(opts.name, opts); + return Promise.resolve(); + }), }, }; -module.exports = () => client; +module.exports.createGitLabClient = jest.fn(() => client); +module.exports.createGitLabClient.releases = releases; diff --git a/commands/__mocks__/@lerna/has-npm-version.js b/commands/__mocks__/@lerna/has-npm-version.js index 8672aec5c36..18cbed93197 100644 --- a/commands/__mocks__/@lerna/has-npm-version.js +++ b/commands/__mocks__/@lerna/has-npm-version.js @@ -1,7 +1,5 @@ "use strict"; const mockHasNpmVersion = jest.fn(() => true); -const mockMakePredicate = jest.fn(() => range => mockHasNpmVersion(range)); -module.exports = mockHasNpmVersion; -module.exports.makePredicate = mockMakePredicate; +module.exports.hasNpmVersion = mockHasNpmVersion; diff --git a/commands/__mocks__/@lerna/npm-publish.js b/commands/__mocks__/@lerna/npm-publish.js index ef0ab0c86ed..a7aca4042f1 100644 --- a/commands/__mocks__/@lerna/npm-publish.js +++ b/commands/__mocks__/@lerna/npm-publish.js @@ -19,6 +19,6 @@ afterEach(() => { registry.clear(); }); -module.exports = mockNpmPublish; -module.exports.order = order; -module.exports.registry = registry; +module.exports.npmPublish = mockNpmPublish; +module.exports.npmPublish.order = order; +module.exports.npmPublish.registry = registry; diff --git a/commands/__mocks__/@lerna/output.js b/commands/__mocks__/@lerna/output.js index 7cbd027c1f6..33b7659923b 100644 --- a/commands/__mocks__/@lerna/output.js +++ b/commands/__mocks__/@lerna/output.js @@ -1,17 +1,17 @@ "use strict"; const chalk = require("chalk"); -const multiLineTrimRight = require("@lerna-test/multi-line-trim-right"); +const { multiLineTrimRight } = require("@lerna-test/multi-line-trim-right"); // keep snapshots stable cross-platform -chalk.enabled = false; +chalk.level = 0; // @lerna/output is just a wrapper around console.log const mockOutput = jest.fn(); function logged() { - return mockOutput.mock.calls.map(args => multiLineTrimRight(args[0])).join("\n"); + return mockOutput.mock.calls.map((args) => multiLineTrimRight(args[0])).join("\n"); } -module.exports = mockOutput; -module.exports.logged = logged; +module.exports.output = mockOutput; +module.exports.output.logged = logged; diff --git a/commands/__mocks__/@lerna/pack-directory.js b/commands/__mocks__/@lerna/pack-directory.js index 3e1ba271a7d..be17d0448a2 100644 --- a/commands/__mocks__/@lerna/pack-directory.js +++ b/commands/__mocks__/@lerna/pack-directory.js @@ -2,7 +2,7 @@ const registry = new Set(); -const mockPackDirectory = jest.fn(pkg => { +const mockPackDirectory = jest.fn((pkg) => { registry.add(pkg.name); return Promise.resolve({ @@ -16,5 +16,5 @@ afterEach(() => { registry.clear(); }); -module.exports = mockPackDirectory; -module.exports.registry = registry; +module.exports.packDirectory = mockPackDirectory; +module.exports.packDirectory.registry = registry; diff --git a/commands/__mocks__/@lerna/prompt.js b/commands/__mocks__/@lerna/prompt.js index ea99c7db0f8..e88750341d4 100644 --- a/commands/__mocks__/@lerna/prompt.js +++ b/commands/__mocks__/@lerna/prompt.js @@ -15,9 +15,9 @@ const mockSelect = jest.fn((_, { choices }) => { }); const mockInput = jest.fn(() => Promise.resolve()); -exports.confirm = mockConfirm; -exports.select = mockSelect; -exports.input = mockInput; +exports.promptConfirmation = mockConfirm; +exports.promptSelectOne = mockSelect; +exports.promptTextInput = mockInput; const semverIndex = new Map( [ @@ -32,6 +32,6 @@ const semverIndex = new Map( ].map((keyword, idx) => [keyword, idx]) ); -exports.mockChoices = (...keywords) => { - choiceIndices = keywords.map(keyword => semverIndex.get(keyword)); +mockSelect.chooseBump = (keyword) => { + choiceIndices.push(semverIndex.get(keyword)); }; diff --git a/commands/__mocks__/@lerna/run-lifecycle.js b/commands/__mocks__/@lerna/run-lifecycle.js index 4244513af7f..05d56aef5b0 100644 --- a/commands/__mocks__/@lerna/run-lifecycle.js +++ b/commands/__mocks__/@lerna/run-lifecycle.js @@ -1,7 +1,7 @@ "use strict"; -const mockRunLifecycle = jest.fn(pkg => Promise.resolve(pkg)); -const mockCreateRunner = jest.fn(opts => (pkg, stage) => { +const mockRunLifecycle = jest.fn((pkg) => Promise.resolve(pkg)); +const mockCreateRunner = jest.fn((opts) => (pkg, stage) => { // no longer the actual API, but approximates inner logic of default export if (pkg.scripts[stage]) { return mockRunLifecycle(pkg, stage, opts); @@ -14,6 +14,6 @@ function getOrderedCalls() { return mockRunLifecycle.mock.calls.map(([pkg, script]) => [pkg.name, script]); } -module.exports = mockRunLifecycle; +module.exports.runLifecycle = mockRunLifecycle; module.exports.createRunner = mockCreateRunner; -module.exports.getOrderedCalls = getOrderedCalls; +module.exports.runLifecycle.getOrderedCalls = getOrderedCalls; diff --git a/commands/__mocks__/load-json-file.js b/commands/__mocks__/load-json-file.js index 5babe2aedd0..e0d493d2474 100644 --- a/commands/__mocks__/load-json-file.js +++ b/commands/__mocks__/load-json-file.js @@ -3,7 +3,7 @@ const path = require("path"); const normalizePath = require("normalize-path"); -const loadJsonFile = require.requireActual("load-json-file"); +const loadJsonFile = jest.requireActual("load-json-file"); const asyncRegistry = new Map(); const syncRegistry = new Map(); @@ -17,13 +17,13 @@ function incrementCalled(registry, manifestLocation) { } // by default, act like a spy that counts number of times each location was loaded -const mockLoadJsonFile = jest.fn(manifestLocation => { +const mockLoadJsonFile = jest.fn((manifestLocation) => { incrementCalled(asyncRegistry, manifestLocation); return loadJsonFile(manifestLocation); }); -const mockLoadJsonFileSync = jest.fn(manifestLocation => { +const mockLoadJsonFileSync = jest.fn((manifestLocation) => { incrementCalled(syncRegistry, manifestLocation); return loadJsonFile.sync(manifestLocation); diff --git a/commands/__mocks__/write-pkg.js b/commands/__mocks__/write-pkg.js index 6bd2363f3cf..a65066094c4 100644 --- a/commands/__mocks__/write-pkg.js +++ b/commands/__mocks__/write-pkg.js @@ -1,6 +1,6 @@ "use strict"; -const writePkg = require.requireActual("write-pkg"); +const writePkg = jest.requireActual("write-pkg"); const registry = new Map(); // by default, act like a spy that populates registry @@ -10,7 +10,7 @@ const mockWritePkg = jest.fn((fp, data) => { return writePkg(fp, data); }); -const updatedManifest = name => registry.get(name); +const updatedManifest = (name) => registry.get(name); // a convenient format for assertions function updatedVersions() { diff --git a/commands/add/CHANGELOG.md b/commands/add/CHANGELOG.md index 5f8f303cfc8..0d8078f11cd 100644 --- a/commands/add/CHANGELOG.md +++ b/commands/add/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** @evocateur/pacote -> pacote@^11.1.13 ([99b4217](https://github.com/lerna/lerna/commit/99b4217ed143527a45969f3a46f1bd9b84999d68)) +* **deps:** npm-package-arg@^8.1.0 ([12c8923](https://github.com/lerna/lerna/commit/12c892342d33b86a00ee2cf9079f9b26fe316dc6)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* **deps:** semver@^7.3.2 ([003ad66](https://github.com/lerna/lerna/commit/003ad6641fab8b4e3a82251ebffd27061bd6a31b)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/add diff --git a/commands/add/__tests__/add-command.test.js b/commands/add/__tests__/add-command.test.js index 8926934730f..70ba08e96f8 100644 --- a/commands/add/__tests__/add-command.test.js +++ b/commands/add/__tests__/add-command.test.js @@ -1,11 +1,11 @@ "use strict"; jest.mock("@lerna/bootstrap"); -jest.mock("@evocateur/pacote/manifest"); +jest.mock("pacote"); // mocked or stubbed modules const bootstrap = require("@lerna/bootstrap"); -const getManifest = require("@evocateur/pacote/manifest"); +const pacote = require("pacote"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); @@ -21,7 +21,7 @@ describe("AddCommand", () => { // we already have enough tests of BootstrapCommand bootstrap.mockResolvedValue(); // we don't need network requests during unit tests - getManifest.mockResolvedValue({ version: "1.0.0" }); + pacote.manifest.mockResolvedValue({ version: "1.0.0" }); it("should throw without packages", async () => { const testDir = await initFixture("basic"); @@ -55,7 +55,7 @@ describe("AddCommand", () => { expect(pkg3).toDependOn("tiny-tarball"); expect(pkg4).toDependOn("tiny-tarball"); - expect(getManifest).toHaveBeenLastCalledWith( + expect(pacote.manifest).toHaveBeenLastCalledWith( expect.objectContaining({ // an npm-package-arg Result name: "tiny-tarball", @@ -235,7 +235,7 @@ describe("AddCommand", () => { it("accepts --registry option", async () => { const testDir = await initFixture("basic"); - getManifest.mockImplementationOnce(() => { + pacote.manifest.mockImplementationOnce(() => { const err = new Error("ENOTFOUND"); return Promise.reject(err); }); @@ -249,7 +249,7 @@ describe("AddCommand", () => { // obviously this registry doesn't exist, thus it will always error await expect(command).rejects.toThrow(/ENOTFOUND/); - expect(getManifest).toHaveBeenLastCalledWith( + expect(pacote.manifest).toHaveBeenLastCalledWith( expect.objectContaining({ name: "@my-own/private-idaho", }), diff --git a/commands/add/command.js b/commands/add/command.js index b97647e4812..3c982c08061 100644 --- a/commands/add/command.js +++ b/commands/add/command.js @@ -1,6 +1,6 @@ "use strict"; -const filterable = require("@lerna/filter-options"); +const { filterOptions } = require("@lerna/filter-options"); /** * @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#providing-a-command-module @@ -9,7 +9,7 @@ exports.command = "add [globs..]"; exports.describe = "Add a single dependency to matched packages"; -exports.builder = yargs => { +exports.builder = (yargs) => { yargs .positional("pkg", { describe: "Package name to add as a dependency", @@ -66,7 +66,7 @@ exports.builder = yargs => { .example("$0 add module-1 --no-bootstrap", "Skip automatic `lerna bootstrap`") .example("$0 add babel-core", "Install babel-core in all modules"); - return filterable(yargs); + return filterOptions(yargs); }; exports.handler = function handler(argv) { diff --git a/commands/add/index.js b/commands/add/index.js index 2d9611c4343..fb1fff8bf8d 100644 --- a/commands/add/index.js +++ b/commands/add/index.js @@ -4,15 +4,15 @@ const dedent = require("dedent"); const npa = require("npm-package-arg"); const pMap = require("p-map"); const path = require("path"); -const getManifest = require("@evocateur/pacote/manifest"); +const pacote = require("pacote"); const semver = require("semver"); -const Command = require("@lerna/command"); +const { Command } = require("@lerna/command"); const npmConf = require("@lerna/npm-conf"); const bootstrap = require("@lerna/bootstrap"); -const ValidationError = require("@lerna/validation-error"); +const { ValidationError } = require("@lerna/validation-error"); const { getFilteredPackages } = require("@lerna/filter-options"); -const getRangeToReference = require("./lib/get-range-to-reference"); +const { getRangeToReference } = require("./lib/get-range-to-reference"); module.exports = factory; @@ -37,7 +37,7 @@ class AddCommand extends Command { initialize() { this.spec = npa(this.options.pkg); - this.dirs = new Set(this.options.globs.map(fp => path.resolve(this.project.rootPath, fp))); + this.dirs = new Set(this.options.globs.map((fp) => path.resolve(this.project.rootPath, fp))); this.selfSatisfied = this.packageSatisfied(); // https://docs.npmjs.com/misc/config#save-prefix @@ -58,7 +58,7 @@ class AddCommand extends Command { let chain = Promise.resolve(); chain = chain.then(() => this.getPackageVersion()); - chain = chain.then(version => { + chain = chain.then((version) => { if (version == null) { throw new ValidationError( "ENOTSATISFIED", @@ -71,12 +71,12 @@ class AddCommand extends Command { }); chain = chain.then(() => getFilteredPackages(this.packageGraph, this.execOpts, this.options)); - chain = chain.then(filteredPackages => { + chain = chain.then((filteredPackages) => { this.filteredPackages = filteredPackages; }); chain = chain.then(() => this.collectPackagesToChange()); - chain = chain.then(packagesToChange => { + chain = chain.then((packagesToChange) => { this.packagesToChange = packagesToChange; }); @@ -132,16 +132,16 @@ class AddCommand extends Command { // Skip packages that only would install themselves if (this.packageGraph.has(targetName)) { - result = result.filter(pkg => pkg.name !== targetName); + result = result.filter((pkg) => pkg.name !== targetName); } // Skip packages that are not selected by dir globs if (this.dirs.size) { - result = result.filter(pkg => this.dirs.has(pkg.location)); + result = result.filter((pkg) => this.dirs.has(pkg.location)); } // Skip packages without actual changes to manifest - result = result.filter(pkg => { + result = result.filter((pkg) => { const deps = this.getPackageDeps(pkg); // Check if one of the packages to install necessitates a change to pkg's manifest @@ -158,7 +158,7 @@ class AddCommand extends Command { makeChanges() { const { name: targetName } = this.spec; - return pMap(this.packagesToChange, pkg => { + return pMap(this.packagesToChange, (pkg) => { const deps = this.getPackageDeps(pkg); const range = getRangeToReference(this.spec, deps, pkg.location, this.savePrefix); @@ -194,7 +194,7 @@ class AddCommand extends Command { registry: this.options.registry, }); - return getManifest(this.spec, opts.snapshot).then(pkg => pkg.version); + return pacote.manifest(this.spec, opts.snapshot).then((pkg) => pkg.version); } packageSatisfied() { @@ -214,9 +214,9 @@ class AddCommand extends Command { // existing relative file spec means local dep should be added the same way this.spec.saveRelativeFileSpec = Array.from(this.packageGraph.values()).some( - node => + (node) => node.localDependencies.size && - Array.from(node.localDependencies.values()).some(resolved => resolved.type === "directory") + Array.from(node.localDependencies.values()).some((resolved) => resolved.type === "directory") ); if (fetchSpec === "latest") { diff --git a/commands/add/lib/get-range-to-reference.js b/commands/add/lib/get-range-to-reference.js index cf1398dbaf3..aad0f04ae6b 100644 --- a/commands/add/lib/get-range-to-reference.js +++ b/commands/add/lib/get-range-to-reference.js @@ -4,8 +4,17 @@ const npa = require("npm-package-arg"); const path = require("path"); const semver = require("semver"); -module.exports = getRangeToReference; +module.exports.getRangeToReference = getRangeToReference; +/** @typedef {import("npm-package-arg").Result & { version: string; saveRelativeFileSpec?: boolean; }} DecoratedSpec */ + +/** + * Determine version range used when serializing changes or choosing packages to change. + * @param {DecoratedSpec} spec + * @param {Record} deps + * @param {string} loc + * @param {string} prefix + */ function getRangeToReference(spec, deps, loc, prefix) { const current = deps[spec.name]; const resolved = spec.type === "tag" ? `${prefix}${spec.version}` : spec.fetchSpec; diff --git a/commands/add/package.json b/commands/add/package.json index 36255c82f44..0f3b9923612 100644 --- a/commands/add/package.json +++ b/commands/add/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/add", - "version": "3.21.0", + "version": "4.0.0", "description": "Add a dependency to matched packages", "keywords": [ "lerna", @@ -19,7 +19,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -33,15 +33,15 @@ "test": "echo \"Run tests from root\" && exit 1" }, "dependencies": { - "@evocateur/pacote": "^9.6.3", "@lerna/bootstrap": "file:../bootstrap", "@lerna/command": "file:../../core/command", "@lerna/filter-options": "file:../../core/filter-options", "@lerna/npm-conf": "file:../../utils/npm-conf", "@lerna/validation-error": "file:../../core/validation-error", "dedent": "^0.7.0", - "npm-package-arg": "^6.1.0", - "p-map": "^2.1.0", - "semver": "^6.2.0" + "npm-package-arg": "^8.1.0", + "p-map": "^4.0.0", + "pacote": "^11.2.6", + "semver": "^7.3.4" } } diff --git a/commands/bootstrap/CHANGELOG.md b/commands/bootstrap/CHANGELOG.md index 57dec921b9e..99cedd16ae5 100644 --- a/commands/bootstrap/CHANGELOG.md +++ b/commands/bootstrap/CHANGELOG.md @@ -3,6 +3,40 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** get-port@^5.1.1 ([b1b2275](https://github.com/lerna/lerna/commit/b1b2275237f16a26e6f96deffee8b0f72d8ce17d)) +* **deps:** multimatch@^5.0.0 ([0172526](https://github.com/lerna/lerna/commit/017252644cfd2394e77680673bae0e31ffa58d5e)) +* **deps:** npm-package-arg@^8.1.0 ([12c8923](https://github.com/lerna/lerna/commit/12c892342d33b86a00ee2cf9079f9b26fe316dc6)) +* **deps:** p-finally -> Promise.prototype.finally() ([028db04](https://github.com/lerna/lerna/commit/028db045b1221df000a2b98c5dceb1e4915a7806)) +* **deps:** p-finally@^2.0.1 ([165e47e](https://github.com/lerna/lerna/commit/165e47e722acf6462cf0b4e3a7d0e14d3971e7fb)) +* **deps:** p-map-series@^2.1.0 ([7f68076](https://github.com/lerna/lerna/commit/7f680767e0b3c7a15f951c51d4975150fb6e9112)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* **deps:** p-waterfall@^2.1.0 ([7b7ea50](https://github.com/lerna/lerna/commit/7b7ea503e8371e7f663fd604bff51aebfe9e7b33)) +* **deps:** read-package-tree@^5.3.1 ([3311780](https://github.com/lerna/lerna/commit/331178049e61f3c401a074d27e84d12856e3494e)) +* **deps:** semver@^7.3.2 ([003ad66](https://github.com/lerna/lerna/commit/003ad6641fab8b4e3a82251ebffd27061bd6a31b)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/bootstrap diff --git a/commands/bootstrap/__tests__/bootstrap-command.test.js b/commands/bootstrap/__tests__/bootstrap-command.test.js index c33ec9ef817..5545e0f0d90 100644 --- a/commands/bootstrap/__tests__/bootstrap-command.test.js +++ b/commands/bootstrap/__tests__/bootstrap-command.test.js @@ -9,32 +9,32 @@ const fs = require("fs-extra"); const path = require("path"); // mocked or stubbed modules -const rimrafDir = require("@lerna/rimraf-dir"); -const npmInstall = require("@lerna/npm-install"); -const runLifecycle = require("@lerna/run-lifecycle"); -const createSymlink = require("@lerna/create-symlink"); -const hasNpmVersion = require("@lerna/has-npm-version"); +const { rimrafDir } = require("@lerna/rimraf-dir"); +const { npmInstall, npmInstallDependencies } = require("@lerna/npm-install"); +const { runLifecycle } = require("@lerna/run-lifecycle"); +const { createSymlink } = require("@lerna/create-symlink"); +const { hasNpmVersion } = require("@lerna/has-npm-version"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const normalizeRelativeDir = require("@lerna-test/normalize-relative-dir"); -const updateLernaConfig = require("@lerna-test/update-lerna-config"); +const { normalizeRelativeDir } = require("@lerna-test/normalize-relative-dir"); +const { updateLernaConfig } = require("@lerna-test/update-lerna-config"); // file under test const lernaBootstrap = require("@lerna-test/command-runner")(require("../command")); // assertion helpers -const installedPackagesInDirectories = testDir => - npmInstall.dependencies.mock.calls.reduce((obj, [pkg, dependencies]) => { +const installedPackagesInDirectories = (testDir) => + npmInstallDependencies.mock.calls.reduce((obj, [pkg, dependencies]) => { const relative = normalizeRelativeDir(testDir, pkg.location); obj[relative || "ROOT"] = dependencies; return obj; }, {}); -const removedDirectories = testDir => +const removedDirectories = (testDir) => rimrafDir.mock.calls.map(([directory]) => normalizeRelativeDir(testDir, directory)); -const symlinkedDirectories = testDir => +const symlinkedDirectories = (testDir) => createSymlink.mock.calls .slice() // ensure sort is always consistent, despite promise variability @@ -64,7 +64,7 @@ describe("BootstrapCommand", () => { // we stub npmInstall in most tests because // we already have enough tests of npmInstall npmInstall.mockResolvedValue(); - npmInstall.dependencies.mockResolvedValue(); + npmInstallDependencies.mockResolvedValue(); // stub runLifecycle because it is a huge source // of slowness when running tests for no good reason @@ -111,7 +111,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--ignore-scripts"); expect(runLifecycle).not.toHaveBeenCalled(); - expect(npmInstall.dependencies).toHaveBeenCalledWith( + expect(npmInstallDependencies).toHaveBeenCalledWith( expect.objectContaining({ name: "package-prepare", }), @@ -144,7 +144,7 @@ describe("BootstrapCommand", () => { expect(removedDirectories(testDir)).toMatchSnapshot(); // root includes explicit dependencies and hoisted from leaves - expect(npmInstall.dependencies).toHaveBeenCalledWith( + expect(npmInstallDependencies).toHaveBeenCalledWith( expect.objectContaining({ name: "basic", }), @@ -159,7 +159,7 @@ describe("BootstrapCommand", () => { ); // foo@0.1.2 differs from the more common foo@^1.0.0 - expect(npmInstall.dependencies).toHaveBeenLastCalledWith( + expect(npmInstallDependencies).toHaveBeenLastCalledWith( expect.objectContaining({ name: "package-3", }), @@ -219,7 +219,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--ci"); expect(hasNpmVersion).toHaveBeenLastCalledWith(">=5.7.0"); - expect(npmInstall.dependencies.mock.calls[0][2]).toEqual({ + expect(npmInstallDependencies.mock.calls[0][2]).toEqual({ subCommand: "ci", registry: undefined, npmClient: "npm", @@ -236,7 +236,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--ci"); - expect(npmInstall.dependencies.mock.calls[0][2]).toEqual({ + expect(npmInstallDependencies.mock.calls[0][2]).toEqual({ registry: undefined, npmClient: "npm", npmClientArgs: [], @@ -250,7 +250,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--hoist", "package-*", "--ci"); - expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({ + expect(npmInstallDependencies.mock.calls[0][2]).toMatchObject({ subCommand: "install", // not "ci" npmClient: "npm", npmClientArgs: ["--no-save"], @@ -270,7 +270,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)(); expect(hasNpmVersion).not.toHaveBeenCalled(); - expect(npmInstall.dependencies.mock.calls[0][2]).toEqual({ + expect(npmInstallDependencies.mock.calls[0][2]).toEqual({ registry: undefined, npmClient: "npm", npmClientArgs: [], @@ -350,7 +350,7 @@ describe("BootstrapCommand", () => { expect(installedPackagesInDirectories(testDir)).toMatchSnapshot(); expect(symlinkedDirectories(testDir)).toMatchSnapshot(); - expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({ + expect(npmInstallDependencies.mock.calls[0][2]).toMatchObject({ subCommand: "install", // not "ci" npmClient: "npm", npmClientArgs: ["--no-save"], @@ -362,7 +362,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--scope", "@test/package-2", "--npm-client", "yarn", "--ci"); - expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({ + expect(npmInstallDependencies.mock.calls[0][2]).toMatchObject({ npmClient: "yarn", npmClientArgs: ["--pure-lockfile"], }); @@ -373,7 +373,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)(); - expect(npmInstall.dependencies).toHaveBeenCalledWith( + expect(npmInstallDependencies).toHaveBeenCalledWith( expect.objectContaining({ name: "@test/package-2", }), @@ -450,7 +450,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--npm-client", "yarn"); - expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({ + expect(npmInstallDependencies.mock.calls[0][2]).toMatchObject({ npmClient: "yarn", mutex: expect.stringMatching(/^network:\d+$/), }); @@ -461,7 +461,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--npm-client", "yarn", "--mutex", "file:/test/this/path"); - expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({ + expect(npmInstallDependencies.mock.calls[0][2]).toMatchObject({ npmClient: "yarn", mutex: "file:/test/this/path", }); @@ -486,7 +486,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)(); - expect(npmInstall.dependencies).not.toHaveBeenCalled(); + expect(npmInstallDependencies).not.toHaveBeenCalled(); }); it("hoists appropriately", async () => { @@ -531,7 +531,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)(); - expect(npmInstall.dependencies).not.toHaveBeenCalled(); + expect(npmInstallDependencies).not.toHaveBeenCalled(); }); }); @@ -542,7 +542,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)(); expect(installedPackagesInDirectories(testDir)).toMatchSnapshot(); - expect(npmInstall.dependencies).toHaveBeenLastCalledWith( + expect(npmInstallDependencies).toHaveBeenLastCalledWith( expect.objectContaining({ name: "@test/package-1", }), @@ -563,7 +563,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--", "--no-optional", "--production"); - expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({ + expect(npmInstallDependencies.mock.calls[0][2]).toMatchObject({ npmClientArgs: ["--no-optional", "--production"], }); }); @@ -575,7 +575,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)("--", "--no-optional"); - expect(npmInstall.dependencies.mock.calls[0][2]).toMatchObject({ + expect(npmInstallDependencies.mock.calls[0][2]).toMatchObject({ npmClientArgs: ["--production", "--no-optional"], }); }); @@ -588,7 +588,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)(); - expect(npmInstall.dependencies).not.toHaveBeenCalled(); + expect(npmInstallDependencies).not.toHaveBeenCalled(); expect(npmInstall).toHaveBeenLastCalledWith( expect.objectContaining({ name: "root" }), expect.objectContaining({ @@ -614,7 +614,7 @@ describe("BootstrapCommand", () => { await lernaBootstrap(testDir)(); - expect(npmInstall.dependencies).not.toHaveBeenCalled(); + expect(npmInstallDependencies).not.toHaveBeenCalled(); expect(npmInstall).toHaveBeenLastCalledWith( expect.objectContaining({ name: "relative-file-specs" }), expect.objectContaining({ diff --git a/commands/bootstrap/command.js b/commands/bootstrap/command.js index defe21e7624..3d25c65231e 100644 --- a/commands/bootstrap/command.js +++ b/commands/bootstrap/command.js @@ -1,6 +1,6 @@ "use strict"; -const filterable = require("@lerna/filter-options"); +const { filterOptions } = require("@lerna/filter-options"); /** * @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#providing-a-command-module @@ -9,7 +9,7 @@ exports.command = "bootstrap"; exports.describe = "Link local packages together and install remaining package dependencies"; -exports.builder = yargs => { +exports.builder = (yargs) => { yargs .example( "$0 bootstrap -- --no-optional", @@ -79,7 +79,7 @@ exports.builder = yargs => { }, }); - return filterable(yargs); + return filterOptions(yargs); }; exports.handler = function handler(argv) { diff --git a/commands/bootstrap/index.js b/commands/bootstrap/index.js index 0f35cba1171..a30f17475be 100644 --- a/commands/bootstrap/index.js +++ b/commands/bootstrap/index.js @@ -4,26 +4,25 @@ const dedent = require("dedent"); const getPort = require("get-port"); const npa = require("npm-package-arg"); const path = require("path"); -const pFinally = require("p-finally"); const pMap = require("p-map"); const pMapSeries = require("p-map-series"); const pWaterfall = require("p-waterfall"); -const Command = require("@lerna/command"); -const rimrafDir = require("@lerna/rimraf-dir"); -const hasNpmVersion = require("@lerna/has-npm-version"); -const npmInstall = require("@lerna/npm-install"); +const { Command } = require("@lerna/command"); +const { rimrafDir } = require("@lerna/rimraf-dir"); +const { hasNpmVersion } = require("@lerna/has-npm-version"); +const { npmInstall, npmInstallDependencies } = require("@lerna/npm-install"); const { createRunner } = require("@lerna/run-lifecycle"); -const runTopologically = require("@lerna/run-topologically"); -const symlinkBinary = require("@lerna/symlink-binary"); -const symlinkDependencies = require("@lerna/symlink-dependencies"); -const ValidationError = require("@lerna/validation-error"); +const { runTopologically } = require("@lerna/run-topologically"); +const { symlinkBinary } = require("@lerna/symlink-binary"); +const { symlinkDependencies } = require("@lerna/symlink-dependencies"); +const { ValidationError } = require("@lerna/validation-error"); const { getFilteredPackages } = require("@lerna/filter-options"); -const PackageGraph = require("@lerna/package-graph"); -const pulseTillDone = require("@lerna/pulse-till-done"); +const { PackageGraph } = require("@lerna/package-graph"); +const { pulseTillDone } = require("@lerna/pulse-till-done"); -const hasDependencyInstalled = require("./lib/has-dependency-installed"); -const isHoistedPackage = require("./lib/is-hoisted-package"); +const { hasDependencyInstalled } = require("./lib/has-dependency-installed"); +const { isHoistedPackage } = require("./lib/is-hoisted-package"); module.exports = factory; @@ -90,7 +89,7 @@ class BootstrapCommand extends Command { hoisting = hoisting.concat(`!${nohoist}`); } else { // `--nohoist` multiple or lerna.json `nohoist: [...]` - hoisting = hoisting.concat(nohoist.map(str => `!${str}`)); + hoisting = hoisting.concat(nohoist.map((str) => `!${str}`)); } } @@ -137,7 +136,7 @@ class BootstrapCommand extends Command { return getFilteredPackages(this.targetGraph, this.execOpts, this.options); }); - chain = chain.then(filteredPackages => { + chain = chain.then((filteredPackages) => { this.filteredPackages = filteredPackages; if (this.options.contents) { @@ -165,7 +164,7 @@ class BootstrapCommand extends Command { chain = chain.then(() => { if (npmClient === "yarn" && !mutex) { - return getPort({ port: 42424, host: "0.0.0.0" }).then(port => { + return getPort({ port: 42424, host: "0.0.0.0" }).then((port) => { this.npmConfig.mutex = `network:${port}`; this.logger.silly("npmConfig", this.npmConfig); }); @@ -199,7 +198,7 @@ class BootstrapCommand extends Command { tasks.push( () => this.getDependenciesToInstall(), - result => this.installExternalDependencies(result), + (result) => this.installExternalDependencies(result), () => this.symlinkPackages() ); @@ -241,7 +240,7 @@ class BootstrapCommand extends Command { const rootDependencies = Object.assign({}, this.project.manifest.dependencies); return Object.keys(rootDependencies).some( - name => + (name) => this.targetGraph.has(name) && npa.resolve(name, rootDependencies[name], this.project.rootPath).type === "directory" ); @@ -256,7 +255,7 @@ class BootstrapCommand extends Command { const tracker = this.logger.newItem(stage); - const mapPackageWithScript = pkg => + const mapPackageWithScript = (pkg) => this.runPackageLifecycle(pkg, stage).then(() => { tracker.completeWork(1); }); @@ -270,7 +269,7 @@ class BootstrapCommand extends Command { }) : pMap(this.filteredPackages, mapPackageWithScript, { concurrency: this.concurrency }); - return pFinally(runner, () => tracker.finish()); + return runner.finally(() => tracker.finish()); } hoistedDirectory(dependency) { @@ -322,7 +321,7 @@ class BootstrapCommand extends Command { */ const depsToInstall = new Map(); const filteredNodes = new Map( - this.filteredPackages.map(pkg => [pkg.name, this.targetGraph.get(pkg.name)]) + this.filteredPackages.map((pkg) => [pkg.name, this.targetGraph.get(pkg.name)]) ); // collect root dependency versions @@ -333,7 +332,7 @@ class BootstrapCommand extends Command { rootPkg.dependencies ); const rootExternalVersions = new Map( - Object.keys(mergedRootDeps).map(externalName => [externalName, mergedRootDeps[externalName]]) + Object.keys(mergedRootDeps).map((externalName) => [externalName, mergedRootDeps[externalName]]) ); // seed the root dependencies @@ -389,7 +388,7 @@ class BootstrapCommand extends Command { } const dependents = Array.from(externalDependents.get(rootVersion)).map( - leafName => this.targetGraph.get(leafName).pkg + (leafName) => this.targetGraph.get(leafName).pkg ); // remove collection so leaves don't repeat it @@ -399,7 +398,7 @@ class BootstrapCommand extends Command { // Even if it's already installed there we still need to make sure any // binaries are linked to the packages that depend on them. rootActions.push(() => - hasDependencyInstalled(rootPkg, externalName, rootVersion).then(isSatisfied => { + hasDependencyInstalled(rootPkg, externalName, rootVersion).then((isSatisfied) => { rootSet.add({ name: externalName, dependents, @@ -429,7 +428,7 @@ class BootstrapCommand extends Command { // only install dependency if it's not already installed leafActions.push(() => - hasDependencyInstalled(leafNode.pkg, externalName, leafVersion).then(isSatisfied => { + hasDependencyInstalled(leafNode.pkg, externalName, leafVersion).then((isSatisfied) => { leafRecord.add({ dependency: `${externalName}@${leafVersion}`, isSatisfied, @@ -446,7 +445,7 @@ class BootstrapCommand extends Command { ); } - return pMapSeries([...rootActions, ...leafActions], el => el()).then(() => { + return pMapSeries([...rootActions, ...leafActions], (el) => el()).then(() => { this.logger.silly("root dependencies", JSON.stringify(rootSet, null, 2)); this.logger.silly("leaf dependencies", JSON.stringify(leaves, null, 2)); @@ -479,7 +478,7 @@ class BootstrapCommand extends Command { tracker.info("hoist", "Installing hoisted dependencies into root"); } - const promise = npmInstall.dependencies(rootPkg, depsToInstallInRoot, this.npmConfig); + const promise = npmInstallDependencies(rootPkg, depsToInstallInRoot, this.npmConfig); return pulseTillDone(promise) .then(() => @@ -489,7 +488,7 @@ class BootstrapCommand extends Command { const { bin } = this.hoistedPackageJson(name); if (bin) { - return pMap(dependents, pkg => { + return pMap(dependents, (pkg) => { const src = this.hoistedDirectory(name); return symlinkBinary(src, pkg); @@ -508,11 +507,11 @@ class BootstrapCommand extends Command { actions.push(() => { // Compute the list of candidate directories synchronously const candidates = root - .filter(dep => dep.dependents.length) + .filter((dep) => dep.dependents.length) .reduce((list, { name, dependents }) => { const dirs = dependents - .filter(pkg => pkg.nodeModulesLocation !== rootPkg.nodeModulesLocation) - .map(pkg => path.join(pkg.nodeModulesLocation, name)); + .filter((pkg) => pkg.nodeModulesLocation !== rootPkg.nodeModulesLocation) + .map((pkg) => path.join(pkg.nodeModulesLocation, name)); return list.concat(dirs); }, []); @@ -530,7 +529,7 @@ class BootstrapCommand extends Command { return pMap( candidates, - dirPath => + (dirPath) => pulseTillDone(rimrafDir(dirPath)).then(() => { tracker.verbose("prune", dirPath); tracker.completeWork(1); @@ -558,7 +557,7 @@ class BootstrapCommand extends Command { if (deps.some(({ isSatisfied }) => !isSatisfied)) { actions.push(() => { const dependencies = deps.map(({ dependency }) => dependency); - const promise = npmInstall.dependencies(leafNode.pkg, dependencies, leafNpmConfig); + const promise = npmInstallDependencies(leafNode.pkg, dependencies, leafNpmConfig); return pulseTillDone(promise).then(() => { tracker.verbose("installed leaf", leafNode.name); @@ -574,10 +573,7 @@ class BootstrapCommand extends Command { tracker.addWork(actions.length); } - return pFinally( - pMap(actions, act => act(), { concurrency: this.concurrency }), - () => tracker.finish() - ); + return pMap(actions, (act) => act(), { concurrency: this.concurrency }).finally(() => tracker.finish()); } /** diff --git a/commands/bootstrap/lib/has-dependency-installed.js b/commands/bootstrap/lib/has-dependency-installed.js index 6f5f2c542f4..a36892b97d9 100644 --- a/commands/bootstrap/lib/has-dependency-installed.js +++ b/commands/bootstrap/lib/has-dependency-installed.js @@ -4,26 +4,32 @@ const log = require("npmlog"); const readPackageTree = require("read-package-tree"); const semver = require("semver"); +/** @typedef {Map} InstalledDependencies dependency name -> installed version */ + // cache installed lookups +/** @type {Map} */ const cache = new Map(); -module.exports = hasDependencyInstalled; +module.exports.hasDependencyInstalled = hasDependencyInstalled; /** * Determine if a dependency has already been installed for this package - * @param {Package} pkg The Package instance to check for installed dependency - * @param {String} depName Name of the dependency - * @param {String} needVersion version to test with - * @returns {Boolean} + * @param {import("@lerna/package").Package} pkg The Package instance to check for installed dependency + * @param {string} depName Name of the dependency + * @param {string} needVersion version to test with */ function hasDependencyInstalled(pkg, depName, needVersion) { log.silly("hasDependencyInstalled", pkg.name, depName); return getInstalled(pkg).then( - versions => versions.has(depName) && semver.satisfies(versions.get(depName), needVersion) + (versions) => versions.has(depName) && semver.satisfies(versions.get(depName), needVersion) ); } +/** + * @param {import("@lerna/package").Package} pkg + * @returns {Promise} + */ function getInstalled(pkg) { return new Promise((resolve, reject) => { if (cache.has(pkg)) { @@ -35,6 +41,7 @@ function getInstalled(pkg) { return reject(err); } + /** @type {InstalledDependencies} */ const deps = new Map(children.map(({ package: { name, version } }) => [name, version])); cache.set(pkg, deps); resolve(deps); @@ -42,15 +49,19 @@ function getInstalled(pkg) { }); } +/** + * @param {import("read-package-tree").Node} node + * @param {string} kidName + */ function filterTopLevel(node, kidName) { if (node.parent) { return false; } - return ( + return Boolean( (node.package.dependencies && node.package.dependencies[kidName]) || - (node.package.devDependencies && node.package.devDependencies[kidName]) || - (node.package.peerDependencies && node.package.peerDependencies[kidName]) || - (node.package.optionalDependencies && node.package.optionalDependencies[kidName]) + (node.package.devDependencies && node.package.devDependencies[kidName]) || + (node.package.peerDependencies && node.package.peerDependencies[kidName]) || + (node.package.optionalDependencies && node.package.optionalDependencies[kidName]) ); } diff --git a/commands/bootstrap/lib/is-hoisted-package.js b/commands/bootstrap/lib/is-hoisted-package.js index 93400185433..a01bfa8d83b 100644 --- a/commands/bootstrap/lib/is-hoisted-package.js +++ b/commands/bootstrap/lib/is-hoisted-package.js @@ -2,8 +2,12 @@ const multimatch = require("multimatch"); -module.exports = isHoistedPackage; +module.exports.isHoistedPackage = isHoistedPackage; +/** + * @param {string} name + * @param {string[]} hoisting + */ function isHoistedPackage(name, hoisting) { return multimatch([name], hoisting).length > 0; } diff --git a/commands/bootstrap/package.json b/commands/bootstrap/package.json index 84e507b0f60..2735c58137e 100644 --- a/commands/bootstrap/package.json +++ b/commands/bootstrap/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/bootstrap", - "version": "3.21.0", + "version": "4.0.0", "description": "Link local packages together and install remaining package dependencies", "keywords": [ "lerna", @@ -19,7 +19,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -46,15 +46,14 @@ "@lerna/symlink-dependencies": "file:../../utils/symlink-dependencies", "@lerna/validation-error": "file:../../core/validation-error", "dedent": "^0.7.0", - "get-port": "^4.2.0", - "multimatch": "^3.0.0", - "npm-package-arg": "^6.1.0", + "get-port": "^5.1.1", + "multimatch": "^5.0.0", + "npm-package-arg": "^8.1.0", "npmlog": "^4.1.2", - "p-finally": "^1.0.0", - "p-map": "^2.1.0", - "p-map-series": "^1.0.0", - "p-waterfall": "^1.0.0", - "read-package-tree": "^5.1.6", - "semver": "^6.2.0" + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1", + "read-package-tree": "^5.3.1", + "semver": "^7.3.4" } } diff --git a/commands/changed/CHANGELOG.md b/commands/changed/CHANGELOG.md index 3fc14acd8b0..070da3a5ac5 100644 --- a/commands/changed/CHANGELOG.md +++ b/commands/changed/CHANGELOG.md @@ -3,6 +3,29 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/changed diff --git a/commands/changed/__tests__/changed-command.test.js b/commands/changed/__tests__/changed-command.test.js index 7d6028f9630..4b918d7aa6c 100644 --- a/commands/changed/__tests__/changed-command.test.js +++ b/commands/changed/__tests__/changed-command.test.js @@ -1,13 +1,13 @@ "use strict"; // mocked modules -const collectUpdates = require("@lerna/collect-updates"); -const output = require("@lerna/output"); +const { collectUpdates } = require("@lerna/collect-updates"); +const { output } = require("@lerna/output"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const loggingOutput = require("@lerna-test/logging-output"); -const updateLernaConfig = require("@lerna-test/update-lerna-config"); +const { loggingOutput } = require("@lerna-test/logging-output"); +const { updateLernaConfig } = require("@lerna-test/update-lerna-config"); // file under test const lernaChanged = require("@lerna-test/command-runner")(require("../command")); diff --git a/commands/changed/command.js b/commands/changed/command.js index 1f22c46dbc1..baf92c64228 100644 --- a/commands/changed/command.js +++ b/commands/changed/command.js @@ -11,7 +11,7 @@ exports.aliases = ["updated"]; exports.describe = "List local packages that have changed since the last tagged release"; -exports.builder = yargs => { +exports.builder = (yargs) => { const opts = { // only the relevant bits from `lerna version` "conventional-commits": { diff --git a/commands/changed/index.js b/commands/changed/index.js index c4fa14d50a7..8c385843ef5 100644 --- a/commands/changed/index.js +++ b/commands/changed/index.js @@ -1,9 +1,9 @@ "use strict"; -const Command = require("@lerna/command"); -const collectUpdates = require("@lerna/collect-updates"); +const { Command } = require("@lerna/command"); +const { collectUpdates } = require("@lerna/collect-updates"); const listable = require("@lerna/listable"); -const output = require("@lerna/output"); +const { output } = require("@lerna/output"); module.exports = factory; @@ -35,7 +35,7 @@ class ChangedCommand extends Command { ); this.result = listable.format( - updates.map(node => node.pkg), + updates.map((node) => node.pkg), this.options ); diff --git a/commands/changed/package.json b/commands/changed/package.json index 49a08a336d8..53d857583ff 100644 --- a/commands/changed/package.json +++ b/commands/changed/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/changed", - "version": "3.21.0", + "version": "4.0.0", "description": "List local packages that have changed since the last tagged release", "keywords": [ "lerna", @@ -18,7 +18,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" diff --git a/commands/clean/CHANGELOG.md b/commands/clean/CHANGELOG.md index a44a20ace05..6825b4c9c61 100644 --- a/commands/clean/CHANGELOG.md +++ b/commands/clean/CHANGELOG.md @@ -3,6 +3,33 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** p-map-series@^2.1.0 ([7f68076](https://github.com/lerna/lerna/commit/7f680767e0b3c7a15f951c51d4975150fb6e9112)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* **deps:** p-waterfall@^2.1.0 ([7b7ea50](https://github.com/lerna/lerna/commit/7b7ea503e8371e7f663fd604bff51aebfe9e7b33)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/clean diff --git a/commands/clean/__tests__/clean-command.test.js b/commands/clean/__tests__/clean-command.test.js index b9e4e9a4b78..e300273d577 100644 --- a/commands/clean/__tests__/clean-command.test.js +++ b/commands/clean/__tests__/clean-command.test.js @@ -7,18 +7,18 @@ const fs = require("fs-extra"); const path = require("path"); // mocked or stubbed modules -const rimrafDir = require("@lerna/rimraf-dir"); -const PromptUtilities = require("@lerna/prompt"); +const { rimrafDir } = require("@lerna/rimraf-dir"); +const { promptConfirmation } = require("@lerna/prompt"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const normalizeRelativeDir = require("@lerna-test/normalize-relative-dir"); +const { normalizeRelativeDir } = require("@lerna-test/normalize-relative-dir"); // file under test const lernaClean = require("@lerna-test/command-runner")(require("../command")); // assertion helpers -const removedDirectories = testDir => +const removedDirectories = (testDir) => rimrafDir.mock.calls.map(([directory]) => normalizeRelativeDir(testDir, directory)); describe("CleanCommand", () => { @@ -26,7 +26,7 @@ describe("CleanCommand", () => { // .mockResolvedValue() doesn't work when you want to reject it later rimrafDir.mockImplementation(() => Promise.resolve()); - PromptUtilities.confirm.mockResolvedValue(true); + promptConfirmation.mockResolvedValue(true); describe("basic tests", () => { it("should rm -rf the node_modules", async () => { @@ -34,7 +34,7 @@ describe("CleanCommand", () => { await lernaClean(testDir)(); - expect(PromptUtilities.confirm).toHaveBeenCalled(); + expect(promptConfirmation).toHaveBeenCalled(); expect(removedDirectories(testDir)).toEqual([ "packages/package-1/node_modules", "packages/package-2/node_modules", @@ -45,7 +45,7 @@ describe("CleanCommand", () => { it("exits early when confirmation is rejected", async () => { const testDir = await initFixture("basic"); - PromptUtilities.confirm.mockResolvedValueOnce(false); + promptConfirmation.mockResolvedValueOnce(false); await lernaClean(testDir)(); @@ -57,7 +57,7 @@ describe("CleanCommand", () => { await lernaClean(testDir)("--yes"); - expect(PromptUtilities.confirm).not.toHaveBeenCalled(); + expect(promptConfirmation).not.toHaveBeenCalled(); }); it("should only clean scoped packages", async () => { diff --git a/commands/clean/command.js b/commands/clean/command.js index c4bcf7c6ffb..bf10cf2c2bc 100644 --- a/commands/clean/command.js +++ b/commands/clean/command.js @@ -1,6 +1,6 @@ "use strict"; -const filterable = require("@lerna/filter-options"); +const { filterOptions } = require("@lerna/filter-options"); /** * @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#providing-a-command-module @@ -9,7 +9,7 @@ exports.command = "clean"; exports.describe = "Remove the node_modules directory from all packages"; -exports.builder = yargs => { +exports.builder = (yargs) => { yargs.options({ y: { group: "Command Options:", @@ -19,7 +19,7 @@ exports.builder = yargs => { }, }); - return filterable(yargs); + return filterOptions(yargs); }; exports.handler = function handler(argv) { diff --git a/commands/clean/index.js b/commands/clean/index.js index 1dfaf127f4c..7b8112a9a94 100644 --- a/commands/clean/index.js +++ b/commands/clean/index.js @@ -3,11 +3,11 @@ const path = require("path"); const pMap = require("p-map"); -const Command = require("@lerna/command"); -const rimrafDir = require("@lerna/rimraf-dir"); -const PromptUtilities = require("@lerna/prompt"); +const { Command } = require("@lerna/command"); +const { rimrafDir } = require("@lerna/rimraf-dir"); +const { promptConfirmation } = require("@lerna/prompt"); const { getFilteredPackages } = require("@lerna/filter-options"); -const pulseTillDone = require("@lerna/pulse-till-done"); +const { pulseTillDone } = require("@lerna/pulse-till-done"); module.exports = factory; @@ -24,8 +24,8 @@ class CleanCommand extends Command { let chain = Promise.resolve(); chain = chain.then(() => getFilteredPackages(this.packageGraph, this.execOpts, this.options)); - chain = chain.then(filteredPackages => { - this.directoriesToDelete = filteredPackages.map(pkg => pkg.nodeModulesLocation); + chain = chain.then((filteredPackages) => { + this.directoriesToDelete = filteredPackages.map((pkg) => pkg.nodeModulesLocation); }); return chain.then(() => { @@ -36,10 +36,10 @@ class CleanCommand extends Command { this.logger.info("", "Removing the following directories:"); this.logger.info( "clean", - this.directoriesToDelete.map(dir => path.relative(this.project.rootPath, dir)).join("\n") + this.directoriesToDelete.map((dir) => path.relative(this.project.rootPath, dir)).join("\n") ); - return PromptUtilities.confirm("Proceed?"); + return promptConfirmation("Proceed?"); }); } @@ -47,7 +47,7 @@ class CleanCommand extends Command { this.enableProgressBar(); const tracker = this.logger.newItem("clean"); - const mapper = dirPath => { + const mapper = (dirPath) => { tracker.info("clean", "removing", dirPath); return pulseTillDone(rimrafDir(dirPath)).then(() => { diff --git a/commands/clean/package.json b/commands/clean/package.json index e48c771c1a6..7ee94ba19a1 100644 --- a/commands/clean/package.json +++ b/commands/clean/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/clean", - "version": "3.21.0", + "version": "4.0.0", "description": "Remove the node_modules directory from all packages", "keywords": [ "lerna", @@ -18,7 +18,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -37,8 +37,8 @@ "@lerna/prompt": "file:../../core/prompt", "@lerna/pulse-till-done": "file:../../utils/pulse-till-done", "@lerna/rimraf-dir": "file:../../utils/rimraf-dir", - "p-map": "^2.1.0", - "p-map-series": "^1.0.0", - "p-waterfall": "^1.0.0" + "p-map": "^4.0.0", + "p-map-series": "^2.1.0", + "p-waterfall": "^2.1.1" } } diff --git a/commands/create/CHANGELOG.md b/commands/create/CHANGELOG.md index 2e716dab93c..722c8d7050f 100644 --- a/commands/create/CHANGELOG.md +++ b/commands/create/CHANGELOG.md @@ -3,6 +3,47 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Bug Fixes + +* **create:** Use main as default Github branch ([1a951e9](https://github.com/lerna/lerna/commit/1a951e92376b2aff2e1866791a0ae0b03f19515d)) + + +### Features + +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** @evocateur/pacote -> pacote@^11.1.13 ([99b4217](https://github.com/lerna/lerna/commit/99b4217ed143527a45969f3a46f1bd9b84999d68)) +* **deps:** camelcase -> yargs-parser/camelCase ([d966e8b](https://github.com/lerna/lerna/commit/d966e8b3d36ad9eb02f656b73d9b41882ca7b208)) +* **deps:** execa@^4.1.0 ([9051dca](https://github.com/lerna/lerna/commit/9051dcab1a68b56db09b82ab0345c5f36bcfee2d)) +* **deps:** fs-extra@^9.0.1 ([2f6f4e0](https://github.com/lerna/lerna/commit/2f6f4e066d5a41b4cd508b3405ac1d0a342932dc)) +* **deps:** globby@^11.0.1 ([6cb5bbe](https://github.com/lerna/lerna/commit/6cb5bbec5599cdd93d314ffdc4abea8822e48075)) +* **deps:** init-package-json@^2.0.1 ([4042e8e](https://github.com/lerna/lerna/commit/4042e8e0a73427d1f9585ff285554e2a954b7be6)) +* **deps:** npm-package-arg@^8.1.0 ([12c8923](https://github.com/lerna/lerna/commit/12c892342d33b86a00ee2cf9079f9b26fe316dc6)) +* **deps:** p-reduce@^2.1.0 ([fd4289a](https://github.com/lerna/lerna/commit/fd4289ad20fd9ce5921b83d97f82984abf4f65b0)) +* **deps:** pify@^5.0.0 ([6b34452](https://github.com/lerna/lerna/commit/6b3445219f0f022411a7cb282b0ba39a072e2ef2)) +* **deps:** semver@^7.3.2 ([003ad66](https://github.com/lerna/lerna/commit/003ad6641fab8b4e3a82251ebffd27061bd6a31b)) +* **deps:** slash@^3.0.0 ([5dec383](https://github.com/lerna/lerna/commit/5dec383109bcd1cce9abbc80796369db9314acc9)) +* **deps:** whatwg-url@^8.4.0 ([5dfb7f0](https://github.com/lerna/lerna/commit/5dfb7f0ee196a0c9b9010339d512a5b5b9b75a47)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.22.0](https://github.com/lerna/lerna/compare/v3.21.0...v3.22.0) (2020-05-24) diff --git a/commands/create/__tests__/create-command.test.js b/commands/create/__tests__/create-command.test.js index a00e7c05a91..1ffef87a070 100644 --- a/commands/create/__tests__/create-command.test.js +++ b/commands/create/__tests__/create-command.test.js @@ -1,6 +1,6 @@ "use strict"; -jest.mock("@evocateur/pacote/manifest"); +jest.mock("pacote"); const fs = require("fs-extra"); const path = require("path"); @@ -8,11 +8,11 @@ const execa = require("execa"); const slash = require("slash"); // mocked modules -const getManifest = require("@evocateur/pacote/manifest"); +const pacote = require("pacote"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const gitAdd = require("@lerna-test/git-add"); +const { gitAdd } = require("@lerna-test/git-add"); // file under test const lernaCreate = require("@lerna-test/command-runner")(require("../command")); @@ -24,27 +24,31 @@ expect.addSnapshotSerializer(require("@lerna-test/serialize-git-sha")); const addRemote = (cwd, remote = "origin", url = "git@github.com:test/test.git") => execa("git", ["remote", "add", remote, url], { cwd }); -const diffStaged = (cwd, ...args) => execa.stdout("git", ["diff", "--cached", ...args], { cwd }); +const diffStaged = (cwd, ...args) => + execa("git", ["diff", "--cached", ...args], { cwd }).then((result) => result.stdout); -const initRemoteFixture = fixtureName => initFixture(fixtureName).then(cwd => addRemote(cwd).then(() => cwd)); +const initRemoteFixture = (fixtureName) => + initFixture(fixtureName).then((cwd) => addRemote(cwd).then(() => cwd)); const gitLsOthers = (cwd, ...args) => - execa.stdout("git", ["ls-files", "--others", "--exclude-standard", ...args], { cwd }); + execa("git", ["ls-files", "--others", "--exclude-standard", ...args], { cwd }).then( + (result) => result.stdout + ); -const listUntracked = async cwd => { +const listUntracked = async (cwd) => { const list = await gitLsOthers(cwd, "-z"); - return list.split("\0").map(fp => slash(fp)); + return list.split("\0").map((fp) => slash(fp)); }; -const manifestCreated = async cwd => { +const manifestCreated = async (cwd) => { const file = await gitLsOthers(cwd, "--", "**/package.json"); return fs.readJSON(path.join(cwd, file)); }; describe("CreateCommand", () => { - getManifest.mockImplementation(() => Promise.resolve({ version: "1.0.0-mocked" })); + pacote.manifest.mockImplementation(() => Promise.resolve({ version: "1.0.0-mocked" })); // preserve value from @lerna-test/set-npm-userconfig const userconfig = process.env.npm_config_userconfig; @@ -118,7 +122,7 @@ describe("CreateCommand", () => { expect(result).toMatchSnapshot(); // yargs is automatically added when CLI is stubbed - expect(getManifest).toHaveBeenLastCalledWith( + expect(pacote.manifest).toHaveBeenLastCalledWith( expect.objectContaining({ name: "yargs", type: "tag", diff --git a/commands/create/command.js b/commands/create/command.js index 47425c88aaa..9a367fe4eb1 100644 --- a/commands/create/command.js +++ b/commands/create/command.js @@ -7,7 +7,7 @@ exports.command = "create [loc]"; exports.describe = "Create a new lerna-managed package"; -exports.builder = yargs => { +exports.builder = (yargs) => { yargs .positional("name", { describe: "The package name (including scope), which must be locally unique _and_ publicly available", diff --git a/commands/create/index.js b/commands/create/index.js index eaf6affde0b..7fc888ce2df 100644 --- a/commands/create/index.js +++ b/commands/create/index.js @@ -4,20 +4,20 @@ const fs = require("fs-extra"); const path = require("path"); const os = require("os"); const { URL } = require("whatwg-url"); -const camelCase = require("camelcase"); +const { camelCase } = require("yargs-parser"); const dedent = require("dedent"); const initPackageJson = require("pify")(require("init-package-json")); -const getManifest = require("@evocateur/pacote/manifest"); +const pacote = require("pacote"); const npa = require("npm-package-arg"); const pReduce = require("p-reduce"); const slash = require("slash"); -const Command = require("@lerna/command"); -const ChildProcessUtilities = require("@lerna/child-process"); +const { Command } = require("@lerna/command"); +const childProcess = require("@lerna/child-process"); const npmConf = require("@lerna/npm-conf"); -const ValidationError = require("@lerna/validation-error"); -const builtinNpmrc = require("./lib/builtin-npmrc"); -const catFile = require("./lib/cat-file"); +const { ValidationError } = require("@lerna/validation-error"); +const { builtinNpmrc } = require("./lib/builtin-npmrc"); +const { catFile } = require("./lib/cat-file"); const LERNA_MODULE_DATA = require.resolve("./lib/lerna-module-data.js"); const DEFAULT_DESCRIPTION = [ @@ -57,7 +57,7 @@ class CreateCommand extends Command { this.dirName = scope ? name.split("/").pop() : name; this.pkgName = name; this.pkgsDir = - this.project.packageParentDirs.find(pd => pd.indexOf(pkgLocation) > -1) || + this.project.packageParentDirs.find((pd) => pd.indexOf(pkgLocation) > -1) || this.project.packageParentDirs[0]; this.camelName = camelCase(this.dirName); @@ -159,7 +159,7 @@ class CreateCommand extends Command { chain = chain.then(() => initPackageJson(this.targetDir, LERNA_MODULE_DATA, this.conf)); - return chain.then(data => { + return chain.then((data) => { if (this.options.esModule) { this.logger.notice( "✔", @@ -178,7 +178,7 @@ class CreateCommand extends Command { } gitConfig(prop) { - return ChildProcessUtilities.execSync("git", ["config", "--get", prop], this.execOpts); + return childProcess.execSync("git", ["config", "--get", prop], this.execOpts); } collectExternalVersions() { @@ -231,7 +231,7 @@ class CreateCommand extends Command { const savePrefix = this.conf.get("save-exact") ? "" : this.conf.get("save-prefix"); const pacoteOpts = this.conf.snapshot; - const decideVersion = spec => { + const decideVersion = (spec) => { if (this.packageGraph.has(spec.name)) { // sibling dependency const depNode = this.packageGraph.get(spec.name); @@ -253,7 +253,7 @@ class CreateCommand extends Command { } // from registry - return getManifest(spec, pacoteOpts).then(pkg => `${savePrefix}${pkg.version}`); + return pacote.manifest(spec, pacoteOpts).then((pkg) => `${savePrefix}${pkg.version}`); } if (spec.type === "git") { @@ -274,7 +274,7 @@ class CreateCommand extends Command { return Promise.resolve(spec) .then(decideVersion) - .then(version => { + .then((version) => { obj[spec.name] = version; return obj; @@ -284,7 +284,7 @@ class CreateCommand extends Command { ) ); - chain = chain.then(dependencies => { + chain = chain.then((dependencies) => { this.conf.set("dependencies", dependencies); }); @@ -358,7 +358,7 @@ class CreateCommand extends Command { setRepository() { try { - const url = ChildProcessUtilities.execSync("git", ["remote", "get-url", "origin"], this.execOpts); + const url = childProcess.execSync("git", ["remote", "get-url", "origin"], this.execOpts); this.conf.set("repository", url); } catch (err) { diff --git a/commands/create/lib/builtin-npmrc.js b/commands/create/lib/builtin-npmrc.js index 8937e27be11..d5fb397edca 100644 --- a/commands/create/lib/builtin-npmrc.js +++ b/commands/create/lib/builtin-npmrc.js @@ -3,7 +3,7 @@ const fs = require("fs-extra"); const path = require("path"); -module.exports = builtinNpmrc; +module.exports.builtinNpmrc = builtinNpmrc; function builtinNpmrc() { let resolvedPath = ""; diff --git a/commands/create/lib/cat-file.js b/commands/create/lib/cat-file.js index 726c419ba90..f3f043c9e86 100644 --- a/commands/create/lib/cat-file.js +++ b/commands/create/lib/cat-file.js @@ -3,8 +3,14 @@ const fs = require("fs-extra"); const path = require("path"); -module.exports = catFile; +module.exports.catFile = catFile; +/** + * @param {string} baseDir + * @param {string} fileName + * @param {string} content + * @param {string | import('fs-extra').WriteFileOptions} [opts] + */ function catFile(baseDir, fileName, content, opts = "utf8") { return fs.writeFile(path.join(baseDir, fileName), `${content}\n`, opts); } diff --git a/commands/create/lib/lerna-module-data.js b/commands/create/lib/lerna-module-data.js index 42318ab2209..29afbfb894e 100644 --- a/commands/create/lib/lerna-module-data.js +++ b/commands/create/lib/lerna-module-data.js @@ -31,7 +31,7 @@ const validateName = require("validate-npm-package-name"); const npa = require("npm-package-arg"); const semver = require("semver"); -const niceName = rudeName => +const niceName = (rudeName) => rudeName .replace(/^node-|[.-]js$/g, "") .replace(" ", "-") @@ -59,7 +59,7 @@ if (scope) { exports.name = this.yes ? name - : this.prompt("package name", niceName(name), data => { + : this.prompt("package name", niceName(name), (data) => { const its = validateName(data); if (its.validForNewPackages) { return data; @@ -74,7 +74,7 @@ exports.name = this.yes const version = this.package.version || this.config.get("init-version") || "1.0.0"; exports.version = this.yes ? version - : this.prompt("version", version, data => { + : this.prompt("version", version, (data) => { if (semver.valid(data)) { return data; } @@ -96,7 +96,7 @@ if (!this.package.keywords) { const keywords = this.config.get("keywords") || ""; exports.keywords = this.yes ? keywords - : this.prompt("keywords", keywords, data => { + : this.prompt("keywords", keywords, (data) => { if (!data) { return undefined; } @@ -136,7 +136,7 @@ if (!this.package.homepage) { const license = this.package.license || this.config.get("init-license") || "ISC"; exports.license = this.yes ? license - : this.prompt("license", license, data => { + : this.prompt("license", license, (data) => { const its = validateLicense(data); if (its.validForNewPackages) { return data; @@ -169,7 +169,7 @@ if (!this.package.directories && this.config.get("directories")) { } if (!this.package.files && this.config.get("files")) { - exports.files = cb => { + exports.files = (cb) => { // callback MUST yield the thread for some inexplicable reason process.nextTick(cb, null, this.config.get("files")); }; @@ -180,7 +180,7 @@ if (!this.package.publishConfig && this.config.get("publishConfig")) { } if (!this.package.repository) { - exports.repository = cb => { + exports.repository = (cb) => { let val = this.config.get("repository"); if (val && val.match(/^git@github.com:/)) { diff --git a/commands/create/package.json b/commands/create/package.json index 08dc789edc0..3c8bea9412c 100644 --- a/commands/create/package.json +++ b/commands/create/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/create", - "version": "3.22.0", + "version": "4.0.0", "description": "Create a new lerna-managed package", "keywords": [ "lerna", @@ -19,7 +19,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -33,23 +33,23 @@ "test": "echo \"Run tests from root\" && exit 1" }, "dependencies": { - "@evocateur/pacote": "^9.6.3", "@lerna/child-process": "file:../../core/child-process", "@lerna/command": "file:../../core/command", "@lerna/npm-conf": "file:../../utils/npm-conf", "@lerna/validation-error": "file:../../core/validation-error", - "camelcase": "^5.0.0", "dedent": "^0.7.0", - "fs-extra": "^8.1.0", - "globby": "^9.2.0", - "init-package-json": "^1.10.3", - "npm-package-arg": "^6.1.0", - "p-reduce": "^1.0.0", - "pify": "^4.0.1", - "semver": "^6.2.0", - "slash": "^2.0.0", - "validate-npm-package-license": "^3.0.3", + "fs-extra": "^9.1.0", + "globby": "^11.0.2", + "init-package-json": "^2.0.2", + "npm-package-arg": "^8.1.0", + "p-reduce": "^2.1.0", + "pacote": "^11.2.6", + "pify": "^5.0.0", + "semver": "^7.3.4", + "slash": "^3.0.0", + "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "^3.0.0", - "whatwg-url": "^7.0.0" + "whatwg-url": "^8.4.0", + "yargs-parser": "20.2.4" } } diff --git a/commands/diff/CHANGELOG.md b/commands/diff/CHANGELOG.md index 71fcd9ec377..1f31b0fab65 100644 --- a/commands/diff/CHANGELOG.md +++ b/commands/diff/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** execa@^4.1.0 ([9051dca](https://github.com/lerna/lerna/commit/9051dcab1a68b56db09b82ab0345c5f36bcfee2d)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/diff diff --git a/commands/diff/__tests__/diff-command.test.js b/commands/diff/__tests__/diff-command.test.js index e88c95b9578..9c9a627d49b 100644 --- a/commands/diff/__tests__/diff-command.test.js +++ b/commands/diff/__tests__/diff-command.test.js @@ -6,14 +6,14 @@ const path = require("path"); const { getPackages } = require("@lerna/project"); // mocked modules -const ChildProcessUtilities = require("@lerna/child-process"); +const childProcess = require("@lerna/child-process"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const gitAdd = require("@lerna-test/git-add"); -const gitCommit = require("@lerna-test/git-commit"); -const gitInit = require("@lerna-test/git-init"); -const gitTag = require("@lerna-test/git-tag"); +const { gitAdd } = require("@lerna-test/git-add"); +const { gitCommit } = require("@lerna-test/git-commit"); +const { gitInit } = require("@lerna-test/git-init"); +const { gitTag } = require("@lerna-test/git-tag"); // file under test const lernaDiff = require("@lerna-test/command-runner")(require("../command")); @@ -23,7 +23,7 @@ expect.addSnapshotSerializer(require("@lerna-test/serialize-git-sha")); describe("DiffCommand", () => { // overwrite spawn so we get piped stdout, not inherited - ChildProcessUtilities.spawn = jest.fn((...args) => execa(...args)); + childProcess.spawn = jest.fn((...args) => execa(...args)); it("should diff packages from the first commit", async () => { const cwd = await initFixture("basic"); @@ -102,9 +102,9 @@ describe("DiffCommand", () => { it("should error when git diff exits non-zero", async () => { const cwd = await initFixture("basic"); - ChildProcessUtilities.spawn.mockImplementationOnce(() => { + childProcess.spawn.mockImplementationOnce(() => { const nonZero = new Error("An actual non-zero, not git diff pager SIGPIPE"); - nonZero.code = 1; + nonZero.exitCode = 1; throw nonZero; }); diff --git a/commands/diff/command.js b/commands/diff/command.js index 836d6369500..37e80aeb396 100644 --- a/commands/diff/command.js +++ b/commands/diff/command.js @@ -7,7 +7,7 @@ exports.command = "diff [pkgName]"; exports.describe = "Diff all packages or a single package since the last release"; -exports.builder = yargs => +exports.builder = (yargs) => yargs .positional("pkgName", { describe: "An optional package name to filter the diff output", diff --git a/commands/diff/index.js b/commands/diff/index.js index 77869dc1efd..218d9ce3afb 100644 --- a/commands/diff/index.js +++ b/commands/diff/index.js @@ -1,10 +1,10 @@ "use strict"; -const ChildProcessUtilities = require("@lerna/child-process"); -const Command = require("@lerna/command"); -const ValidationError = require("@lerna/validation-error"); -const getLastCommit = require("./lib/get-last-commit"); -const hasCommit = require("./lib/has-commit"); +const childProcess = require("@lerna/child-process"); +const { Command } = require("@lerna/command"); +const { ValidationError } = require("@lerna/validation-error"); +const { getLastCommit } = require("./lib/get-last-commit"); +const { hasCommit } = require("./lib/has-commit"); module.exports = factory; @@ -39,7 +39,7 @@ class DiffCommand extends Command { } if (this.options.ignoreChanges) { - this.options.ignoreChanges.forEach(ignorePattern => { + this.options.ignoreChanges.forEach((ignorePattern) => { // https://stackoverflow.com/a/21079437 args.push(`:(exclude,glob)${ignorePattern}`); }); @@ -49,8 +49,8 @@ class DiffCommand extends Command { } execute() { - return ChildProcessUtilities.spawn("git", this.args, this.execOpts).catch(err => { - if (err.code) { + return childProcess.spawn("git", this.args, this.execOpts).catch((err) => { + if (err.exitCode) { // quitting the diff viewer is not an error throw err; } diff --git a/commands/diff/lib/get-last-commit.js b/commands/diff/lib/get-last-commit.js index 073c5f85f0b..d22144a9a57 100644 --- a/commands/diff/lib/get-last-commit.js +++ b/commands/diff/lib/get-last-commit.js @@ -3,8 +3,11 @@ const log = require("npmlog"); const childProcess = require("@lerna/child-process"); -module.exports = getLastCommit; +module.exports.getLastCommit = getLastCommit; +/** + * @param {import("@lerna/child-process").ExecOpts} execOpts + */ function getLastCommit(execOpts) { if (hasTags(execOpts)) { log.silly("getLastTagInBranch"); @@ -16,6 +19,9 @@ function getLastCommit(execOpts) { return childProcess.execSync("git", ["rev-list", "--max-parents=0", "HEAD"], execOpts); } +/** + * @param {import("@lerna/child-process").ExecOpts} opts + */ function hasTags(opts) { let result = false; diff --git a/commands/diff/lib/has-commit.js b/commands/diff/lib/has-commit.js index 5429c13bb10..c7488f1fa5d 100644 --- a/commands/diff/lib/has-commit.js +++ b/commands/diff/lib/has-commit.js @@ -3,8 +3,11 @@ const log = require("npmlog"); const childProcess = require("@lerna/child-process"); -module.exports = hasCommit; +module.exports.hasCommit = hasCommit; +/** + * @param {import("@lerna/child-process").ExecOpts} opts + */ function hasCommit(opts) { log.silly("hasCommit"); let retVal; diff --git a/commands/diff/package.json b/commands/diff/package.json index d5252b5b07e..8dac8b48024 100644 --- a/commands/diff/package.json +++ b/commands/diff/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/diff", - "version": "3.21.0", + "version": "4.0.0", "description": "Diff all packages or a single package since the last release", "keywords": [ "lerna", @@ -19,7 +19,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" diff --git a/commands/exec/CHANGELOG.md b/commands/exec/CHANGELOG.md index aa631c9d52b..3e8b32721d7 100644 --- a/commands/exec/CHANGELOG.md +++ b/commands/exec/CHANGELOG.md @@ -3,6 +3,31 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** execa@^4.1.0 ([9051dca](https://github.com/lerna/lerna/commit/9051dcab1a68b56db09b82ab0345c5f36bcfee2d)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/exec diff --git a/commands/exec/__tests__/exec-command.test.js b/commands/exec/__tests__/exec-command.test.js index 4cc4b59be04..a7f765384f0 100644 --- a/commands/exec/__tests__/exec-command.test.js +++ b/commands/exec/__tests__/exec-command.test.js @@ -5,22 +5,21 @@ const fs = require("fs-extra"); const globby = require("globby"); // mocked modules -const ChildProcessUtilities = require("@lerna/child-process"); +const childProcess = require("@lerna/child-process"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const loggingOutput = require("@lerna-test/logging-output"); -const normalizeRelativeDir = require("@lerna-test/normalize-relative-dir"); +const { loggingOutput } = require("@lerna-test/logging-output"); +const { normalizeRelativeDir } = require("@lerna-test/normalize-relative-dir"); // file under test const lernaExec = require("@lerna-test/command-runner")(require("../command")); // assertion helpers -const calledInPackages = () => - ChildProcessUtilities.spawn.mock.calls.map(([, , opts]) => path.basename(opts.cwd)); +const calledInPackages = () => childProcess.spawn.mock.calls.map(([, , opts]) => path.basename(opts.cwd)); -const execInPackagesStreaming = testDir => - ChildProcessUtilities.spawnStreaming.mock.calls.reduce((arr, [command, params, opts, prefix]) => { +const execInPackagesStreaming = (testDir) => + childProcess.spawnStreaming.mock.calls.reduce((arr, [command, params, opts, prefix]) => { const dir = normalizeRelativeDir(testDir, opts.cwd); arr.push([dir, command, `(prefix: ${prefix})`].concat(params).join(" ")); return arr; @@ -28,8 +27,8 @@ const execInPackagesStreaming = testDir => describe("ExecCommand", () => { // TODO: it's very suspicious that mockResolvedValue() doesn't work here - ChildProcessUtilities.spawn = jest.fn(() => Promise.resolve({ code: 0 })); - ChildProcessUtilities.spawnStreaming = jest.fn(() => Promise.resolve({ code: 0 })); + childProcess.spawn = jest.fn(() => Promise.resolve({ exitCode: 0 })); + childProcess.spawnStreaming = jest.fn(() => Promise.resolve({ exitCode: 0 })); afterEach(() => { process.exitCode = undefined; @@ -50,12 +49,12 @@ describe("ExecCommand", () => { }); it("rejects with execution error", async () => { - ChildProcessUtilities.spawn.mockImplementationOnce((cmd, args) => { + childProcess.spawn.mockImplementationOnce((cmd, args) => { const boom = new Error("execution error"); boom.failed = true; - boom.code = 123; - boom.cmd = [cmd].concat(args).join(" "); + boom.exitCode = 123; + boom.command = [cmd].concat(args).join(" "); throw boom; }); @@ -65,18 +64,18 @@ describe("ExecCommand", () => { await expect(command).rejects.toThrow( expect.objectContaining({ message: "execution error", - cmd: "boom", + command: "boom", }) ); expect(process.exitCode).toBe(123); }); it("should ignore execution errors with --no-bail", async () => { - ChildProcessUtilities.spawn.mockImplementationOnce((cmd, args, { pkg }) => { + childProcess.spawn.mockImplementationOnce((cmd, args, { pkg }) => { const boom = new Error(pkg.name); boom.failed = true; - boom.code = 456; + boom.exitCode = 456; boom.cmd = [cmd].concat(args).join(" "); // --no-bail passes { reject: false } to execa, so throwing is inappropriate @@ -88,8 +87,8 @@ describe("ExecCommand", () => { // command doesn't throw, but it _does_ set exitCode expect(process.exitCode).toBe(456); - expect(ChildProcessUtilities.spawn).toHaveBeenCalledTimes(2); - expect(ChildProcessUtilities.spawn).toHaveBeenLastCalledWith( + expect(childProcess.spawn).toHaveBeenCalledTimes(2); + expect(childProcess.spawn).toHaveBeenLastCalledWith( "boom", ["--shaka", "--lakka"], expect.objectContaining({ @@ -101,8 +100,8 @@ describe("ExecCommand", () => { it("should filter packages with `ignore`", async () => { await lernaExec(testDir)("ls", "--ignore", "package-1"); - expect(ChildProcessUtilities.spawn).toHaveBeenCalledTimes(1); - expect(ChildProcessUtilities.spawn).toHaveBeenLastCalledWith("ls", [], { + expect(childProcess.spawn).toHaveBeenCalledTimes(1); + expect(childProcess.spawn).toHaveBeenLastCalledWith("ls", [], { cwd: path.join(testDir, "packages/package-2"), pkg: expect.objectContaining({ name: "package-2", @@ -120,15 +119,15 @@ describe("ExecCommand", () => { it("should run a command", async () => { await lernaExec(testDir)("ls"); - expect(ChildProcessUtilities.spawn).toHaveBeenCalledTimes(2); + expect(childProcess.spawn).toHaveBeenCalledTimes(2); expect(calledInPackages()).toEqual(["package-1", "package-2"]); }); it("should run a command with parameters", async () => { await lernaExec(testDir)("ls", "--", "-la"); - expect(ChildProcessUtilities.spawn).toHaveBeenCalledTimes(2); - expect(ChildProcessUtilities.spawn).toHaveBeenLastCalledWith("ls", ["-la"], expect.any(Object)); + expect(childProcess.spawn).toHaveBeenCalledTimes(2); + expect(childProcess.spawn).toHaveBeenLastCalledWith("ls", ["-la"], expect.any(Object)); }); it("runs a command for a given scope", async () => { diff --git a/commands/exec/command.js b/commands/exec/command.js index dc1eb40077a..5e97dd2ca62 100644 --- a/commands/exec/command.js +++ b/commands/exec/command.js @@ -1,6 +1,6 @@ "use strict"; -const filterable = require("@lerna/filter-options"); +const { filterOptions } = require("@lerna/filter-options"); /** * @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#providing-a-command-module @@ -9,7 +9,7 @@ exports.command = "exec [cmd] [args..]"; exports.describe = "Execute an arbitrary command in each package"; -exports.builder = yargs => { +exports.builder = (yargs) => { yargs .example("$0 exec ls -- --la", "# execute `ls -la` in all packages") .example("$0 exec -- ls --la", "# execute `ls -la` in all packages, keeping cmd outside") @@ -69,7 +69,7 @@ exports.builder = yargs => { }, }); - return filterable(yargs); + return filterOptions(yargs); }; exports.handler = function handler(argv) { diff --git a/commands/exec/index.js b/commands/exec/index.js index 7e2d9358534..7c8598369aa 100644 --- a/commands/exec/index.js +++ b/commands/exec/index.js @@ -2,11 +2,11 @@ const pMap = require("p-map"); -const ChildProcessUtilities = require("@lerna/child-process"); -const Command = require("@lerna/command"); -const Profiler = require("@lerna/profiler"); -const runTopologically = require("@lerna/run-topologically"); -const ValidationError = require("@lerna/validation-error"); +const childProcess = require("@lerna/child-process"); +const { Command } = require("@lerna/command"); +const { Profiler } = require("@lerna/profiler"); +const { runTopologically } = require("@lerna/run-topologically"); +const { ValidationError } = require("@lerna/validation-error"); const { getFilteredPackages } = require("@lerna/filter-options"); module.exports = factory; @@ -41,7 +41,7 @@ class ExecCommand extends Command { let chain = Promise.resolve(); chain = chain.then(() => getFilteredPackages(this.packageGraph, this.execOpts, this.options)); - chain = chain.then(filteredPackages => { + chain = chain.then((filteredPackages) => { this.filteredPackages = filteredPackages; }); @@ -73,19 +73,19 @@ class ExecCommand extends Command { if (this.bail) { // only the first error is caught - chain = chain.catch(err => { - process.exitCode = err.code; + chain = chain.catch((err) => { + process.exitCode = err.exitCode; // rethrow to halt chain and log properly throw err; }); } else { // detect error (if any) from collected results - chain = chain.then(results => { + chain = chain.then((results) => { /* istanbul ignore else */ - if (results.some(result => result.failed)) { + if (results.some((result) => result.failed)) { // propagate "highest" error code, it's probably the most useful - const codes = results.filter(result => result.failed).map(result => result.code); + const codes = results.filter((result) => result.failed).map((result) => result.exitCode); const exitCode = Math.max(...codes, 1); this.logger.error("", "Received non-zero exit code %d during execution", exitCode); @@ -122,8 +122,8 @@ class ExecCommand extends Command { getRunner() { return this.options.stream - ? pkg => this.runCommandInPackageStreaming(pkg) - : pkg => this.runCommandInPackageCapturing(pkg); + ? (pkg) => this.runCommandInPackageStreaming(pkg) + : (pkg) => this.runCommandInPackageCapturing(pkg); } runCommandInPackagesTopological() { @@ -138,7 +138,7 @@ class ExecCommand extends Command { }); const callback = this.getRunner(); - runner = pkg => profiler.run(() => callback(pkg), pkg.name); + runner = (pkg) => profiler.run(() => callback(pkg), pkg.name); } else { runner = this.getRunner(); } @@ -149,14 +149,14 @@ class ExecCommand extends Command { }); if (profiler) { - chain = chain.then(results => profiler.output().then(() => results)); + chain = chain.then((results) => profiler.output().then(() => results)); } return chain; } runCommandInPackagesParallel() { - return pMap(this.filteredPackages, pkg => this.runCommandInPackageStreaming(pkg)); + return pMap(this.filteredPackages, (pkg) => this.runCommandInPackageStreaming(pkg)); } runCommandInPackagesLexical() { @@ -164,16 +164,11 @@ class ExecCommand extends Command { } runCommandInPackageStreaming(pkg) { - return ChildProcessUtilities.spawnStreaming( - this.command, - this.args, - this.getOpts(pkg), - this.prefix && pkg.name - ); + return childProcess.spawnStreaming(this.command, this.args, this.getOpts(pkg), this.prefix && pkg.name); } runCommandInPackageCapturing(pkg) { - return ChildProcessUtilities.spawn(this.command, this.args, this.getOpts(pkg)); + return childProcess.spawn(this.command, this.args, this.getOpts(pkg)); } } diff --git a/commands/exec/package.json b/commands/exec/package.json index a1734d329cc..d96dada36f9 100644 --- a/commands/exec/package.json +++ b/commands/exec/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/exec", - "version": "3.21.0", + "version": "4.0.0", "description": "Execute an arbitrary command in each package", "keywords": [ "lerna", @@ -18,7 +18,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -38,6 +38,6 @@ "@lerna/profiler": "file:../../utils/profiler", "@lerna/run-topologically": "file:../../utils/run-topologically", "@lerna/validation-error": "file:../../core/validation-error", - "p-map": "^2.1.0" + "p-map": "^4.0.0" } } diff --git a/commands/import/CHANGELOG.md b/commands/import/CHANGELOG.md index cd077a58c90..0b7f0280264 100644 --- a/commands/import/CHANGELOG.md +++ b/commands/import/CHANGELOG.md @@ -3,6 +3,38 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Bug Fixes + +* **import:** Better handling of "Patch is empty" ([#2588](https://github.com/lerna/lerna/issues/2588)) ([0497bc7](https://github.com/lerna/lerna/commit/0497bc73043b2b646cc614f54187b68ba007000e)) + + +### Features + +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** execa@^4.1.0 ([9051dca](https://github.com/lerna/lerna/commit/9051dcab1a68b56db09b82ab0345c5f36bcfee2d)) +* **deps:** fs-extra@^9.0.1 ([2f6f4e0](https://github.com/lerna/lerna/commit/2f6f4e066d5a41b4cd508b3405ac1d0a342932dc)) +* **deps:** p-map-series@^2.1.0 ([7f68076](https://github.com/lerna/lerna/commit/7f680767e0b3c7a15f951c51d4975150fb6e9112)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.22.0](https://github.com/lerna/lerna/compare/v3.21.0...v3.22.0) (2020-05-24) diff --git a/commands/import/__tests__/import-command.test.js b/commands/import/__tests__/import-command.test.js index 605e8598abd..cd34804f7be 100644 --- a/commands/import/__tests__/import-command.test.js +++ b/commands/import/__tests__/import-command.test.js @@ -8,23 +8,24 @@ const path = require("path"); const pathExists = require("path-exists"); // mocked or stubbed modules -const PromptUtilities = require("@lerna/prompt"); +const { promptConfirmation } = require("@lerna/prompt"); // helpers const initNamedFixture = require("@lerna-test/init-named-fixture")(__dirname); const initFixture = require("@lerna-test/init-fixture")(__dirname); -const gitAdd = require("@lerna-test/git-add"); -const gitCommit = require("@lerna-test/git-commit"); -const updateLernaConfig = require("@lerna-test/update-lerna-config"); +const { gitAdd } = require("@lerna-test/git-add"); +const { gitCommit } = require("@lerna-test/git-commit"); +const { updateLernaConfig } = require("@lerna-test/update-lerna-config"); // file under test const lernaImport = require("@lerna-test/command-runner")(require("../command")); // assertion helpers -const lastCommitInDir = cwd => execa.stdout("git", ["log", "-1", "--format=%s"], { cwd }); +const lastCommitInDir = (cwd) => + execa("git", ["log", "-1", "--format=%s"], { cwd }).then((result) => result.stdout); describe("ImportCommand", () => { - PromptUtilities.confirm.mockResolvedValue(true); + promptConfirmation.mockResolvedValue(true); describe("import", () => { const initBasicFixtures = async () => { @@ -109,7 +110,7 @@ describe("ImportCommand", () => { it("supports filepaths that have spaces within the external repo", async () => Promise.all( // running the same test with and without --flatten - [true, false].map(async shouldFlatten => { + [true, false].map(async (shouldFlatten) => { const externalDir = await initFixture("files-with-spaces", "Init external commit"); const testDir = await initFixture("basic"); const newPackagePath = path.join(testDir, "packages", path.basename(externalDir)); @@ -131,7 +132,7 @@ describe("ImportCommand", () => { it("supports filepaths that have non-ascii char within the external repo", async () => Promise.all( // running the same test with and without --flatten - [true, false].map(async shouldFlatten => { + [true, false].map(async (shouldFlatten) => { const externalDir = await initFixture("files-with-non-ascii-char", "Init external commit"); const testDir = await initFixture("basic"); const newPackagePath = path.join(testDir, "packages", path.basename(externalDir)); @@ -177,7 +178,7 @@ describe("ImportCommand", () => { it("exits early when confirmation is rejected", async () => { const [testDir, externalDir] = await initBasicFixtures(); - PromptUtilities.confirm.mockResolvedValueOnce(false); + promptConfirmation.mockResolvedValueOnce(false); await lernaImport(testDir)(externalDir); @@ -187,7 +188,7 @@ describe("ImportCommand", () => { it("preserves original committer and date with --preserve-commit", async () => Promise.all( // running the same test with and without --preserve-commit - [true, false].map(async shouldPreserve => { + [true, false].map(async (shouldPreserve) => { const [testDir, externalDir] = await initBasicFixtures(); const filePath = path.join(externalDir, "old-file"); let expectedEmail; @@ -221,7 +222,7 @@ describe("ImportCommand", () => { const [testDir, externalDir] = await initBasicFixtures(); await lernaImport(testDir)(externalDir, "--yes"); - expect(PromptUtilities.confirm).not.toHaveBeenCalled(); + expect(promptConfirmation).not.toHaveBeenCalled(); }); it("errors without an argument", async () => { diff --git a/commands/import/command.js b/commands/import/command.js index 648511572a2..9ee07a56489 100644 --- a/commands/import/command.js +++ b/commands/import/command.js @@ -7,7 +7,7 @@ exports.command = "import "; exports.describe = "Import a package into the monorepo with commit history"; -exports.builder = yargs => +exports.builder = (yargs) => yargs .positional("dir", { describe: "The path to an external git repository that contains an npm package" }) .options({ diff --git a/commands/import/index.js b/commands/import/index.js index 6ec818b596a..459fed0bc80 100644 --- a/commands/import/index.js +++ b/commands/import/index.js @@ -5,11 +5,11 @@ const fs = require("fs-extra"); const path = require("path"); const pMapSeries = require("p-map-series"); -const ChildProcessUtilities = require("@lerna/child-process"); -const Command = require("@lerna/command"); -const PromptUtilities = require("@lerna/prompt"); -const ValidationError = require("@lerna/validation-error"); -const pulseTillDone = require("@lerna/pulse-till-done"); +const childProcess = require("@lerna/child-process"); +const { Command } = require("@lerna/command"); +const { promptConfirmation } = require("@lerna/prompt"); +const { ValidationError } = require("@lerna/validation-error"); +const { pulseTillDone } = require("@lerna/pulse-till-done"); module.exports = factory; @@ -79,9 +79,7 @@ class ImportCommand extends Command { throw new ValidationError("EEXISTS", `Target directory already exists "${targetDir}"`); } - this.commits = this.externalExecSync("git", this.gitParamsForTargetCommits()) - .split("\n") - .reverse(); + this.commits = this.externalExecSync("git", this.gitParamsForTargetCommits()).split("\n").reverse(); // this.commits = this.externalExecSync("git", [ // "rev-list", // "--no-merges", @@ -116,11 +114,11 @@ class ImportCommand extends Command { return true; } - return PromptUtilities.confirm("Are you sure you want to import these commits onto the current branch?"); + return promptConfirmation("Are you sure you want to import these commits onto the current branch?"); } getPackageDirectories() { - return this.project.packageConfigs.filter(p => p.endsWith("*")).map(p => path.dirname(p)); + return this.project.packageConfigs.filter((p) => p.endsWith("*")).map((p) => path.dirname(p)); } getTargetBase() { @@ -140,11 +138,11 @@ class ImportCommand extends Command { } execSync(cmd, args) { - return ChildProcessUtilities.execSync(cmd, args, this.execOpts); + return childProcess.execSync(cmd, args, this.execOpts); } externalExecSync(cmd, args) { - return ChildProcessUtilities.execSync(cmd, args, this.externalExecOpts); + return childProcess.execSync(cmd, args, this.externalExecOpts); } createPatchForCommit(sha) { @@ -212,7 +210,7 @@ class ImportCommand extends Command { this.enableProgressBar(); const tracker = this.logger.newItem("execute"); - const mapper = sha => { + const mapper = (sha) => { tracker.info(sha); const patch = this.createPatchForCommit(sha); @@ -228,7 +226,7 @@ class ImportCommand extends Command { // // Fall back to three-way merge, which can help with duplicate commits // due to merge history. - const proc = ChildProcessUtilities.exec("git", procArgs, this.execOpts); + const proc = childProcess.exec("git", procArgs, this.execOpts); proc.stdin.end(patch); @@ -236,14 +234,14 @@ class ImportCommand extends Command { .then(() => { tracker.completeWork(1); }) - .catch(err => { + .catch((err) => { // Getting commit diff to see if it's empty const diff = this.externalExecSync("git", ["diff", "-s", `${sha}^!`]).trim(); if (diff === "") { tracker.completeWork(1); // Automatically skip empty commits - return ChildProcessUtilities.exec("git", ["am", "--skip"], this.execOpts); + return childProcess.exec("git", ["am", "--skip"], this.execOpts); } err.sha = sha; @@ -266,7 +264,7 @@ class ImportCommand extends Command { this.logger.success("import", "finished"); }) - .catch(err => { + .catch((err) => { tracker.finish(); if (this.options.preserveCommit) { diff --git a/commands/import/package.json b/commands/import/package.json index d0376844398..22ad2c8779f 100644 --- a/commands/import/package.json +++ b/commands/import/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/import", - "version": "3.22.0", + "version": "4.0.0", "description": "Import a package into the monorepo with commit history", "keywords": [ "lerna", @@ -18,7 +18,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -38,7 +38,7 @@ "@lerna/pulse-till-done": "file:../../utils/pulse-till-done", "@lerna/validation-error": "file:../../core/validation-error", "dedent": "^0.7.0", - "fs-extra": "^8.1.0", - "p-map-series": "^1.0.0" + "fs-extra": "^9.1.0", + "p-map-series": "^2.1.0" } } diff --git a/commands/info/CHANGELOG.md b/commands/info/CHANGELOG.md index 99b7ca4394e..f199db978a4 100644 --- a/commands/info/CHANGELOG.md +++ b/commands/info/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/info diff --git a/commands/info/__tests__/info-command.test.js b/commands/info/__tests__/info-command.test.js index 7cdc1b04d23..06a473b11ea 100644 --- a/commands/info/__tests__/info-command.test.js +++ b/commands/info/__tests__/info-command.test.js @@ -8,7 +8,7 @@ const envinfo = require("envinfo"); envinfo.run.mockResolvedValue("MOCK_ENVINFO"); // helper -const output = require("@lerna/output"); +const { output } = require("@lerna/output"); // file under test const lernaInfo = require("@lerna-test/command-runner")(require("../command")); diff --git a/commands/info/index.js b/commands/info/index.js index caa44121e4d..443506fdabd 100644 --- a/commands/info/index.js +++ b/commands/info/index.js @@ -1,7 +1,7 @@ "use strict"; -const Command = require("@lerna/command"); -const output = require("@lerna/output"); +const { Command } = require("@lerna/command"); +const { output } = require("@lerna/output"); const envinfo = require("envinfo"); module.exports = factory; diff --git a/commands/info/package.json b/commands/info/package.json index e62b0ae86c7..f5c88e32898 100644 --- a/commands/info/package.json +++ b/commands/info/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/info", - "version": "3.21.0", + "version": "4.0.0", "description": "Prints local environnment information", "keywords": [ "lerna", @@ -18,7 +18,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -34,6 +34,6 @@ "dependencies": { "@lerna/command": "file:../../core/command", "@lerna/output": "file:../../utils/output", - "envinfo": "^7.3.1" + "envinfo": "^7.7.4" } } diff --git a/commands/init/CHANGELOG.md b/commands/init/CHANGELOG.md index 2aa1fa2029f..90a2c466441 100644 --- a/commands/init/CHANGELOG.md +++ b/commands/init/CHANGELOG.md @@ -3,6 +3,33 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** fs-extra@^9.0.1 ([2f6f4e0](https://github.com/lerna/lerna/commit/2f6f4e066d5a41b4cd508b3405ac1d0a342932dc)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* **deps:** write-json-file@^4.3.0 ([d552c53](https://github.com/lerna/lerna/commit/d552c533c45489a1774f3c3b9ae8d15fc5d3b2a8)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/init diff --git a/commands/init/index.js b/commands/init/index.js index d153fafa21d..6a50f9d16bf 100644 --- a/commands/init/index.js +++ b/commands/init/index.js @@ -5,7 +5,7 @@ const path = require("path"); const pMap = require("p-map"); const writeJsonFile = require("write-json-file"); -const Command = require("@lerna/command"); +const { Command } = require("@lerna/command"); const childProcess = require("@lerna/child-process"); module.exports = factory; @@ -138,7 +138,7 @@ class InitCommand extends Command { ensurePackagesDir() { this.logger.info("", "Creating packages directory"); - return pMap(this.project.packageParentDirs, dir => fs.mkdirp(dir)); + return pMap(this.project.packageParentDirs, (dir) => fs.mkdirp(dir)); } } diff --git a/commands/init/package.json b/commands/init/package.json index f139b1c89df..4e6f0b0a10b 100644 --- a/commands/init/package.json +++ b/commands/init/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/init", - "version": "3.21.0", + "version": "4.0.0", "description": "Create a new Lerna repo or upgrade an existing repo to the current version of Lerna", "keywords": [ "lerna", @@ -18,7 +18,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -34,8 +34,8 @@ "dependencies": { "@lerna/child-process": "file:../../core/child-process", "@lerna/command": "file:../../core/command", - "fs-extra": "^8.1.0", - "p-map": "^2.1.0", - "write-json-file": "^3.2.0" + "fs-extra": "^9.1.0", + "p-map": "^4.0.0", + "write-json-file": "^4.3.0" } } diff --git a/commands/link/CHANGELOG.md b/commands/link/CHANGELOG.md index 24dc09f03a8..1cfa7dbb58d 100644 --- a/commands/link/CHANGELOG.md +++ b/commands/link/CHANGELOG.md @@ -3,6 +3,31 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* **deps:** slash@^3.0.0 ([5dec383](https://github.com/lerna/lerna/commit/5dec383109bcd1cce9abbc80796369db9314acc9)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/link diff --git a/commands/link/__tests__/link-command.test.js b/commands/link/__tests__/link-command.test.js index 871f9fc4973..99f1c7e94bd 100644 --- a/commands/link/__tests__/link-command.test.js +++ b/commands/link/__tests__/link-command.test.js @@ -3,17 +3,17 @@ jest.mock("@lerna/create-symlink"); // mocked or stubbed modules -const createSymlink = require("@lerna/create-symlink"); +const { createSymlink } = require("@lerna/create-symlink"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const normalizeRelativeDir = require("@lerna-test/normalize-relative-dir"); +const { normalizeRelativeDir } = require("@lerna-test/normalize-relative-dir"); // file under test const lernaLink = require("@lerna-test/command-runner")(require("../command")); // assertion helpers -const symlinkedDirectories = testDir => +const symlinkedDirectories = (testDir) => createSymlink.mock.calls .slice() // ensure sort is always consistent, despite promise variability diff --git a/commands/link/command.js b/commands/link/command.js index d6c05b51503..2a8c851ac15 100644 --- a/commands/link/command.js +++ b/commands/link/command.js @@ -7,7 +7,7 @@ exports.command = "link"; exports.describe = "Symlink together all packages that are dependencies of each other"; -exports.builder = yargs => { +exports.builder = (yargs) => { yargs.options({ "force-local": { group: "Command Options:", diff --git a/commands/link/index.js b/commands/link/index.js index 2cfe70e7cec..bb0cc9fbd59 100644 --- a/commands/link/index.js +++ b/commands/link/index.js @@ -3,9 +3,9 @@ const path = require("path"); const pMap = require("p-map"); const slash = require("slash"); -const Command = require("@lerna/command"); -const PackageGraph = require("@lerna/package-graph"); -const symlinkDependencies = require("@lerna/symlink-dependencies"); +const { Command } = require("@lerna/command"); +const { PackageGraph } = require("@lerna/package-graph"); +const { symlinkDependencies } = require("@lerna/symlink-dependencies"); module.exports = factory; @@ -74,7 +74,7 @@ class LinkCommand extends Command { rootPkg.set("dependencies", rootDependencies); rootPkg.set("devDependencies", Object.assign(rootPkg.get("devDependencies") || {}, hoisted)); - return pMap(changed, node => node.pkg.serialize()).then(() => rootPkg.serialize()); + return pMap(changed, (node) => node.pkg.serialize()).then(() => rootPkg.serialize()); } } diff --git a/commands/link/package.json b/commands/link/package.json index f7e2829b97b..9d967fefeb0 100644 --- a/commands/link/package.json +++ b/commands/link/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/link", - "version": "3.21.0", + "version": "4.0.0", "description": "Symlink together all packages that are dependencies of each other", "keywords": [ "lerna", @@ -18,7 +18,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -35,7 +35,7 @@ "@lerna/command": "file:../../core/command", "@lerna/package-graph": "file:../../core/package-graph", "@lerna/symlink-dependencies": "file:../../utils/symlink-dependencies", - "p-map": "^2.1.0", - "slash": "^2.0.0" + "p-map": "^4.0.0", + "slash": "^3.0.0" } } diff --git a/commands/list/CHANGELOG.md b/commands/list/CHANGELOG.md index 7f725c6e62c..26d8a0393f1 100644 --- a/commands/list/CHANGELOG.md +++ b/commands/list/CHANGELOG.md @@ -3,6 +3,29 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/list diff --git a/commands/list/__tests__/list-command.test.js b/commands/list/__tests__/list-command.test.js index 93974bbed90..0213216a6ad 100644 --- a/commands/list/__tests__/list-command.test.js +++ b/commands/list/__tests__/list-command.test.js @@ -1,8 +1,8 @@ "use strict"; // mocked modules -const output = require("@lerna/output"); -const collectUpdates = require("@lerna/collect-updates"); +const { output } = require("@lerna/output"); +const { collectUpdates } = require("@lerna/collect-updates"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); diff --git a/commands/list/command.js b/commands/list/command.js index 10396bace44..b672e3debb1 100644 --- a/commands/list/command.js +++ b/commands/list/command.js @@ -1,6 +1,6 @@ "use strict"; -const filterable = require("@lerna/filter-options"); +const { filterOptions } = require("@lerna/filter-options"); const listable = require("@lerna/listable"); /** @@ -12,10 +12,10 @@ exports.aliases = ["ls", "la", "ll"]; exports.describe = "List local packages"; -exports.builder = yargs => { +exports.builder = (yargs) => { listable.options(yargs); - return filterable(yargs); + return filterOptions(yargs); }; exports.handler = function handler(argv) { diff --git a/commands/list/index.js b/commands/list/index.js index c30840e8d2a..d6dc750c838 100644 --- a/commands/list/index.js +++ b/commands/list/index.js @@ -1,8 +1,8 @@ "use strict"; -const Command = require("@lerna/command"); +const { Command } = require("@lerna/command"); const listable = require("@lerna/listable"); -const output = require("@lerna/output"); +const { output } = require("@lerna/output"); const { getFilteredPackages } = require("@lerna/filter-options"); module.exports = factory; @@ -20,7 +20,7 @@ class ListCommand extends Command { let chain = Promise.resolve(); chain = chain.then(() => getFilteredPackages(this.packageGraph, this.execOpts, this.options)); - chain = chain.then(filteredPackages => { + chain = chain.then((filteredPackages) => { this.result = listable.format(filteredPackages, this.options); }); diff --git a/commands/list/package.json b/commands/list/package.json index 7c1f2fd7005..a9b39fc92ea 100644 --- a/commands/list/package.json +++ b/commands/list/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/list", - "version": "3.21.0", + "version": "4.0.0", "description": "List local packages", "keywords": [ "lerna", @@ -18,7 +18,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" diff --git a/commands/publish/CHANGELOG.md b/commands/publish/CHANGELOG.md index 7ebf259e836..7e11cbb5cff 100644 --- a/commands/publish/CHANGELOG.md +++ b/commands/publish/CHANGELOG.md @@ -3,6 +3,47 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Bug Fixes + +* Improve accuracy of JSDoc type annotations ([1ec69f0](https://github.com/lerna/lerna/commit/1ec69f0e0f7a3f1e0c74dbacb17fab2d7b7a8a44)) + + +### Features + +* **deps:** Bump dependencies ([affed1c](https://github.com/lerna/lerna/commit/affed1ce0fce91f01b0a9eafe357db2d985b974f)) +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** @evocateur/libnpmaccess -> libnpmaccess@^4.0.1 ([7974b35](https://github.com/lerna/lerna/commit/7974b351e53575503dd881c639b53d820e4f525e)) +* **deps:** @evocateur/npm-registry-fetch -> npm-registry-fetch@^9.0.0 ([6df42f2](https://github.com/lerna/lerna/commit/6df42f2caf0887c38870c07a9f850dae0e9c4253)) +* **deps:** @evocateur/pacote -> pacote@^11.1.13 ([99b4217](https://github.com/lerna/lerna/commit/99b4217ed143527a45969f3a46f1bd9b84999d68)) +* **deps:** execa@^4.1.0 ([9051dca](https://github.com/lerna/lerna/commit/9051dcab1a68b56db09b82ab0345c5f36bcfee2d)) +* **deps:** fs-extra@^9.0.1 ([2f6f4e0](https://github.com/lerna/lerna/commit/2f6f4e066d5a41b4cd508b3405ac1d0a342932dc)) +* **deps:** npm-package-arg@^8.1.0 ([12c8923](https://github.com/lerna/lerna/commit/12c892342d33b86a00ee2cf9079f9b26fe316dc6)) +* **deps:** p-finally -> Promise.prototype.finally() ([028db04](https://github.com/lerna/lerna/commit/028db045b1221df000a2b98c5dceb1e4915a7806)) +* **deps:** p-finally@^2.0.1 ([165e47e](https://github.com/lerna/lerna/commit/165e47e722acf6462cf0b4e3a7d0e14d3971e7fb)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* **deps:** p-pipe@^3.1.0 ([489f59e](https://github.com/lerna/lerna/commit/489f59e28657a039becb4cdba5a1955043c73cf1)) +* **deps:** semver@^7.3.2 ([003ad66](https://github.com/lerna/lerna/commit/003ad6641fab8b4e3a82251ebffd27061bd6a31b)) +* **publish:** Remove figgy-pudding ([caf823e](https://github.com/lerna/lerna/commit/caf823e01e9eb5463b452b929a74dbc83ffc5df7)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + ## [3.22.1](https://github.com/lerna/lerna/compare/v3.22.0...v3.22.1) (2020-06-09) diff --git a/commands/publish/__tests__/create-temp-licenses.test.js b/commands/publish/__tests__/create-temp-licenses.test.js index e4687f1b7bd..248ea0c603d 100644 --- a/commands/publish/__tests__/create-temp-licenses.test.js +++ b/commands/publish/__tests__/create-temp-licenses.test.js @@ -2,9 +2,9 @@ const fs = require("fs-extra"); const path = require("path"); -const Project = require("@lerna/project"); +const { Project } = require("@lerna/project"); const initFixture = require("@lerna-test/init-fixture")(__dirname); -const createTempLicenses = require("../lib/create-temp-licenses"); +const { createTempLicenses } = require("../lib/create-temp-licenses"); describe("createTempLicenses", () => { it("copies root license into package location", async () => { diff --git a/commands/publish/__tests__/get-current-sha.test.js b/commands/publish/__tests__/get-current-sha.test.js index dcfaa2811da..25e1c3cd217 100644 --- a/commands/publish/__tests__/get-current-sha.test.js +++ b/commands/publish/__tests__/get-current-sha.test.js @@ -1,7 +1,7 @@ "use strict"; const initFixture = require("@lerna-test/init-fixture")(__dirname); -const getCurrentSHA = require("../lib/get-current-sha"); +const { getCurrentSHA } = require("../lib/get-current-sha"); test("getCurrentSHA", async () => { const cwd = await initFixture("root-manifest-only"); diff --git a/commands/publish/__tests__/get-npm-username.test.js b/commands/publish/__tests__/get-npm-username.test.js index 92ff135ae57..43d5c2a87e1 100644 --- a/commands/publish/__tests__/get-npm-username.test.js +++ b/commands/publish/__tests__/get-npm-username.test.js @@ -1,15 +1,13 @@ "use strict"; -jest.mock("@evocateur/npm-registry-fetch"); +jest.mock("npm-registry-fetch"); -const fetch = require("@evocateur/npm-registry-fetch"); -const loggingOutput = require("@lerna-test/logging-output"); -const getNpmUsername = require("../lib/get-npm-username"); +const fetch = require("npm-registry-fetch"); +const { loggingOutput } = require("@lerna-test/logging-output"); +const { getNpmUsername } = require("../lib/get-npm-username"); fetch.json.mockImplementation(() => Promise.resolve({ username: "lerna-test" })); -expect.extend(require("@lerna-test/figgy-pudding-matchers")); - describe("getNpmUsername", () => { const origConsoleError = console.error; @@ -29,13 +27,12 @@ describe("getNpmUsername", () => { return Promise.reject(err); }); - const opts = new Map(); - opts.set("registry", "such-config-wow"); + const opts = { registry: "such-config-wow" }; const username = await getNpmUsername(opts); expect(username).toBe("lerna-test"); - expect(fetch.json).toHaveBeenLastCalledWith("/-/whoami", expect.figgyPudding({ "fetch-retries": 0 })); + expect(fetch.json).toHaveBeenLastCalledWith("/-/whoami", expect.objectContaining({ fetchRetries: 0 })); }); test("throws an error when successful fetch yields empty username", async () => { @@ -63,8 +60,7 @@ describe("getNpmUsername", () => { return Promise.reject(err); }); - const opts = new Map(); - opts.set("registry", "https://registry.npmjs.org/"); + const opts = { registry: "https://registry.npmjs.org/" }; await expect(getNpmUsername(opts)).rejects.toThrow( "Authentication error. Use `npm whoami` to troubleshoot." @@ -81,8 +77,7 @@ describe("getNpmUsername", () => { return Promise.reject(err); }); - const opts = new Map(); - opts.set("registry", "http://my-own-private-idaho.com"); + const opts = { registry: "http://my-own-private-idaho.com" }; const username = await getNpmUsername(opts); diff --git a/commands/publish/__tests__/get-packages-without-license.test.js b/commands/publish/__tests__/get-packages-without-license.test.js index 6fa06a0fb92..0418a4b4cea 100644 --- a/commands/publish/__tests__/get-packages-without-license.test.js +++ b/commands/publish/__tests__/get-packages-without-license.test.js @@ -1,8 +1,8 @@ "use strict"; -const Project = require("@lerna/project"); +const { Project } = require("@lerna/project"); const initFixture = require("@lerna-test/init-fixture")(__dirname); -const getPackagesWithoutLicense = require("../lib/get-packages-without-license"); +const { getPackagesWithoutLicense } = require("../lib/get-packages-without-license"); test("getPackagesWithoutLicense", async () => { const cwd = await initFixture("licenses"); diff --git a/commands/publish/__tests__/get-two-factor-auth-required.test.js b/commands/publish/__tests__/get-two-factor-auth-required.test.js index bf7ab8c7bf1..90750fb4715 100644 --- a/commands/publish/__tests__/get-two-factor-auth-required.test.js +++ b/commands/publish/__tests__/get-two-factor-auth-required.test.js @@ -2,14 +2,12 @@ jest.mock("../lib/get-profile-data"); -const loggingOutput = require("@lerna-test/logging-output"); -const getProfileData = require("../lib/get-profile-data"); -const getTwoFactorAuthRequired = require("../lib/get-two-factor-auth-required"); +const { loggingOutput } = require("@lerna-test/logging-output"); +const { getProfileData } = require("../lib/get-profile-data"); +const { getTwoFactorAuthRequired } = require("../lib/get-two-factor-auth-required"); getProfileData.mockImplementation(() => Promise.resolve({ tfa: {} })); -expect.extend(require("@lerna-test/figgy-pudding-matchers")); - describe("getTwoFactorAuthRequired", () => { const origConsoleError = console.error; @@ -30,7 +28,7 @@ describe("getTwoFactorAuthRequired", () => { const result = await getTwoFactorAuthRequired(); expect(result).toBe(true); - expect(getProfileData).toHaveBeenLastCalledWith(expect.figgyPudding({ "fetch-retries": 0 })); + expect(getProfileData).toHaveBeenLastCalledWith(expect.objectContaining({ fetchRetries: 0 })); }); it("resolves false if tfa.mode !== 'auth-and-writes'", async () => { @@ -80,14 +78,12 @@ describe("getTwoFactorAuthRequired", () => { return Promise.reject(err); }); - const opts = new Map([["registry", "such-registry-wow"]]); + const opts = { registry: "such-registry-wow" }; const result = await getTwoFactorAuthRequired(opts); expect(result).toBe(false); expect(loggingOutput("warn")).toContain( - `Registry "${opts.get( - "registry" - )}" does not support 'npm profile get', skipping two-factor auth check...` + `Registry "${opts.registry}" does not support 'npm profile get', skipping two-factor auth check...` ); }); diff --git a/commands/publish/__tests__/get-unpublished-packages.test.js b/commands/publish/__tests__/get-unpublished-packages.test.js index a1225930211..e6deedba0a4 100644 --- a/commands/publish/__tests__/get-unpublished-packages.test.js +++ b/commands/publish/__tests__/get-unpublished-packages.test.js @@ -1,19 +1,19 @@ "use strict"; -jest.mock("@evocateur/pacote/packument"); +jest.mock("pacote"); // mocked module(s) -const getPackument = require("@evocateur/pacote/packument"); +const pacote = require("pacote"); // helpers -const PackageGraph = require("@lerna/package-graph"); +const { PackageGraph } = require("@lerna/package-graph"); const { getPackages } = require("@lerna/project"); const initFixture = require("@lerna-test/init-fixture")(__dirname); // file under test -const getUnpublishedPackages = require("../lib/get-unpublished-packages"); +const { getUnpublishedPackages } = require("../lib/get-unpublished-packages"); -getPackument.mockImplementation(async pkg => { +pacote.packument.mockImplementation(async (pkg) => { if (pkg === "package-1") { return { versions: {}, @@ -36,9 +36,10 @@ test("getUnpublishedPackages", async () => { const packages = await getPackages(cwd); const packageGraph = new PackageGraph(packages); - const opts = new Map(); + const opts = {}; const pkgs = await getUnpublishedPackages(packageGraph, opts); + expect(pacote.packument).toHaveBeenCalledWith("package-1", opts); expect(pkgs).toMatchInlineSnapshot(` Array [ PackageGraphNode { @@ -74,9 +75,10 @@ test("getUnpublishedPackages with private package", async () => { const packages = await getPackages(cwd); const packageGraph = new PackageGraph(packages); - const opts = new Map(); + const opts = {}; const pkgs = await getUnpublishedPackages(packageGraph, opts); + expect(pacote.packument).toHaveBeenCalledWith("package-1", opts); expect(pkgs).toMatchInlineSnapshot(` Array [ PackageGraphNode { diff --git a/commands/publish/__tests__/git-checkout.test.js b/commands/publish/__tests__/git-checkout.test.js index 873d586d1cd..3b83c601953 100644 --- a/commands/publish/__tests__/git-checkout.test.js +++ b/commands/publish/__tests__/git-checkout.test.js @@ -4,31 +4,31 @@ const execa = require("execa"); const fs = require("fs-extra"); const path = require("path"); const initFixture = require("@lerna-test/init-fixture")(__dirname); -const gitCheckout = require("../lib/git-checkout"); +const { gitCheckout } = require("../lib/git-checkout"); test("gitCheckout files", async () => { const cwd = await initFixture("no-interdependencies"); - const files = ["package-1", "package-2"].map(name => path.join("packages", name, "package.json")); + const files = ["package-1", "package-2"].map((name) => path.join("packages", name, "package.json")); - await Promise.all(files.map(fp => fs.writeJSON(path.join(cwd, fp), { foo: "bar" }))); + await Promise.all(files.map((fp) => fs.writeJSON(path.join(cwd, fp), { foo: "bar" }))); await gitCheckout(files, { granularPathspec: true }, { cwd }); - const modified = await execa.stdout("git", ["ls-files", "--modified"], { cwd }); + const { stdout: modified } = await execa("git", ["ls-files", "--modified"], { cwd }); expect(modified).toBe(""); }); test("gitCheckout files with .gitignored files", async () => { const cwd = await initFixture("no-interdependencies"); - const files = ["package-1", "package-2", "package-3"].map(name => + const files = ["package-1", "package-2", "package-3"].map((name) => path.join("packages", name, "package.json") ); // simulate a "dynamic", intentionally unversioned package by gitignoring it await fs.writeFile(path.join(cwd, ".gitignore"), "packages/package-3/*", "utf8"); - await Promise.all(files.map(fp => fs.outputJSON(path.join(cwd, fp), { foo: "bar" }))); + await Promise.all(files.map((fp) => fs.outputJSON(path.join(cwd, fp), { foo: "bar" }))); await gitCheckout(files, { granularPathspec: false }, { cwd }); - const modified = await execa.stdout("git", ["ls-files", "--others"], { cwd }); + const { stdout: modified } = await execa("git", ["ls-files", "--others"], { cwd }); expect(modified).toBe("packages/package-3/package.json"); }); diff --git a/commands/publish/__tests__/publish-canary.test.js b/commands/publish/__tests__/publish-canary.test.js index 509d14ca39d..0710a9bb9a9 100644 --- a/commands/publish/__tests__/publish-canary.test.js +++ b/commands/publish/__tests__/publish-canary.test.js @@ -15,16 +15,16 @@ const childProcess = require("@lerna/child-process"); // mocked modules const writePkg = require("write-pkg"); -const npmPublish = require("@lerna/npm-publish"); -const PromptUtilities = require("@lerna/prompt"); -const checkWorkingTree = require("@lerna/check-working-tree"); +const { npmPublish } = require("@lerna/npm-publish"); +const { promptConfirmation } = require("@lerna/prompt"); +const { throwIfUncommitted } = require("@lerna/check-working-tree"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const gitAdd = require("@lerna-test/git-add"); -const gitTag = require("@lerna-test/git-tag"); -const gitCommit = require("@lerna-test/git-commit"); -const loggingOutput = require("@lerna-test/logging-output"); +const { gitAdd } = require("@lerna-test/git-add"); +const { gitTag } = require("@lerna-test/git-tag"); +const { gitCommit } = require("@lerna-test/git-commit"); +const { loggingOutput } = require("@lerna-test/logging-output"); // test command const lernaPublish = require("@lerna-test/command-runner")(require("../command")); @@ -75,9 +75,7 @@ test("publish --canary", async () => { ); await lernaPublish(cwd)("--canary"); - expect(PromptUtilities.confirm).toHaveBeenLastCalledWith( - "Are you sure you want to publish these packages?" - ); + expect(promptConfirmation).toHaveBeenLastCalledWith("Are you sure you want to publish these packages?"); expect(npmPublish.registry).toMatchInlineSnapshot(` Map { "package-1" => "canary", @@ -353,7 +351,7 @@ Object { }); test("publish --canary with dirty tree throws error", async () => { - checkWorkingTree.throwIfUncommitted.mockImplementationOnce(() => { + throwIfUncommitted.mockImplementationOnce(() => { throw new Error("uncommitted"); }); diff --git a/commands/publish/__tests__/publish-command.test.js b/commands/publish/__tests__/publish-command.test.js index 32dcfac8ad4..a50e79df5ab 100644 --- a/commands/publish/__tests__/publish-command.test.js +++ b/commands/publish/__tests__/publish-command.test.js @@ -16,20 +16,20 @@ jest.mock("../../version/lib/is-behind-upstream"); jest.mock("../../version/lib/remote-branch-exists"); // mocked or stubbed modules -const otplease = require("@lerna/otplease"); +const { getOneTimePassword } = require("@lerna/otplease"); const npmDistTag = require("@lerna/npm-dist-tag"); -const npmPublish = require("@lerna/npm-publish"); -const packDirectory = require("@lerna/pack-directory"); -const PromptUtilities = require("@lerna/prompt"); -const collectUpdates = require("@lerna/collect-updates"); -const getNpmUsername = require("../lib/get-npm-username"); -const verifyNpmPackageAccess = require("../lib/verify-npm-package-access"); -const getTwoFactorAuthRequired = require("../lib/get-two-factor-auth-required"); -const gitCheckout = require("../lib/git-checkout"); +const { npmPublish } = require("@lerna/npm-publish"); +const { packDirectory } = require("@lerna/pack-directory"); +const { promptConfirmation } = require("@lerna/prompt"); +const { collectUpdates } = require("@lerna/collect-updates"); +const { getNpmUsername } = require("../lib/get-npm-username"); +const { verifyNpmPackageAccess } = require("../lib/verify-npm-package-access"); +const { getTwoFactorAuthRequired } = require("../lib/get-two-factor-auth-required"); +const { gitCheckout } = require("../lib/git-checkout"); // helpers -const commitChangeToPackage = require("@lerna-test/commit-change-to-package"); -const loggingOutput = require("@lerna-test/logging-output"); +const { commitChangeToPackage } = require("@lerna-test/commit-change-to-package"); +const { loggingOutput } = require("@lerna-test/logging-output"); const initFixture = require("@lerna-test/init-fixture")(__dirname); const path = require("path"); const fs = require("fs-extra"); @@ -41,8 +41,6 @@ const lernaPublish = require("@lerna-test/command-runner")(require("../command") gitCheckout.mockImplementation(() => Promise.resolve()); -expect.extend(require("@lerna-test/figgy-pudding-matchers")); - describe("PublishCommand", () => { describe("cli validation", () => { let cwd; @@ -101,9 +99,7 @@ describe("PublishCommand", () => { await lernaPublish(testDir)(); - expect(PromptUtilities.confirm).toHaveBeenLastCalledWith( - "Are you sure you want to publish these packages?" - ); + expect(promptConfirmation).toHaveBeenLastCalledWith("Are you sure you want to publish these packages?"); expect(packDirectory.registry).toMatchInlineSnapshot(` Set { "package-1", @@ -132,20 +128,20 @@ Map { expect(getNpmUsername).toHaveBeenCalled(); expect(getNpmUsername).toHaveBeenLastCalledWith( - expect.figgyPudding({ registry: "https://registry.npmjs.org/" }) + expect.objectContaining({ registry: "https://registry.npmjs.org/" }) ); expect(verifyNpmPackageAccess).toHaveBeenCalled(); expect(verifyNpmPackageAccess).toHaveBeenLastCalledWith( expect.any(Array), "lerna-test", - expect.figgyPudding({ registry: "https://registry.npmjs.org/" }) + expect.objectContaining({ registry: "https://registry.npmjs.org/" }) ); expect(getTwoFactorAuthRequired).toHaveBeenCalled(); expect(getTwoFactorAuthRequired).toHaveBeenLastCalledWith( // extra insurance that @lerna/npm-conf is defaulting things correctly - expect.figgyPudding({ otp: undefined }) + expect.objectContaining({ otp: undefined }) ); expect(gitCheckout).toHaveBeenCalledWith( @@ -214,7 +210,7 @@ Map { }); describe("--otp", () => { - otplease.getOneTimePassword.mockImplementation(() => Promise.resolve("654321")); + getOneTimePassword.mockImplementation(() => Promise.resolve("654321")); it("passes one-time password to npm commands", async () => { const testDir = await initFixture("normal"); @@ -231,7 +227,7 @@ Map { expect.objectContaining({ otp }), expect.objectContaining({ otp }) ); - expect(otplease.getOneTimePassword).not.toHaveBeenCalled(); + expect(getOneTimePassword).not.toHaveBeenCalled(); }); it("prompts for OTP when option missing and account-level 2FA enabled", async () => { @@ -247,7 +243,7 @@ Map { expect.objectContaining({ otp: undefined }), expect.objectContaining({ otp: "654321" }) ); - expect(otplease.getOneTimePassword).toHaveBeenLastCalledWith("Enter OTP:"); + expect(getOneTimePassword).toHaveBeenLastCalledWith("Enter OTP:"); }); }); diff --git a/commands/publish/__tests__/publish-from-git.test.js b/commands/publish/__tests__/publish-from-git.test.js index c237c5aaea3..b17f10d9cef 100644 --- a/commands/publish/__tests__/publish-from-git.test.js +++ b/commands/publish/__tests__/publish-from-git.test.js @@ -16,21 +16,19 @@ jest.mock("../../version/lib/is-behind-upstream"); jest.mock("../../version/lib/remote-branch-exists"); // mocked or stubbed modules -const npmPublish = require("@lerna/npm-publish"); -const PromptUtilities = require("@lerna/prompt"); -const output = require("@lerna/output"); -const checkWorkingTree = require("@lerna/check-working-tree"); +const { npmPublish } = require("@lerna/npm-publish"); +const { promptConfirmation } = require("@lerna/prompt"); +const { output } = require("@lerna/output"); +const { throwIfUncommitted } = require("@lerna/check-working-tree"); // helpers -const loggingOutput = require("@lerna-test/logging-output"); -const gitTag = require("@lerna-test/git-tag"); +const { loggingOutput } = require("@lerna-test/logging-output"); +const { gitTag } = require("@lerna-test/git-tag"); const initFixture = require("@lerna-test/init-fixture")(__dirname); // file under test const lernaPublish = require("@lerna-test/command-runner")(require("../command")); -expect.extend(require("@lerna-test/figgy-pudding-matchers")); - describe("publish from-git", () => { it("publishes tagged packages", async () => { const cwd = await initFixture("normal"); @@ -39,11 +37,9 @@ describe("publish from-git", () => { await lernaPublish(cwd)("from-git"); // called from chained describeRef() - expect(checkWorkingTree.throwIfUncommitted).toHaveBeenCalled(); + expect(throwIfUncommitted).toHaveBeenCalled(); - expect(PromptUtilities.confirm).toHaveBeenLastCalledWith( - "Are you sure you want to publish these packages?" - ); + expect(promptConfirmation).toHaveBeenLastCalledWith("Are you sure you want to publish these packages?"); expect(output.logged()).toMatch("Found 4 packages to publish:"); expect(npmPublish.order()).toEqual([ "package-1", @@ -112,7 +108,7 @@ describe("publish from-git", () => { }); it("throws an error when uncommitted changes are present", async () => { - checkWorkingTree.throwIfUncommitted.mockImplementationOnce(() => { + throwIfUncommitted.mockImplementationOnce(() => { throw new Error("uncommitted"); }); diff --git a/commands/publish/__tests__/publish-from-package.test.js b/commands/publish/__tests__/publish-from-package.test.js index a969b8a1ff6..bb54a60a114 100644 --- a/commands/publish/__tests__/publish-from-package.test.js +++ b/commands/publish/__tests__/publish-from-package.test.js @@ -17,35 +17,31 @@ const path = require("path"); // mocked or stubbed modules const writePkg = require("write-pkg"); -const npmPublish = require("@lerna/npm-publish"); -const PromptUtilities = require("@lerna/prompt"); -const output = require("@lerna/output"); -const checkWorkingTree = require("@lerna/check-working-tree"); -const getUnpublishedPackages = require("../lib/get-unpublished-packages"); +const { npmPublish } = require("@lerna/npm-publish"); +const { promptConfirmation } = require("@lerna/prompt"); +const { output } = require("@lerna/output"); +const { throwIfUncommitted } = require("@lerna/check-working-tree"); +const { getUnpublishedPackages } = require("../lib/get-unpublished-packages"); // helpers -const loggingOutput = require("@lerna-test/logging-output"); +const { loggingOutput } = require("@lerna-test/logging-output"); const initFixture = require("@lerna-test/init-fixture")(__dirname); // file under test const lernaPublish = require("@lerna-test/command-runner")(require("../command")); -expect.extend(require("@lerna-test/figgy-pudding-matchers")); - describe("publish from-package", () => { it("publishes unpublished packages", async () => { const cwd = await initFixture("normal"); - getUnpublishedPackages.mockImplementationOnce(packageGraph => { + getUnpublishedPackages.mockImplementationOnce((packageGraph) => { const pkgs = packageGraph.rawPackageList.slice(1, 3); - return pkgs.map(pkg => packageGraph.get(pkg.name)); + return pkgs.map((pkg) => packageGraph.get(pkg.name)); }); await lernaPublish(cwd)("from-package"); - expect(PromptUtilities.confirm).toHaveBeenLastCalledWith( - "Are you sure you want to publish these packages?" - ); + expect(promptConfirmation).toHaveBeenLastCalledWith("Are you sure you want to publish these packages?"); expect(output.logged()).toMatch("Found 2 packages to publish:"); expect(npmPublish.order()).toEqual(["package-2", "package-3"]); }); @@ -53,7 +49,7 @@ describe("publish from-package", () => { it("publishes unpublished independent packages", async () => { const cwd = await initFixture("independent"); - getUnpublishedPackages.mockImplementationOnce(packageGraph => Array.from(packageGraph.values())); + getUnpublishedPackages.mockImplementationOnce((packageGraph) => Array.from(packageGraph.values())); await lernaPublish(cwd)("from-package"); @@ -78,7 +74,7 @@ describe("publish from-package", () => { }); it("throws an error when uncommitted changes are present", async () => { - checkWorkingTree.throwIfUncommitted.mockImplementationOnce(() => { + throwIfUncommitted.mockImplementationOnce(() => { throw new Error("uncommitted"); }); @@ -90,7 +86,7 @@ describe("publish from-package", () => { }); it("does not require a git repo", async () => { - getUnpublishedPackages.mockImplementationOnce(packageGraph => [packageGraph.get("package-1")]); + getUnpublishedPackages.mockImplementationOnce((packageGraph) => [packageGraph.get("package-1")]); const cwd = await initFixture("independent"); @@ -110,7 +106,7 @@ describe("publish from-package", () => { }); it("accepts --git-head override", async () => { - getUnpublishedPackages.mockImplementationOnce(packageGraph => [packageGraph.get("package-1")]); + getUnpublishedPackages.mockImplementationOnce((packageGraph) => [packageGraph.get("package-1")]); const cwd = await initFixture("independent"); diff --git a/commands/publish/__tests__/publish-licenses.test.js b/commands/publish/__tests__/publish-licenses.test.js index ba84874bfec..d59f033bdb8 100644 --- a/commands/publish/__tests__/publish-licenses.test.js +++ b/commands/publish/__tests__/publish-licenses.test.js @@ -4,8 +4,8 @@ jest.mock("../lib/verify-npm-package-access"); jest.mock("../lib/get-npm-username"); jest.mock("../lib/get-two-factor-auth-required"); -jest.mock("../lib/create-temp-licenses", () => jest.fn(() => Promise.resolve())); -jest.mock("../lib/remove-temp-licenses", () => jest.fn(() => Promise.resolve())); +jest.mock("../lib/create-temp-licenses", () => ({ createTempLicenses: jest.fn(() => Promise.resolve()) })); +jest.mock("../lib/remove-temp-licenses", () => ({ removeTempLicenses: jest.fn(() => Promise.resolve()) })); // FIXME: better mock for version command jest.mock("../../version/lib/git-push"); jest.mock("../../version/lib/is-anything-committed"); @@ -16,13 +16,13 @@ const fs = require("fs-extra"); const path = require("path"); // mocked modules -const packDirectory = require("@lerna/pack-directory"); -const createTempLicenses = require("../lib/create-temp-licenses"); -const removeTempLicenses = require("../lib/remove-temp-licenses"); +const { packDirectory } = require("@lerna/pack-directory"); +const { createTempLicenses } = require("../lib/create-temp-licenses"); +const { removeTempLicenses } = require("../lib/remove-temp-licenses"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const loggingOutput = require("@lerna-test/logging-output"); +const { loggingOutput } = require("@lerna-test/logging-output"); // test command const lernaPublish = require("@lerna-test/command-runner")(require("../command")); diff --git a/commands/publish/__tests__/publish-lifecycle-scripts.test.js b/commands/publish/__tests__/publish-lifecycle-scripts.test.js index b18a3cbb651..e7a9ac08a8c 100644 --- a/commands/publish/__tests__/publish-lifecycle-scripts.test.js +++ b/commands/publish/__tests__/publish-lifecycle-scripts.test.js @@ -12,8 +12,8 @@ jest.mock("../../version/lib/is-behind-upstream"); jest.mock("../../version/lib/remote-branch-exists"); // mocked modules -const packDirectory = require("@lerna/pack-directory"); -const runLifecycle = require("@lerna/run-lifecycle"); +const { packDirectory } = require("@lerna/pack-directory"); +const { runLifecycle } = require("@lerna/run-lifecycle"); const loadJsonFile = require("load-json-file"); // helpers @@ -35,7 +35,7 @@ describe("lifecycle scripts", () => { await lernaPublish(cwd)(); - ["prepare", "prepublishOnly", "prepack", "postpack", "postpublish"].forEach(script => { + ["prepare", "prepublishOnly", "prepack", "postpack", "postpublish"].forEach((script) => { // "lifecycle" is the root manifest name expect(runLifecycle).toHaveBeenCalledWith( expect.objectContaining({ name: "lifecycle" }), diff --git a/commands/publish/__tests__/publish-relative-file-specifiers.test.js b/commands/publish/__tests__/publish-relative-file-specifiers.test.js index 966faed3a2c..8c61c66150a 100644 --- a/commands/publish/__tests__/publish-relative-file-specifiers.test.js +++ b/commands/publish/__tests__/publish-relative-file-specifiers.test.js @@ -22,9 +22,9 @@ const writePkg = require("write-pkg"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const gitAdd = require("@lerna-test/git-add"); -const gitTag = require("@lerna-test/git-tag"); -const gitCommit = require("@lerna-test/git-commit"); +const { gitAdd } = require("@lerna-test/git-add"); +const { gitTag } = require("@lerna-test/git-tag"); +const { gitCommit } = require("@lerna-test/git-commit"); // test command const lernaPublish = require("@lerna-test/command-runner")(require("../command")); diff --git a/commands/publish/__tests__/publish-tagging.test.js b/commands/publish/__tests__/publish-tagging.test.js index 4f62a233e85..d1fd564f8ba 100644 --- a/commands/publish/__tests__/publish-tagging.test.js +++ b/commands/publish/__tests__/publish-tagging.test.js @@ -12,9 +12,9 @@ jest.mock("../../version/lib/is-behind-upstream"); jest.mock("../../version/lib/remote-branch-exists"); // mocked modules -const collectUpdates = require("@lerna/collect-updates"); +const { collectUpdates } = require("@lerna/collect-updates"); const npmDistTag = require("@lerna/npm-dist-tag"); -const npmPublish = require("@lerna/npm-publish"); +const { npmPublish } = require("@lerna/npm-publish"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); diff --git a/commands/publish/__tests__/remove-temp-licenses.test.js b/commands/publish/__tests__/remove-temp-licenses.test.js index 81ee642080b..d9b7746f3ec 100644 --- a/commands/publish/__tests__/remove-temp-licenses.test.js +++ b/commands/publish/__tests__/remove-temp-licenses.test.js @@ -2,9 +2,9 @@ const fs = require("fs-extra"); const path = require("path"); -const Project = require("@lerna/project"); +const { Project } = require("@lerna/project"); const initFixture = require("@lerna-test/init-fixture")(__dirname); -const removeTempLicenses = require("../lib/remove-temp-licenses"); +const { removeTempLicenses } = require("../lib/remove-temp-licenses"); describe("removeTempLicenses", () => { it("removes license file from target packages", async () => { diff --git a/commands/publish/__tests__/verify-npm-package-access.test.js b/commands/publish/__tests__/verify-npm-package-access.test.js index 9933aa62e5f..1def477cab9 100644 --- a/commands/publish/__tests__/verify-npm-package-access.test.js +++ b/commands/publish/__tests__/verify-npm-package-access.test.js @@ -1,12 +1,12 @@ "use strict"; -jest.mock("@evocateur/libnpmaccess"); +jest.mock("libnpmaccess"); -const access = require("@evocateur/libnpmaccess"); +const access = require("libnpmaccess"); const { getPackages } = require("@lerna/project"); -const loggingOutput = require("@lerna-test/logging-output"); +const { loggingOutput } = require("@lerna-test/logging-output"); const initFixture = require("@lerna-test/init-fixture")(__dirname); -const verifyNpmPackageAccess = require("../lib/verify-npm-package-access"); +const { verifyNpmPackageAccess } = require("../lib/verify-npm-package-access"); access.lsPackages.mockImplementation(() => Promise.resolve({ @@ -15,8 +15,6 @@ access.lsPackages.mockImplementation(() => }) ); -expect.extend(require("@lerna-test/figgy-pudding-matchers")); - describe("verifyNpmPackageAccess", () => { const origConsoleError = console.error; @@ -36,22 +34,22 @@ describe("verifyNpmPackageAccess", () => { test("validates that all packages have read-write permission", async () => { const packages = await getPackages(cwd); - const opts = new Map().set("registry", "https://registry.npmjs.org/"); + const opts = { registry: "https://registry.npmjs.org/" }; await verifyNpmPackageAccess(packages, "lerna-test", opts); expect(access.lsPackages).toHaveBeenLastCalledWith( "lerna-test", - expect.figgyPudding({ + expect.objectContaining({ registry: "https://registry.npmjs.org/", - "fetch-retries": 0, + fetchRetries: 0, }) ); }); test("allows unpublished packages to pass", async () => { const packages = await getPackages(cwd); - const opts = new Map().set("registry", "https://registry.npmjs.org/"); + const opts = { registry: "https://registry.npmjs.org/" }; access.lsPackages.mockImplementationOnce(() => Promise.resolve({ @@ -68,7 +66,7 @@ describe("verifyNpmPackageAccess", () => { test("allows null result to pass with warning", async () => { const packages = await getPackages(cwd); - const opts = new Map().set("registry", "https://registry.npmjs.org/"); + const opts = { registry: "https://registry.npmjs.org/" }; access.lsPackages.mockImplementationOnce(() => // access.lsPackages() returns null when _no_ results returned @@ -85,7 +83,7 @@ describe("verifyNpmPackageAccess", () => { test("throws EACCESS when any package does not have read-write permission", async () => { const packages = await getPackages(cwd); - const opts = new Map().set("registry", "https://registry.npmjs.org/"); + const opts = { registry: "https://registry.npmjs.org/" }; access.lsPackages.mockImplementationOnce(() => Promise.resolve({ @@ -102,7 +100,7 @@ describe("verifyNpmPackageAccess", () => { test("passes when npm Enterprise registry returns E500", async () => { const packages = await getPackages(cwd); const registry = "http://outdated-npm-enterprise.mycompany.com:12345/"; - const opts = new Map().set("registry", registry); + const opts = { registry }; access.lsPackages.mockImplementationOnce(() => { const err = new Error("npm-enterprise-what"); @@ -122,7 +120,7 @@ describe("verifyNpmPackageAccess", () => { test("passes when Artifactory registry returns E404", async () => { const packages = await getPackages(cwd); const registry = "https://artifactory-partial-implementation.corpnet.mycompany.com/"; - const opts = new Map().set("registry", registry); + const opts = { registry }; access.lsPackages.mockImplementationOnce(() => { const err = new Error("artifactory-why"); @@ -141,7 +139,7 @@ describe("verifyNpmPackageAccess", () => { test("logs unexpected failure message before throwing EWHOAMI", async () => { const packages = await getPackages(cwd); - const opts = new Map(); + const opts = {}; access.lsPackages.mockImplementationOnce(() => { const err = new Error("gonna-need-a-bigger-boat"); diff --git a/commands/publish/command.js b/commands/publish/command.js index 853a3d868a4..39f2b6a50b2 100644 --- a/commands/publish/command.js +++ b/commands/publish/command.js @@ -10,7 +10,7 @@ exports.command = "publish [bump]"; exports.describe = "Publish packages in the current project."; -exports.builder = yargs => { +exports.builder = (yargs) => { const opts = { c: { describe: "Publish packages after every successful merge using the sha as part of the tag.", @@ -132,7 +132,7 @@ exports.builder = yargs => { for (const sharedKey of sharedKeys) { hiddenOptions.splice( - hiddenOptions.findIndex(k => k === sharedKey), + hiddenOptions.findIndex((k) => k === sharedKey), 1 ); } @@ -158,7 +158,7 @@ exports.builder = yargs => { hidden: true, type: "boolean", }) - .check(argv => { + .check((argv) => { /* eslint-disable no-param-reassign */ if (argv.npmTag) { argv.distTag = argv.npmTag; diff --git a/commands/publish/index.js b/commands/publish/index.js index a68a37239d9..c72c5b92210 100644 --- a/commands/publish/index.js +++ b/commands/publish/index.js @@ -4,41 +4,40 @@ const os = require("os"); const fs = require("fs"); const path = require("path"); const crypto = require("crypto"); -const pFinally = require("p-finally"); const pMap = require("p-map"); const pPipe = require("p-pipe"); const semver = require("semver"); -const Command = require("@lerna/command"); -const ValidationError = require("@lerna/validation-error"); -const describeRef = require("@lerna/describe-ref"); -const checkWorkingTree = require("@lerna/check-working-tree"); -const PromptUtilities = require("@lerna/prompt"); -const output = require("@lerna/output"); -const collectUpdates = require("@lerna/collect-updates"); +const { Command } = require("@lerna/command"); +const { ValidationError } = require("@lerna/validation-error"); +const { describeRef } = require("@lerna/describe-ref"); +const { throwIfUncommitted } = require("@lerna/check-working-tree"); +const { promptConfirmation } = require("@lerna/prompt"); +const { output } = require("@lerna/output"); +const { collectUpdates } = require("@lerna/collect-updates"); const npmConf = require("@lerna/npm-conf"); const npmDistTag = require("@lerna/npm-dist-tag"); -const npmPublish = require("@lerna/npm-publish"); -const packDirectory = require("@lerna/pack-directory"); -const logPacked = require("@lerna/log-packed"); +const { npmPublish } = require("@lerna/npm-publish"); +const { packDirectory } = require("@lerna/pack-directory"); +const { logPacked } = require("@lerna/log-packed"); const { createRunner } = require("@lerna/run-lifecycle"); -const runTopologically = require("@lerna/run-topologically"); -const pulseTillDone = require("@lerna/pulse-till-done"); +const { runTopologically } = require("@lerna/run-topologically"); +const { pulseTillDone } = require("@lerna/pulse-till-done"); const versionCommand = require("@lerna/version"); -const prereleaseIdFromVersion = require("@lerna/prerelease-id-from-version"); -const otplease = require("@lerna/otplease"); - -const createTempLicenses = require("./lib/create-temp-licenses"); -const getCurrentSHA = require("./lib/get-current-sha"); -const getCurrentTags = require("./lib/get-current-tags"); -const getUnpublishedPackages = require("./lib/get-unpublished-packages"); -const getNpmUsername = require("./lib/get-npm-username"); -const getTaggedPackages = require("./lib/get-tagged-packages"); -const getPackagesWithoutLicense = require("./lib/get-packages-without-license"); -const gitCheckout = require("./lib/git-checkout"); -const removeTempLicenses = require("./lib/remove-temp-licenses"); -const verifyNpmPackageAccess = require("./lib/verify-npm-package-access"); -const getTwoFactorAuthRequired = require("./lib/get-two-factor-auth-required"); +const { prereleaseIdFromVersion } = require("@lerna/prerelease-id-from-version"); +const { getOneTimePassword } = require("@lerna/otplease"); + +const { createTempLicenses } = require("./lib/create-temp-licenses"); +const { getCurrentSHA } = require("./lib/get-current-sha"); +const { getCurrentTags } = require("./lib/get-current-tags"); +const { getUnpublishedPackages } = require("./lib/get-unpublished-packages"); +const { getNpmUsername } = require("./lib/get-npm-username"); +const { getTaggedPackages } = require("./lib/get-tagged-packages"); +const { getPackagesWithoutLicense } = require("./lib/get-packages-without-license"); +const { gitCheckout } = require("./lib/git-checkout"); +const { removeTempLicenses } = require("./lib/remove-temp-licenses"); +const { verifyNpmPackageAccess } = require("./lib/verify-npm-package-access"); +const { getTwoFactorAuthRequired } = require("./lib/get-two-factor-auth-required"); module.exports = factory; @@ -156,10 +155,10 @@ class PublishCommand extends Command { // don't execute recursively if run from a poorly-named script this.runRootLifecycle = /^(pre|post)?publish$/.test(process.env.npm_lifecycle_event) - ? stage => { + ? (stage) => { this.logger.warn("lifecycle", "Skipping root %j because it has already been called", stage); } - : stage => this.runPackageLifecycle(this.project.manifest, stage); + : (stage) => this.runPackageLifecycle(this.project.manifest, stage); let chain = Promise.resolve(); @@ -173,7 +172,7 @@ class PublishCommand extends Command { chain = chain.then(() => versionCommand(this.argv)); } - return chain.then(result => { + return chain.then((result) => { if (!result) { // early return from nested VersionCommand return false; @@ -187,10 +186,10 @@ class PublishCommand extends Command { } // (occasionally) redundant private filtering necessary to handle nested VersionCommand - this.updates = result.updates.filter(node => !node.pkg.private); + this.updates = result.updates.filter((node) => !node.pkg.private); this.updatesVersions = new Map(result.updatesVersions); - this.packagesToPublish = this.updates.map(node => node.pkg); + this.packagesToPublish = this.updates.map((node) => node.pkg); if (this.options.contents) { // globally override directory to publish @@ -268,7 +267,7 @@ class PublishCommand extends Command { } verifyWorkingTreeClean() { - return describeRef(this.execOpts).then(checkWorkingTree.throwIfUncommitted); + return describeRef(this.execOpts).then(throwIfUncommitted); } detectFromGit() { @@ -280,7 +279,7 @@ class PublishCommand extends Command { chain = chain.then(() => this.verifyWorkingTreeClean()); chain = chain.then(() => getCurrentTags(this.execOpts, matchingPattern)); - chain = chain.then(taggedPackageNames => { + chain = chain.then((taggedPackageNames) => { if (!taggedPackageNames.length) { this.logger.notice("from-git", "No tagged release found"); @@ -288,17 +287,17 @@ class PublishCommand extends Command { } if (this.project.isIndependent()) { - return taggedPackageNames.map(name => this.packageGraph.get(name)); + return taggedPackageNames.map((name) => this.packageGraph.get(name)); } return getTaggedPackages(this.packageGraph, this.project.rootPath, this.execOpts); }); // private packages are never published, full stop. - chain = chain.then(updates => updates.filter(node => !node.pkg.private)); + chain = chain.then((updates) => updates.filter((node) => !node.pkg.private)); - return chain.then(updates => { - const updatesVersions = updates.map(node => [node.name, node.version]); + return chain.then((updates) => { + const updatesVersions = updates.map((node) => [node.name, node.version]); return { updates, @@ -314,9 +313,9 @@ class PublishCommand extends Command { // attempting to publish a release with local changes is not allowed chain = chain .then(() => this.verifyWorkingTreeClean()) - .catch(err => { + .catch((err) => { // an execa error is thrown when git suffers a fatal error (such as no git repository present) - if (err.failed && /git describe/.test(err.cmd)) { + if (err.failed && /git describe/.test(err.command)) { // (we tried) this.logger.silly("EWORKINGTREE", err.message); this.logger.notice("FYI", "Unable to verify working tree, proceed at your own risk"); @@ -328,7 +327,7 @@ class PublishCommand extends Command { // private packages are already omitted by getUnpublishedPackages() chain = chain.then(() => getUnpublishedPackages(this.packageGraph, this.conf.snapshot)); - chain = chain.then(unpublished => { + chain = chain.then((unpublished) => { if (!unpublished.length) { this.logger.notice("from-package", "No unpublished release found"); } @@ -336,8 +335,8 @@ class PublishCommand extends Command { return unpublished; }); - return chain.then(updates => { - const updatesVersions = updates.map(node => [node.name, node.version]); + return chain.then((updates) => { + const updatesVersions = updates.map((node) => [node.name, node.version]); return { updates, @@ -373,10 +372,10 @@ class PublishCommand extends Command { forcePublish, includeMergedTags, // private packages are never published, don't bother describing their refs. - }).filter(node => !node.pkg.private) + }).filter((node) => !node.pkg.private) ); - const makeVersion = fallback => ({ lastVersion = fallback, refCount, sha }) => { + const makeVersion = (fallback) => ({ lastVersion = fallback, refCount, sha }) => { // the next version is bumped without concern for preid or current index const nextVersion = semver.inc(lastVersion.replace(this.tagPrefix, ""), release.replace("pre", "")); @@ -387,8 +386,8 @@ class PublishCommand extends Command { if (this.project.isIndependent()) { // each package is described against its tags only - chain = chain.then(updates => - pMap(updates, node => + chain = chain.then((updates) => + pMap(updates, (node) => describeRef( { match: `${node.name}@*`, @@ -398,15 +397,15 @@ class PublishCommand extends Command { ) // an unpublished package will have no reachable git tag .then(makeVersion(node.version)) - .then(version => [node.name, version]) - ).then(updatesVersions => ({ + .then((version) => [node.name, version]) + ).then((updatesVersions) => ({ updates, updatesVersions, })) ); } else { // all packages are described against the last tag - chain = chain.then(updates => + chain = chain.then((updates) => describeRef( { match: `${this.tagPrefix}*.*.*`, @@ -416,8 +415,8 @@ class PublishCommand extends Command { ) // a repo with no tags should default to whatever lerna.json claims .then(makeVersion(this.project.version)) - .then(version => updates.map(node => [node.name, version])) - .then(updatesVersions => ({ + .then((version) => updates.map((node) => [node.name, version])) + .then((updatesVersions) => ({ updates, updatesVersions, })) @@ -434,7 +433,7 @@ class PublishCommand extends Command { confirmPublish() { const count = this.packagesToPublish.length; const message = this.packagesToPublish.map( - pkg => ` - ${pkg.name} => ${this.updatesVersions.get(pkg.name)}` + (pkg) => ` - ${pkg.name} => ${this.updatesVersions.get(pkg.name)}` ); output(""); @@ -447,17 +446,17 @@ class PublishCommand extends Command { return true; } - return PromptUtilities.confirm("Are you sure you want to publish these packages?"); + return promptConfirmation("Are you sure you want to publish these packages?"); } prepareLicenseActions() { return Promise.resolve() .then(() => getPackagesWithoutLicense(this.project, this.packagesToPublish)) - .then(packagesWithoutLicense => { + .then((packagesWithoutLicense) => { if (packagesWithoutLicense.length && !this.project.licensePath) { this.packagesToBeLicensed = []; - const names = packagesWithoutLicense.map(pkg => pkg.name); + const names = packagesWithoutLicense.map((pkg) => pkg.name); const noun = names.length > 1 ? "Packages" : "Package"; const verb = names.length > 1 ? "are" : "is"; const list = @@ -501,7 +500,7 @@ class PublishCommand extends Command { // validate user has valid npm credentials first, // by far the most common form of failed execution chain = chain.then(() => getNpmUsername(this.conf.snapshot)); - chain = chain.then(username => { + chain = chain.then((username) => { // if no username was retrieved, don't bother validating if (username) { return verifyNpmPackageAccess(this.packagesToPublish, username, this.conf.snapshot); @@ -510,7 +509,7 @@ class PublishCommand extends Command { // read profile metadata to determine if account-level 2FA is enabled chain = chain.then(() => getTwoFactorAuthRequired(this.conf.snapshot)); - chain = chain.then(isRequired => { + chain = chain.then((isRequired) => { // notably, this still doesn't handle package-level 2FA requirements this.twoFactorAuthRequired = isRequired; }); @@ -520,7 +519,7 @@ class PublishCommand extends Command { } updateCanaryVersions() { - return pMap(this.updates, node => { + return pMap(this.updates, (node) => { node.pkg.set("version", this.updatesVersions.get(node.name)); for (const [depName, resolved] of node.localDependencies) { @@ -537,11 +536,11 @@ class PublishCommand extends Command { resolveLocalDependencyLinks() { // resolve relative file: links to their actual version range - const updatesWithLocalLinks = this.updates.filter(node => - Array.from(node.localDependencies.values()).some(resolved => resolved.type === "directory") + const updatesWithLocalLinks = this.updates.filter((node) => + Array.from(node.localDependencies.values()).some((resolved) => resolved.type === "directory") ); - return pMap(updatesWithLocalLinks, node => { + return pMap(updatesWithLocalLinks, (node) => { for (const [depName, resolved] of node.localDependencies) { // regardless of where the version comes from, we can't publish "file:../sibling-pkg" specs const depVersion = this.updatesVersions.get(depName) || this.packageGraph.get(depName).pkg.version; @@ -575,7 +574,7 @@ class PublishCommand extends Command { } serializeChanges() { - return pMap(this.packagesToPublish, pkg => pkg.serialize()); + return pMap(this.packagesToPublish, (pkg) => pkg.serialize()); } resetChanges() { @@ -587,9 +586,9 @@ class PublishCommand extends Command { }; const dirtyManifests = [this.project.manifest] .concat(this.packagesToPublish) - .map(pkg => path.relative(cwd, pkg.manifestLocation)); + .map((pkg) => path.relative(cwd, pkg.manifestLocation)); - return gitCheckout(dirtyManifests, gitOpts, this.execOpts).catch(err => { + return gitCheckout(dirtyManifests, gitOpts, this.execOpts).catch((err) => { this.logger.silly("EGITCHECKOUT", err.message); this.logger.notice("FYI", "Unable to reset working tree changes, this probably isn't a git repo."); }); @@ -611,7 +610,7 @@ class PublishCommand extends Command { removeTempLicensesOnError(error) { return Promise.resolve() .then(() => - removeTempLicenses(this.packagesToBeLicensed).catch(removeError => { + removeTempLicenses(this.packagesToBeLicensed).catch((removeError) => { this.logger.error( "licenses", "error removing temporary license files", @@ -632,8 +631,8 @@ class PublishCommand extends Command { } return Promise.resolve() - .then(() => otplease.getOneTimePassword("Enter OTP:")) - .then(otp => { + .then(() => getOneTimePassword("Enter OTP:")) + .then((otp) => { this.otpCache.otp = otp; }); } @@ -672,11 +671,11 @@ class PublishCommand extends Command { const opts = this.conf.snapshot; const mapper = pPipe( - [ - this.options.requireScripts && (pkg => this.execScript(pkg, "prepublish")), + ...[ + this.options.requireScripts && ((pkg) => this.execScript(pkg, "prepublish")), - pkg => - pulseTillDone(packDirectory(pkg, pkg.location, opts)).then(packed => { + (pkg) => + pulseTillDone(packDirectory(pkg, pkg.location, opts)).then((packed) => { tracker.verbose("packed", path.relative(this.project.rootPath, pkg.contents)); tracker.completeWork(1); @@ -694,13 +693,13 @@ class PublishCommand extends Command { chain = chain.then(() => removeTempLicenses(this.packagesToBeLicensed)); // remove temporary license files if _any_ error occurs _anywhere_ in the promise chain - chain = chain.catch(error => this.removeTempLicensesOnError(error)); + chain = chain.catch((error) => this.removeTempLicensesOnError(error)); if (!this.hasRootedLeaf) { chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, "postpack")); } - return pFinally(chain, () => tracker.finish()); + return chain.finally(() => tracker.finish()); } publishPacked() { @@ -722,8 +721,8 @@ class PublishCommand extends Command { }); const mapper = pPipe( - [ - pkg => { + ...[ + (pkg) => { const preDistTag = this.getPreDistTag(pkg); const tag = !this.options.tempTag && preDistTag ? preDistTag : opts.tag; const pkgOpts = Object.assign({}, opts, { tag }); @@ -738,7 +737,7 @@ class PublishCommand extends Command { }); }, - this.options.requireScripts && (pkg => this.execScript(pkg, "postpublish")), + this.options.requireScripts && ((pkg) => this.execScript(pkg, "postpublish")), ].filter(Boolean) ); @@ -750,7 +749,7 @@ class PublishCommand extends Command { chain = chain.then(() => this.runRootLifecycle("postpublish")); } - return pFinally(chain, () => tracker.finish()); + return chain.finally(() => tracker.finish()); } npmUpdateAsLatest() { @@ -762,14 +761,14 @@ class PublishCommand extends Command { let chain = Promise.resolve(); const opts = this.conf.snapshot; - const getDistTag = publishConfig => { + const getDistTag = (publishConfig) => { if (opts.tag === "latest" && publishConfig && publishConfig.tag) { return publishConfig.tag; } return opts.tag; }; - const mapper = pkg => { + const mapper = (pkg) => { const spec = `${pkg.name}@${pkg.version}`; const preDistTag = this.getPreDistTag(pkg); const distTag = preDistTag || getDistTag(pkg.get("publishConfig")); @@ -787,7 +786,7 @@ class PublishCommand extends Command { chain = chain.then(() => this.topoMapPackages(mapper)); - return pFinally(chain, () => tracker.finish()); + return chain.finally(() => tracker.finish()); } getDistTag() { diff --git a/commands/publish/lib/__mocks__/get-npm-username.js b/commands/publish/lib/__mocks__/get-npm-username.js index 2528ee42f40..fd0fb26d7f3 100644 --- a/commands/publish/lib/__mocks__/get-npm-username.js +++ b/commands/publish/lib/__mocks__/get-npm-username.js @@ -3,4 +3,4 @@ // to mock user modules, you _must_ call `jest.mock('./path/to/module')` const mockGetNpmUsername = jest.fn(() => Promise.resolve("lerna-test")); -module.exports = mockGetNpmUsername; +module.exports.getNpmUsername = mockGetNpmUsername; diff --git a/commands/publish/lib/__mocks__/get-packages-without-license.js b/commands/publish/lib/__mocks__/get-packages-without-license.js index 1e4621f0483..b9a63fb8b48 100644 --- a/commands/publish/lib/__mocks__/get-packages-without-license.js +++ b/commands/publish/lib/__mocks__/get-packages-without-license.js @@ -1,4 +1,4 @@ "use strict"; // to mock user modules, you _must_ call `jest.mock('./path/to/module')` -module.exports = jest.fn(() => Promise.resolve([])); +module.exports.getPackagesWithoutLicense = jest.fn(() => Promise.resolve([])); diff --git a/commands/publish/lib/__mocks__/get-two-factor-auth-required.js b/commands/publish/lib/__mocks__/get-two-factor-auth-required.js index 08c93b24795..b4cbd449c30 100644 --- a/commands/publish/lib/__mocks__/get-two-factor-auth-required.js +++ b/commands/publish/lib/__mocks__/get-two-factor-auth-required.js @@ -3,4 +3,4 @@ // to mock user modules, you _must_ call `jest.mock('./path/to/module')` const mockGetTwoFactorAuthRequired = jest.fn(() => Promise.resolve(false)); -module.exports = mockGetTwoFactorAuthRequired; +module.exports.getTwoFactorAuthRequired = mockGetTwoFactorAuthRequired; diff --git a/commands/publish/lib/__mocks__/get-unpublished-packages.js b/commands/publish/lib/__mocks__/get-unpublished-packages.js index b8c02e99db8..a0390d51208 100644 --- a/commands/publish/lib/__mocks__/get-unpublished-packages.js +++ b/commands/publish/lib/__mocks__/get-unpublished-packages.js @@ -1,3 +1,3 @@ "use strict"; -module.exports = jest.fn(() => Promise.resolve([])); +module.exports.getUnpublishedPackages = jest.fn(() => Promise.resolve([])); diff --git a/commands/publish/lib/__mocks__/verify-npm-package-access.js b/commands/publish/lib/__mocks__/verify-npm-package-access.js index 7b92c44b7f6..d83c769b1d2 100644 --- a/commands/publish/lib/__mocks__/verify-npm-package-access.js +++ b/commands/publish/lib/__mocks__/verify-npm-package-access.js @@ -3,4 +3,4 @@ // to mock user modules, you _must_ call `jest.mock('./path/to/module')` const mockVerifyNpmPackageAccess = jest.fn(() => Promise.resolve()); -module.exports = mockVerifyNpmPackageAccess; +module.exports.verifyNpmPackageAccess = mockVerifyNpmPackageAccess; diff --git a/commands/publish/lib/create-temp-licenses.js b/commands/publish/lib/create-temp-licenses.js index 4a16c7ff0fc..b4f311684ab 100644 --- a/commands/publish/lib/create-temp-licenses.js +++ b/commands/publish/lib/create-temp-licenses.js @@ -4,8 +4,13 @@ const fs = require("fs-extra"); const path = require("path"); const pMap = require("p-map"); -module.exports = createTempLicenses; +module.exports.createTempLicenses = createTempLicenses; +/** + * Create temporary license files. + * @param {string} srcLicensePath + * @param {Packages[]} packagesToBeLicensed + */ function createTempLicenses(srcLicensePath, packagesToBeLicensed) { if (!srcLicensePath || !packagesToBeLicensed.length) { return Promise.resolve(); @@ -20,9 +25,9 @@ function createTempLicenses(srcLicensePath, packagesToBeLicensed) { }; // store target path for removal later - packagesToBeLicensed.forEach(pkg => { + packagesToBeLicensed.forEach((pkg) => { pkg.licensePath = path.join(pkg.contents, licenseFileName); }); - return pMap(packagesToBeLicensed, pkg => fs.copy(srcLicensePath, pkg.licensePath, options)); + return pMap(packagesToBeLicensed, (pkg) => fs.copy(srcLicensePath, pkg.licensePath, options)); } diff --git a/commands/publish/lib/fetch-config.js b/commands/publish/lib/fetch-config.js index c8df461b197..b24f2582188 100644 --- a/commands/publish/lib/fetch-config.js +++ b/commands/publish/lib/fetch-config.js @@ -1,20 +1,27 @@ "use strict"; const log = require("npmlog"); -const figgyPudding = require("figgy-pudding"); -module.exports = figgyPudding( - { - "fetch-retries": {}, - fetchRetries: "fetch-retries", - log: { default: log }, - registry: {}, - username: {}, - }, - { - other() { - // open it up for the sake of tests - return true; - }, - } -); +module.exports.getFetchConfig = getFetchConfig; + +/** + * Create a merged options object suitable for npm-registry-fetch. + * @param {{ [key: string]: unknown }} options + * @param {Partial} [extra] + * @returns {FetchConfig} + */ +function getFetchConfig(options, extra) { + return { + log, + ...options, + ...extra, + }; +} + +/** + * @typedef {object} FetchConfig + * @property {number} [fetchRetries] + * @property {typeof log} log + * @property {string} [registry] + * @property {string} [username] + */ diff --git a/commands/publish/lib/get-current-sha.js b/commands/publish/lib/get-current-sha.js index 00ea68de3e9..12c03ad3b1c 100644 --- a/commands/publish/lib/get-current-sha.js +++ b/commands/publish/lib/get-current-sha.js @@ -3,8 +3,12 @@ const log = require("npmlog"); const childProcess = require("@lerna/child-process"); -module.exports = getCurrentSHA; +module.exports.getCurrentSHA = getCurrentSHA; +/** + * Retrieve current SHA from git. + * @param {import("@lerna/child-process").ExecOpts} opts + */ function getCurrentSHA(opts) { log.silly("getCurrentSHA"); diff --git a/commands/publish/lib/get-current-tags.js b/commands/publish/lib/get-current-tags.js index 7c58d5be1d4..c666ed4587f 100644 --- a/commands/publish/lib/get-current-tags.js +++ b/commands/publish/lib/get-current-tags.js @@ -4,8 +4,14 @@ const log = require("npmlog"); const npa = require("npm-package-arg"); const childProcess = require("@lerna/child-process"); -module.exports = getCurrentTags; +module.exports.getCurrentTags = getCurrentTags; +/** + * Retrieve a list of git tags pointing to the current HEAD that match the provided pattern. + * @param {import("@lerna/child-process").ExecOpts} execOpts + * @param {string} matchingPattern + * @returns {string[]} + */ function getCurrentTags(execOpts, matchingPattern) { log.silly("getCurrentTags", "matching %j", matchingPattern); @@ -16,13 +22,13 @@ function getCurrentTags(execOpts, matchingPattern) { return childProcess .exec("git", ["tag", "--sort", "version:refname", "--points-at", "HEAD", "--list", matchingPattern], opts) - .then(result => { + .then((result) => { const lines = result.stdout.split("\n").filter(Boolean); if (matchingPattern === "*@*") { // independent mode does not respect tagVersionPrefix, // but embeds the package name in the tag "prefix" - return lines.map(tag => npa(tag).name); + return lines.map((tag) => npa(tag).name); } // "fixed" mode can have a custom tagVersionPrefix, diff --git a/commands/publish/lib/get-npm-username.js b/commands/publish/lib/get-npm-username.js index e6ecdf9000d..9ed75949e6d 100644 --- a/commands/publish/lib/get-npm-username.js +++ b/commands/publish/lib/get-npm-username.js @@ -1,22 +1,27 @@ "use strict"; -const ValidationError = require("@lerna/validation-error"); -const FetchConfig = require("./fetch-config"); -const getProfileData = require("./get-profile-data"); -const getWhoAmI = require("./get-whoami"); +const { ValidationError } = require("@lerna/validation-error"); +const { getFetchConfig } = require("./fetch-config"); +const { getProfileData } = require("./get-profile-data"); +const { getWhoAmI } = require("./get-whoami"); -module.exports = getNpmUsername; +module.exports.getNpmUsername = getNpmUsername; -function getNpmUsername(_opts) { - const opts = FetchConfig(_opts, { +/** + * Retrieve username of logged-in user. + * @param {import("./fetch-config").FetchConfig} options + * @returns {Promise} + */ +function getNpmUsername(options) { + const opts = getFetchConfig(options, { // don't wait forever for third-party failures to be dealt with - "fetch-retries": 0, + fetchRetries: 0, }); opts.log.info("", "Verifying npm credentials"); return getProfileData(opts) - .catch(err => { + .catch((err) => { // Many third-party registries do not implement the user endpoint // Legacy npm Enterprise returns E500 instead of E404 if (err.code === "E500" || err.code === "E404") { diff --git a/commands/publish/lib/get-packages-without-license.js b/commands/publish/lib/get-packages-without-license.js index 60ab2102733..a633706d186 100644 --- a/commands/publish/lib/get-packages-without-license.js +++ b/commands/publish/lib/get-packages-without-license.js @@ -2,14 +2,20 @@ const path = require("path"); -module.exports = getPackagesWithoutLicense; +module.exports.getPackagesWithoutLicense = getPackagesWithoutLicense; +/** + * Retrieve a list of packages that lack a license file. + * @param {Project} project + * @param {Package[]} packagesToPublish + * @returns {Package[]} + */ function getPackagesWithoutLicense(project, packagesToPublish) { - return project.getPackageLicensePaths().then(licensePaths => { + return project.getPackageLicensePaths().then((licensePaths) => { // this assumes any existing license is a sibling of package.json, which is pretty safe // it also dedupes package locations, since we don't care about duplicate license files - const licensed = new Set(licensePaths.map(lp => path.dirname(lp))); + const licensed = new Set(licensePaths.map((lp) => path.dirname(lp))); - return packagesToPublish.filter(pkg => !licensed.has(pkg.location)); + return packagesToPublish.filter((pkg) => !licensed.has(pkg.location)); }); } diff --git a/commands/publish/lib/get-profile-data.js b/commands/publish/lib/get-profile-data.js index 48b45e3b74c..62e097346b2 100644 --- a/commands/publish/lib/get-profile-data.js +++ b/commands/publish/lib/get-profile-data.js @@ -1,14 +1,19 @@ "use strict"; -const fetch = require("@evocateur/npm-registry-fetch"); -const pulseTillDone = require("@lerna/pulse-till-done"); +const fetch = require("npm-registry-fetch"); +const { pulseTillDone } = require("@lerna/pulse-till-done"); -module.exports = getProfileData; +module.exports.getProfileData = getProfileData; +/** + * Retrieve profile data of logged-in user. + * @param {import("./fetch-config").FetchConfig} opts + * @returns {Promise} + */ function getProfileData(opts) { opts.log.verbose("", "Retrieving npm user profile"); - return pulseTillDone(fetch.json("/-/npm/v1/user", opts)).then(data => { + return pulseTillDone(fetch.json("/-/npm/v1/user", opts)).then((data) => { opts.log.silly("npm profile get", "received %j", data); return Object.assign( @@ -18,3 +23,17 @@ function getProfileData(opts) { ); }); } + +/** + * @typedef {object} ProfileData + * @property {{ pending: boolean; mode: 'auth-and-writes' | 'auth-only' }} tfa + * @property {string} name + * @property {string} username legacy field alias of `name` + * @property {string} email + * @property {boolean} email_verified + * @property {string} created + * @property {string} updated + * @property {string} [fullname] + * @property {string} [twitter] + * @property {string} [github] + */ diff --git a/commands/publish/lib/get-tagged-packages.js b/commands/publish/lib/get-tagged-packages.js index 7c05fd2ea58..3d931cbee1b 100644 --- a/commands/publish/lib/get-tagged-packages.js +++ b/commands/publish/lib/get-tagged-packages.js @@ -4,19 +4,26 @@ const path = require("path"); const log = require("npmlog"); const childProcess = require("@lerna/child-process"); -module.exports = getTaggedPackages; +module.exports.getTaggedPackages = getTaggedPackages; -function getTaggedPackages(packageGraph, rootPath, opts) { +/** + * Retrieve a list of graph nodes for packages that were tagged in a non-independent release. + * @param {import("@lerna/package-graph").PackageGraph} packageGraph + * @param {string} rootPath + * @param {import("@lerna/child-process").ExecOpts} execOpts + * @returns {Promise} + */ +function getTaggedPackages(packageGraph, rootPath, execOpts) { log.silly("getTaggedPackages"); // @see https://stackoverflow.com/a/424142/5707 // FIXME: --root is only necessary for tests :P return childProcess - .exec("git", ["diff-tree", "--name-only", "--no-commit-id", "--root", "-r", "-c", "HEAD"], opts) + .exec("git", ["diff-tree", "--name-only", "--no-commit-id", "--root", "-r", "-c", "HEAD"], execOpts) .then(({ stdout }) => { - const manifests = stdout.split("\n").filter(fp => path.basename(fp) === "package.json"); - const locations = new Set(manifests.map(fp => path.join(rootPath, path.dirname(fp)))); + const manifests = stdout.split("\n").filter((fp) => path.basename(fp) === "package.json"); + const locations = new Set(manifests.map((fp) => path.join(rootPath, path.dirname(fp)))); - return Array.from(packageGraph.values()).filter(node => locations.has(node.location)); + return Array.from(packageGraph.values()).filter((node) => locations.has(node.location)); }); } diff --git a/commands/publish/lib/get-two-factor-auth-required.js b/commands/publish/lib/get-two-factor-auth-required.js index 2e795778c1d..986dea8324f 100644 --- a/commands/publish/lib/get-two-factor-auth-required.js +++ b/commands/publish/lib/get-two-factor-auth-required.js @@ -1,15 +1,20 @@ "use strict"; -const ValidationError = require("@lerna/validation-error"); -const FetchConfig = require("./fetch-config"); -const getProfileData = require("./get-profile-data"); - -module.exports = getTwoFactorAuthRequired; - -function getTwoFactorAuthRequired(_opts) { - const opts = FetchConfig(_opts, { +const { ValidationError } = require("@lerna/validation-error"); +const { getFetchConfig } = require("./fetch-config"); +const { getProfileData } = require("./get-profile-data"); + +module.exports.getTwoFactorAuthRequired = getTwoFactorAuthRequired; + +/** + * Determine if the logged-in user has enabled two-factor auth. + * @param {import("./fetch-config").FetchConfig} options + * @returns {Promise} + */ +function getTwoFactorAuthRequired(options) { + const opts = getFetchConfig(options, { // don't wait forever for third-party failures to be dealt with - "fetch-retries": 0, + fetchRetries: 0, }); opts.log.info("", "Checking two-factor auth mode"); diff --git a/commands/publish/lib/get-unpublished-packages.js b/commands/publish/lib/get-unpublished-packages.js index cacb69aeb07..156febba642 100644 --- a/commands/publish/lib/get-unpublished-packages.js +++ b/commands/publish/lib/get-unpublished-packages.js @@ -2,10 +2,16 @@ const log = require("npmlog"); const pMap = require("p-map"); -const getPackument = require("@evocateur/pacote/packument"); +const pacote = require("pacote"); -module.exports = getUnpublishedPackages; +module.exports.getUnpublishedPackages = getUnpublishedPackages; +/** + * Retrieve a list of graph nodes for packages that need to be published. + * @param {import("@lerna/package-graph").PackageGraph} packageGraph + * @param {import("./fetch-config").FetchConfig} opts + * @returns {Promise} + */ function getUnpublishedPackages(packageGraph, opts) { log.silly("getUnpublishedPackages"); @@ -14,9 +20,9 @@ function getUnpublishedPackages(packageGraph, opts) { // don't bother attempting to get the packument for private packages const graphNodesToCheck = Array.from(packageGraph.values()).filter(({ pkg }) => !pkg.private); - const mapper = pkg => - getPackument(pkg.name, opts).then( - packument => { + const mapper = (pkg) => + pacote.packument(pkg.name, opts).then( + (packument) => { if (packument.versions === undefined || packument.versions[pkg.version] === undefined) { return pkg; } @@ -29,5 +35,5 @@ function getUnpublishedPackages(packageGraph, opts) { chain = chain.then(() => pMap(graphNodesToCheck, mapper, { concurrency: 4 })); - return chain.then(results => results.filter(Boolean)); + return chain.then((results) => results.filter(Boolean)); } diff --git a/commands/publish/lib/get-whoami.js b/commands/publish/lib/get-whoami.js index c373b566c86..4c9d30e07ec 100644 --- a/commands/publish/lib/get-whoami.js +++ b/commands/publish/lib/get-whoami.js @@ -1,17 +1,27 @@ "use strict"; -const fetch = require("@evocateur/npm-registry-fetch"); -const pulseTillDone = require("@lerna/pulse-till-done"); +const fetch = require("npm-registry-fetch"); +const { pulseTillDone } = require("@lerna/pulse-till-done"); -module.exports = getWhoAmI; +module.exports.getWhoAmI = getWhoAmI; +/** + * Retrieve logged-in user's username via legacy API. + * @param {import("./fetch-config").FetchConfig} opts + * @returns {WhoIAm} + */ function getWhoAmI(opts) { opts.log.verbose("", "Retrieving npm username"); - return pulseTillDone(fetch.json("/-/whoami", opts)).then(data => { + return pulseTillDone(fetch.json("/-/whoami", opts)).then((data) => { opts.log.silly("npm whoami", "received %j", data); // { username: String } return data; }); } + +/** + * @typedef {object} WhoIAm + * @property {string} username + */ diff --git a/commands/publish/lib/git-checkout.js b/commands/publish/lib/git-checkout.js index 81c83c1ff95..303e43e58f5 100644 --- a/commands/publish/lib/git-checkout.js +++ b/commands/publish/lib/git-checkout.js @@ -3,8 +3,14 @@ const log = require("npmlog"); const childProcess = require("@lerna/child-process"); -module.exports = gitCheckout; +module.exports.gitCheckout = gitCheckout; +/** + * Reset files modified by publish steps. + * @param {string[]} stagedFiles + * @param {{ granularPathspec: boolean; }} gitOpts + * @param {import("@lerna/child-process").ExecOpts} execOpts + */ function gitCheckout(stagedFiles, gitOpts, execOpts) { const files = gitOpts.granularPathspec ? stagedFiles : "."; diff --git a/commands/publish/lib/remove-temp-licenses.js b/commands/publish/lib/remove-temp-licenses.js index 11c131af03d..2644c8c7a89 100644 --- a/commands/publish/lib/remove-temp-licenses.js +++ b/commands/publish/lib/remove-temp-licenses.js @@ -3,12 +3,16 @@ const fs = require("fs-extra"); const pMap = require("p-map"); -module.exports = removeTempLicenses; +module.exports.removeTempLicenses = removeTempLicenses; +/** + * Remove temporary license files. + * @param {Package[]} packagesToBeLicensed + */ function removeTempLicenses(packagesToBeLicensed) { if (!packagesToBeLicensed.length) { return Promise.resolve(); } - return pMap(packagesToBeLicensed, pkg => fs.remove(pkg.licensePath)); + return pMap(packagesToBeLicensed, (pkg) => fs.remove(pkg.licensePath)); } diff --git a/commands/publish/lib/verify-npm-package-access.js b/commands/publish/lib/verify-npm-package-access.js index a8f7aa82217..97e8a000ce8 100644 --- a/commands/publish/lib/verify-npm-package-access.js +++ b/commands/publish/lib/verify-npm-package-access.js @@ -1,16 +1,23 @@ "use strict"; -const access = require("@evocateur/libnpmaccess"); -const pulseTillDone = require("@lerna/pulse-till-done"); -const ValidationError = require("@lerna/validation-error"); -const FetchConfig = require("./fetch-config"); +const access = require("libnpmaccess"); +const { pulseTillDone } = require("@lerna/pulse-till-done"); +const { ValidationError } = require("@lerna/validation-error"); +const { getFetchConfig } = require("./fetch-config"); -module.exports = verifyNpmPackageAccess; +module.exports.verifyNpmPackageAccess = verifyNpmPackageAccess; -function verifyNpmPackageAccess(packages, username, _opts) { - const opts = FetchConfig(_opts, { +/** + * Throw an error if the logged-in user does not have read-write access to all packages. + * @param {{ name: string; }[]} packages + * @param {string} username + * @param {import("./fetch-config").FetchConfig} options + * @returns {Promise} + */ +function verifyNpmPackageAccess(packages, username, options) { + const opts = getFetchConfig(options, { // don't wait forever for third-party failures to be dealt with - "fetch-retries": 0, + fetchRetries: 0, }); opts.log.silly("verifyNpmPackageAccess"); diff --git a/commands/publish/package.json b/commands/publish/package.json index 74d03f4c3f9..7e46b5cf238 100644 --- a/commands/publish/package.json +++ b/commands/publish/package.json @@ -1,6 +1,6 @@ { "name": "@lerna/publish", - "version": "3.22.1", + "version": "4.0.0", "description": "Publish packages in the current project", "keywords": [ "lerna", @@ -20,7 +20,7 @@ ], "main": "index.js", "engines": { - "node": ">= 6.9.0" + "node": ">= 10.18.0" }, "publishConfig": { "access": "public" @@ -34,9 +34,6 @@ "test": "echo \"Run tests from root\" && exit 1" }, "dependencies": { - "@evocateur/libnpmaccess": "^3.1.2", - "@evocateur/npm-registry-fetch": "^4.0.0", - "@evocateur/pacote": "^9.6.3", "@lerna/check-working-tree": "file:../../utils/check-working-tree", "@lerna/child-process": "file:../../core/child-process", "@lerna/collect-updates": "file:../../utils/collect-updates", @@ -56,13 +53,14 @@ "@lerna/run-topologically": "file:../../utils/run-topologically", "@lerna/validation-error": "file:../../core/validation-error", "@lerna/version": "file:../version", - "figgy-pudding": "^3.5.1", - "fs-extra": "^8.1.0", - "npm-package-arg": "^6.1.0", + "fs-extra": "^9.1.0", + "libnpmaccess": "^4.0.1", + "npm-package-arg": "^8.1.0", + "npm-registry-fetch": "^9.0.0", "npmlog": "^4.1.2", - "p-finally": "^1.0.0", - "p-map": "^2.1.0", - "p-pipe": "^1.2.0", - "semver": "^6.2.0" + "p-map": "^4.0.0", + "p-pipe": "^3.1.0", + "pacote": "^11.2.6", + "semver": "^7.3.4" } } diff --git a/commands/run/CHANGELOG.md b/commands/run/CHANGELOG.md index 14857e55770..7c2d0ac159e 100644 --- a/commands/run/CHANGELOG.md +++ b/commands/run/CHANGELOG.md @@ -3,6 +3,31 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.0.0](https://github.com/lerna/lerna/compare/v3.22.1...v4.0.0) (2021-02-10) + + +### Features + +* Consume named exports of sibling modules ([63499e3](https://github.com/lerna/lerna/commit/63499e33652bc78fe23751875d74017e2f16a689)) +* **deps:** execa@^4.1.0 ([9051dca](https://github.com/lerna/lerna/commit/9051dcab1a68b56db09b82ab0345c5f36bcfee2d)) +* **deps:** p-map@^4.0.0 ([92b1364](https://github.com/lerna/lerna/commit/92b1364735e1f2cf379cf1047c60c4fb897d55f5)) +* Drop support for Node v6.x & v8.x ([ff4bb4d](https://github.com/lerna/lerna/commit/ff4bb4da215555e3bb136f5af09b5cbc631e57bb)) + + +### BREAKING CHANGES + +* Node v6.x & v8.x are no longer supported. Please upgrade to the latest LTS release. + +Here's the gnarly one-liner I used to make these changes: +``` +npx lerna exec --concurrency 1 --stream -- 'json -I -f package.json -e '"'"'this.engines=this.engines||{};this.engines.node=">= 10.18.0"'"'" +``` +(requires `npm i -g json` beforehand) + + + + + # [3.21.0](https://github.com/lerna/lerna/compare/v3.20.2...v3.21.0) (2020-05-13) **Note:** Version bump only for package @lerna/run diff --git a/commands/run/__tests__/run-command.test.js b/commands/run/__tests__/run-command.test.js index 8a143e84e4e..f493e3c7a6d 100644 --- a/commands/run/__tests__/run-command.test.js +++ b/commands/run/__tests__/run-command.test.js @@ -6,20 +6,20 @@ const fs = require("fs-extra"); const globby = require("globby"); // mocked modules -const npmRunScript = require("@lerna/npm-run-script"); -const output = require("@lerna/output"); +const { npmRunScript, npmRunScriptStreaming } = require("@lerna/npm-run-script"); +const { output } = require("@lerna/output"); // helpers const initFixture = require("@lerna-test/init-fixture")(__dirname); -const loggingOutput = require("@lerna-test/logging-output"); -const normalizeRelativeDir = require("@lerna-test/normalize-relative-dir"); +const { loggingOutput } = require("@lerna-test/logging-output"); +const { normalizeRelativeDir } = require("@lerna-test/normalize-relative-dir"); // file under test const lernaRun = require("@lerna-test/command-runner")(require("../command")); // assertion helpers -const ranInPackagesStreaming = testDir => - npmRunScript.stream.mock.calls.reduce((arr, [script, { args, npmClient, pkg, prefix }]) => { +const ranInPackagesStreaming = (testDir) => + npmRunScriptStreaming.mock.calls.reduce((arr, [script, { args, npmClient, pkg, prefix }]) => { const dir = normalizeRelativeDir(testDir, pkg.location); const record = [dir, npmClient, "run", script, `(prefixed: ${prefix})`].concat(args); arr.push(record.join(" ")); @@ -27,8 +27,8 @@ const ranInPackagesStreaming = testDir => }, []); describe("RunCommand", () => { - npmRunScript.mockImplementation((script, { pkg }) => Promise.resolve({ code: 0, stdout: pkg.name })); - npmRunScript.stream.mockImplementation(() => Promise.resolve({ code: 0 })); + npmRunScript.mockImplementation((script, { pkg }) => Promise.resolve({ exitCode: 0, stdout: pkg.name })); + npmRunScriptStreaming.mockImplementation(() => Promise.resolve({ exitCode: 0 })); afterEach(() => { process.exitCode = undefined; @@ -117,7 +117,7 @@ describe("RunCommand", () => { const err = new Error(pkg.name); err.failed = true; - err.code = 123; + err.exitCode = 123; return Promise.reject(err); }); @@ -133,7 +133,7 @@ describe("RunCommand", () => { const err = new Error(pkg.name); err.failed = true; - err.code = 456; + err.exitCode = 456; err.stdout = pkg.name; return Promise.resolve(err); diff --git a/commands/run/command.js b/commands/run/command.js index 6cfbebaa5c6..92cab572580 100644 --- a/commands/run/command.js +++ b/commands/run/command.js @@ -1,6 +1,6 @@ "use strict"; -const filterable = require("@lerna/filter-options"); +const { filterOptions } = require("@lerna/filter-options"); /** * @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#providing-a-command-module @@ -9,7 +9,7 @@ exports.command = "run