Skip to content
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

Clarifying Pre-release Version Handling and Dependency Overrides in Swift Package Manager. #7880

Open
bc-lee opened this issue Aug 14, 2024 · 0 comments

Comments

@bc-lee
Copy link
Contributor

bc-lee commented Aug 14, 2024

From what I understand, pre-release versions (e.g., 1.1.0-beta.1) can be used in Swift Package Manager. However, when range-based versioning is applied, the pre-release versions are not considered. I believe this behavior violates Semantic Versioning 2.0.0 (https://semver.org/). This issue has been long-standing in Swift Package Manager, and it seems to be intentional. [1]

Examples of related issues can be found here:

I discovered this issue only when I tried to use a pre-release version in Swift Package Manager. I believe it would be beneficial to clarify this behavior in the documentation.

Additionally, I initially believed there was no way to override the version of a dependency in Swift Package Manager. However, I discovered that it is possible to override a dependency's version by specifying the revision of the dependency in the Package.swift file. I believe this, too, should be documented.

I created some test code to demonstrate these behaviors. I used commit 708f50b31f569096d2a164f753a14c7af98757b8 for testing. The code snippets is for the Tests/PackageGraphTests/PubgrubTests.swift file.

func testResolutionOverridingWithRevision() throws {
    // Given: foo 1.0.0, abcdef0123456789 (unversioned)
    // Given: bar 1.0.0, which requires foo 1.0.0..<9999.0.0
    // The package requests foo abcdef0123456789 and bar 1.0.0 (exact)

    let fooRevision = "abcdef0123456789"

    try builder.serve("foo", at: v1)
    try builder.serve("foo", at: .revision(fooRevision))

    try builder.serve("bar", at: v1, with: [
        "bar": ["foo": (.versionSet(.range("1.0.0"..<"9999.0.0")), .specific(["foo"]))]
    ])

    let resolver = builder.create()
    let dependencies = try builder.create(dependencies: [
        "foo": (.revision(fooRevision), .specific(["foo"])),
        "bar": (.versionSet(.exact(v1)), .specific(["bar"])),
    ])

    let result = resolver.solve(constraints: dependencies)

    AssertResult(result, [
        ("foo", .revision(fooRevision)),
        ("bar", .version(v1)),
    ])
}

func testResolutionOverridingWithPreVersion() throws {
    // Given: foo 1.0.0, 1.1.0-beta.1
    // Given: bar 1.0.0, which requires foo 1.0.0..<9999.0.0
    // The package requests foo 1.1.0-beta.1 (exact) and bar 1.0.0 (exact)

    try builder.serve("foo", at: v1)
    try builder.serve("foo", at: "1.1.0-beta.1")

    try builder.serve("bar", at: v1, with: [
        "bar": ["foo": (.versionSet(.range("1.0.0"..<"9999.0.0")), .specific(["foo"]))]
    ])

    let resolver = builder.create()
    let dependencies = try builder.create(dependencies: [
        "foo": (.versionSet(.exact("1.1.0-beta.1")), .specific(["foo"])),
        "bar": (.versionSet(.exact(v1)), .specific(["bar"])),
    ])

    let result = resolver.solve(constraints: dependencies)

    // This will fail because prerelease versions are completely ignored
    // during resolution
    // AssertResult(result, [
    //     ("foo", .version("1.1.0-beta.1")),
    //     ("bar", .version(v1)),
    // ])

    XCTAssertEqual(result.errorMsg, """
        Dependencies could not be resolved because root depends on 'bar' 1.0.0.
        'bar' 1.0.0 cannot be used because 'bar' 1.0.0 depends on 'foo' 1.0.0..<9999.0.0 and root depends on 'foo' 1.1.0-beta.1.
        """)
}

Ideally, these behaviors should be documented at https://github.com/swiftlang/swift-package-manager/tree/main/Documentation, but I am unsure where exactly they should be placed. I would appreciate any opinions on this matter.

[1] If the range does not contain prerelease identifiers, return false. https://github.com/swiftlang/swift-tools-support-core/blob/a76104dbd3c3fff41adb70bc7e917a4b2d076cef/Sources/TSCUtility/Version.swift#L350

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant