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

[bug] version range selection from pre-release order #17631

Open
mrjoel opened this issue Jan 25, 2025 · 1 comment
Open

[bug] version range selection from pre-release order #17631

mrjoel opened this issue Jan 25, 2025 · 1 comment
Assignees

Comments

@mrjoel
Copy link
Contributor

mrjoel commented Jan 25, 2025

Describe the bug

In Conan 2 the version range selection criteria with pre-release versions differs from Conan 1. That's not itself problematic, however it appears that the Conan 2 behavior is incorrect with regards to SemVer semantics. Based on my investigation I'm suggesting that the bug is both in code and the docs.

Specifically, SemVer 2.0 11.3 stipulates that

When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version

Example: 1.0.0-alpha < 1.0.0.

We use a package with automatic version assignment based on git for development snapshots of dependencies. We add pre-release tags to indicate development towards the next anticipated release, but since it's developmental we don't want to have the final tag be a suitable version. (We may also add reved pre-release tags several times as an indicator for when compatibility boundaries occur within the development cycle).

As noted on the version ranges page, pre-release versions can be nuanced. I'm also checking my expectations, but there does seem to be an issue here. I don't make the suggestion lightly; notably, I'll acknowledge that I'm also suggesting that semver-checker is also wrong when comparing pre-release versions by strict less-than operator (including for the specific example in SemVer 11.3).

The following two example files illustrate my expectation. The dependency works in Conan 1, but Conan 2 doesn't match on the strictly less than operator.

from conan import ConanFile

class PackageA(ConanFile):
    name = "packagea"
    version = "2.1.0-0.dev+123.g0abcdef"
from conan import ConanFile, conan_version

class PackageB(ConanFile):
    name = "packageb"
    version = "1.0.0"

    def requirements(self):
        prerelease = "include_prereleases" if conan_version.major==2 else "include_prerelease=True"
        self.requires(
            # The full expression I actually want, but doesn't work.
            #f"packagea/[>=2.1.0-0.dev <2.1.0 || 2.0.0, {prerelease}]"

            # The OR expression part doesn't seem to be relevant.
            f"packagea/[>=2.1.0-0.dev <2.1.0, {prerelease}]"

            # Using <= instead of < does strangely allow selection of the pre-release package.
            #f"packagea/[>=2.1.0-0.dev <=2.1.0, {prerelease}]"
        )

As for documentation, the following pages appear to have inconsistencies/inaccuracies.

  • version ranges page

    The green important admonition early in the page is correct when it states

    "So 1.1-alpha.1 is older than 1.1, not newer."

    However, when discussing the include_prerelease option later in the page, it seems incorrect to state that for the example expression requires = "pkg/[>1 <2, include_prerelease]" that 1.0-pre.1 should be included, or that 2.0-pre1 should be excluded. Strictly speaking, 1.0-pre.1 is earlier than >1 should allow, and 2.0-pre1 is definitely earlier (less) than the full 2.0.0 release implied by <2.

  • requires attribute

    Similarly, the pre-releases table of examples is not as I'd expect either.

    • For [>=1.0 <2], the value 1.0.0-pre.1 should not be included, while 2.0-pre.1 should be
    • For [<3.2.1], the value 3.2.1-pre.1 should be included

How to reproduce it

No response

@memsharded memsharded self-assigned this Jan 26, 2025
@memsharded
Copy link
Member

Hi @mrjoel

This is something that we thoroughly discussed and iterated, based on user feedback and expectations.
At the moment it doesn't seem a bug, but expected design:

For [>=1.0 <2], the value 1.0.0-pre.1 should not be included, while 2.0-pre.1 should be

The logic is that 1.0.0-pre.1 is a 1.0 release. It is not a 0.9 one, but a 1.0 one

For [<3.2.1], the value 3.2.1-pre.1 should be included

Likewise, the 3.2.1-pre.1 is also a 3.2.1 release.

So the logic to include and exclude them is correct.

I'll also like to clarify that in Conan 2, hardcoding the resolution to prereleases in requires is not the most recommended approach, and an new conf core.version_ranges:resolve_prereleases (see https://docs.conan.io/2/devops/versioning/resolve_prereleases.html#handling-version-ranges-and-pre-releases)

I'll give an example that makes this more evident:

  • A team has a project with some dependency to one of their packages mypkg/[>=1.0 <2.0]
  • They happily release patches and minors, that are API compatible and move forward to the mypkg/1.3.8 for example
  • When they are not sure about some API compatible but possibly behavior breaking releases like mypkg/1.4, they create prereleases like mypkg/1.4-pre.1
  • The conf core.version_ranges:resolve_prereleases is activated whenever the CI or developers want to test these prereleases
  • Now the team starts to work in an API breaking major release, because they need to move forward a big change in mypkg
  • They start to work in that version, it will take time, so they start to create alpha prereleases like mypkg/2.0-alpha.1
  • If these pre-releases are automatically accepted by the mypkg/[>=1.0 <2.0] range, that will break all the consumers that were depending on mypkg
  • Even if they explicitly said "we don't want to depend on the next API breaking major releases 2.0 (<2.0, strictly lower than 2.0)

Then, it was concluded that even if 2.0-alpha < 2.0 in strict version ordering, the version ranges like mypkg/[>=1.0 <2.0] are semantically equivalent to mypkg/[>=1.0- <2.0-], that is, including prereleases in the lower bound for >=, and excluding prereleases in the upper bound for strictly lower than < bounds.

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

No branches or pull requests

2 participants