Should Gradle's buildSrc folder be committed to source code repo? - gradle

Sorry for the naive question. I am new to Gradle.
Conceptually, it looks like we should commit the buildSrc folder to repo but I see some temp files as well in that folder, which led me to ask this question - Should we commit the entire buildSrc folder to the repo?

buildSrc can be used to abstract imperative logic. In other words, declutter your main Gradle build files.
https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources
The buildSrc folder is basically another Gradle project. So things you would normally ignored for a Gradle project, should also be ignored from the buildSrc project.
If you have logic defined in buildSrc that is required for your project, then yes it should be committed. If not, then that folder should be deleted entirely to avoid Gradle attempting to automatically build it.

Related

Which project files contain information that this is a maven project

There is a project on Spring. If I clone it from GitHub, then open it in IDEA, then it understands that this is a maven project, i.e. it highlights all the project folders with the right color - java, resources, etc. And if I just copy the source files of the project to another directory with all the folders, then IDEA does not perceive it as a maven project, but simply as a set of folders.
But on Github I don't see any other files except the source. And then where is all this information about the structure of the project stored?
That is, what files do I still need to copy so that the IDE recreates the entire folder structure as in the original project?
Usually, if it is a maven project, we use a pom.xml file. In case of gradle, we use build.gradle file.
Whenever a spring project is build, it reads one these files to get all dependancies.

When working on a project and one of it's dependency in parallel how to load it from the file system

I'm working on a java dependency that I publish on GitLab via gradle. In parallel I also work on some projects dependent of it.
When I need to do a change in the parent I have to wait for my CI/CD to be over before I can keep developing the childs. There is most certainly a way to tell gradle 'check there before online' but all I've found until now is to do that with local jar but not raw source files.
I tried most of the things in How to make Gradle repository point to local directory but without success as gradle is excepting a maven repo structure with some pom.xml files.
So how could I achieve something like this ?
After rethinking the problem and studying a bit more gradle/maven I found the solution.
Just execute the task gradle publishToMavenLocal in the parent project. Then in the dependent project add mavenLocal() to your list of repo. That's all you have to do.
I'm still looking for a way to make gradle build and publish the parent automatically on the child's build. But it's already much more practical like this?

How can I add gradle project dependencies without modifying settings.gradle

Background
(Please keep in mind I've simplified the problem for purposes of discussion here)
I've got a set of applications and dependent libraries, something like this (each with a src/ directory and build.gradle):
appa/
appb/
libx/
liby/
libz/
In build.gradle, the dependencies are currently declared like this:
appa/build.gradle:
compile "com.asdf:libx:1.0"
compile "com.asdf:liby:1.0"
appb/build.gradle:
compile "com.asdf:liby:1.0"
liby/build.gradle:
compile "com.asdf:libz:1.0"
What problem am I trying to solve
Say I'm working on appa, and I need to make changes to libx. I need to do multiple steps:
Pull libx from source control and make changes locally
Rebuild and push changes to some repo (not prod!)
Rebuild appa (pulling the recently updated libx from repo)
If my testing reveals a bug in libx, I've got to repeat that over again.
This is super-annoying when working in IDEs like Eclipse, where even though my projects are logically using other projects, I've got to still use the artifacts as dependencies.
Wouldn't it be great if I can just pull the project locally, and projects that logically depend on it will automatically use the source project instead of artifact for building?
What I've done so far
I've written a small gradle plugin (referenced in each project's build.gradle) that identifies com.asdf dependencies, and uses dependency substitution to replace the artifact dependency with a project dependency if that project exists locally.
configurations.all {
resolutionStrategy.dependencySubstitution {
all { DependencySubstitution dependency ->
if (dependency.requested instanceof ModuleComponentSelector && dependency.requested.group == 'com.asdf') {
def targetProject = findProject(":${dependency.requested.module}")
if (targetProject != null) {
dependency.useTarget targetProject
}
}
}
}
}
Yay! With a few modifications to settings.gradle (see below), I've accomplished my goal... Except...
Where I'm stuck
I need to modify settings.gradle to include lines like this for every dependency (otherwise findProject doesn't resolve the dependent project during build):
include ':libx'
project(':libx').projectDir = new File(settingsDir, '../libx')
While it's possible to go through all the settings.gradle files and do this (I've done it for a handful as my proof-of-concept), it's ugly, repetitive, and is logically the same information that is being passed to compile arguments for the build.gradle dependencies.
It's also error-prone when someone adds a new dependency but doesn't update settings.gradle, or introduces a typo between them.
I've also tried making settings.gradle just define projects for all directories it finds at that level, but then building any project turns into a mega-build of all projects.
(I've tried several other things, but my question is getting long in the tooth already)
My question
What's a better way to do this, without duplicating information between settings.gradle and build.gradle? I want to make it so adding new dependencies is still just as easy as adding the compile reference in build.gradle, without touching settings.gradle...
I'm still rather new to groovy/gradle, so maybe I'm missing something that's obvious to the more experienced gradle master?
I believe your use-case is the motivation for Composite Builds.
I have a demo here, which writes to a jars folder as a mock publishing of artifacts. Be sure to check-out the README.md as the demo is a mini-laboratory for trying out the use-case before and after composite builds.
In the demo mainBuild is appa; utils is libx. The key syntax in mainBuild/settings.gradle (here) is:
includeBuild '../utils'
This tells Gradle to use the local codebase instead of the published artifact. Of course, one would not commit this line to source-control.

Gradle search local maven or gradle repository

I am using gradle and its local repository is at \.gradle\caches\modules-2\files-2.1 which has all the downloaded jar but not my modules.Is there any specific place I should be searching it for ?
I need it as is in settings.gradle I am having a dependency path specified like :
include ':model'
project (':model').projectDir = new File(settingsDir, './model')
in a new project. Also I don't want to give path in that way because if I have a dependency from multiple projects on this project then mentioning path will be difficult and weird.
How can I make gradle search it from local maven or gradle repositories.
I'm still not sure what is being asked here, and I suspect there is some confusion over how multi-project builds work. So I'm going to attempt to provide a general-purpose answer.
The first question you need to answer is whether you're interested in dependencies between projects that are part of the same build — as in part of a multi-project build — or in separate builds.
Project dependencies (multi-project builds)
Project dependencies are covered in the user manual and only apply to multi-project builds. They use a logical path, using colons as 'path' separators, to specify the location of the target module, like so:
dependencies {
implementation project(":model")
}
At this point, Gradle needs to know where ":model" exists on the file system. There's no getting around that. You have a few options:
Follow the convention of directory structure matching the logical path structure, i.e. have a MyBigProject/model directory containing the ":model" child project
Specify the file path of ":model" in settings.gradle, e.g. with project(":model").projectDir = new File(rootDir, "unusual/path/to/model")
Automate the discovery of projects
The most common approach is the first one. The second is not unusual, particularly if you want to put child projects into a separate directory, like subprojects — something the build of Gradle itself does. I haven't seen the last option done, and I don't know whether it runs into problems.
For the sake of completeness, and at your own risk if you use something like it, here's an example of automatic discovery of projects in the settings.gradle file:
rootDir.eachDir { File dir ->
if ("build.gradle" in dir.listFiles()*.name) {
include dir.name
}
}
This fragment basically looks for directories within the root project folder that have a build.gradle file in them and adds them as child projects. The child projects' directory names become the projects' names.
It's not particularly clever, and you should really use different names for the build files, but it may give you some ideas to work with.
Non-project dependencies
As with project dependencies, Gradle needs to know where to get the corresponding JAR or other form of artifact for a specified module. You normally specify Maven Central or something similar for this, but there are other useful, but less common, options:
Copy a project's artifacts into the local Maven repository — both the Maven Plugin and Maven Publish Plugin support this
Publish to a Maven-compatible repository using a file:// URL rather than an HTTP/HTTPS one, which protects your projects from corruption of Maven Local
Worth noting is that Gradle supports composite builds that allow you to substitute a normal dependency with (effectively) a project dependency from another build. So if model were part of a separate build but you had the source code and build locally, you could make changes and immediately test them in another build's project without going through the whole "install" intermediate step that's common in the Maven world (and Gradle pre-composite-builds).
Hope all this makes sense.

How to copy file from buildSrc into main build

I have a custom task in buildSrc that, among other things, I want to copy a file from buildSrc into the main build. However, when actually running the custom task, the buildSrc project appears to be pretty much invisible, e.g. I can't reference it as a project. How does one refer to and copy a file from the buildSrc project to the main project?
You are correct that the main projects can not see buildSrc. buildSrc is run as a separate project.
The outputs of buildSrc project are put onto the classpath of the main Gradle projects.
One solution then is to generate a Jar artifact with all of your resources, and then use the classpath resource loader in the main projects to access the files you need.
A second option might be to just manually hard code the buildSrc path into your main projects. Of course you can not access it as project(:buildSrc') because it is not valid. The better option is to use file("${rootProject}/buildSrc/") (Not tested).

Resources