Make SemanticVersion compatible with SemVer 2.0#5037
Make SemanticVersion compatible with SemVer 2.0#5037daxian-dbw merged 8 commits intoPowerShell:masterfrom
Conversation
|
@JamesWTruher @PaulHigin Can you please review this PR? |
PaulHigin
left a comment
There was a problem hiding this comment.
I am not quite finished with the review.
There was a problem hiding this comment.
We don't need to explicitly set properties to null since CLR automatically initializes fields to zero.
There was a problem hiding this comment.
I only thought about symmetry and better readability.
Removed.
There was a problem hiding this comment.
Shouldn't these static strings also be const string? They are never reassigned so there is no point in allocating.
There was a problem hiding this comment.
Can you include examples of allowed label strings in the comment? I don't read regex very well :)
There was a problem hiding this comment.
Complex RegEx is a puzzle for me too. I found some sample RegEx strings for SymVer but after testing I concluded that they all have bugs.
So I split the SymVer regex string on some string (s_VersionSansRegEx, s_LabelRegEx, s_LabelUnitRegEx). This slightly increased the code but helped to avoid bugs.
Comment added.
There was a problem hiding this comment.
The Group.Value always returns an empty string for no matches. Should the PreLable/BuildLable properties be initialized to empty string rather than null?
There was a problem hiding this comment.
I see that we always check strings for NullOrEmpty so I think we are Ok as is.
There was a problem hiding this comment.
I wonder if we should do this preLabel, buildLabel regex validation in the SemanticVersion constructor. That way we can prevent malformed SemanticVersion objects from being created.
There was a problem hiding this comment.
I wonder too why I checked only first char in constructors :-) I wonted to be fast. We should use RegEx.
Fixed.
There was a problem hiding this comment.
I feel we still need this check, otherwise v1.CompareTo will throw null reference exception.
There was a problem hiding this comment.
Fixed by new method Compare()
There was a problem hiding this comment.
I feel we still need this check, otherwise v1.CompareTo will throw null reference exception.
There was a problem hiding this comment.
We should check v1 for null value.
There was a problem hiding this comment.
We should check v1 for null value.
There was a problem hiding this comment.
Please add a comment that PreLabel takes lower precedence when normal versions are equal, per spec. This logic always confuses me until I remember that :)
There was a problem hiding this comment.
Actually this PreLabel null check here can be removed since it is duplicated in ComparePreLabel().
There was a problem hiding this comment.
But please add the comment in ComparePreLabel() method.
There was a problem hiding this comment.
Duplicate checks was removed.
Comment was added.
Replace static strings with const. Add strong checks in constructors. Add comments. Add static Compare() and fix comparisions operators.
53ea5b7 to
9571e06
Compare
|
I've rebased to resolve a merge conflict. |
|
@anmenaga Can you please also review this PR? Thanks! |
| /// <param name="preLabel">The preLabel for the version</param> | ||
| /// <param name="buildLabel">The buildLabel for the version</param> | ||
| /// <exception cref="FormatException"> | ||
| /// If <paramref name="preLabel"/> starts with '-' ot contains '+'. |
There was a problem hiding this comment.
I changed the comments because the code was changed previously.
| { | ||
| private const string s_VersionSansRegEx = @"^(?<major>\d+)(\.(?<minor>\d+))?(\.(?<patch>\d+))?$"; | ||
| private const string s_LabelRegEx = @"^((?<preLabel>[0-9A-Za-z][0-9A-Za-z\-\.]*))?(\+(?<buildLabel>[0-9A-Za-z][0-9A-Za-z\-\.]*))?$"; | ||
| private const string s_LabelUnitRegEx = @"^[0-9A-Za-z][0-9A-Za-z\-\.]*?$"; |
There was a problem hiding this comment.
The variable names should be changed. s_ indicates static private variables, but they are const variables.
There was a problem hiding this comment.
-.]*?$
Since you are matching to the end of line, is the question mark ? (lazy matching) needed?
There was a problem hiding this comment.
s_ was removed.
? was removed - I think it is bug in any case.
| /// PreLabel position in the SymVer string 'major.minor.patch-PreLabel+BuildLabel'. | ||
| /// </summary> | ||
|
|
||
| public string PreLabel { get; } |
There was a problem hiding this comment.
Maybe we should just the full name PrereleaseLabel for the public property?
There was a problem hiding this comment.
Replaced with PreReleaseLabel - it looks more readable.
| /// The last component in a SemanticVersion - may be null if not specified. | ||
| /// PreLabel position in the SymVer string 'major.minor.patch-PreLabel+BuildLabel'. | ||
| /// </summary> | ||
|
|
There was a problem hiding this comment.
Can you please remove the extra new line?
| /// </summary> | ||
| public static int Compare(SemanticVersion versionA, SemanticVersion versionB) | ||
| { | ||
| if (versionA == null) return -1; |
There was a problem hiding this comment.
what about versionA and versionB are both null?
There was a problem hiding this comment.
Good catch!
Fixed.
| Minor.GetHashCode(), | ||
| Patch.GetHashCode(), | ||
| Label == null ? 0 : Label.GetHashCode()); | ||
| return versionString.GetHashCode(); |
There was a problem hiding this comment.
versionString could be null when running this method.
Besides, if we use the hashcode of versionString for the SemanticVersion, we would have a hashcode collision, would that be a problem? Why not continue to use Utils.CombineHashCodes?
There was a problem hiding this comment.
null - fixed.
versionString is relatively short string - why you believe that CoreFX implementation of String.GetHashCode() so bad that we should make more complex hashcode?
There was a problem hiding this comment.
What I mean is the hashcode of a SemanticsVersion instance would be the same of the hashcode of a string (the versionString), so there is a collision in terms that 2 different objects have the same hashcode.
There was a problem hiding this comment.
In the docs I don't found that the hash must be different for different objects of different types. It seems we follow the docs - it will be work well with Dictionary and Hashtable types.
There was a problem hiding this comment.
Maybe I'm just overthinking it. Let's keep it as is. #Close
| } | ||
| else | ||
| { | ||
| if (isNumber1) { return -1; } |
There was a problem hiding this comment.
It would be great if you can add comment here saying that "Numeric identifiers always have lower precedence than non-numeric identifiers. "
There was a problem hiding this comment.
I copy-paste all text from the standard.
| .AddPropertyColumn("Major") | ||
| .AddPropertyColumn("Minor") | ||
| .AddPropertyColumn("Patch") | ||
| .AddPropertyColumn("PreLabel") |
There was a problem hiding this comment.
The property name has changed to 'PrereleaseLabel'.
| .AddPropertyColumn("Minor") | ||
| .AddPropertyColumn("Build") | ||
| .AddPropertyColumn("Revision") | ||
| .AddPropertyColumn("PSSemanticVersionPreLabel") |
There was a problem hiding this comment.
Would it make sense to change this property name to PSSemanticVersionPrereleaseLabel?
There was a problem hiding this comment.
Maybe PSSemVerPreReleaseLabel?
There was a problem hiding this comment.
That looks good to me, especially semver is the type accelerator for SemanticVersion.
| /// If <paramref name="preLabel"/> don't match 'LabelUnitRegEx'. | ||
| /// If <paramref name="buildLabel"/> don't match 'LabelUnitRegEx'. | ||
| /// </exception> | ||
| public SemanticVersion(int major, int minor, int patch, string preLabel, string buildLabel) |
There was a problem hiding this comment.
Shall we rename preLabel to prereleaseLabel too? It's the parameter of a public method.
| private const string VersionSansRegEx = @"^(?<major>\d+)(\.(?<minor>\d+))?(\.(?<patch>\d+))?$"; | ||
| private const string LabelRegEx = @"^((?<preLabel>[0-9A-Za-z][0-9A-Za-z\-\.]*))?(\+(?<buildLabel>[0-9A-Za-z][0-9A-Za-z\-\.]*))?$"; | ||
| private const string LabelUnitRegEx = @"^[0-9A-Za-z][0-9A-Za-z\-\.]*$"; | ||
| private const string PreLabelPropertyName = "PSSemanticVersionPreLabel"; |
There was a problem hiding this comment.
Same here. We probably should use PSSemanticVersionPrereleaseLabel, since it's for a public property.
| /// </summary> | ||
| public static int Compare(SemanticVersion versionA, SemanticVersion versionB) | ||
| { | ||
| if (versionA != null) { |
There was a problem hiding this comment.
Minor comment: it's better to follow the same open curly brace style in this file.
| if (versionB != null) | ||
| { | ||
| return versionA.CompareTo(versionB); | ||
| } |
There was a problem hiding this comment.
The instance method CompareTo handles null value in it, so this versionB != null check is not needed. It can just be:
if (versionA != null)
{
return versionA.CompareTo(versionB);
}
if (versionB != null)
{
return -1;
}
return 0;
|
I still have a concern about the |
|
@SteveL-MSFT This PR changes the public APIs, including:
Do you think it needs the committee review? |
| td252.Members.Add("ToString", | ||
| new ScriptMethodData(@"ToString", GetScriptBlock(@" | ||
| $suffix = """" | ||
| if (![String]::IsNullOrEmpty($this.PSSemanticVersionPreLabel)) |
There was a problem hiding this comment.
This needs to be changed if the property name is changed.
|
@daxian-dbw the general guidance is that for small api changes, the code review process is sufficient. However, any maintainer can request Committee review if needed or if the contributors for the code review can't come to an agreement. |
|
SemanticVersion API is new in PowerShell Core so until RTM we can change it free if we need. |
|
I'm fine with the API changes in this PR. |
1f45175 to
c1a9945
Compare
daxian-dbw
left a comment
There was a problem hiding this comment.
It looks to me you just simply replaced preLabel with PreReleaseLabel and didn't care about the local variables and parameter names. Local variable names and parameter names should start with a lower case letter. I will fix it for you.
.vscode/tasks.json
Outdated
There was a problem hiding this comment.
A local variable name should start with a lower-case letter.
In fact, I think you can continue to use preLabel for any non-public members.
There was a problem hiding this comment.
Same here, I think it's OK to use preLabel here.
There was a problem hiding this comment.
Same here. Local variable should start with lower case letter.
c1a9945 to
2836c8b
Compare
|
The test failure in AppVeyor is a known issue and will be fixed by #5379 |
|
😕 Sorry, I forgot to set VS Code case-sensitive flag to search and replace. |
|
The macOS CI was shown as passed yesterday after clicking the Travis CI "Details" link. I have no idea why it's shown as canceled today. Now we seem to have a problem with macOS CI -- it takes forever to start. Given that I know the Travis CI previously passed, I will merge this PR. |
Fix #5004
Fix description
Made compatible with SymVer 2.0 http://semver.org/ (p.10)
Fixed comparisons
Refactored tests
Added new tests
Additional information
Useful sample https://github.com/maxhauser/semver/blob/master/src/Semver/SemVersion.cs
Related #2983