Skip to content

Commit

Permalink
Enable lenient parsing of Git version tags
Browse files Browse the repository at this point in the history
- Git version tags will now be parsed leniently, allowing for tags like 2.0 to be treated equivelently to 2.0.0.
- Previous behavior was that a tag without a v-prefix would be preferred over one with a v-prefix. This behavior was maintained.
- A tag with more version components is preferred. 2.0.0 will be preferred over 2.0.
  • Loading branch information
colincornaby committed Aug 5, 2021
1 parent ddeb849 commit f194df2
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Sources/Basics/Version+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ extension Version {
/// - Parameter tag: A version string possibly prepended with "v".
public init?(tag: String) {
if tag.first == "v" {
self.init(string: String(tag.dropFirst()))
try? self.init(versionString: String(tag.dropFirst()), usesLenientParsing: true)
} else {
self.init(string: tag)
try? self.init(versionString: tag, usesLenientParsing: true)
}
}
}
18 changes: 16 additions & 2 deletions Sources/PackageGraph/RepositoryPackageContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,23 @@ public class RepositoryPackageContainer: PackageContainer, CustomStringConvertib
let knownVersionsWithDuplicates = Git.convertTagsToVersionMap(try repository.getTags())

return knownVersionsWithDuplicates.mapValues({ tags -> String in
if tags.count == 2 {
if tags.count > 1 {
// FIXME: Warn if the two tags point to different git references.
return tags.first(where: { !$0.hasPrefix("v") })!

// If multiple tags are present with the same semantic version (e.g. v1.0.0, 1.0.0, 1.0) reconcile which one we prefer.
// Prefer the most specific tag, e.g. 1.0.0 is preferred over 1.0.
// Sort the tags so the most specific tag is first, order is ascending so the most specific tag will be last
let tagsSortedBySpecificity = tags.sorted {
let componentCounts = ($0.components(separatedBy: ".").count, $1.components(separatedBy: ".").count)
if componentCounts.0 == componentCounts.1 {
//if they are both have the same number of components, favor the one without a v prefix.
//this matches previously defined behavior
//this assumes we can only enter this situation because one tag has a v prefix and the other does not.
return $0.hasPrefix("v")
}
return componentCounts.0 < componentCounts.1
}
return tagsSortedBySpecificity.last!
}
assert(tags.count == 1, "Unexpected number of tags")
return tags[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,12 @@ class RepositoryPackageContainerProviderTests: XCTestCase {
try repo.commit()
try repo.tag(name: "v1.0.0")
try repo.tag(name: "1.0.0")
try repo.tag(name: "v1.1.0")
try repo.tag(name: "1.1.0")
try repo.tag(name: "1.1")
try repo.tag(name: "1.2")
try repo.tag(name: "1.3")
try repo.tag(name: "1.3.0")
try repo.tag(name: "1.0.1")
try repo.tag(name: "v1.0.2")
try repo.tag(name: "1.0.4")
Expand All @@ -366,7 +372,7 @@ class RepositoryPackageContainerProviderTests: XCTestCase {
let ref = PackageReference.remote(identity: PackageIdentity(path: repoPath), location: repoPath.pathString)
let container = try provider.getContainer(for: ref, skipUpdate: false)
let v = try container.toolsVersionsAppropriateVersionsDescending().map { $0 }
XCTAssertEqual(v, ["2.0.1", "1.0.4", "1.0.2", "1.0.1", "1.0.0"])
XCTAssertEqual(v, ["2.0.1", "1.3.0", "1.2.0", "1.1.0", "1.0.4", "1.0.2", "1.0.1", "1.0.0"])
}

func testDependencyConstraints() throws {
Expand Down

0 comments on commit f194df2

Please sign in to comment.