Skip to content
This repository was archived by the owner on Sep 26, 2023. It is now read-only.

chore: Add Maven build#1562

Merged
meltsufin merged 29 commits intomainfrom
maven
Jun 9, 2022
Merged

chore: Add Maven build#1562
meltsufin merged 29 commits intomainfrom
maven

Conversation

@meltsufin
Copy link
Copy Markdown
Member

@meltsufin meltsufin commented Nov 19, 2021

The goal of adding Maven is to align with the rest of the client library repositories that use Maven. This should enable us to take advantage of more automation tools that have been designed and tested against Maven-based repositories. This should also simplify integration with Bazel and eliminate the need for /dependencies.properties.

[blakeli] Please note that this PR is the first step towards migrating to maven, the purpose is to add a maven build in parallel of gradle/bazel. There will be a lot of follow up PRs to replicate all the features of gradle/bazel and eventually replace gradle.

@meltsufin meltsufin requested review from a team November 19, 2021 05:10
@google-cla google-cla Bot added the cla: yes This human has signed the Contributor License Agreement. label Nov 19, 2021
Copy link
Copy Markdown
Contributor

@chanseokoh chanseokoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it'll cause less friction to remove benchmark in a separate PR.

I guess this is the first step, and it'll be (a lot of) more work we can eventually get rid of Gradle, right? Hopefully we don't end up keeping three build systems for a considerable amount of time.

Comment thread gax-grpc/pom.xml
Comment thread versions.txt Outdated
Comment thread pom.xml Outdated
</exclusion>
<exclusion>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
Copy link
Copy Markdown
Contributor

@chanseokoh chanseokoh Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is is basically a standard practice to exclude these dependencies? I feel the maintainers of the truth should fix their project setup so that these transitive dependencies are not exposed to library users?

No action needed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I had to exclude it was because different dependencies were pulling in different versions of error_prone_annotations transitively and causing upper bound failures. Apparently, some error prone annotations have runtime scope. So, the dependency can't be provided.
@suztomo In case you have any comments on this.

Comment thread gax/pom.xml Outdated
Comment thread gax/pom.xml
Comment thread gax/build.gradle
@chanseokoh
Copy link
Copy Markdown
Contributor

This should also simplify integration with Bazel and eliminate the need for /dependencies.properties

Q: how can this be done? That is, how to ensure they both Bazel and Maven are always synced to use the same versions of all the JARs involved (whether for the compile classpath, runtime classpath, annotation classpath, etc.)?

Comment thread build.gradle
Comment thread versions.txt Outdated
Comment thread pom.xml
Comment thread pom.xml
Comment thread pom.xml

<parent>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-shared-config</artifactId>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this parent necessary? For what? The Gradle doesn't seem to use it? And we specify all the versions of the libraries in the dependency management section?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to help us align better with client libraries. It has some checks and general configuration that is useful.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Just wanted to make sure we don't diverge from the Bazel setup. Once we start doing that, it will be difficult to reconcile and maintain them later.

Copy link
Copy Markdown
Contributor

@vam-google vam-google Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will technically change how gax artifacts get published on maven (they are getting parents which they used to not have).

Maybe it is ok, but we should be careful here. Can it cause any breakages and/or dependency conflicts for existing users of this? Also, I'm not sure if changing a parent can be considered a breaking change for maven atrifact or not.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a breaking change. Besides, almost everything else in the Java SDK has it as the parent.

@meltsufin meltsufin changed the title chore: Add Maven build and remove benchmark module chore: Add Maven build Nov 19, 2021
@meltsufin meltsufin requested a review from chanseokoh November 19, 2021 18:15
Comment thread build.gradle Outdated
// ----------

task sourcesJar(type: Jar, dependsOn: classes) {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, interesting. Were we having duplicate entries? Which files? Or, was it that you just noticed a deprecation warning and found a way to resolve it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get it on the gax/src/main/resources/dependencies.properties and only when running ./gradlew build publishToMavenLocal. It looks like the file created by build overlaps with sourcesJar. If there is a better way to handle it, please let me know.

Copy link
Copy Markdown
Contributor

@chanseokoh chanseokoh Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... I think this is because now gax/src/main/resources/dependencies.properties is checked in as source. So I guess what's happening is that, because a final version is generated at gax/build/resources/main/dependencies.properties, now you have two dependencies.properties files to include.

I think DuplicatesStrategy.EXCLUDE could be a problem, because it doesn't deterministically guarantee which file will win in the end. However, for a source JAR, I actually start to think there may be no reason to add this properties file? Not sure if it's the standard practice to add this kind of resource files into a source JAR. OTOH, since the file is part of the source set (it's under src/main), it also makes sense to include it, perhaps the one before processing with templating.

Let me try to find a way to include the original source file.

Copy link
Copy Markdown
Contributor

@chanseokoh chanseokoh Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it is correct that the error is due to the new gax/src/main/resources/dependencies.properties, but this is not because we have a processed file with the same filename under gax/build/.

  task sourcesJar(type: Jar, dependsOn: classes) {
    archiveClassifier = 'sources'

    from sourceSets.main.allSource, sourceSets.test.allSource, sourceSets.main.resources.srcDirs
    exclude('**/*Test.java')
  }

So the sources JAR is composed of main.allSource, test.allSource, and main.resources. (BTW, we could just say sourceSets.main.resources instead of sourceSets.main.resources.srcDirs.)

The thing is, allSource already includes resources. The default is a list [java, resources] as documented. So, it's redundant to specify main.resources again. Indeed, if I change it to

from sourceSets.main.allSource, sourceSets.test.allSource

I still see dependencies.properties in build/libs/gax-2.7.1-SNAPSHOT-sources.jar after running ./gradlew :gax:sourcesJar. OTOH, if I change it to from sourceSets.main.allJava, sourceSets.test.allSource, I don't see the properties file in the -sources.jar.

To sum, don't set duplicatesStrategy, but set from sourceSets.main.allSource, sourceSets.test.allSource (remove main.resources).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the investigation. This clears things up. As a side note, I'm not sure why we are including test sources at all, yet exclude all files ending in *Test.java.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... good point. My guess is that, this repo is also generating *-testlib.jar files that I think contain some test utility classes (whose filename doesn't end with *Test.java). Maybe per the Maven Central requirements or convention, because we are publishing -testlib.jar files, we also need to include source files.

Copy link
Copy Markdown
Contributor

@vam-google vam-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change looks fine to me, but please make sure that:

  1. Change of the parent (in terms of maven artifacts) is ok and non-breaking.
  2. Please verify that mvn install works and then using the newly installed version (x.x.x-SNAPSHOT) directly in any of the existing gapic clients (I would recommend java-language as it is a simple one) still works.
  3. For dependencies.properties file, please note it is also accessed in java code (https://github.com/googleapis/gax-java/blob/main/gax/src/main/java/com/google/api/gax/core/GaxProperties.java#L69), so it ineeds to be cleaned up too (may be not that simple, as it is needed to get gax library version when it is not packaged in a jar and is executed from sources or bazel contex).
  4. The root pom.xml has all transitive dependencies listed (such that bazel integration still can get all the dependencies and their versions).

Comment thread pom.xml

<parent>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-shared-config</artifactId>
Copy link
Copy Markdown
Contributor

@vam-google vam-google Nov 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will technically change how gax artifacts get published on maven (they are getting parents which they used to not have).

Maybe it is ok, but we should be careful here. Can it cause any breakages and/or dependency conflicts for existing users of this? Also, I'm not sure if changing a parent can be considered a breaking change for maven atrifact or not.

@meltsufin
Copy link
Copy Markdown
Member Author

This should also simplify integration with Bazel and eliminate the need for /dependencies.properties

Q: how can this be done? That is, how to ensure they both Bazel and Maven are always synced to use the same versions of all the JARs involved (whether for the compile classpath, runtime classpath, annotation classpath, etc.)?

@vam-google, I think you told me that there is an easier way to integrate Maven with Bazel.

@meltsufin
Copy link
Copy Markdown
Member Author

The change looks fine to me, but please make sure that:

  1. Change of the parent (in terms of maven artifacts) is ok and non-breaking.
  2. Please verify that mvn install works and then using the newly installed version (x.x.x-SNAPSHOT) directly in any of the existing gapic clients (I would recommend java-language as it is a simple one) still works.

@vam-google I created an issue googleapis/gapic-generator-java#1318 to track the various steps in the migration to Maven.

  1. For dependencies.properties file, please note it is also accessed in java code (https://github.com/googleapis/gax-java/blob/main/gax/src/main/java/com/google/api/gax/core/GaxProperties.java#L69), so it ineeds to be cleaned up too (may be not that simple, as it is needed to get gax library version when it is not packaged in a jar and is executed from sources or bazel contex).

Note that the dependencies.properties that is referenced in GaxProperties is actually a different file that we generate from gax/src/main/resources/dependencies.properties.

  1. The root pom.xml has all transitive dependencies listed (such that bazel integration still can get all the dependencies and their versions).

Can you provide some pointers to help understand the "bazel integration"?

@chanseokoh
Copy link
Copy Markdown
Contributor

Note that the dependencies.properties that is referenced in GaxProperties is actually a different file that we generate from gax/src/main/resources/dependencies.properties

We still need to keep this mind, since we are going to remove dependencies.properties per the plan in googleapis/gapic-generator-java#1318.

@chanseokoh
Copy link
Copy Markdown
Contributor

Looks like both the Gradle dependency api and implementation "scopes" are translated into the same compile Maven scope, which will make the implementation dependencies leak into the library user's classpath again (regression). Is it not possible to achieve the same behavior in Maven?

@meltsufin
Copy link
Copy Markdown
Member Author

@vam-google @chanseokoh Are you guys comfortable with merging this in? Remember, this is by no means a full replacement for Gradle yet. There are more steps to come.

Copy link
Copy Markdown
Contributor

@chanseokoh chanseokoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from my side.

Comment thread gax/src/test/java/com/google/api/gax/retrying/ScheduledRetryingExecutorTest.java Outdated
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Feb 3, 2022

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@chanseokoh chanseokoh added automerge Merge the pull request once unit tests and other checks pass. and removed automerge Merge the pull request once unit tests and other checks pass. labels Feb 8, 2022
@gcf-merge-on-green
Copy link
Copy Markdown
Contributor

Merge-on-green attempted to merge your PR for 6 hours, but it was not mergeable because either one of your required status checks failed, one of your required reviews was not approved, or there is a do not merge label. Learn more about your required status checks here: https://help.github.com/en/github/administering-a-repository/enabling-required-status-checks. You can remove and reapply the label to re-run the bot.

@gcf-merge-on-green gcf-merge-on-green Bot removed the automerge Merge the pull request once unit tests and other checks pass. label Feb 10, 2022
Comment thread .github/workflows/ci.yaml Outdated
Comment thread .github/workflows/ci.yaml
pull_request:
name: ci
jobs:
maven-units:
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you pull the bazel build part out into a sepaarate workflow file, you should be able to use GitHub Matrix feature and save some code duplication.

matrix:
  script: [build.sh, maven-build.sh]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. However, the gradle build will eventually be replaced by maven build though, so not sure if it's worth it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's up to you. I guess removing Gradle would be easy in this setup too.

blakeli0 added 3 commits June 2, 2022 13:55
…and maven folder from META-INF folder in the maven built jar. Change the phase of format plugin from verify to validate to match the gradle behavior.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 4, 2022

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

@meltsufin
Copy link
Copy Markdown
Member Author

LGTM! Thanks for taking this PR across the finish line.

Copy link
Copy Markdown
Contributor

@vam-google vam-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it looks good, but there is a big concern about dependencies consistency across different build systems and if we have any strategy for that.

Comment thread pom.xml
<dependency>
<groupId>com.google.api</groupId>
<artifactId>api-common</artifactId>
<version>2.1.5</version>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes inconsistent which versions are used for gradle+bazel and which for maven. I understand that this is a good first step, but for this to work properly, we need some mechanism for a single source of truth for those version numbers between different build systems (now it is dependencies.properties).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interim state. The plan is for the Gradle build to go away. We can keep the versions in sync with Bazel manually. Ultimately, we need to figure out if we can just rely on a single build system. Is the Bazel build used for self-service? I'm not sure why we absolutely need it.

Copy link
Copy Markdown
Contributor

@blakeli0 blakeli0 Jun 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Mike as well that eventually we want to be on a single build system, and I checked gapic-generator-java and googleapis that the bazel stuff in gax-java are only used for loading dependencies, which I think can be replaced completely by bazel targets in gapic-generator-java. My vision is that the pom.xml in the GAPIC generator mono repo will be the source of truth for dependencies, and I don't think we can get rid of dependencies.properties completely before we move gax-java to the mono repo.

In short, this is the plan:

  1. Add maven build(This PR).
  2. Replicate all gradle features(CI, release etc.) in maven and remove gradle build.
  3. Release with Maven dependencies. Before each gax-java release, we may have to manually sync dependency.properties to keep things in sync for the time being.
  4. Move gax-java to the GAPIC mono repo so that it shares dependency management with gapic-generator-java.
  5. Do some changes accordingly in the mono repo so that the client library generation depends on the root pom.xml for loading dependencies(This part is not well designed yet but I believe it can be done).

We are probably not going to change the bazel surface in gapic-generator-java(like java_gapic_library), so that all the client libraries and self service can still be generated seamlessly, but we will change how the dependencies are loaded.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@meltsufin Every single automatically generated PR that you currently getting from owlbot is created using bazel build (and that relies on gax dependencies.properties). It is also used for self-service, that is correct.

And it is also very useful for development, though it may look useless on release step. For any gapic-gen/gax development work it s extremely useful. For example, with the REST transport work, I can simply plug in gax and gapic-generator in build and generate, compile and run all unit tests for all APIs in both transport (27,000 tests in one run on one maching by simply replacing http_archive to local_repository). It is also very easy to do and repeat it after every change in the generator (and due to caching, the run is also fast). I literally have no idea how else I would test and fix this whole thing on googleapis scale without this bazel build.

I'm afraid that we are on a path of fixing problems in release workflow by creating severe problems in development workflow. The reason why the autogenerated PRs produce working and compilable code and Java, for example, does not suffer from the same problems as Python releases suffer (broken code being generated), is precisely due to gax and gapic-generator being tightly integrated into the bazel build.

Copy link
Copy Markdown
Member Author

@meltsufin meltsufin Jun 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We fully intend to keep dependencies.properties up to date and we have no plans to break the Bazel build as part of the migration to Maven. If we are actually breaking any of the existing workflows, please let us know. However, this PR is not doing that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can simply plug in gax and gapic-generator in build and generate, compile and run all unit tests for all APIs in both transport

This is very interesting, can you please share the script you are using? I can make sure we are not breaking the script or create a similar experience with maven.

The reason why the autogenerated PRs produce working and compilable code and Java, for example, does not suffer from the same problems as Python releases suffer (broken code being generated), is precisely due to gax and gapic-generator being tightly integrated into the bazel build.

Can you please elaborate the example? How bazel build can help prevent generating broken code? I thought it's mostly the code logic(like AST stuff) in the generator itself not the build system.

Copy link
Copy Markdown
Contributor

@vam-google vam-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but we need a good strategy for dependencies management and supporting both maven and bazel builds.

@meltsufin meltsufin merged commit 95c4770 into main Jun 9, 2022
@meltsufin meltsufin deleted the maven branch June 9, 2022 18:17
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla: yes This human has signed the Contributor License Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants