Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

process: add version constants and compare #19587

Closed

Conversation

devsnek
Copy link
Member

@devsnek devsnek commented Mar 25, 2018

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

@devsnek devsnek requested review from mscdex and tniessen March 25, 2018 05:44
@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. process Issues and PRs related to the process subsystem. labels Mar 25, 2018
minorVersion,
patchVersion,
} = process.release;
const prereleaseTag = process.release.prereleaseTag.replace(/^-/, '');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this replace() unnecessary since substr(1, ..) is already done in C++ land?

return -1;
if (prerelease && patch === patchVersion)
return 1;
if (patch > patchVersion)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps move these last two conditionals to the top of this section (after the minor version checks) and then drop the patch === patchVersion check from each of the other three conditionals?

if (prereleaseTag && prereleaseTag === prerelease &&
patch === patchVersion)
return 0;
if (prereleaseTag && patch === patchVersion)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the the above two checks could be grouped together under a if (prereleaseTag) conditional to avoid checking it twice.

@mscdex
Copy link
Contributor

mscdex commented Mar 25, 2018

I'm not so sure about the usefulness of allowing a single version string argument. I think it's just complicating things and might slow things down if version checks are being done during runtime.

* `tag` {string} The pre-release tag to compare.
* Returns: {number} `-1` if the given version is lower than the release
version, `0` if the given version matches the process version, and `1`
if the given version is greater than the release version.
Copy link
Member

@tniessen tniessen Mar 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already explained in #19574 why this design is problematic:

The signum of the result of compareVersion seems counter-intuitive to me. In most (if not all) frameworks, a comparator returns a negative result if the first argument (or this) is considered to be "before" the second argument, and a positive result if the first argument (or this) is considered to be "after" the second argument (see e.g. java.lang.Comparable for a single-argument comparison). compareVersion contradicts this well-established norm. I would expect compareVersion(10, 0, 0) >= 0 to return whether this release is v10 or newer, which follows the norm and is intuitive, but #19438 implements the opposite.

In one of your earlier revisions of your comment in that PR, you seemed to agree with me. Is there a reason to stick to the old design?

if (typeof major === 'string')
[major, minor, patch] = major.split('.');
if (/-/.test(patch))
[patch, prerelease] = patch.split('-');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both split() calls are problematic if you are trying to comply with semver, see section 9 of the spec. The prerelease label can contain dots and dashes.

minor = +minor;
patch = +patch;
if (/^-/.test(prerelease))
prerelease = prerelease.slice(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct. As far as I understand the specification, 1.1.0-- is a valid version, where { major: 1, minor: 1, patch: 0, prerelease: '-' }.

* `majorVersion` {number} The major version of Node.js.
* `minorVersion` {number} The minor version of Node.js.
* `patchVersion` {number} The patch version of Node.js.
* `prereleaseTag` {string} The SemVer pre-release tag for Node.js.
Copy link
Member

@tniessen tniessen Mar 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the name of this property originates from how the variable is called in node.cc? Is "prerelease tag" a common term for this? The spec does not use it.

Edit: I just saw that https://github.com/npm/node-semver#prerelease-tags also uses this term, so it is probably not a bad choice.

majorVersion: 4,
minorVersion: 4,
patchVersion: 5,
prereleaseTag: '',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as compareVersion is enumerable, it should be listed here.

@tniessen
Copy link
Member

To me, the most important questions are: Do we need / want an API like compareVersion? In how far should it be semver-compliant regarding prerelease labels? Should it accept a string or a list of integers or both? I would love to hear some opinions.

* `minorVersion` {number} The minor version of Node.js.
* `patchVersion` {number} The patch version of Node.js.
* `prereleaseTag` {string} The SemVer pre-release tag for Node.js.
* `compareVersion` {function} Perform a SemVer comparison to the release
Copy link
Contributor

@vsemozhetbyt vsemozhetbyt Mar 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Nit: {function} -> {Function} (only primitives are lowercased).
  2. We may need to add the function signature here, with all the optional parameters marked with [] (nested or not).
  3. I am not sure if this is a common practice to not single out such API in its own section. Let us see what others think.

const prereleaseTag = process.release.prereleaseTag.replace(/^-/, '');

process.release.compareVersion =
(major, minor, patch, prerelease = false) => {
Copy link
Contributor

@vsemozhetbyt vsemozhetbyt Mar 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should happen if all of or some of major, minor, patch are undefined? Should the function throw or should these arguments be 0? Currently, it seems they are NaN in this case.

return 1;

if (prereleaseTag) {
if (prereleaseTag === prerelease && patch === patchVersion)
Copy link
Contributor

@mscdex mscdex Mar 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would shorten this to something like:

if (prereleaseTag) {
  if (patch === patchVersion)
    return (prereleaseTag === prerelease ? 0 : 1);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually scratch that. How about this for the entire bottom part?:

if (patch > patchVersion)
  return -1;
if (patch < patchVersion)
  return 1;
if (prereleaseTag)
  return (prereleaseTag === prerelease ? 0 : 1);
if (prerelease)
  return -1;

return 0;

Copy link
Contributor

@mscdex mscdex Mar 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and possibly shorten the last two returns even further to just return (prerelease ? -1 : 0);

if (patch === patchVersion)
return 1;
}
if (prerelease && patch === patchVersion)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

patch === patchVersion can be removed here if this check is moved to the bottom.

@Trott Trott added the semver-minor PRs that contain new features and should be released in the next minor version. label Mar 26, 2018
@devsnek devsnek force-pushed the feature/process-release-more-version branch from ba49805 to 526836c Compare March 29, 2018 16:24
} = process.release;

process.release.compareVersion =
(major, minor, patch, prerelease = false) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the default value for the last parameter here can be removed as it's not necessary and will not affect tag comparisons when it is undefined instead of false.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah hehe, copied from older implementation :p

@devsnek
Copy link
Member Author

devsnek commented Mar 29, 2018

@tniessen ptal

@tniessen tniessen dismissed their stale review March 29, 2018 22:16

Comments have been addressed.

@tniessen
Copy link
Member

#19587 (comment) should probably be addressed, and #19587 (comment) should be discussed.

@devsnek devsnek force-pushed the feature/process-release-more-version branch from b7aef4a to bb27e9c Compare March 29, 2018 23:31
Copy link
Contributor

@cjihrig cjihrig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly LGTM, but left a few comments.

if (typeof minor !== 'number')
throw new ERR_INVALID_ARG_TYPE('minor', 'number', minor);
if (typeof patch !== 'number')
throw new ERR_INVALID_ARG_TYPE('patch', 'number', minor);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last argument should be patch I think.

compareVersion,
} = process.release;

assert.strictEqual(0, compareVersion(major, minor, patch, tag));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change the order of the arguments in these assertions to reflect the assert.strictEqual(actual, expected) signature.

assert.strictEqual(0, compareVersion(major, minor, patch, tag));

assert.strictEqual(-1, compareVersion(major, minor, patch + 1, tag));
assert.strictEqual(1, compareVersion(major - 1, minor, patch, tag));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think more tests are needed to achieve code coverage - increment/decrement each value and pass bad values for each.

@devsnek
Copy link
Member Author

devsnek commented Apr 5, 2018

unless anyone objects i think i'll land this on friday


Perform a SemVer comparison to the release version.

* `major` {string | number} The major version to compare or a string containing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A string is not accepted by the function

@devsnek devsnek force-pushed the feature/process-release-more-version branch from 3913cef to 4be45cd Compare April 5, 2018 16:53
Copy link
Member

@apapirovski apapirovski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few nits and one relevant question / note that I think needs to be addressed?

[0, 0, 0, 0],
]) {
common.expectsError(() => {
compareVersion(args[0], args[1], args[2], args[3]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: could just ...args here?

@@ -1509,6 +1512,10 @@ tarball.
- `'Argon'` for the 4.x LTS line beginning with 4.2.0.
- `'Boron'` for the 6.x LTS line beginning with 6.9.0.
- `'Carbon'` for the 8.x LTS line beginning with 8.9.1.
* `majorVersion` {number} The major version of Node.js.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: for consistency, this might be better as "of this release" or something?


* `major` {number} The major version to compare or a string containing the
entire version.
* `minor` {number} The minor version number to compare.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: can we stick to "version number" or just "version" consistently between the three descriptions for major, minor & patch?


Perform a SemVer comparison to the release version.

* `major` {number} The major version to compare or a string containing the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's totally possible I'm missing something here but I don't see the functionality for

or a string containing the entire version

implemented in this PR. Did I miss something?

@devsnek devsnek force-pushed the feature/process-release-more-version branch from 4be45cd to bd94813 Compare April 6, 2018 13:44
@devsnek
Copy link
Member Author

devsnek commented Apr 6, 2018

@devsnek
Copy link
Member Author

devsnek commented Apr 7, 2018

@devsnek
Copy link
Member Author

devsnek commented Apr 7, 2018

both times failures are unrelated, I'll land this soonish

@devsnek
Copy link
Member Author

devsnek commented Apr 14, 2018

Landed in 91e0f8d

@devsnek devsnek closed this Apr 14, 2018
@devsnek devsnek deleted the feature/process-release-more-version branch April 14, 2018 05:03
devsnek added a commit that referenced this pull request Apr 14, 2018
PR-URL: #19587
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
@rvagg
Copy link
Member

rvagg commented Apr 16, 2018

tagged as dont-land-on-v9.x, I'm proposing reversion @ #20062 and would like that to be resolved before moving forward with a 9.x release

jasnell pushed a commit that referenced this pull request Apr 16, 2018
PR-URL: #19587
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
@bcoe
Copy link
Contributor

bcoe commented Aug 15, 2018

@rvagg @devsnek could you bring me up to speed as to why this was ultimately closed. Feels like having a numeric major, minor, patch, prereleaseTag could simplify feature detection for upstream libraries.

I'm +1 that we don't want to pull in any additional semver functionality, unless we go all the way and merge in the library semver. But, having the major and minor broken out in a parameter could be nice.

@rvagg
Copy link
Member

rvagg commented Aug 15, 2018

compareVersion() is the controversial piece here. As for the numeric options, they are less of a problem and may slide in if attempted by themselves. Although it's really not hard to do a quick slice and parse or do a proper job and pull in semver to do a real compare that takes into account all of the edge cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. process Issues and PRs related to the process subsystem. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet