fix: honour pinned versions in layered coursier installs (#1631)
diff --git a/MODULE.bazel b/MODULE.bazel
index 22e50a9..0c9502e 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -1076,6 +1076,18 @@
resolver = "coursier",
)
+dev_maven.install(
+ name = "coursier_pinned_layering",
+ artifacts = [
+ "com.google.code.findbugs:jsr305:3.0.1",
+ ],
+ known_contributing_modules = [
+ "coursier_higher_layer",
+ ],
+ resolver = "coursier",
+ version_conflict_policy = "pinned",
+)
+
bazel_dep(name = "coursier_higher_layer", version = "0.0.0", dev_dependency = True)
local_path_override(
module_name = "coursier_higher_layer",
@@ -1117,6 +1129,7 @@
"amend_artifacts",
"bom_only_pinning",
"coursier_layering",
+ "coursier_pinned_layering",
"duplicate_version_error",
"duplicate_version_warning",
"duplicate_version_warning_same_version",
diff --git a/docs/bzlmod-api.md b/docs/bzlmod-api.md
index 38e7474..0a29f54 100644
--- a/docs/bzlmod-api.md
+++ b/docs/bzlmod-api.md
@@ -114,7 +114,7 @@
| <a id="maven.install-strict_visibility_value"></a>strict_visibility_value | - | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `["@rules_jvm_external//visibility:private"]` |
| <a id="maven.install-use_credentials_from_home_netrc_file"></a>use_credentials_from_home_netrc_file | Whether to pass machine login credentials from the ~/.netrc file to coursier. | Boolean | optional | `False` |
| <a id="maven.install-use_starlark_android_rules"></a>use_starlark_android_rules | Whether to use the native or Starlark version of the Android rules. | Boolean | optional | `False` |
-| <a id="maven.install-version_conflict_policy"></a>version_conflict_policy | Policy for user-defined vs. transitive dependency version conflicts<br><br>If "pinned", choose the user-specified version in maven_install unconditionally. With the Gradle and Maven resolvers, this only applies to artifacts contributed by the root module. If "default", follow the selected resolver's default policy. | String | optional | `"default"` |
+| <a id="maven.install-version_conflict_policy"></a>version_conflict_policy | Policy for user-defined vs. transitive dependency version conflicts<br><br>If "pinned", choose the user-specified version in maven_install unconditionally. In layered installs, artifacts contributed by the root module take precedence over versions contributed by other modules. If "default", follow the selected resolver's default policy. | String | optional | `"default"` |
<a id="maven.override"></a>
diff --git a/docs/bzlmod.md b/docs/bzlmod.md
index 400c00c..7636db1 100644
--- a/docs/bzlmod.md
+++ b/docs/bzlmod.md
@@ -216,16 +216,16 @@
"Highest" uses the Maven `ComparableVersion` ordering implemented by
`private/rules/maven_version.bzl`, not lexical string ordering.
-`version_conflict_policy = "pinned"` changes this interaction. For the Gradle and Maven resolvers,
-root artifacts are marked as `force_version` before layering. The duplicate-force check applies to
-declared forces before this policy is applied. Maven then marks every versioned root declaration.
-Gradle first selects one version for each root `group:artifact`: an unclassified declaration takes
-precedence over classified declarations, and Maven `ComparableVersion` order selects among
-declarations with the same classification status. Every root declaration for that module at the
-selected version is then marked forced, including classified declarations. The root consequently
-wins because it now forces the coordinate. For Coursier, layering is unchanged and the one
-surviving direct version is later passed as a `--force-version` argument. A higher non-root
-version can therefore displace the root under Coursier and then be pinned.
+`version_conflict_policy = "pinned"` changes this interaction. Root artifacts are marked as
+`force_version` before layering, whatever the resolver. The duplicate-force check applies to
+declared forces before this policy is applied. Maven and Coursier mark every versioned root
+declaration. Gradle first selects one version for each root `group:artifact`: an unclassified
+declaration takes precedence over classified declarations, and Maven `ComparableVersion` order
+selects among declarations with the same classification status. Every root declaration for that
+module at the selected version is then marked forced, including classified declarations. The
+root consequently wins because it now forces the coordinate. Coursier additionally passes every
+direct artifact's version as a `--force-version` argument, so transitive dependencies cannot
+displace the pinned version either.
The `force_version` flag can be set by an `artifact` tag, an `amend_artifact` tag, or a regular
artifact read by `from_toml`. Coordinates in `install.artifacts` cannot carry the flag. BOMs use the
diff --git a/examples/android_local_test/maven_install.json b/examples/android_local_test/maven_install.json
index 2734089..0115c75 100644
--- a/examples/android_local_test/maven_install.json
+++ b/examples/android_local_test/maven_install.json
@@ -1,24 +1,24 @@
{
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
"__INPUT_ARTIFACTS_HASH": {
- "androidx.annotation:annotation": 588494489,
- "androidx.appcompat:appcompat": -864916242,
- "androidx.emoji2:emoji2": -667316066,
- "androidx.emoji2:emoji2-views-helper": -799295894,
- "androidx.lifecycle:lifecycle-common": 965287242,
- "androidx.lifecycle:lifecycle-livedata-core": -1534752455,
- "androidx.lifecycle:lifecycle-runtime": -1133978085,
- "androidx.lifecycle:lifecycle-viewmodel-savedstate": -1098900718,
- "androidx.savedstate:savedstate": -833725607,
- "androidx.test.ext:junit": 923457984,
+ "androidx.annotation:annotation": 1998854284,
+ "androidx.appcompat:appcompat": 526874845,
+ "androidx.emoji2:emoji2": 1270171825,
+ "androidx.emoji2:emoji2-views-helper": -985278619,
+ "androidx.lifecycle:lifecycle-common": -84119015,
+ "androidx.lifecycle:lifecycle-livedata-core": 993085898,
+ "androidx.lifecycle:lifecycle-runtime": 1906619816,
+ "androidx.lifecycle:lifecycle-viewmodel-savedstate": -577646767,
+ "androidx.savedstate:savedstate": -671028048,
+ "androidx.test.ext:junit": 199011195,
"com.google.code.findbugs:jsr305": 495355163,
- "com.google.code.gson:gson": 2063056812,
- "com.google.errorprone:error_prone_annotations": 1790047777,
- "com.google.guava:guava": -249069712,
- "com.google.j2objc:j2objc-annotations": -26400317,
- "junit:junit": -744267592,
- "org.assertj:assertj-core": -1145412507,
- "org.robolectric:robolectric": -1784339344,
+ "com.google.code.gson:gson": 579810017,
+ "com.google.errorprone:error_prone_annotations": 1828684942,
+ "com.google.guava:guava": 1001533771,
+ "com.google.j2objc:j2objc-annotations": -57684360,
+ "junit:junit": 1633899997,
+ "org.assertj:assertj-core": -88843862,
+ "org.robolectric:robolectric": 1761992425,
"repositories": 1670674627
},
"__RESOLVED_ARTIFACTS_HASH": {
@@ -1140,13 +1140,40 @@
]
},
"packages": {
+ "androidx.activity:activity:aar": [
+ "androidx.activity",
+ "androidx.activity.contextaware",
+ "androidx.activity.result",
+ "androidx.activity.result.contract"
+ ],
+ "androidx.annotation:annotation-experimental:aar": [
+ "androidx.annotation",
+ "androidx.annotation.experimental"
+ ],
"androidx.annotation:annotation-jvm": [
"androidx.annotation"
],
+ "androidx.appcompat:appcompat-resources:aar": [
+ "androidx.appcompat.content.res",
+ "androidx.appcompat.graphics.drawable",
+ "androidx.appcompat.resources",
+ "androidx.appcompat.widget"
+ ],
+ "androidx.appcompat:appcompat:aar": [
+ "androidx.appcompat.app",
+ "androidx.appcompat.graphics.drawable",
+ "androidx.appcompat.text",
+ "androidx.appcompat.view",
+ "androidx.appcompat.view.menu",
+ "androidx.appcompat.widget"
+ ],
"androidx.arch.core:core-common": [
"androidx.arch.core.internal",
"androidx.arch.core.util"
],
+ "androidx.arch.core:core-runtime:aar": [
+ "androidx.arch.core.executor"
+ ],
"androidx.collection:collection-jvm": [
"androidx.collection",
"androidx.collection.internal"
@@ -1157,12 +1184,196 @@
"androidx.concurrent:concurrent-futures-ktx": [
"androidx.concurrent.futures"
],
+ "androidx.core:core-ktx:aar": [
+ "androidx.core.animation",
+ "androidx.core.content",
+ "androidx.core.content.res",
+ "androidx.core.database",
+ "androidx.core.database.sqlite",
+ "androidx.core.graphics",
+ "androidx.core.graphics.drawable",
+ "androidx.core.location",
+ "androidx.core.net",
+ "androidx.core.os",
+ "androidx.core.text",
+ "androidx.core.transition",
+ "androidx.core.util",
+ "androidx.core.view",
+ "androidx.core.widget"
+ ],
+ "androidx.core:core-viewtree:aar": [
+ "androidx.core.viewtree"
+ ],
+ "androidx.core:core:aar": [
+ "android.support.v4.app",
+ "android.support.v4.graphics.drawable",
+ "android.support.v4.os",
+ "androidx.core.accessibilityservice",
+ "androidx.core.app",
+ "androidx.core.app.unusedapprestrictions",
+ "androidx.core.content",
+ "androidx.core.content.pm",
+ "androidx.core.content.res",
+ "androidx.core.database",
+ "androidx.core.database.sqlite",
+ "androidx.core.graphics",
+ "androidx.core.graphics.drawable",
+ "androidx.core.hardware.display",
+ "androidx.core.hardware.fingerprint",
+ "androidx.core.internal.view",
+ "androidx.core.location",
+ "androidx.core.math",
+ "androidx.core.net",
+ "androidx.core.os",
+ "androidx.core.provider",
+ "androidx.core.service.quicksettings",
+ "androidx.core.telephony",
+ "androidx.core.telephony.mbms",
+ "androidx.core.text",
+ "androidx.core.text.method",
+ "androidx.core.text.util",
+ "androidx.core.util",
+ "androidx.core.view",
+ "androidx.core.view.accessibility",
+ "androidx.core.view.animation",
+ "androidx.core.view.autofill",
+ "androidx.core.view.contentcapture",
+ "androidx.core.view.inputmethod",
+ "androidx.core.widget"
+ ],
+ "androidx.cursoradapter:cursoradapter:aar": [
+ "androidx.cursoradapter.widget"
+ ],
+ "androidx.customview:customview:aar": [
+ "androidx.customview.view",
+ "androidx.customview.widget"
+ ],
+ "androidx.drawerlayout:drawerlayout:aar": [
+ "androidx.drawerlayout.widget"
+ ],
+ "androidx.emoji2:emoji2-views-helper:aar": [
+ "androidx.emoji2.viewsintegration"
+ ],
+ "androidx.emoji2:emoji2:aar": [
+ "androidx.emoji2.text",
+ "androidx.emoji2.text.flatbuffer"
+ ],
+ "androidx.fragment:fragment:aar": [
+ "androidx.fragment.app",
+ "androidx.fragment.app.strictmode"
+ ],
+ "androidx.interpolator:interpolator:aar": [
+ "androidx.interpolator.view.animation"
+ ],
"androidx.lifecycle:lifecycle-common-jvm": [
"androidx.lifecycle"
],
+ "androidx.lifecycle:lifecycle-livedata-core:aar": [
+ "androidx.lifecycle"
+ ],
+ "androidx.lifecycle:lifecycle-livedata:aar": [
+ "androidx.lifecycle"
+ ],
+ "androidx.lifecycle:lifecycle-process:aar": [
+ "androidx.lifecycle"
+ ],
+ "androidx.lifecycle:lifecycle-runtime-android:aar": [
+ "androidx.lifecycle"
+ ],
+ "androidx.lifecycle:lifecycle-viewmodel-android:aar": [
+ "androidx.lifecycle",
+ "androidx.lifecycle.viewmodel",
+ "androidx.lifecycle.viewmodel.internal"
+ ],
+ "androidx.lifecycle:lifecycle-viewmodel-savedstate-android:aar": [
+ "androidx.lifecycle",
+ "androidx.lifecycle.internal",
+ "androidx.lifecycle.serialization"
+ ],
+ "androidx.loader:loader:aar": [
+ "androidx.loader.app",
+ "androidx.loader.content"
+ ],
+ "androidx.profileinstaller:profileinstaller:aar": [
+ "androidx.profileinstaller"
+ ],
"androidx.resourceinspection:resourceinspection-annotation": [
"androidx.resourceinspection.annotation"
],
+ "androidx.savedstate:savedstate-android:aar": [
+ "androidx.savedstate",
+ "androidx.savedstate.internal",
+ "androidx.savedstate.serialization",
+ "androidx.savedstate.serialization.serializers"
+ ],
+ "androidx.startup:startup-runtime:aar": [
+ "androidx.startup"
+ ],
+ "androidx.test.espresso:espresso-idling-resource:aar": [
+ "androidx.test.espresso",
+ "androidx.test.espresso.idling"
+ ],
+ "androidx.test.ext:junit:aar": [
+ "androidx.test.ext.junit.rules",
+ "androidx.test.ext.junit.runners"
+ ],
+ "androidx.test.services:storage:aar": [
+ "androidx.test.services.storage",
+ "androidx.test.services.storage.file",
+ "androidx.test.services.storage.internal"
+ ],
+ "androidx.test:core:aar": [
+ "androidx.test.core.app",
+ "androidx.test.core.content.pm",
+ "androidx.test.core.graphics",
+ "androidx.test.core.internal.os",
+ "androidx.test.core.os",
+ "androidx.test.core.view"
+ ],
+ "androidx.test:monitor:aar": [
+ "androidx.test",
+ "androidx.test.annotation",
+ "androidx.test.internal.platform",
+ "androidx.test.internal.platform.app",
+ "androidx.test.internal.platform.content",
+ "androidx.test.internal.platform.os",
+ "androidx.test.internal.platform.reflect",
+ "androidx.test.internal.platform.util",
+ "androidx.test.internal.runner",
+ "androidx.test.internal.runner.hidden",
+ "androidx.test.internal.runner.intent",
+ "androidx.test.internal.runner.intercepting",
+ "androidx.test.internal.runner.lifecycle",
+ "androidx.test.internal.util",
+ "androidx.test.platform",
+ "androidx.test.platform.app",
+ "androidx.test.platform.concurrent",
+ "androidx.test.platform.device",
+ "androidx.test.platform.graphics",
+ "androidx.test.platform.io",
+ "androidx.test.platform.tracing",
+ "androidx.test.platform.ui",
+ "androidx.test.platform.view.inspector",
+ "androidx.test.runner",
+ "androidx.test.runner.intent",
+ "androidx.test.runner.intercepting",
+ "androidx.test.runner.lifecycle"
+ ],
+ "androidx.tracing:tracing:aar": [
+ "androidx.tracing"
+ ],
+ "androidx.vectordrawable:vectordrawable-animated:aar": [
+ "androidx.vectordrawable.graphics.drawable"
+ ],
+ "androidx.vectordrawable:vectordrawable:aar": [
+ "androidx.vectordrawable.graphics.drawable"
+ ],
+ "androidx.versionedparcelable:versionedparcelable:aar": [
+ "androidx.versionedparcelable"
+ ],
+ "androidx.viewpager:viewpager:aar": [
+ "androidx.viewpager.widget"
+ ],
"com.almworks.sqlite4java:sqlite4java": [
"com.almworks.sqlite4java",
"javolution.util.stripped"
diff --git a/examples/kt_android_local_test/maven_install.json b/examples/kt_android_local_test/maven_install.json
index 2734089..0115c75 100644
--- a/examples/kt_android_local_test/maven_install.json
+++ b/examples/kt_android_local_test/maven_install.json
@@ -1,24 +1,24 @@
{
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
"__INPUT_ARTIFACTS_HASH": {
- "androidx.annotation:annotation": 588494489,
- "androidx.appcompat:appcompat": -864916242,
- "androidx.emoji2:emoji2": -667316066,
- "androidx.emoji2:emoji2-views-helper": -799295894,
- "androidx.lifecycle:lifecycle-common": 965287242,
- "androidx.lifecycle:lifecycle-livedata-core": -1534752455,
- "androidx.lifecycle:lifecycle-runtime": -1133978085,
- "androidx.lifecycle:lifecycle-viewmodel-savedstate": -1098900718,
- "androidx.savedstate:savedstate": -833725607,
- "androidx.test.ext:junit": 923457984,
+ "androidx.annotation:annotation": 1998854284,
+ "androidx.appcompat:appcompat": 526874845,
+ "androidx.emoji2:emoji2": 1270171825,
+ "androidx.emoji2:emoji2-views-helper": -985278619,
+ "androidx.lifecycle:lifecycle-common": -84119015,
+ "androidx.lifecycle:lifecycle-livedata-core": 993085898,
+ "androidx.lifecycle:lifecycle-runtime": 1906619816,
+ "androidx.lifecycle:lifecycle-viewmodel-savedstate": -577646767,
+ "androidx.savedstate:savedstate": -671028048,
+ "androidx.test.ext:junit": 199011195,
"com.google.code.findbugs:jsr305": 495355163,
- "com.google.code.gson:gson": 2063056812,
- "com.google.errorprone:error_prone_annotations": 1790047777,
- "com.google.guava:guava": -249069712,
- "com.google.j2objc:j2objc-annotations": -26400317,
- "junit:junit": -744267592,
- "org.assertj:assertj-core": -1145412507,
- "org.robolectric:robolectric": -1784339344,
+ "com.google.code.gson:gson": 579810017,
+ "com.google.errorprone:error_prone_annotations": 1828684942,
+ "com.google.guava:guava": 1001533771,
+ "com.google.j2objc:j2objc-annotations": -57684360,
+ "junit:junit": 1633899997,
+ "org.assertj:assertj-core": -88843862,
+ "org.robolectric:robolectric": 1761992425,
"repositories": 1670674627
},
"__RESOLVED_ARTIFACTS_HASH": {
@@ -1140,13 +1140,40 @@
]
},
"packages": {
+ "androidx.activity:activity:aar": [
+ "androidx.activity",
+ "androidx.activity.contextaware",
+ "androidx.activity.result",
+ "androidx.activity.result.contract"
+ ],
+ "androidx.annotation:annotation-experimental:aar": [
+ "androidx.annotation",
+ "androidx.annotation.experimental"
+ ],
"androidx.annotation:annotation-jvm": [
"androidx.annotation"
],
+ "androidx.appcompat:appcompat-resources:aar": [
+ "androidx.appcompat.content.res",
+ "androidx.appcompat.graphics.drawable",
+ "androidx.appcompat.resources",
+ "androidx.appcompat.widget"
+ ],
+ "androidx.appcompat:appcompat:aar": [
+ "androidx.appcompat.app",
+ "androidx.appcompat.graphics.drawable",
+ "androidx.appcompat.text",
+ "androidx.appcompat.view",
+ "androidx.appcompat.view.menu",
+ "androidx.appcompat.widget"
+ ],
"androidx.arch.core:core-common": [
"androidx.arch.core.internal",
"androidx.arch.core.util"
],
+ "androidx.arch.core:core-runtime:aar": [
+ "androidx.arch.core.executor"
+ ],
"androidx.collection:collection-jvm": [
"androidx.collection",
"androidx.collection.internal"
@@ -1157,12 +1184,196 @@
"androidx.concurrent:concurrent-futures-ktx": [
"androidx.concurrent.futures"
],
+ "androidx.core:core-ktx:aar": [
+ "androidx.core.animation",
+ "androidx.core.content",
+ "androidx.core.content.res",
+ "androidx.core.database",
+ "androidx.core.database.sqlite",
+ "androidx.core.graphics",
+ "androidx.core.graphics.drawable",
+ "androidx.core.location",
+ "androidx.core.net",
+ "androidx.core.os",
+ "androidx.core.text",
+ "androidx.core.transition",
+ "androidx.core.util",
+ "androidx.core.view",
+ "androidx.core.widget"
+ ],
+ "androidx.core:core-viewtree:aar": [
+ "androidx.core.viewtree"
+ ],
+ "androidx.core:core:aar": [
+ "android.support.v4.app",
+ "android.support.v4.graphics.drawable",
+ "android.support.v4.os",
+ "androidx.core.accessibilityservice",
+ "androidx.core.app",
+ "androidx.core.app.unusedapprestrictions",
+ "androidx.core.content",
+ "androidx.core.content.pm",
+ "androidx.core.content.res",
+ "androidx.core.database",
+ "androidx.core.database.sqlite",
+ "androidx.core.graphics",
+ "androidx.core.graphics.drawable",
+ "androidx.core.hardware.display",
+ "androidx.core.hardware.fingerprint",
+ "androidx.core.internal.view",
+ "androidx.core.location",
+ "androidx.core.math",
+ "androidx.core.net",
+ "androidx.core.os",
+ "androidx.core.provider",
+ "androidx.core.service.quicksettings",
+ "androidx.core.telephony",
+ "androidx.core.telephony.mbms",
+ "androidx.core.text",
+ "androidx.core.text.method",
+ "androidx.core.text.util",
+ "androidx.core.util",
+ "androidx.core.view",
+ "androidx.core.view.accessibility",
+ "androidx.core.view.animation",
+ "androidx.core.view.autofill",
+ "androidx.core.view.contentcapture",
+ "androidx.core.view.inputmethod",
+ "androidx.core.widget"
+ ],
+ "androidx.cursoradapter:cursoradapter:aar": [
+ "androidx.cursoradapter.widget"
+ ],
+ "androidx.customview:customview:aar": [
+ "androidx.customview.view",
+ "androidx.customview.widget"
+ ],
+ "androidx.drawerlayout:drawerlayout:aar": [
+ "androidx.drawerlayout.widget"
+ ],
+ "androidx.emoji2:emoji2-views-helper:aar": [
+ "androidx.emoji2.viewsintegration"
+ ],
+ "androidx.emoji2:emoji2:aar": [
+ "androidx.emoji2.text",
+ "androidx.emoji2.text.flatbuffer"
+ ],
+ "androidx.fragment:fragment:aar": [
+ "androidx.fragment.app",
+ "androidx.fragment.app.strictmode"
+ ],
+ "androidx.interpolator:interpolator:aar": [
+ "androidx.interpolator.view.animation"
+ ],
"androidx.lifecycle:lifecycle-common-jvm": [
"androidx.lifecycle"
],
+ "androidx.lifecycle:lifecycle-livedata-core:aar": [
+ "androidx.lifecycle"
+ ],
+ "androidx.lifecycle:lifecycle-livedata:aar": [
+ "androidx.lifecycle"
+ ],
+ "androidx.lifecycle:lifecycle-process:aar": [
+ "androidx.lifecycle"
+ ],
+ "androidx.lifecycle:lifecycle-runtime-android:aar": [
+ "androidx.lifecycle"
+ ],
+ "androidx.lifecycle:lifecycle-viewmodel-android:aar": [
+ "androidx.lifecycle",
+ "androidx.lifecycle.viewmodel",
+ "androidx.lifecycle.viewmodel.internal"
+ ],
+ "androidx.lifecycle:lifecycle-viewmodel-savedstate-android:aar": [
+ "androidx.lifecycle",
+ "androidx.lifecycle.internal",
+ "androidx.lifecycle.serialization"
+ ],
+ "androidx.loader:loader:aar": [
+ "androidx.loader.app",
+ "androidx.loader.content"
+ ],
+ "androidx.profileinstaller:profileinstaller:aar": [
+ "androidx.profileinstaller"
+ ],
"androidx.resourceinspection:resourceinspection-annotation": [
"androidx.resourceinspection.annotation"
],
+ "androidx.savedstate:savedstate-android:aar": [
+ "androidx.savedstate",
+ "androidx.savedstate.internal",
+ "androidx.savedstate.serialization",
+ "androidx.savedstate.serialization.serializers"
+ ],
+ "androidx.startup:startup-runtime:aar": [
+ "androidx.startup"
+ ],
+ "androidx.test.espresso:espresso-idling-resource:aar": [
+ "androidx.test.espresso",
+ "androidx.test.espresso.idling"
+ ],
+ "androidx.test.ext:junit:aar": [
+ "androidx.test.ext.junit.rules",
+ "androidx.test.ext.junit.runners"
+ ],
+ "androidx.test.services:storage:aar": [
+ "androidx.test.services.storage",
+ "androidx.test.services.storage.file",
+ "androidx.test.services.storage.internal"
+ ],
+ "androidx.test:core:aar": [
+ "androidx.test.core.app",
+ "androidx.test.core.content.pm",
+ "androidx.test.core.graphics",
+ "androidx.test.core.internal.os",
+ "androidx.test.core.os",
+ "androidx.test.core.view"
+ ],
+ "androidx.test:monitor:aar": [
+ "androidx.test",
+ "androidx.test.annotation",
+ "androidx.test.internal.platform",
+ "androidx.test.internal.platform.app",
+ "androidx.test.internal.platform.content",
+ "androidx.test.internal.platform.os",
+ "androidx.test.internal.platform.reflect",
+ "androidx.test.internal.platform.util",
+ "androidx.test.internal.runner",
+ "androidx.test.internal.runner.hidden",
+ "androidx.test.internal.runner.intent",
+ "androidx.test.internal.runner.intercepting",
+ "androidx.test.internal.runner.lifecycle",
+ "androidx.test.internal.util",
+ "androidx.test.platform",
+ "androidx.test.platform.app",
+ "androidx.test.platform.concurrent",
+ "androidx.test.platform.device",
+ "androidx.test.platform.graphics",
+ "androidx.test.platform.io",
+ "androidx.test.platform.tracing",
+ "androidx.test.platform.ui",
+ "androidx.test.platform.view.inspector",
+ "androidx.test.runner",
+ "androidx.test.runner.intent",
+ "androidx.test.runner.intercepting",
+ "androidx.test.runner.lifecycle"
+ ],
+ "androidx.tracing:tracing:aar": [
+ "androidx.tracing"
+ ],
+ "androidx.vectordrawable:vectordrawable-animated:aar": [
+ "androidx.vectordrawable.graphics.drawable"
+ ],
+ "androidx.vectordrawable:vectordrawable:aar": [
+ "androidx.vectordrawable.graphics.drawable"
+ ],
+ "androidx.versionedparcelable:versionedparcelable:aar": [
+ "androidx.versionedparcelable"
+ ],
+ "androidx.viewpager:viewpager:aar": [
+ "androidx.viewpager.widget"
+ ],
"com.almworks.sqlite4java:sqlite4java": [
"com.almworks.sqlite4java",
"javolution.util.stripped"
diff --git a/private/extensions/maven.bzl b/private/extensions/maven.bzl
index 503e6c2..0c3a5ea 100644
--- a/private/extensions/maven.bzl
+++ b/private/extensions/maven.bzl
@@ -114,7 +114,8 @@
doc = """Policy for user-defined vs. transitive dependency version conflicts
If "pinned", choose the user-specified version in maven_install unconditionally.
- With the Gradle and Maven resolvers, this only applies to artifacts contributed by the root module.
+ In layered installs, artifacts contributed by the root module take precedence
+ over versions contributed by other modules.
If "default", follow the selected resolver's default policy.
""",
default = "default",
diff --git a/private/lib/layering.bzl b/private/lib/layering.bzl
index 71079a8..eea32ab 100644
--- a/private/lib/layering.bzl
+++ b/private/lib/layering.bzl
@@ -330,7 +330,7 @@
def apply_root_version_conflict_policy(artifacts, resolver, version_conflict_policy):
"""Applies the install-level conflict policy to root module artifacts."""
- if resolver not in ["gradle", "maven"] or version_conflict_policy != "pinned":
+ if version_conflict_policy != "pinned":
return artifacts
if resolver == "gradle":
diff --git a/tests/custom_maven_install/coursier_resolved_install.json b/tests/custom_maven_install/coursier_resolved_install.json
index 5ce89d4..7954d08 100644
--- a/tests/custom_maven_install/coursier_resolved_install.json
+++ b/tests/custom_maven_install/coursier_resolved_install.json
@@ -2,7 +2,7 @@
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
"__INPUT_ARTIFACTS_HASH": {
"com.google.auth:google-auth-library-oauth2-http": 991267597,
- "com.google.auto:auto-common": -832702775,
+ "com.google.auto:auto-common": 605821486,
"com.google.cloud:google-cloud-bigquery": 1661989687,
"com.google.cloud:libraries-bom": 710163787,
"repositories": -1949687017
@@ -882,20 +882,12 @@
"autovalue.shaded.com.google.auto.service",
"autovalue.shaded.com.google.common.annotations",
"autovalue.shaded.com.google.common.base",
- "autovalue.shaded.com.google.common.cache",
"autovalue.shaded.com.google.common.collect",
- "autovalue.shaded.com.google.common.escape",
- "autovalue.shaded.com.google.common.eventbus",
- "autovalue.shaded.com.google.common.graph",
"autovalue.shaded.com.google.common.hash",
- "autovalue.shaded.com.google.common.html",
"autovalue.shaded.com.google.common.io",
"autovalue.shaded.com.google.common.math",
- "autovalue.shaded.com.google.common.net",
"autovalue.shaded.com.google.common.primitives",
"autovalue.shaded.com.google.common.reflect",
- "autovalue.shaded.com.google.common.util.concurrent",
- "autovalue.shaded.com.google.common.xml",
"autovalue.shaded.com.google.errorprone.annotations",
"autovalue.shaded.com.google.errorprone.annotations.concurrent",
"autovalue.shaded.com.google.escapevelocity",
@@ -1162,8 +1154,6 @@
"io.netty.util.concurrent",
"io.netty.util.internal",
"io.netty.util.internal.logging",
- "io.netty.util.internal.shaded.org.jctools.counters",
- "io.netty.util.internal.shaded.org.jctools.maps",
"io.netty.util.internal.shaded.org.jctools.queues",
"io.netty.util.internal.shaded.org.jctools.queues.atomic",
"io.netty.util.internal.shaded.org.jctools.queues.atomic.unpadded",
diff --git a/tests/custom_maven_install/policy_pinned_testing_install.json b/tests/custom_maven_install/policy_pinned_testing_install.json
index 85cf17f..f3a1b13 100644
--- a/tests/custom_maven_install/policy_pinned_testing_install.json
+++ b/tests/custom_maven_install/policy_pinned_testing_install.json
@@ -1,7 +1,48 @@
{
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
- "__INPUT_ARTIFACTS_HASH": 316608203,
- "__RESOLVED_ARTIFACTS_HASH": -968606658,
+ "__INPUT_ARTIFACTS_HASH": {
+ "com.google.cloud:google-cloud-storage": -1491579406,
+ "com.google.guava:guava": -1853738824,
+ "repositories": -1949687017
+ },
+ "__RESOLVED_ARTIFACTS_HASH": {
+ "com.fasterxml.jackson.core:jackson-core": -262972278,
+ "com.google.api-client:google-api-client": -793854737,
+ "com.google.api.grpc:proto-google-common-protos": -1885550498,
+ "com.google.api.grpc:proto-google-iam-v1": -453830571,
+ "com.google.api:api-common": -549936361,
+ "com.google.api:gax": 805574868,
+ "com.google.api:gax-httpjson": -1168617842,
+ "com.google.apis:google-api-services-storage": 158985735,
+ "com.google.auth:google-auth-library-credentials": 1709815480,
+ "com.google.auth:google-auth-library-oauth2-http": 735705443,
+ "com.google.cloud:google-cloud-core": -2024787513,
+ "com.google.cloud:google-cloud-core-http": -327232662,
+ "com.google.cloud:google-cloud-storage": -2032350017,
+ "com.google.code.findbugs:jsr305": 870839855,
+ "com.google.code.gson:gson": 1862043778,
+ "com.google.errorprone:error_prone_annotations": 875547987,
+ "com.google.guava:guava": -164902174,
+ "com.google.http-client:google-http-client": -294460505,
+ "com.google.http-client:google-http-client-apache": -921946789,
+ "com.google.http-client:google-http-client-appengine": -849655450,
+ "com.google.http-client:google-http-client-jackson2": -1187124445,
+ "com.google.j2objc:j2objc-annotations": 1702790440,
+ "com.google.oauth-client:google-oauth-client": 1855107119,
+ "com.google.protobuf:protobuf-java": 1939119124,
+ "com.google.protobuf:protobuf-java-util": -944010332,
+ "commons-codec:commons-codec": -1216058892,
+ "commons-logging:commons-logging": 1248790901,
+ "io.grpc:grpc-context": -1228139597,
+ "io.opencensus:opencensus-api": 1930972101,
+ "io.opencensus:opencensus-contrib-http-util": -528120454,
+ "javax.annotation:javax.annotation-api": -1009230154,
+ "org.apache.httpcomponents:httpclient": 483019193,
+ "org.apache.httpcomponents:httpcore": 283803218,
+ "org.checkerframework:checker-compat-qual": -1467964223,
+ "org.codehaus.mojo:animal-sniffer-annotations": -349140135,
+ "org.threeten:threetenbp": 659773227
+ },
"artifacts": {
"com.fasterxml.jackson.core:jackson-core": {
"shasums": {
@@ -672,5 +713,5 @@
]
}
},
- "version": "2"
+ "version": "3"
}
diff --git a/tests/integration/BUILD b/tests/integration/BUILD
index 71654c7..1eac56a 100644
--- a/tests/integration/BUILD
+++ b/tests/integration/BUILD
@@ -179,6 +179,33 @@
tags = [] if is_bzlmod_enabled() else ["manual"],
)
+genquery(
+ name = "coursier-pinned-layering-deps",
+ expression = "deps(@coursier_pinned_layering//:com_google_code_findbugs_jsr305)",
+ opts = [
+ "--nohost_deps",
+ "--noimplicit_deps",
+ ],
+ scope = ["@coursier_pinned_layering//:com_google_code_findbugs_jsr305"],
+)
+
+genrule(
+ name = "coursier-pinned-layering-deps-sorted",
+ srcs = [":coursier-pinned-layering-deps"],
+ outs = ["coursier-pinned-layering-deps-sorted.txt"],
+ cmd = "cat $< | grep coursier_pinned_layering | sed -e 's|^@@|@|g; s|\\r||g' | sed -e 's|^@[^/]*[+~]|@|g; s|\\r||g' | sort > $@",
+)
+
+# The root pins jsr305 at 3.0.1 while the contributing module offers 3.0.2.
+# Without root precedence under `version_conflict_policy = "pinned"` the
+# resolved version would be 3.0.2.
+diff_test(
+ name = "coursier-pinned-layering-deps-test",
+ file1 = "coursier-pinned-layering-deps.golden.unix",
+ file2 = ":coursier-pinned-layering-deps-sorted.txt",
+ tags = [] if is_bzlmod_enabled() else ["manual"],
+)
+
# This target will fail to build if we're not handling merging of maven.install
# tags properly, and if we don't handle multiple lock files properly.
java_library(
diff --git a/tests/integration/coursier-pinned-layering-deps.golden.unix b/tests/integration/coursier-pinned-layering-deps.golden.unix
new file mode 100644
index 0000000..652243d
--- /dev/null
+++ b/tests/integration/coursier-pinned-layering-deps.golden.unix
@@ -0,0 +1,2 @@
+@coursier_pinned_layering//:com_google_code_findbugs_jsr305
+@coursier_pinned_layering//:v1/https/repo1.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.1/jsr305-3.0.1.jar
diff --git a/tests/integration/coursier_higher_layer/MODULE.bazel b/tests/integration/coursier_higher_layer/MODULE.bazel
index 16f3d13..0e7bfba 100644
--- a/tests/integration/coursier_higher_layer/MODULE.bazel
+++ b/tests/integration/coursier_higher_layer/MODULE.bazel
@@ -14,3 +14,14 @@
],
)
use_repo(maven, "coursier_layering")
+
+# Contributes a higher version to the `coursier_pinned_layering` repo, whose
+# root pins jsr305 at 3.0.1. The root's `version_conflict_policy = "pinned"`
+# must win over this higher version.
+maven.install(
+ name = "coursier_pinned_layering",
+ artifacts = [
+ "com.google.code.findbugs:jsr305:3.0.2",
+ ],
+)
+use_repo(maven, "coursier_pinned_layering")
diff --git a/tests/unit/layering_test.bzl b/tests/unit/layering_test.bzl
index 597054f..98d6312 100644
--- a/tests/unit/layering_test.bzl
+++ b/tests/unit/layering_test.bzl
@@ -718,6 +718,63 @@
pinned_gradle_root_beats_higher_nonroot_force_test = unittest.make(_pinned_gradle_root_beats_higher_nonroot_force_impl)
+def _pinned_coursier_root_beats_higher_nonroot_impl(ctx):
+ env = unittest.begin(ctx)
+ root = _artifact("1.0")
+
+ result = _layer(
+ root_artifacts = [root],
+ resolver = "coursier",
+ version_conflict_policy = "pinned",
+ non_root_artifacts = {"dep": [_artifact("2.0")]},
+ )
+
+ asserts.equals(env, ["1.0"], [artifact.version for artifact in result.artifacts])
+ asserts.true(env, result.artifacts[0].force_version)
+
+ return unittest.end(env)
+
+pinned_coursier_root_beats_higher_nonroot_test = unittest.make(_pinned_coursier_root_beats_higher_nonroot_impl)
+
+def _pinned_coursier_root_beats_higher_nonroot_force_impl(ctx):
+ env = unittest.begin(ctx)
+ root = _artifact("1.0")
+
+ result = _layer(
+ root_artifacts = [root],
+ resolver = "coursier",
+ version_conflict_policy = "pinned",
+ non_root_artifacts = {"dep": [_artifact("2.0", force_version = True)]},
+ )
+
+ asserts.equals(env, ["1.0"], [artifact.version for artifact in result.artifacts])
+ asserts.true(env, result.artifacts[0].force_version)
+
+ return unittest.end(env)
+
+pinned_coursier_root_beats_higher_nonroot_force_test = unittest.make(_pinned_coursier_root_beats_higher_nonroot_force_impl)
+
+def _pinned_coursier_root_wins_without_override_diagnostics_impl(ctx):
+ env = unittest.begin(ctx)
+
+ # `duplicate_version_warning = "error"` must not fail: `pinned` resolves
+ # the displacement deterministically in favour of the root.
+ result = _layer(
+ root_artifacts = [_artifact("1.0")],
+ resolver = "coursier",
+ version_conflict_policy = "pinned",
+ duplicate_version_warning = "error",
+ known_contributing_modules = sets.make(["dep"]),
+ non_root_artifacts = {"dep": [_artifact("2.0")]},
+ )
+
+ asserts.equals(env, ["1.0"], [artifact.version for artifact in result.artifacts])
+ asserts.equals(env, [], result.diagnostics)
+
+ return unittest.end(env)
+
+pinned_coursier_root_wins_without_override_diagnostics_test = unittest.make(_pinned_coursier_root_wins_without_override_diagnostics_impl)
+
def _namespaces_are_layered_independently_impl(ctx):
env = unittest.begin(ctx)
@@ -918,6 +975,9 @@
partial.make(boms_merge_with_root_priority_test, size = "small"),
partial.make(classifier_and_packaging_layer_independently_test, size = "small"),
partial.make(pinned_gradle_root_beats_higher_nonroot_force_test, size = "small"),
+ partial.make(pinned_coursier_root_beats_higher_nonroot_test, size = "small"),
+ partial.make(pinned_coursier_root_beats_higher_nonroot_force_test, size = "small"),
+ partial.make(pinned_coursier_root_wins_without_override_diagnostics_test, size = "small"),
partial.make(namespaces_are_layered_independently_test, size = "small"),
partial.make(diagnostics_preserve_text_gates_and_order_test, size = "small"),
partial.make(default_namespace_contribution_warning_is_preserved_test, size = "small"),
diff --git a/tests/unit/version_conflict_policy_test.bzl b/tests/unit/version_conflict_policy_test.bzl
index 891a434..1e87a00 100644
--- a/tests/unit/version_conflict_policy_test.bzl
+++ b/tests/unit/version_conflict_policy_test.bzl
@@ -8,7 +8,7 @@
def _pinned_policy_forces_versioned_root_artifacts_impl(ctx):
env = unittest.begin(ctx)
- for resolver in ["gradle", "maven"]:
+ for resolver in ["gradle", "maven", "coursier"]:
versioned = unpack_coordinates("com.example:root:1.0")
versionless = unpack_coordinates("com.example:managed-by-bom")
@@ -30,11 +30,9 @@
artifact = unpack_coordinates("com.example:root:1.0")
- default_artifacts = apply_root_version_conflict_policy([artifact], "gradle", "default")
- coursier_artifacts = apply_root_version_conflict_policy([artifact], "coursier", "pinned")
-
- asserts.false(env, hasattr(default_artifacts[0], "force_version"))
- asserts.false(env, hasattr(coursier_artifacts[0], "force_version"))
+ for resolver in ["gradle", "maven", "coursier"]:
+ default_artifacts = apply_root_version_conflict_policy([artifact], resolver, "default")
+ asserts.false(env, hasattr(default_artifacts[0], "force_version"))
return unittest.end(env)