Skip to content

Commit 72ff1e8

Browse files
committed
Add support for pinning snapshots in gradle resolver
1 parent 1bcdaea commit 72ff1e8

File tree

10 files changed

+146
-25
lines changed

10 files changed

+146
-25
lines changed

MODULE.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,12 +753,15 @@ dev_maven.install(
753753
"androidx.annotation:annotation:1.6.0",
754754
# https://github.com/bazel-contrib/rules_jvm_external/issues/1409
755755
"com.squareup.okhttp3:okhttp:4.12.0",
756+
# Snapshot pinning support: https://github.com/bazel-contrib/rules_jvm_external/pull/1412
757+
"com.google.guava:guava:999.0.0-HEAD-jre-SNAPSHOT",
756758
],
757759
generate_compat_repositories = True,
758760
lock_file = "//tests/custom_maven_install:regression_testing_gradle_install.json",
759761
repositories = [
760762
"https://repo1.maven.org/maven2",
761763
"https://maven.google.com",
764+
"https://oss.sonatype.org/content/repositories/snapshots",
762765
],
763766
resolver = "gradle",
764767
)

private/rules/v2_lock_file.bzl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ def _compute_lock_file_hash(lock_file_contents):
4848
return hash(repr(to_hash))
4949

5050
def _to_m2_path(unpacked):
51-
path = "{group}/{artifact}/{version}/{artifact}-{version}".format(
51+
path = "{group}/{artifact}/{version}/{artifact}-{version_revision}".format(
5252
artifact = unpacked["artifact"],
5353
group = unpacked["group"].replace(".", "/"),
5454
version = unpacked["version"],
55+
version_revision = unpacked.get("version_revision") or unpacked["version"]
5556
)
5657

5758
classifier = unpacked.get("classifier", "jar")
@@ -138,6 +139,7 @@ def _get_artifacts(lock_file_contents):
138139
"group": parts[0],
139140
"artifact": parts[1],
140141
"version": data["version"],
142+
"version_revision": data.get("version_revision"),
141143
}
142144
if len(parts) > 2:
143145
root_unpacked["packaging"] = parts[2]

private/tools/java/com/github/bazelbuild/rules_jvm_external/Coordinates.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class Coordinates implements Comparable<Coordinates> {
2424
private final String groupId;
2525
private final String artifactId;
2626
private final String version;
27+
private final String versionRevision;
2728
private final String classifier;
2829
private final String extension;
2930

@@ -59,16 +60,23 @@ public Coordinates(String coordinates) {
5960
classifier = "jar".equals(parts[3]) ? "" : parts[3];
6061
version = parts[4];
6162
}
63+
this.versionRevision = null;
6264
}
6365

6466
public Coordinates(
6567
String groupId, String artifactId, String extension, String classifier, String version) {
68+
this(groupId, artifactId, extension, classifier, version, null);
69+
}
70+
71+
public Coordinates(
72+
String groupId, String artifactId, String extension, String classifier, String version, String versionRevision) {
6673
this.groupId = Objects.requireNonNull(groupId, "Group ID");
6774
this.artifactId = Objects.requireNonNull(artifactId, "Artifact ID");
6875
this.extension = extension == null || extension.isEmpty() ? "jar" : extension;
6976
this.classifier =
7077
classifier == null || classifier.isEmpty() || "jar".equals(classifier) ? "" : classifier;
7178
this.version = version == null || version.isEmpty() ? "" : version;
79+
this.versionRevision = versionRevision;
7280
}
7381

7482
public String getGroupId() {
@@ -88,21 +96,29 @@ public String getClassifier() {
8896
}
8997

9098
public Coordinates setClassifier(String classifier) {
91-
return new Coordinates(getGroupId(), getArtifactId(), getExtension(), classifier, getVersion());
99+
return new Coordinates(getGroupId(), getArtifactId(), getExtension(), classifier, getVersion(), getVersionRevision());
92100
}
93101

94102
public Coordinates setExtension(String extension) {
95-
return new Coordinates(getGroupId(), getArtifactId(), extension, getClassifier(), getVersion());
103+
return new Coordinates(getGroupId(), getArtifactId(), extension, getClassifier(), getVersion(), getVersionRevision());
96104
}
97105

98106
public Coordinates setVersion(String version) {
99-
return new Coordinates(getGroupId(), getArtifactId(), getExtension(), getClassifier(), version);
107+
return new Coordinates(getGroupId(), getArtifactId(), getExtension(), getClassifier(), version, getVersionRevision());
108+
}
109+
110+
public Coordinates setVersionRevision(String versionRevision) {
111+
return new Coordinates(getGroupId(), getArtifactId(), getExtension(), getClassifier(), getVersion(), versionRevision);
100112
}
101113

102114
public String getExtension() {
103115
return extension;
104116
}
105117

118+
public String getVersionRevision() {
119+
return versionRevision;
120+
}
121+
106122
public String asKey() {
107123
StringBuilder coords = new StringBuilder();
108124
coords.append(groupId).append(":").append(artifactId);
@@ -133,7 +149,7 @@ public String toRepoPath() {
133149
.append("/")
134150
.append(getArtifactId())
135151
.append("-")
136-
.append(getVersion());
152+
.append(isNullOrEmpty(getVersionRevision()) ? getVersion() : getVersionRevision());
137153

138154
String classifier = getClassifier();
139155

@@ -178,14 +194,15 @@ public boolean equals(Object o) {
178194
return getGroupId().equals(that.getGroupId())
179195
&& getArtifactId().equals(that.getArtifactId())
180196
&& Objects.equals(getVersion(), that.getVersion())
197+
&& Objects.equals(getVersionRevision(), that.getVersionRevision())
181198
&& Objects.equals(getClassifier(), that.getClassifier())
182199
&& Objects.equals(getExtension(), that.getExtension());
183200
}
184201

185202
@Override
186203
public int hashCode() {
187204
return Objects.hash(
188-
getGroupId(), getArtifactId(), getVersion(), getClassifier(), getExtension());
205+
getGroupId(), getArtifactId(), getVersion(), getVersionRevision(), getClassifier(), getExtension());
189206
}
190207

191208
private boolean isNullOrEmpty(String value) {

private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ private ResolutionResult parseDependencies(
181181
gradleCoordinates.getArtifactId(),
182182
extension,
183183
classifier,
184-
gradleCoordinates.getVersion());
184+
gradleCoordinates.getVersion(),
185+
dependency.getVersionRevision());
185186
addDependency(graph, coordinates, dependency, conflicts, requestedDeps, visited);
186187
// if there's a conflict and the conflicting version isn't one that's actually requested
187188
// then it's an actual conflict we want to report
@@ -275,7 +276,8 @@ private void addDependency(
275276
childCoordinates.getArtifactId(),
276277
extension,
277278
childCoordinates.getClassifier(),
278-
childCoordinates.getVersion());
279+
childCoordinates.getVersion(),
280+
childInfo.getVersionRevision());
279281
graph.addNode(child);
280282
graph.putEdge(parent, child);
281283
// if there's a conflict and the conflicting version isn't one that's actually requested

private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/models/GradleResolvedDependency.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ public interface GradleResolvedDependency {
3434

3535
void setVersion(String version);
3636

37+
String getVersionRevision();
38+
39+
void setVersionRevision(String versionRevision);
40+
3741
Set<String> getRequestedVersions();
3842

3943
void addRequestedVersion(String requestedVersion);

private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/models/GradleResolvedDependencyImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class GradleResolvedDependencyImpl implements Serializable, GradleResolve
2525
private String group;
2626
private String name;
2727
private String version;
28+
private String versionRevision;
2829
private Set<String> requestedVersions;
2930
private boolean conflict;
3031
private List<GradleResolvedDependency> children;
@@ -61,6 +62,14 @@ public void setVersion(String version) {
6162
this.version = version;
6263
}
6364

65+
public String getVersionRevision() {
66+
return versionRevision;
67+
}
68+
69+
public void setVersionRevision(String versionRevision) {
70+
this.versionRevision = versionRevision;
71+
}
72+
6473
public Set<String> getRequestedVersions() {
6574
return requestedVersions;
6675
}

private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/plugin/GradleDependencyModelBuilder.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,17 @@ private GradleResolvedDependency walkResolvedComponent(
268268
info = new GradleResolvedDependencyImpl();
269269
info.setGroup(component.getModuleVersion().getGroup());
270270
info.setName(component.getModuleVersion().getName());
271-
info.setVersion(component.getModuleVersion().getVersion());
271+
String version = component.getModuleVersion().getVersion();
272+
info.setVersion(version);
273+
274+
// For snapshot dependencies, extract the timestamped version from the component ID
275+
// Note: this is unsafe, is there a better way of obtaining the timestamp for an snapshot? I could not find any
276+
if (component.getId().getClass().getName().contains("MavenUniqueSnapshotComponentIdentifier")) {
277+
String snapshotVersion = version.substring(0, version.length() - "-SNAPSHOT".length());
278+
// Extract timestamped version from format: group:artifact:version:timestamp-buildnum
279+
String snapshotId = snapshotVersion + "-" + component.getId().toString().split(":")[3];
280+
info.setVersionRevision(snapshotId);
281+
}
272282
}
273283

274284
info.addRequestedVersion(info.getVersion()); // add a new version that may have been requested

private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/lockfile/V2LockFile.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,11 @@ public Map<String, Object> render() {
216216
Map<String, Object> artifactValue =
217217
artifacts.computeIfAbsent(shortKey, k -> new TreeMap<>());
218218
artifactValue.put("version", coords.getVersion());
219+
220+
// Add version_revision for reproducible builds when available
221+
if (coords.getVersionRevision() != null && !coords.getVersionRevision().isEmpty()) {
222+
artifactValue.put("version_revision", coords.getVersionRevision());
223+
}
219224

220225
String classifier;
221226
if (coords.getClassifier() == null || coords.getClassifier().isEmpty()) {

private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/remote/Downloader.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,7 @@ public DownloadResult download(Coordinates coords) {
8484
return result;
8585
}
8686

87-
// Are we dealing with a packaging dep? Download the `pom.xml` and check
88-
String originalTarget = coords.toRepoPath();
89-
String pomName = String.format("%s-%s.pom", coords.getArtifactId(), coords.getVersion());
90-
String pom = Paths.get(originalTarget).getParent().resolve(pomName).toString();
91-
87+
String pom = coords.setExtension("pom").toRepoPath();
9288
DownloadResult pomResult = performDownload(coords, pom);
9389
if (pomResult == null) {
9490
System.out.println(

tests/custom_maven_install/regression_testing_gradle_install.json

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL",
3-
"__INPUT_ARTIFACTS_HASH": -1648244252,
4-
"__RESOLVED_ARTIFACTS_HASH": -1940227237,
3+
"__INPUT_ARTIFACTS_HASH": 325832765,
4+
"__RESOLVED_ARTIFACTS_HASH": 1086745,
55
"artifacts": {
66
"androidx.activity:activity-ktx:aar": {
77
"shasums": {
@@ -345,11 +345,36 @@
345345
},
346346
"version": "1.1.1"
347347
},
348+
"com.google.errorprone:error_prone_annotations": {
349+
"shasums": {
350+
"jar": "77440e270b0bc9a249903c5a076c36a722c4886ca4f42675f2903a1c53ed61a5"
351+
},
352+
"version": "2.36.0"
353+
},
354+
"com.google.guava:failureaccess": {
355+
"shasums": {
356+
"jar": "cbfc3906b19b8f55dd7cfd6dfe0aa4532e834250d7f080bd8d211a3e246b59cb"
357+
},
358+
"version": "1.0.3"
359+
},
360+
"com.google.guava:guava": {
361+
"shasums": {
362+
"jar": "79abe7953803b20d1deb5f36283d4d640c7aacbdb1ddd7601aae369b1633e903"
363+
},
364+
"version": "999.0.0-HEAD-jre-SNAPSHOT",
365+
"version_revision": "999.0.0-HEAD-jre-20250623.150948-114"
366+
},
348367
"com.google.guava:listenablefuture": {
349368
"shasums": {
350-
"jar": "e4ad7607e5c0477c6f890ef26a49cb8d1bb4dffb650bab4502afee64644e3069"
369+
"jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99"
370+
},
371+
"version": "9999.0-empty-to-avoid-conflict-with-guava"
372+
},
373+
"com.google.j2objc:j2objc-annotations": {
374+
"shasums": {
375+
"jar": "88241573467ddca44ffd4d74aa04c2bbfd11bf7c17e0c342c94c9de7a70a7c64"
351376
},
352-
"version": "1.0"
377+
"version": "3.0.0"
353378
},
354379
"com.squareup.okhttp3:okhttp": {
355380
"shasums": {
@@ -422,6 +447,12 @@
422447
"jar": "ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478"
423448
},
424449
"version": "13.0"
450+
},
451+
"org.jspecify:jspecify": {
452+
"shasums": {
453+
"jar": "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab"
454+
},
455+
"version": "1.0.0"
425456
}
426457
},
427458
"conflict_resolution": {
@@ -668,8 +699,7 @@
668699
"org.jetbrains.kotlinx:kotlinx-coroutines-core"
669700
],
670701
"androidx.concurrent:concurrent-futures": [
671-
"androidx.annotation:annotation",
672-
"com.google.guava:listenablefuture"
702+
"androidx.annotation:annotation"
673703
],
674704
"androidx.core:core-ktx:aar": [
675705
"androidx.annotation:annotation",
@@ -820,8 +850,7 @@
820850
"androidx.profileinstaller:profileinstaller:aar": [
821851
"androidx.annotation:annotation",
822852
"androidx.concurrent:concurrent-futures",
823-
"androidx.startup:startup-runtime:aar",
824-
"com.google.guava:listenablefuture"
853+
"androidx.startup:startup-runtime:aar"
825854
],
826855
"androidx.savedstate:savedstate-ktx:aar": [
827856
"androidx.savedstate:savedstate:aar",
@@ -845,6 +874,13 @@
845874
"androidx.annotation:annotation",
846875
"androidx.collection:collection"
847876
],
877+
"com.google.guava:guava": [
878+
"com.google.errorprone:error_prone_annotations",
879+
"com.google.guava:failureaccess",
880+
"com.google.guava:listenablefuture",
881+
"com.google.j2objc:j2objc-annotations",
882+
"org.jspecify:jspecify"
883+
],
848884
"com.squareup.okhttp3:okhttp": [
849885
"com.squareup.okio:okio",
850886
"org.jetbrains.kotlin:kotlin-stdlib-jdk8"
@@ -901,8 +937,35 @@
901937
"androidx.lifecycle:lifecycle-common": [
902938
"androidx.lifecycle"
903939
],
904-
"com.google.guava:listenablefuture": [
905-
"com.google.common.util.concurrent"
940+
"com.google.errorprone:error_prone_annotations": [
941+
"com.google.errorprone.annotations",
942+
"com.google.errorprone.annotations.concurrent"
943+
],
944+
"com.google.guava:failureaccess": [
945+
"com.google.common.util.concurrent.internal"
946+
],
947+
"com.google.guava:guava": [
948+
"com.google.common.annotations",
949+
"com.google.common.base",
950+
"com.google.common.base.internal",
951+
"com.google.common.cache",
952+
"com.google.common.collect",
953+
"com.google.common.escape",
954+
"com.google.common.eventbus",
955+
"com.google.common.graph",
956+
"com.google.common.hash",
957+
"com.google.common.html",
958+
"com.google.common.io",
959+
"com.google.common.math",
960+
"com.google.common.net",
961+
"com.google.common.primitives",
962+
"com.google.common.reflect",
963+
"com.google.common.util.concurrent",
964+
"com.google.common.xml",
965+
"com.google.thirdparty.publicsuffix"
966+
],
967+
"com.google.j2objc:j2objc-annotations": [
968+
"com.google.j2objc.annotations"
906969
],
907970
"com.squareup.okhttp3:okhttp": [
908971
"okhttp3",
@@ -991,6 +1054,9 @@
9911054
"org.jetbrains:annotations": [
9921055
"org.intellij.lang.annotations",
9931056
"org.jetbrains.annotations"
1057+
],
1058+
"org.jspecify:jspecify": [
1059+
"org.jspecify.annotations"
9941060
]
9951061
},
9961062
"repositories": {
@@ -1053,8 +1119,14 @@
10531119
"androidx.tracing:tracing:aar",
10541120
"androidx.versionedparcelable:versionedparcelable:aar"
10551121
],
1122+
"https://oss.sonatype.org/content/repositories/snapshots/": [
1123+
"com.google.guava:guava"
1124+
],
10561125
"https://repo1.maven.org/maven2/": [
1126+
"com.google.errorprone:error_prone_annotations",
1127+
"com.google.guava:failureaccess",
10571128
"com.google.guava:listenablefuture",
1129+
"com.google.j2objc:j2objc-annotations",
10581130
"com.squareup.okhttp3:okhttp",
10591131
"com.squareup.okio:okio",
10601132
"com.squareup.okio:okio-jvm",
@@ -1066,7 +1138,8 @@
10661138
"org.jetbrains.kotlinx:kotlinx-coroutines-bom",
10671139
"org.jetbrains.kotlinx:kotlinx-coroutines-core",
10681140
"org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm",
1069-
"org.jetbrains:annotations"
1141+
"org.jetbrains:annotations",
1142+
"org.jspecify:jspecify"
10701143
]
10711144
},
10721145
"services": {

0 commit comments

Comments
 (0)