VersionConflictResolutionIntegrationTest.groovy

Clone Tools
  • last updated a few seconds ago
Constraints
Constraints: committers
 
Constraints: files
Constraints: dates
Consistently report conflict resolution

This commit refactors how conflict resolution selection reasons are handled, in order to:

- collect the list of versions which participated in conflict resolution

- report a single conflict resolution cause when conflicts are resolved several times for the same module

- consistently report module replacement rules as rules, not conflict resolution. Before this change,

a module replacement was reported as both a conflict and a rule

    • -6
    • +6
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 29 more files in changeset.
Add test showing dependency ordering issue

    • -0
    • +49
    ./VersionConflictResolutionIntegrationTest.groovy
Fix incorrect conflict resolution when a cycle exists with root component

Whenever the root component was added back through a dependency cycle, we

introduced a conflict, which was solved by the latest module conflict

resolver _unless_ `failOnVersionConflict()` was used. Instead, we shouldn't

even try to resolve a conflict because there's none. This commit fixes the

problem by checking if the root component is already added.

Fixes gradle/gradle-private#1268

    • -0
    • +34
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 1 more file in changeset.
Add coverage for resolution result where some selectors fail

    • -5
    • +41
    ./VersionConflictResolutionIntegrationTest.groovy
Support version range merging for '.+' selectors

Fixes #4180

    • -2
    • +2
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 2 more files in changeset.
Fix test so that it verifies behaviour we want

    • -1
    • +1
    ./VersionConflictResolutionIntegrationTest.groovy
Test resolving version conflicts in transitive dependencies

    • -2
    • +51
    ./VersionConflictResolutionIntegrationTest.groovy
Add test case showing a selection problem

This test case highlights a problem in dependency resolution, when a node was evicted in favor of another node,

but that this other node constraint should go away because it came in through transitivity of a node which itself

has been evicted: since the node is no longer reachable, there's no reason why it should force the selection of

a branch that knows nothing about it.

    • -0
    • +34
    ./VersionConflictResolutionIntegrationTest.groovy
Remove concept of orphan node as it can put the graph into corrupt state

This commit removes the detection of orphan nodes, which triggered the removal of unused selectors. The problem

is that the selector could be used somewhere else in the graph, even if this node doesn't have any incoming edge.

Basically it means that the strategy for "eliminating previous constraints" when a subgraph is elimintated doesn't

work. As a consequence some tests are now marked as `@NotYetImplemented`.

    • -0
    • +2
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 1 more file in changeset.
Add another `@NotYetImplemented` test case

    • -0
    • +34
    ./VersionConflictResolutionIntegrationTest.groovy
Fix assertion error, when restarting happens during conflict resolution...

but component was already selected. This can happen if a node is re-selected between the conflict resolution

has been registered and the moment conflict resolution occurs.

    • -0
    • +70
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 1 more file in changeset.
Make sure we don't create conflicts when the candidate list is empty

It is possible that we're out of candidates now that we filter out versions which are not

selectable from candidates. This happens when we have an orphan node, then a selector chooses

the same version, but cannot be used for short-circuiting (typically, `latest` selector).

    • -0
    • +37
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 3 more files in changeset.
Introduce check on replaced modules before short-circuit selection

When we perform short-circuit selection for a module (where its selected version is `null`), we need to check that

this module actually doesn't participate in module replacements. If it does, we need to fall back on classic conflict

resolution. Otherwise, the following situation might occur:

- `a` is replaced by `b`

- we add `a:1` to the graph. No version is selected for `a`, so we select `a:1`

- we add `b:1` to the graph. No version is selected for `b`, so we select `b:1`

- we end up with both `a` and `b` in the result

Instead, we now follow this process:

- `a` is replaced by `b`

- we add `a:1` to the graph. No version is selected for `a`, but `a` participates in replacements. We don't short-circuit,

but in the end we select `a:1`

- we add `b:1` to the graph. No version is selected for `b`, but `b` participates in replacements. We fall back to conflict

resolution, which sees that `a` needs to be replaced by `b`.

- only `b:1` ends up in the result

    • -2
    • +0
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 5 more files in changeset.
Improve version range selection

This commit fixes a couple of bugs in range selection. It refactors the code, making it clearer what the different states

of a module can be. In particular, the previous version included both `Conflict` and `Evicted`, but in practice there was

no difference in using one or the other!

Now the selection uses four different states (`Selected`, `Selectable`, `Evicted` and `Orphan`) which allows us to

discriminate between cases a node was evicted in conflict resolution, or when it was simplify preferred over another

possible choice.

    • -0
    • +76
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 2 more files in changeset.
Fixup tests

    • -5
    • +2
    ./VersionConflictResolutionIntegrationTest.groovy
Rework range selection algorithm

This commit changes the handling of range intersection: instead of relying on restarting selection of nodes,

we now perform additional checks, when a version is encountered, to see if it is _compatible_ with an already

selected version.

Conflict resolution will kick in as last resort.

    • -3
    • +3
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 26 more files in changeset.
Add test case showing that conflicts on different modules are handled separately

    • -0
    • +41
    ./VersionConflictResolutionIntegrationTest.groovy
Fix case where an upper bound of a range could take precedence over a fixed dependency number

This commit fixes an edge case where the graph contains multiple ranges, a fixed version, and that the upper

bound of the intersection of the range equals the fixed version. In that case, no element would be selected.

    • -0
    • +47
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 2 more files in changeset.
Rework intersecting ranges handling

This commit reworks the intersection range discovery handling using the

infrastructure put in place in the previous commit: instead of having

special metadata which has to be wrapped/unwrapped using a special case,

there is now a conflict resolution rule aimed at restarting selection for

a node when we see that 2 conflicting ranges are intersecting. This can

happen when a new node is added in the graph with a different range.

    • -12
    • +0
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 28 more files in changeset.
Introduce a way to restart selection of a module

This commit allows restarting selection of a module from a conflict resolution rule. The idea is to be able to restart

selection when "new information" is available. One use case is the range selection of a module. If, during graph

visit, a different range is seen, then we know we can potentially have disjoint ranges, in which case classic

resolution occurs, or intersecting ranges, in which case we need to select the highest version in range. This commit

prepares a different solution to the problem by allowing us to restart selection once we determine we have two

intersecting ranges.

It's worth noting that this commit requires temporary disabling of the tests, because the rule doesn't enforce this

behavior: it will now create an infinite loop, without ever selecting a version. The reason is precisely that we

don't make this "new information" available to selection. This will be implemented in a subsequent commit.

    • -0
    • +12
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 5 more files in changeset.
Add more integration tests to highlight the behavior with `failOnVersionConflict`

    • -0
    • +108
    ./VersionConflictResolutionIntegrationTest.groovy
Add test coverage for version range conflict resolution

    • -0
    • +245
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 1 more file in changeset.
Implement range intersection conflict resolution

This commit introduces a range intersection conflict resolution strategy. To deal with this, an additional flag has been added to

selectors. The flag will tell if a selector is allowed to return multiple candidates. In this case, it is expected to be called

multiple times for different matching versions. The first version checked will always be the latest.

Before this change, if 2 dependencies disagree on a range, there could be a chance that a version was selected out of the intersection.

For example, if one depends on range `[3,6]` and another depends on range `[4,8]`, then the first range selects the latest revision in

range, which is `6`, and the second version selects `8`, which is the highest version within its range. Then conflict resolution kicks

in and sees `6` and `8`. It decides to upgrade to version `8`.

This commit, on the other hand, makes sure that if a selector can have multiple valid candidates, then we remember the other candidates

as well. When we see that `6` and `8` are in conflict, we then check if those selected versions come from a selector which had multiple

possible answers. If yes, then we compute the intersection of the ranges. In our example, the intersection of `[3,6]` and `[4,8]` is

`[4,6]`. The intersection is not empty, so it means that there's actually no conflict between the two ranges, because both ranges

agree that there are possible answers.

We then select the highest version within range, which is `6`, and choose the candidate which has this as its selected component version.

This is range `[3,6]`.

    • -4
    • +1
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 13 more files in changeset.
Simplify `DynamicVersionResolver`

This commit merges `RepositoryResolveState` with `ComponentSelectionContext`. This makes the code easier to read, by avoiding

incomprehensible back references. Unit tests are also clearer since they now clearly show which versions were tested, rejected

and not found.

    • -0
    • +36
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 9 more files in changeset.
Changed the way that the target configuration for a project dependency is calculated, to always select only from the configurations of the target project that have attributes attached, regardless of whether the consumer has defined any attributes or not. Fall back to `default` only when the target project has no configurations with attributes defined.

This introduces a breaking change when consuming the output of a project with the Java plugin applied from a project that does not have the Java plugin applied. Previously, the `default` configuration would be selected, now the `runtimeElements` configuration is selected. However, this is consistent with the case where the consuming project is also using the Java plugin or is using the Android plugin. It also means that custom configurations in these projects will select the same thing as the runtime classpath configuration.

    • -0
    • +2
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 13 more files in changeset.
Changed traversal of dependency graph results so that the `ArtifactSet` instances included in the result are visited in consumer first order, rather than the nodes, so that the artifact sets can be collected directly into a list in the correct order rather than collecting and retaining an additional map from node -> artifact set to apply the ordering.

    • -1
    • +1
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 16 more files in changeset.
Reworked dependency result artifact/file ordering to address some issues and to make 'consumer first' the default ordering.

Specifically, nodes in the graph are now sorted by component, rather than sorting by node. When sorting by node for a component with multiple nodes in the graph (eg a direct dependency on a maven module from a Gradle project plus a transitive dependency via another maven module, but also possible in other ways) it was possible for a particular component to appear _before_ all of its consumers.

This change affects the arbitrary order for files/artifacts that form a cycle.

    • -3
    • +3
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 13 more files in changeset.
Enable parallel resolution of the dependency graph

This commit introduces parallel resolution of a dependency graph. When the graph is resolved:

- pick a node from the queue (starting from the root node)

- for its outgoing edges, resolve them serially, or concurrently if:

- all of the edges reference nodes which metadata hasn't been resolved yet

- or there are more than 8 edges

- then add discovered edges _in order_ add the end of the queue

This means that not _all_ graph resolution is done concurrently: there's a heuristic to tell if it's worth doing it,

and similarly, there are operations which still need to be done serially in order to have guarantees on the shape

of the graph (typically, to make sure that files are visible in a certain order).

    • -1
    • +1
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 12 more files in changeset.
Use doLast instead of left shift operator

Made this change in preparation for deprecating the left shift operator.

+review REVIEW-6236

    • -42
    • +62
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 163 more files in changeset.
Use component id rather than module version id in the 'required by' paths in resolve exceptions. This provides a better description for local components, and also allows for components that don't have a module version id.

    • -1
    • +1
    ./VersionConflictResolutionIntegrationTest.groovy
  1. … 13 more files in changeset.