Skip to content

Commit 841d40a

Browse files
committed
Enable lenient parsing of Git version tags
- 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. Enable lenient parsing of Git version tags - 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.
1 parent ddeb849 commit 841d40a

File tree

4 files changed

+27
-5
lines changed

4 files changed

+27
-5
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ Note: This is in reverse chronological order, so newer entries are added to the
22

33
Swift v.Next
44
-----------
5+
* [#3649]
6+
Semantic version dependencies can now be resolved against Git tag names that contain only a major and minor component. A tag with the form `X.X` will be treated as `X.X.0`. This improves compatibility with existing repositories.
57

68

79

Sources/Basics/Version+Extensions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ extension Version {
1616
/// - Parameter tag: A version string possibly prepended with "v".
1717
public init?(tag: String) {
1818
if tag.first == "v" {
19-
self.init(string: String(tag.dropFirst()))
19+
try? self.init(versionString: String(tag.dropFirst()), usesLenientParsing: true)
2020
} else {
21-
self.init(string: tag)
21+
try? self.init(versionString: tag, usesLenientParsing: true)
2222
}
2323
}
2424
}

Sources/PackageGraph/RepositoryPackageContainer.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,23 @@ public class RepositoryPackageContainer: PackageContainer, CustomStringConvertib
9696
let knownVersionsWithDuplicates = Git.convertTagsToVersionMap(try repository.getTags())
9797

9898
return knownVersionsWithDuplicates.mapValues({ tags -> String in
99-
if tags.count == 2 {
99+
if tags.count > 1 {
100100
// FIXME: Warn if the two tags point to different git references.
101-
return tags.first(where: { !$0.hasPrefix("v") })!
101+
102+
// 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.
103+
// Prefer the most specific tag, e.g. 1.0.0 is preferred over 1.0.
104+
// Sort the tags so the most specific tag is first, order is ascending so the most specific tag will be last
105+
let tagsSortedBySpecificity = tags.sorted {
106+
let componentCounts = ($0.components(separatedBy: ".").count, $1.components(separatedBy: ".").count)
107+
if componentCounts.0 == componentCounts.1 {
108+
//if they are both have the same number of components, favor the one without a v prefix.
109+
//this matches previously defined behavior
110+
//this assumes we can only enter this situation because one tag has a v prefix and the other does not.
111+
return $0.hasPrefix("v")
112+
}
113+
return componentCounts.0 < componentCounts.1
114+
}
115+
return tagsSortedBySpecificity.last!
102116
}
103117
assert(tags.count == 1, "Unexpected number of tags")
104118
return tags[0]

Tests/PackageGraphTests/RepositoryPackageContainerProviderTests.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,12 @@ class RepositoryPackageContainerProviderTests: XCTestCase {
341341
try repo.commit()
342342
try repo.tag(name: "v1.0.0")
343343
try repo.tag(name: "1.0.0")
344+
try repo.tag(name: "v1.1.0")
345+
try repo.tag(name: "1.1.0")
346+
try repo.tag(name: "1.1")
347+
try repo.tag(name: "1.2")
348+
try repo.tag(name: "1.3")
349+
try repo.tag(name: "1.3.0")
344350
try repo.tag(name: "1.0.1")
345351
try repo.tag(name: "v1.0.2")
346352
try repo.tag(name: "1.0.4")
@@ -366,7 +372,7 @@ class RepositoryPackageContainerProviderTests: XCTestCase {
366372
let ref = PackageReference.remote(identity: PackageIdentity(path: repoPath), location: repoPath.pathString)
367373
let container = try provider.getContainer(for: ref, skipUpdate: false)
368374
let v = try container.toolsVersionsAppropriateVersionsDescending().map { $0 }
369-
XCTAssertEqual(v, ["2.0.1", "1.0.4", "1.0.2", "1.0.1", "1.0.0"])
375+
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"])
370376
}
371377

372378
func testDependencyConstraints() throws {

0 commit comments

Comments
 (0)