lerna: Lerna does not call "npm ci" when hoisting

I know it’s disabled per the following issue but in my testing I couldn’t reproduce the same error neither in the istanbuljs repo nor in our own repo https://github.com/lerna/lerna/issues/1865

Expected Behavior

When the CI environment variable is set, e.g. CI=1, Lerna should call npm ci

Current Behavior

Lerna calls npm install with --global-style and --no-save arguments

Possible Solution

Remove the code block here: https://github.com/lerna/lerna/blob/master/commands/bootstrap/index.js#L112

Steps to Reproduce (for bugs)

  1. Create a minimal repo with one package
  2. Add hoist: ["is-ci"] to lerna.json
  3. Add is-ci to the package’s own dependencies
  4. Run lerna bootstrap --loglevel=silly -> output shows ['npm', ['install']] is called
  5. Set the CI environment variable to 1 and call lerna: CI=1 lerna bootstrap --loglevel=silly -> output shows ['npm', ['install', '--global-style', '--no-save']] is called
lerna.json

<!-- Please paste your `lerna.json` here -->
{
    "command": {
        "bootstrap": {
            "npmClientArgs": [
                "--loglevel=verbose",
                "--fetch-retries=5",
                "--fetch-retry-factor=20",
                "--fetch-retry-maxtimeout=180000",
                "--fetch-retry-mintimeout=5000"
            ]
        }
    },
    "hoist": [
        "class-validator",
        "deep-equal",
        "json-long",
        "long",
        "node-sass",
        "reflect-metadata",
        "typescript"
    ],
    "packages": [
        "packages/*"
    ],
    "version": "0.0.0"
}

Context

I’m trying to prevent developers from (mostly by forgetting) submitting changes in the package.json files but not updating package-lock.json files.

Your Environment

We use Buildbot for our CI (which isn’t recognized by the ci-info package, that’s why we explicitly set the CI env var

Executable Version
lerna --version 3.13.2
npm --version 6.9.0
node --version 8.14.0
OS Version
Ubuntu 18.10

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 3
  • Comments: 17 (3 by maintainers)

Most upvoted comments

@evocateur wrote:

This all assumes that everyone working in the hoisted monorepo never trundles down into a leaf directory and runs npm install directly. In my experience, this is an extremely counter-intuitive guideline for working in a monorepo, and thus gets violated 95% of the time.

It’s even more counter-intuitive when you run lerna bootstrap --ci and… Lerna doesn’t run npm ci!

We spent countless hours wrestling with unexpected package upgrades despite having package-lock.json files all over the place, scratching our heads what could possibly be going wrong. This issue breaks any serious CI setup, where we want to build with only controlled package versions and fail otherwise.

Could you please reconsider this and provide a way to run npm ci with --hoist?

If the developer went to the trouble of discovering the --ci parameter and calling lerna bootstrap --ci, they damn well expect Lerna to invoke npm ci! To silently ignore the --ci parameter without any warning (especially on a CI server) is way more problematic than some developer trundling into a package folder and running npm install there.

This doesn’t even affect normal lerna bootstrap usage which runs npm install anyway, so users who don’t care about --ci won’t even notice anything.

@mzyil thanks! I missed that when looking at the thread though it’s not clear what the PR actually changed in regards to this issue. I’ll have to review it some more.

If you use hoisting, you don’t go and npm install in the package folder anyway. Otherwise why use hoisting at all.

Our use case was for some packages that needed to have one and only one copy (the boring class-validator and class-transformator packages). We wouldn’t even dream of going on and installing them in the package folder, as it would instantly break the tests.

Anyway we solved it by moving the MUST-BE-hoisted dependencies to peerDependencies and added another package that contained just a package.json with the said dependencies, then symlinked its node_modules folder to the top and committed the symlink.

But my suggestion is at least provide an option like --force-ci-in-hoisting or better yet --force-ci-despite-of-hoisting which makes people aware of what they put themselves into.

Correct me if I’m wrong but, if the package.json file is mutated, and the npm install command is called against that mutated file, then that would mean the package-lock.json file is created according to the mutated package.json file. So if in CI environment Lerna calls npm ci AT THE SAME STEP that where it’s supposed to call npm install, than that would mean npm ci will see the mutated package.json file and ‘accordingly mutated’ (e.g., no entries for hoisted packages) package-lock.json file, which are in sync.

So I would say as long as the package.json file is mutated the same way it was mutated while calling npm install, there isn’t any reason for npm ci to not work. If you look at my suggestion, that’s what it does. Keep everything the same, just change the subcommand.