Today, .exact("1.0.0+debug") does not guarantee selection of that exact identifier because SwiftPM ignores build metadata when matching exact version requirements
Firstly: I 100% agree with what your pitch is asking for. This is how it should work.
However after doing some research, I conclude this is actually just a longstanding bug with SPM. The SemVer 2.0.0. rules clearly state (italics mine):
- Build metadata MUST be ignored when determining version precedence.
- Precedence refers to how versions are compared to each other when ordered
However, the whole point of an "exact" version is specifically to avoid precedence and ordering of versions. We should ONLY be ordering versions when the user has used the from: Version API.
I believe this was simply an oversight/misunderstanding at the original creation of SPM. Because I checked SPM's actual code. Guess what? Nowhere does it actually test whether exact actually works as it should with build metadata specifically. So I added some new cases in VersionSetSpecifierTests, and they all failed:
// Fails ❌
func testThatExactRespectsBuildMetadataVsNone() {
XCTAssertNotEqual(VersionSetSpecifier.exact("1.0.0+debug").difference(.exact("1.0.0")), .empty)
}
// Fails ❌
func testThatExactRespectsBuildMetadataReleaseVsDebug() {
XCTAssertNotEqual(VersionSetSpecifier.exact("1.0.0+release").difference(.exact("1.0.0+debug")), .empty)
}
// Fails ❌
func testThatExactRespectsBuildMetadataDebugVsRelease() {
XCTAssertNotEqual(VersionSetSpecifier.exact("1.0.0+debug").difference(.exact("1.0.0+release")), .empty)
}
// Fails ❌
func testThatExactRespectsBuildMetadataVsDifferentNumbering() {
XCTAssertNotEqual(VersionSetSpecifier.exact("1.0.0+debug.1").difference(.exact("1.0.0+debug.2")), .empty)
}
This would have been caught a long time ago if the tests properly covered these cases.
Also, there is no need to add new syntax. Existing SPM syntax already allows for:
dependencies: [
.package(
url: "https://github.com/gistya/spm-test",
exact: Version(0, 5, 2, prereleaseIdentifiers: ["alpha", "4"], buildMetadataIdentifiers: ["debug"])
)
],
... which it treats identically to simply writing exact: "0.5.2-alpha.4+debug", due to the fact SPM has a string-parsing algorithm that looks for the -, +, and . separators allowed by the Backus Naur Form Grammar.
This parser is well-covered in the SPM tests, e.g.:
XCTAssertEqual(Version(1, 2, 3, prereleaseIdentifiers: ["beta1"], buildMetadataIdentifiers: ["alpha1"]).description, "1.2.3-beta1+alpha1" as String)
Note: I don't know how likely it is that anyone in the SPM community has packages that depend on the existing, buggy behavior, but it might be good to bump the SPM version to 7.0 to communicate it has potentially breaking changes. That way anyone whose package depends on the bug can simply update their use of exact to instead use from.
TLDR:
We just need to fix the bug in SPM where it does not respect build metadata specifiers when evaluating if a given version exactly matches the exact version you specified. I recommend that you update your pitch to fix the existing behavior, instead of leaving it broken while adding a redundant new API.