npm install --tag doesn't behave per docs

(Roger Gonzalez) #1

What I Wanted to Do

I am trying to publish multiple tagged versions. Given the following:

package.json dependencies of @mycompany/htest": "^0.1.0"

npm view @mycompany/htest dist-tags

{ latest: '0.1.1',
  alpha: '0.1.7',
  beta: '0.1.10',
  gamma: '0.1.11-dev.3',
  delta: '0.1.11-dev.4' }

npm install correctly yields 0.1.1
npm install @mycompany/htest@gamma correctly yields 0.1.11-dev.3
npm install --tag gamma doesn’t work correctly…

From the docs for npm-install:

The --tag argument will apply to all of the specified install targets. If a tag with the given name exists,
the tagged version is preferred over newer versions.

What Happened Instead

npm install --tag gamma yields 0.1.10 (wat?!?!)
in fact, npm install --tag foo also yields 0.1.10

Reproduction Steps

should be trivial to repro. just set a tag “hello” something other than latest, and try to install it with npm install --tag=hello

Platform Info

$ npm --versions
{ npm: '6.9.0',
  ares: '1.10.1-DEV',
  cldr: '31.0.1',
  http_parser: '2.7.0',
  icu: '59.1',
  modules: '57',
  node: '8.1.4',
  openssl: '1.0.2l',
  tz: '2017b',
  unicode: '9.0',
  uv: '1.12.0',
  v8: '',
  zlib: '1.2.11' }
$ node -p process.platform

(John Gee) #2

What command are you actually running?

npm install --tag gamma @mycompany/htest
npm install --tag gamma

(Roger Gonzalez) #3

The latter – I don’t want to refer to a particular package. I want it to behave just like “npm install”, except preferentially pick the specified tag whenever it exists.

(Roger Gonzalez) #4

I traced into the source, and it seems related to the fact that my tagged version is a prerelease version.

Inside npm-pick-manifest, it starts out doing the right thing, but then it excludes prereleases and falls back to the highest number that satisfies semver (ignoring latest!). There doesn’t seem to be any way (from a client of pacote) to override this since registry/getManifest rewrites the opts.

(John Gee) #5

My expectation is that --tag only applies when you use the first form I gave, to “the specified install targets”, as it would seldom make sense to use a single tag for a possible huge number of packages in package.json. So effectively --tag being ignored when specify no targets.

(Roger Gonzalez) #6

That interpretation is reasonable, though I will say that it is not being ignored when you specify no targets. It actually behaves the way I want if and only if the tag is not associated with a prerelease version. I.e. in my example, npm install --tag beta actually works.

Rationale: I’m doing this in CI, where we tie git branch to the tag (so that each team can have some isolation), and use the “automatically build every branch” plugin in Jenkins. I don’t want to update major/minor/patch as part of the auto-build, so we increment the prerelease data, and include the branch name there as well. If I can do “npm install --tag myteambranch” then it will automatically include the latest published team artifacts that match the dependency spec. All I want are isolated “latest” semantics, which dist-tags provide, and a place to make unique artifact names without bumping major/patch/minor just because a build was run. If I have to edit the dependency in package.json to include the branch/prerelease info, then that change could leak out of the branch into master/release. Likewise editing the Jenkinsfile to explicitly include branch-specific npm install commands. Whereas just running “npm install --tag ${BRANCHNAME}” for anything other than release branches and “npm install” on release, it’s much cleaner.