I am migrating to Gradle as my build tool for a Java project.
My main project (A) has a dependency on other projects (B and C).
At the moment each of these projects are in CVS individually and when I want to compile A I have to check out A, make a subdir in A called B in which I check out B. Same goes for C.
Im going to migrate to repository manager (nexus) in which B and C can be published to. When this happens, module A can just have a dependency on B and C which it can get from nexus.
However, the difficulty arises if I do not want to publish B and C (for testing purposes) and I want to build A with my latest code from B and C without committing it to nexus.
My initial thoughts on this are to build the jar for B and C and pull it into the "lib" folder for A. However Im sure there is a better way.
In maven I could do a "mvn clean install" which would install B and C in my local maven cache. A would then look there for the appropriate jars.
But Im still not sure this is the best way. I had a look into gradle subprojects but I dont fully understand them. How would the submodules handle in an SCM (would I also need to use git submodules?)
I would appreciate some guidance as to best practices for this situation.
Thanks
EDIT:
The reply below from Vyacheslav Shvets is the most accurate answer I have found so far.
There is one other way of switching out a gradle project dependency with maven-style dependency. This involves dependency substitution as described at https://docs.gradle.org/current/userguide/dependency_management.html#sec:project_to_module_substitution
This can be wrapped around a:
if(project.hasProperty("someSwitch")){
configurations.all{.....
....
}
}
Usage of this method would be:
gradle build -Psomeswitch
The old (classical) way
The same approach as for Maven:
Apply maven plugin on project B
Run gradle clean install on project B
Actually, you don't have to clean every time if your build correctly uses task inputs and outputs
In project A, add mavenLocal() repository and run build
The new way (experemental) - Composite build
A composite build allows you to combine multiple Gradle builds and replace external binary dependencies with project dependencies as if you were using a single multi-project build
https://docs.gradle.org/2.13/release-notes
This is not fully available yet. Since 2.13 you can use it via Tooling API (for example, Buildship 2.0 plugin for Eclipse IDE). The common usage will be available in 3.1, but you can try it now using nightly builds of 3.1
If you download and execute demo build from Gradle's github with latest nightly build you will see the following:
$ gradle build
[composite-build] Configuring build: C:\Users\Shvets\repos\composite\projectB
[composite-build] Configuring build: C:\Users\Shvets\repos\composite\projectC
:compileJava
:projectB:b1:compileJava
:projectB:b1:processResources UP-TO-DATE
:projectB:b1:classes
:projectB:b1:jar
:projectB:b2:compileJava
:projectC:compileJava
:projectC:processResources UP-TO-DATE
:projectC:classes
:projectC:jar
:projectB:b2:processResources UP-TO-DATE
:projectB:b2:classes
:projectB:b2:jar
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
BUILD SUCCESSFUL
Total time: 4.497 secs
For deep understanding, see demo video of both approaches.
Related
I have a Maven package I've hosted on GitHub package registry.
Whenever I make an update to the package I run mvn deploy to publish the changes, but if I simply run gradle install on the dependent application it doesn't seem to install the latest version of the package
(not sure if settings.xml is relevant to this question so I removed it, but it can be seen at the link to my previous question).
I had a similar issue with using the latest snapshot version of the package in another dependent, which was using Maven as the package manager/build tool instead of Gradle. That was resolved by checking a box to "always update snapshots" in Maven settings. I have checked the box in this project as well, but it doesn't seem to resolve the issue now.
What I have tried:
Invalidating cache and restarting IntelliJ
reimporting all gradle projects
deleting the dependency from my build.gradle and then reimporting projects and install, followed by adding it back and reimporting all projects and install
running ./gradlew build -x test --refresh-dependencies (test disabled because they were failing)
This is the log after I run gradle install:
4:07:08 PM: Executing task 'install'...
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :jar SKIPPED
> Task :install
BUILD SUCCESSFUL in 2s
3 actionable tasks: 1 executed, 2 up-to-date
4:07:10 PM: Task execution finished 'install'.
In my build.gradle I use the following syntax for my dependency (under dependencies):
compile('com.companyname:packagename:0.0.3-SNAPSHOT')
and this is what I have under repositories:
maven {
url "https://maven.pkg.github.com/companyname/packagename"
credentials {
username "TaylorBurke"
password "*****************"
}
}
Not sure if it is related, but when I go into my Maven settings to try and update the repository I get this error:
So there it is, I think I've included everything. Is it a configuration issue with Maven, Gradle, or IntelliJ?
Edit: because it has been suggested to close this question I am pointing out that the link to the other question does not address installing with Gradle, it simply addresses an error after running mvn deploy. I have already deployed the new package successfully and can get the new version from my other application. My problem is specific to gradle install. Even though the accepted answer mentions he had a similar problem using Gradle (but my problem is not with deploying either) he goes on to say that snapshot versions would provide a solution to the problem expressed, and I am already using a snapshot version in this package. That question is clearly quite different and not at all related to mine.
You have tried quite a few things with IntelliJ, but the problem happens when you run the build from the command line (./gradlew build). That should be a good indication that the problem is not with IntelliJ.
By default, Gradle will cache changing dependencies (e.g. SNAPHOST dependencies) for 24 hours. During that time, it will not ask the repository for newer versions. So if you publish a new version under the same name, Gradle might not see it for another day.
Using the --refresh-dependencies option will make Gradle ignore the cache, and thereby download the artifacts again.
You can also change the cache retention period through a ResolutionStrategy. You can also configure it to always check for changed dependencies if you like.
Read more about dynamic dependencies here: https://docs.gradle.org/current/userguide/dynamic_versions.html
If you are curious, the Gradle artifact cache is by default located in $USER_HOME/.gradle/caches/modules-2/files-2.1 (the numbers may be different depending on which version of Gradle you are using). This cache is unrelated to the one you mention in IntelliJ.
Also, the authentication error in the IntelliJ maven repository browser is because your credentials are in the Gradle configuration and not in IntelliJ. So this is also unrelated to Gradle.
I have a Gradle build working for a bunch of Java and C sub-modules. I would like to add several sub-modules which are incoming from existing code base and are already setup as Maven builds. Is there a way for Gradle to pickup the Maven sub-modules as part of the parent build?
It seems, there is no native way to run some maven goal within gradle build script. By the way, it is possible to run a maven goal, just providig a custom task of Exec type, which will run a maven build as a command line process. You can read more about this task type here.
Furthermore, it is even possible to provide the maven goal artifacts as dependencies for the gradle project, after you build them from custom gradle task and specify the file-dependency with builtBy property. You can read about it in the official user guide.
I am playing with the example project at:
https://github.com/bmuschko/gradle-in-action-source/tree/master/chapter06/listing_06_03-todo-project-dependencies
After I run the jettyRun task at the "web" subproject I got:
:model:compileJava UP-TO-DATE
:model:processResources UP-TO-DATE
:model:classes UP-TO-DATE
:model:jar UP-TO-DATE
:repository:compileJava UP-TO-DATE
:repository:processResources UP-TO-DATE
:repository:classes UP-TO-DATE
:repository:jar UP-TO-DATE
:web:compileJava UP-TO-DATE
:web:processResources UP-TO-DATE
:web:classes UP-TO-DATE
:web:jettyRun
However in the gradle it only says "web" project depends on "repository" and "repository" depends on "model" which are project level dependencies. So when you run "jettyRun" how does gradle know which tasks to run in the subproject?
When you declare that one project is dependent on another project this means that the first project is dependent on the artifact of the other project. In the java plug-in this artifact is produced by the jar task.
I'm making a case for moving our builds from Maven to Gradle. Below are a few of the Maven command-line options my team finds useful. What are the Gradle equivalent choices?
-am,--also-makeIf project list is specified, also build projects required by the list
-amd,--also-make-dependentsIf project list is specified, also build projects that depend on projects on the list
-o,--offline Work offline
-pl,--projects Build specified reactor projects
instead of all projects
-rf,--resume-from Resume reactor from specified project
Maven Examples:
I only want to build the sub-project I'm working on and its dependencies.
mvn install --also-makeIf --projects :my-sub-project
After fixing an build issue, I want to start the build from the point of failure.
mvn install --resume-from :my-sub-project
I don't want to download external dependencies from an central repo.
mvn install --offline
Here are some rough analogues:
-am: buildNeeded (This triggers a full build of all upstream projects; building those parts of upstream projects that are required to fulfill the command at hand is automatic in Gradle.)
-amd: buildDependents
-o: --offline
-pl: :subproject1:build :subproject2:build
-rf: No direct analogue (not reliable, wouldn't work for parallel builds, etc.), but Gradle's incremental build will get you to the "resume point" quickly.
Note that Gradle's core concepts differ significantly from Maven's. To give one example, in Gradle build order is solely determined by task relationships, and there is no such concept as an execution dependency between projects. Due to these differences, some Maven features aren't necessary or useful in Gradle, some you get for free, and some come in a different form.
According to http://www.gradle.org/docs/current/userguide/java_plugin.html and Figure 23.1, the jar task depends on the classes task.
In my scenario I have a multi project containing three projects - ProjectCommon, ProjectApp1 and ProjectApp2. ProjectApp1 depends on ProjectCommon, ProjectApp2 depends on ProjectCommon.
Here's the build.gradle of ProjectApp1 and ProjectApp2:
dependencies {
compile project(':ProjectCommon')
}
I wan't to build now only ProjectApp1, using
$ gradle :ProjectApp1:build
The output shows, that e.g. test and check of ProjectCommon is not executed:
:ProjectCommon:compileJava UP-TO-DATE
:ProjectCommon:processResources UP-TO-DATE
:ProjectCommon:classes UP-TO-DATE
:ProjectCommon:jar
:ProjectApp1:compileJava UP-TO-DATE
:ProjectApp1:processResources UP-TO-DATE
:ProjectApp1:classes UP-TO-DATE
:ProjectApp1:jar
:ProjectApp1:assemble
:ProjectApp1:compileTestJava UP-TO-DATE
:ProjectApp1:processTestResources UP-TO-DATE
:ProjectApp1:testClasses UP-TO-DATE
:ProjectApp1:test
:ProjectApp1:check
:ProjectApp1:build
BUILD SUCCESSFUL
Total time: 4.633 secs
ProjectApp1 is now built without knowing if ProjectCommon is really fine...
(of course I could do gradle :ProjectCommon:build :ProjectApp1:build instead to avoid this).
Wouldn't it be "safer", if jar would generally depend on check?
Or am I doing something wrong with the dependencies and I better should use in build.gradle of ProjectApp1 and ProjectApp2:
dependsOn(':ProjectCommon')
(which gives a deprecation warning)
The Gradle Java plugin uses project compile dependencies only for certain tasks, the check task is not one of them.
In ProjectApp1, add
check {
dependsOn ':ProjectCommon:check'
}
The jar task doesn't depend on the check task because they have no semantic dependency - the latter doesn't produce anything that the former consumes.
Wouldn't it be "safer", if jar would generally depend on check?
It would cost time without being any safer in some cases (e.g. Java compilation), and would not be safe enough in other cases (e.g. when publishing related projects, where you want all projects to be tested before publishing any of them). With Gradle, you can tailor the behavior to the particular needs.
The Java plugin provides a buildNeeded task, which fully builds upstream projects before building downstream projects. In a similar fashion, it would be possible to make Gradle test upstream projects before using their outputs in downstream projects. The question is how useful this would be.