fix: stop publishing a bigtable-beam-import pom with no dependencies - #4632
Conversation
bigtable-beam-import attaches its shaded jar under a classifier, so the main artifact is the thin, unshaded jar and its pom must keep every compile dependency. maven-shade-plugin still strips them from the generated dependency-reduced pom in that configuration (MSHADE-419), which is not fixed in 3.6.0 despite what the comment in the root pom claimed. The bump to 3.6.0 in googleapis#4626 therefore published 2.20.0 and 2.20.1 poms declaring zero compile dependencies. Consumers resolving the artifact from Maven Central get no transitive deps at all. GoogleCloudPlatform/DataflowTemplates hits this staging the Cloud_Bigtable_to_GCS_SequenceFile template, which fails with ClassNotFoundException: org.apache.hadoop.hbase.io.ImmutableBytesWritable. Nothing caught it in-repo because the reactor resolves sibling modules from source poms and never reads dependency-reduced-pom.xml. - set createDependencyReducedPom=false explicitly on the module rather than relying on a plugin default that changed between 3.2.4 and 3.6.0 - add a verify-published-pom-deps goal to bigtable-build-helper that inspects the pom that would actually be deployed and fails the build if a required compile dependency is missing, wired into the module's verify phase; covered by integration tests for both the healthy and the MSHADE-419-stripped case - correct the root pom comment and drop the renovate rule that pinned maven-shade-plugin away from 3.3.0, which was both an incomplete description of the bug and moot now that the flag is explicit Change-Id: I2d269c60175e10da7e5b361f410dd06f7861ba48
There was a problem hiding this comment.
Code Review
This pull request introduces a new Maven plugin goal, verify-published-pom-deps, to guard against the maven-shade-plugin stripping required compile dependencies from the published POM (as seen in MSHADE-419). It also adds integration tests to verify this behavior. The review feedback suggests improving the robustness of the new Mojo by adding null and validity checks for the POM file and dependency coordinates, and explicitly specifying UTF-8 encoding when reading the build log in the integration test script.
| File publishedPom = project.getFile(); | ||
| Set<String> declared = readPropagatingDependencies(publishedPom); |
There was a problem hiding this comment.
If project.getFile() returns null or a non-existent file (which can happen in certain test environments or synthetic projects), calling readPropagatingDependencies will result in a NullPointerException when opening the FileInputStream. It is safer to check if the file is non-null and is a valid file before proceeding.
File publishedPom = project.getFile();
if (publishedPom == null || !publishedPom.isFile()) {
throw new MojoFailureException("Published POM file is not available or invalid: " + publishedPom);
}
Set<String> declared = readPropagatingDependencies(publishedPom);There was a problem hiding this comment.
Done in 23d3938. Failing loudly beats an NPE here, and more importantly a build that cannot read the pom must not look like it passed the check.
| for (Dependency dependency : model.getDependencies()) { | ||
| String scope = dependency.getScope(); | ||
| // An absent scope means compile. | ||
| if (scope != null && !"compile".equals(scope) && !"runtime".equals(scope)) { | ||
| continue; | ||
| } | ||
| declared.add(resolveGroupId(dependency.getGroupId()) + ":" + dependency.getArtifactId()); | ||
| } |
There was a problem hiding this comment.
If the parsed POM is malformed or missing required fields, dependency.getGroupId() or dependency.getArtifactId() could return null. Adding a null check prevents adding invalid "null:artifactId" or "groupId:null" entries to the declared set.
for (Dependency dependency : model.getDependencies()) {
String scope = dependency.getScope();
// An absent scope means compile.
if (scope != null && !"compile".equals(scope) && !"runtime".equals(scope)) {
continue;
}
String groupId = dependency.getGroupId();
String artifactId = dependency.getArtifactId();
if (groupId != null && artifactId != null) {
declared.add(resolveGroupId(groupId) + ":" + artifactId);
}
}There was a problem hiding this comment.
Done in 23d3938. A half-declared coordinate cannot satisfy a requirement anyway, so skipping it lets the dependency it was meant to be get reported as missing, which is the outcome we want.
| import java.nio.file.Files; | ||
|
|
||
| File buildLog = new File(basedir, "build.log"); | ||
| String content = new String(Files.readAllBytes(buildLog.toPath())); |
There was a problem hiding this comment.
Reading the file bytes into a String without specifying a charset uses the platform's default encoding. This can lead to flaky or failing tests on environments (like Windows runners in CI) where the default encoding is not UTF-8. It is safer to explicitly specify StandardCharsets.UTF_8.
String content = new String(Files.readAllBytes(buildLog.toPath()), java.nio.charset.StandardCharsets.UTF_8);
There was a problem hiding this comment.
Skipping this one. Both assertion strings are pure ASCII, which decodes identically under any charset this would realistically run with, so there is no flakiness to fix. The three existing verify.bsh files in this module (verify-shaded-jar-entries-leak, verify-shaded-exclusions-unpromoted, verify-mirror-deps-misaligned) all read the build log the same way, and making only the new one differ costs consistency for no behavior change. Worth doing as a sweep across all four if we ever want it.
…-pom-deps Change-Id: Ice5b8a44978b4833bc48c5fe037a263bbce68b77
Problem
bigtable-beam-import2.20.0 and 2.20.1 were published to Maven Central with zero compile dependencies in their poms.The module attaches its shaded jar under a classifier (
shadedArtifactAttached=true), so the main artifact is the thin, unshaded jar — it needs every one of its compile dependencies declared. maven-shade-plugin strips them from the generated dependency-reduced pom anyway in that configuration (MSHADE-419), which is not fixed in 3.6.0, despite what the comment in the root pom claimed. The bump to 3.6.0 in #4626 flipped the module onto that code path.Consumers resolving the artifact from a repository get nothing transitively. GoogleCloudPlatform/DataflowTemplates hits this staging the
Cloud_Bigtable_to_GCS_SequenceFiletemplate:Every one of these disappeared from the published pom:
bigtable-hbase-beam,beam-sdks-java-core,beam-sdks-java-io-hadoop-format,beam-runners-google-cloud-dataflow-java,hadoop-client-api,hadoop-client-runtime,hbase-shaded-mapreduce,gcs-connectorWhy CI didn't catch it
The Maven reactor resolves sibling modules from their source poms and never reads
dependency-reduced-pom.xml, so the broken pom is invisible in-repo. There is no in-repo consumer of the published artifact, and neitherdependencies.shnor linkage-monitor inspects the deployed pom.Changes
bigtable-beam-import/pom.xml— set<createDependencyReducedPom>false</createDependencyReducedPom>explicitly, rather than relying on a plugin default whose behavior changed between 3.2.4 and 3.6.0.New
verify-published-pom-depsgoal inbigtable-build-helper, wired into the module'sverifyphase. It readsproject.getFile()— which shade rewrites to the reduced pom when enabled — so it inspects exactly what would be deployed, and fails the build listing any missing required compile dependency plus a pointer to MSHADE-419. Two integration tests cover the healthy pom and the stripped one.Root
pom.xml/renovate.json5— corrected the comment that asserted 3.6.0 was unaffected, and dropped the renovate rule pinning maven-shade-plugin away from 3.3.0. That rule described the bug incompletely (it isn't specific to 3.3.0), and correcting the range would have banned the 3.6.0 we need for the Java 17 multi-release classes; the explicit flag plus the guard replaces it.Verification
bigtable-build-helperintegration testsPassed: 8, Failed: 0, Errors: 0, Skipped: 0mvn -pl bigtable-dataflow-parent/bigtable-beam-import -am verifyBUILD SUCCESS; guard silent; nodependency-reduced-pom.xmlgeneratedcreateDependencyReducedPomflipped back totrueBUILD FAILURE; guard reports all 8 deps missingThe negative run reproduces the shipped defect exactly — the same eight artifacts that vanished for DataflowTemplates.