-
Notifications
You must be signed in to change notification settings - Fork 130
Add lenient mode to Version string parsing that doesn't require patch version #212
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
Add lenient mode to Version string parsing that doesn't require patch version #212
Conversation
Sources/TSCUtility/Version.swift
Outdated
@@ -119,11 +120,15 @@ public extension Version { | |||
.split(separator: ".", maxSplits: 2, omittingEmptySubsequences: false) | |||
.map(String.init).compactMap({ Int($0) }).filter({ $0 >= 0 }) | |||
|
|||
guard requiredComponents.count == 3 else { return nil } | |||
guard requiredComponents.count == 3 || (requiredComponents.count == 2 && lenient) else { return nil } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're doing this, would it be better (or make sense) if the rules are made even more lenient to allow for just a single major version number?
i.e.
guard requiredComponents.count == 3 || lenient else ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My original intention was to make repositories that mix two and three component version styles more compatible. Supporting a single version component would make SPM support repositories that don't technically version semantically, which is a larger change. But that behavior can still map to semantic versions, and it would maximize compatibility with existing repos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to agree that from a conversion point of, tags are either 3 x.0.0
or 2 x.0
segment long. iow a single digit version tag would be pretty exceptional.
@colincornaby thanks for this proposal. do you think package manifest should also allow |
@tomerd - I had noticed that there is a package manifest facing aspect to this. I'll be honest, this is my first pull request to Swift, so I was unsure how large of changes the project is interested in through pull request. I also didn't know what existing opinions project opinions were on this. Short answer is: No, but I'd be willing to make those changes if that's desired by others. My motivation was that we had started to implement SPM manifests in some of our C++ projects. But those teams hadn't always been adding the patch version where it was 0 to their tags (e.g. they used 3.4, 3.4.1, 3.4.2, 3.5). I wanted to be able to introduce SPM manifests into repos without retraining teams. A quick survey found a lot of Git repos also dropping the bug fix version when it was 0. I do also have changes to the SPM repo that would integrate these changes into Git tagging, but they're waiting on these changes. If it's desired for the manifest to also support two digits I can propose those changes in a pull request as well. |
thanks @colincornaby makes sense. I think the proposed change is valuable at the git tag parsing level. @neonichu wdyt? |
@swift-ci please test |
@colincornaby CI is failing on something that looks like an issue with the tests?
|
Sources/TSCUtility/Version.swift
Outdated
@@ -109,7 +109,8 @@ public extension Version { | |||
/// | |||
/// - Parameters: | |||
/// - string: The string to parse. | |||
init?(string: String) { | |||
/// - lenient: Boolean indicating if partial strings should be parsed. Infers that strings without an explicit patch version have a patch version of zero. Defaults to false. | |||
init?(string: String, lenient: Bool = false) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since there are some dependencies in SwiftPM on the concrete ctor signature, lets structure this as:
init?(string: String) {
self.init(string: string, lenient: false)
}
init?(string: String, lenient: Bool) {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need the the lenient
parameter? If the goal is to treat all x.y as x.y.0, then I don't think we can use strict parsing anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to remove the lenient option if no one needs it as a solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo its good to have this option for now so we can enable/disable it from SwiftPM side based on which tools version we are targeting - as this change could break existing packages. @neonichu wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that the flag is useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo its good to have this option for now so we can enable/disable it from SwiftPM side based on which tools version we are targeting - as this change could break existing packages.
This makes sense. I keep forgetting that SwiftPM needs to support previous versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback and pointing me to exactly what the test failure was. I've made the changes and run the in-module tests locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I keep forgetting that SwiftPM needs to support previous versions.
that's the hard part :D
@swift-ci please test |
Looks like the Linux build failed, but it's a module cache issue.
|
@swift-ci please test |
Sorry for asking this, but I wonder if it's OK to merge #214 first (after it's ready) and then rebase this PR on it? These 2 PRs conflict with each other, so one of these has to be rebased after the other is merged. It seems that it's much easier to rebase this PR on #214 than the vice versa, because #214 changes a lot more lines and the logic. And since most of the parsing logic is changed in #214, if this PR is merged first, everything here would have to be reimplemented again in #214. If we end up deciding to merge #214 first, I can help with rebasing this PR. |
sgtm, assuming we can get #214 over the finish line soon |
I think #214 looks good to me at this point, so that one can be merged if @neonichu agrees. |
Following along - I'm fine also doing any cleanup work necessary after #214 gets merged in, or assisting others in that. I have changes in SPM waiting on this pull request to be merged, but no huge rush there. |
@colincornaby #214 is now merged, please rebase. thanks for your patience on this |
@colincornaby Can I have access to this branch, to help with the rebase? |
@WowbaggersLiquidLunch - I sent a collaboration invite over for my fork. I had started on the rebase, but in since you know the changes better I'll let you make the changes! |
Added the `usesLenientParsing` parameter to `Version.init(versionString:) throws` and logic changes to enable parsing version strings without patch versions. Added the `usesLenientParsing: Bool` associated type to `VersionError.invalidVersionCoreIdentifiersCount`, so the error message can be specialised for both strict and lenient parsing.
28c2995
to
19d1c37
Compare
Just force-pushed 19d1c37. I took the liberty of squashing the 3 previous commits on this branch, so that it was easier to rebase. Hopefully this is ok. I also saved a copy of the pre-rebase branch here, just in case. Changes as part of the rebase: Instead of a new
Most of the additional lines of code are test cases. |
/// - Throws: A `VersionError` instance if the `versionString` doesn't follow [SemVer 2.0.0](https://semver.org). | ||
public init(versionString: String) throws { | ||
public init(versionString: String, usesLenientParsing: Bool = false) throws { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iirc we needed two constructors instead of one with default value because of downstream dependencies on the exact signatures (passed into map{})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the one that downstream dependencies use is init?(string: String)
. This initializer still exists (although marked as deprecated) and calls init?(_ versionString: String)
, which then calls init(versionString: versionString, usesLenientParsing: false) throws
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the change ready to commit, but also had the thought the downstream dependencies probably use the deprecated function. I could see the use in having a new version ready to cut over to, but that might get into project planning that I don't know the scope of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @colincornaby and @WowbaggersLiquidLunch - lets get this merged first, then @colincornaby you can submit a PR to SwiftPM to use the new methods where appropriate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good! Thanks!
@swift-ci please test |
thanks again thanks @colincornaby and @WowbaggersLiquidLunch |
Git repos are commonly leaving off the patch segments of version strings in tags. This practice is also commonly repeated in guides on Git tagging. This commit makes the patch version optional to improve compatibility with these Git repositories in SPM.
Because of the possible downstream effects, I've made the lenient version parsing optional, and it defaults to off. Right now it only allows the patch version to be left off.
I considered trying to keep changes entirely in SPM without touching the Version type. This seemed like the most maintainable and performant option.