Skip to content

Dependabot version ordering does not match Gradle #13791

@sultan

Description

@sultan

Dependabot currently relies on Maven-style version ordering, but Gradle uses a different comparator
(StaticVersionComparator). This leads to anomalies when handling qualifiers:

  • Gradle special meanings: dev < ... < rc < snapshot < final < ga < release < sp
  • Qualifiers not in the special list (e.g. alpha, beta, milestone, preview) are treated
    lexicographically at level 0, between dev (-1) and rc (1).
  • Maven, by contrast, treats unknown qualifiers as post-release, so 1.0-preview > 1.0.
  • In Gradle, 1.0-preview < 1.0.

Impact:
Dependabot suggests incorrect updates for Gradle projects because it assumes Maven’s ordering rules.
This causes confusion and wrong upgrade paths when qualifiers like preview, alpha, or dev are used.

Expected behavior:
Dependabot should align with Gradle’s StaticVersionComparator when analyzing Gradle builds, or
provide a configurable version scheme to match Gradle’s semantics.

References:

Here is the current implementation of the version ordering logic in Ruby, showing how prefixed tokens and named qualifiers are handled:

      PREFIXED_TOKEN_HIERARCHY = T.let(
        {
          "." => { qualifier: 1, number: 4 },
          "-" => { qualifier: 2, number: 3 },
          "_" => { qualifier: 2, number: 3 }
        }.freeze,
        T::Hash[String, T::Hash[Symbol, Integer]]
      )
      NAMED_QUALIFIERS_HIERARCHY = T.let(
        {
          "a" => 1, "alpha"     => 1,
          "b" => 2, "beta"      => 2,
          "m" => 3, "milestone" => 3,
          "pr" => 4, "pre" => 4, "preview" => 4,
          "rc" => 5, "cr" => 5,
          "dev" => 6,
          "snapshot" => 7,
          "" => 8, "final" => 8, "ga" => 8, "release" => 8,
          "sp" => 9
        }.freeze,
        T::Hash[String, Integer]

Here is a hypothetical adjustment of the same logic, implicitly having common qualifiers (alpha, beta, milestone, preview) at level 0 to align with Gradle’s StaticVersionComparator behavior:

      PREFIXED_TOKEN_HIERARCHY = T.let(
        {
          "." => { qualifier: 1, number: 4 },
          "-" => { qualifier: 2, number: 3 },
          "_" => { qualifier: 2, number: 3 },
          "+" => { qualifier: 2, number: 2 }
        }.freeze,
        T::Hash[String, T::Hash[Symbol, Integer]]
      )
      NAMED_QUALIFIERS_HIERARCHY = T.let(
        {
          "" => -2,
          "dev" => -1,
          "rc" => 1,
          "snapshot" => 2,
          "final" => 3,
          "ga" => 4,
          "release" => 5,
          "sp" => 6
        }.freeze,
        T::Hash[String, Integer]

Metadata

Metadata

Labels

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions