cli
cli copied to clipboard
[BUG] "npm publish" tags pre-versions as "latest"
Is there an existing issue for this?
- [X] I have searched the existing issues
This issue exists in the latest npm version
- [X] I am using the latest npm
Current Behavior
NOTE: This is rather a footgun than a bug
This was reported in https://github.com/npm/npm/issues/13248 and has been ignored and never re-opened since, even though the problem clearly still exists. Following is the (adapted) description from the issues' original author. I have verified that this behaviour is still present.
Running npm version premajor && npm publish will tag the premajor version as latest by default. I confirmed this happens when running all pre-release options: premajor | preminor | prepatch | prerelease.
As pointed out in https://github.com/npm/npm/issues/10189, there are valid reasons that authors would want to tag pre-release versions as latest. However, I think that this is not good default behaviour (though it is documented: "Publishing a package sets the latest tag to the published version unless the --tag option is used. For example, npm publish --tag=beta.")
Semver documentation states:
A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. Examples: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92.
Source: http://semver.org/#spec-item-9
Expected Behavior
I propose that the latest tag only be set if the version to be published is not a pre-release version. Or, at the very least, there should be a warning about this.
Steps To Reproduce
- While in any package directory...
- Run
npm version prepatchor... preminoror... premajoror... prereleaseor set a pre-release version manually - Run
npm publish - See that the package gets published to the
latesttag without any fuss
Environment
- npm: 10.5.2
- Node.js: 20.13.0
- OS Name: macOS Ventura 13.6.6
- System Model Name: MacBook Pro 14-inch 2023 M2 Pro 32GB RAM
- npm config:
; "project" config from /Users/nikitakaramov/Code/@kytta/npmtest/.npmrc
@kytta:registry = (redacted)
//(redacted)/:_authToken = (protected)
; "env" config from environment
userconfig = "/Users/nikitakaramov/.config/npm/npmrc"
; node bin location = /Users/nikitakaramov/.local/share/mise/installs/node/20.13.0/bin/node
; node version = v20.13.0
; npm local prefix = /Users/nikitakaramov/Code/@kytta/npmtest
; npm version = 10.5.2
; cwd = /Users/nikitakaramov/Code/@kytta/npmtest
; HOME = /Users/nikitakaramov
; Run `npm config ls -l` to show all defaults.
Some tag must always be set - what tag would you expect as an alternative?
Some tag must always be set - what tag would you expect as an alternative?
If not failing for pre-release builds (which would force the user to set the tag), I'd choose either:
nextfor any semver-compliant pre-release version, or- the tag that matches the prerelease suffix, if there is any. For example,
2.0.0-alpha.1would get the tagalpha,2.0.0-rc.3would get the tagrc
failing and forcing a tag seems nice. even better is if it implemented https://npmjs.com/safe-publish-latest, and failed to implicitly publish a latest whenever the version being published isn't a non-prerelease that is "later" than all existing versions.
So, this behaviour, then?
npm version 1.0.0
npm publish # no problem
npm version 1.0.1-alpha.1
npm publish
# npm ERR no tag set
npm publish --tag alpha # no problem
npm version 1.0.1-alpha.2
npm publish --tag latest # no problem; set implicitly
npm version 0.1.0 # assuming it's possible
npm publish
# npm ERR a newer 'latest' version is already published
Another question. What should we do about this behaviour:
- developer willingly publishes a pre-release to
latest(https://github.com/npm/npm/issues/10189#issuecomment-156324153)- say,
1.0.0-rc.1=>latest
- say,
- developer makes a new pre-release version with the same version number (major.minor.patch), and a different pre-release identifier combo
- say,
1.0.0-rc.2
- say,
- developer runs
npm publish
Should we allow this, because the developer "opted-in" to publishing pre-releases for 1.0.0 to latest (in other words, because the current latest is also a pre-release), or should we always require an explicit tag for pre-releases?
If they explicitly want something to be "latest" then it would be wildly improper for npm to prevent that, but it seems reasonable to me that implicit "latest" must always be a "later" non-prerelease.
(to be clear, this is something that'd have to be accepted by the npm team, and probably should be discussed in the RFC repo instead of here)
If they explicitly want something to be "latest" then it would be wildly improper for npm to prevent that, but it seems reasonable to me that implicit "latest" must always be a "later" non-prerelease.
Sounds good. It also matches the behaviour proposed in RFC 7
(to be clear, this is something that'd have to be accepted by the npm team, and probably should be discussed in the RFC repo instead of here)
Thanks for the heads-up! I've drafted one here: https://github.com/npm/rfcs/pull/776
➕ 1 on failing when not passing an explicit --tag for prerelease versions. This has bitten me so many times over the years and has contributed to my beliefs automated publish workflows are superior (despite the tradeoffs). This would remove one of the rough edges around manual publish workflows and seems pretty clearly to be a good thing.
Because this is not a bug I am going to close this issue. The rfc issue is probably the best place to add more input. Personally I'm a huge fan of this idea.