Possible to define gradle extension properties that are not inherited by subprojects? - gradle

I want to use allprojects/afterEvaluate in a multiproject build to do something on each project based on properties that it has set. Is there a way to set properties per project in a way that is not inherited by subprojects?
ext.myProp works if I'm only concerned with leaf projects. But if a parent needs to set that property too, I can't find a way to distinguish which project it was set on. The multiproject guide explains that properties are (begrudgingly) inherited.
This mechanism reminds me of prototypal inheritance in JavaScript. Does gradle have a hasOwnProperty equivalent?

I dug some more and found that while there's no general way to isolate which of the several delegated scopes a project property is coming from, if you're specifically looking for an ext property, then there is a has method you can check on a specific project's ext container that does not delegate (at least not to the extent that hasProperty does).
So proj.ext.has('myProp') will be true if a value has been assigned to that project directly.
An important caveat is that properties set via -P or gradle.properties appear to be replicated into the extension containers of all projects automatically, and I don't think there's a way to distinguish that. Extension or task properties might be easier to isolate since they're not inherited, but they're less ad hoc.

Related

IntelliJ + Gradle Multiproject: How to tell how the target source set is called?

we are currently checking, whether we can switch from Eclipse to IntelliJ as an IDE.
In this project we are using gradle multi projects whose structure looks something like this:
Project
|-ProjectA
|-ProjectAImpl
|-main*
|-ProjectATest
|-test*
|-ProjectB
|-ProjectBImpl
|-main*
|-ProjectBTest
|-test*
= Source set or in IntelliJ it seems a module.
The ProjectBTest has a dependency to ProjectATest, which is configured as
compile project(":ProjectA:ProjectATest")
This always worked properly with Eclipse but in IntelliJ I'm having the problem, that the ProjectBTest is configured such, that it is looking for a module named "Project.ProjectA.ProjectATest.main", instead of "Project.ProjectA.ProjectATest.test"
This module can obviously not be found, leading to a lot of compiler errors.
Can maybe somebody give me a hint how I can tell IntelliJ or gradle here to take the proper module?
Thank you very much.
This is standard Gradle functionality. Unless you have other Gradle customizations (like feature variants or changing the source directories for a source set), project dependencies will naturally target the main source set.
There are several ways to solve this, but two primary ones that stand out to me:
Use Gradle's Java test fixtures.
The "test" source set is not naturally inheritable in any way in Gradle. There is no built-in consumable configuration that provides test classes to downstream projects. However, Java test fixtures allow you to use a separate testFixtures source set which is shareable. To do this, you would do the following:
Add the java-test-fixtures plugin to all projects which need to produce shared test sources
Move your shared test sources to <project directory>/src/testFixtures (ideally this would include as few actual test classes as possible, but rather just shareable test logic instead)
Change your dependency references to point to the upstream project(s)' test fixtures artifact: testImplementation(testFixtures(project(":ProjectA:ProjectATest"))
Register a tests configuration which includes the test classes as an output.
project.configurations.register("tests") {
extendsFrom(project.configurations[JavaPlugin.TEST_RUNTIME_CONFIGURATION_NAME])
}
tasks.register("testJar", Jar::class) {
classifier.set("test-classes")
from(project.the<SourceSetContainer>()[SourceSet.TEST_SOURCE_SET_NAME].output)
}
project.artifacts.add("tests", project.tasks.named("testJar"))
Downstream projects:
dependencies {
compile(project(":ProjectA:ProjectATest", "tests"))
}
None of the above code is tested. It may require some adjustments.
Java test fixtures are a supported way to produce shareable test sources, so they should be preferred, but the tests configuration may be quicker to implement, depending on your use case.

How does the Intellij Idea change the scope of dependencies?

I found this function in Project Structure in Intellij Idea:
It seems that this UI can manually change the scope of the dependencies. However I found that it does not change the pom.xml file, so how can it manages to change the scope?
Besides, what is the corresponding operation in Linux?
That particular view is geared more towards projects which lack dependency management from something like Maven or Gradle, and will not interfere with either. In fact, this particular listing is built based on those dependencies and exclusions.
If you want to change the scope of your dependencies in a project that already contains Maven and Gradle, look to do so in their respective files (pom.xml / build.gradle).

Safe project-agnostic way to specify JDK for Gradle?

As we know, it is possible to specify JDK path in gradle.properties at the project level, in property: org.gradle.java.home. However, this file may be under VCS (i.e. git). Users may have different paths for JDK, hence we can't commit this file.
Is there any safe, project-agnostic way to specify this property, so it works for users and different projects? Maybe using some environment property?
EDIT
I am looking a way to specify JDK per project but not be forced to commit this information.
Your wording is a little confusing since if you place the property in a non-VCS location (like an environment variable) it's not really "cross-user" since every user will have to configure this explicitly.
If you simply want to set properties in a way that is outside of version control there are several ways to do this.
Use an environment variable, like you mention. Simply prefix it with ORG_GRADLE_PROJECT_. For example, ORG_GRADLE_PROJECT_javahome would then be available in your build script as javahome.
Place the properties in a file located at USER_HOME/.gradle/gradle.properties.
Specify the property via the CLI with the -P option.
Use something like the Gradle properties plugin to place additional properties in a separate file ignored by VCS.

Create a maven project to be used as a jar library in another project

I want that a maven project can be used as a black box jar. This is needed because second project was born its way, and I don't want to integrate its code by hand. So the best way is that this project is going to save it's data on db, but it should use a service offered by the "wrapper" project to save them.
The idea is simple, the secondary project can expose just a method to which I will pass the service that offers the save method as a parameter.
The secondary project should not have configuration files, but should rely on the father application's properties.
Any idea to do this fast and almsot good? Thanks for any suggestion.
EDIT 2013/03/07: The idea behind this is that the second project should generate a classic jar library that looks a properties file into the classpath of the host project. Something like Quartz/Spring/... you import jar and you provide the properties file.
I just defined some classes to load properties from the classpath, and some interfaces to make the two projects interact.
In pom.xml of the parent project I imported the child project excluding it's dependencies to avoid conflicts.
It was a pretty easy task at the end.

Gradle build profiles for i18n and PrettyFaces

Is it possible to define different profiles in gradle? I've written a WebApplication and i want to deploy it with the production settings. Furthermore my app is using PrettyFaces. Since i'm using different two languages i also want a language sepcific build. Here is my use case:
production/en, production/ru
The build with a specific language indicates which db to use and which language is the default one. Furthermore the urls (PrettyFaces) are different files. In my opinion i need a different web.xml and a different pretty-faces.xml ?
Thanks in advance!
Here are some options:
Create a task for each setting, so you can do gradle buildEn or gradle buildRu to differentiate the builds. You can write each task manually, or dynamically generate them.
Pass a project property to your build, e.g. gradle build -Plang=ru. Then you can reference lang from your task and do the logic there. Project properties can also be specified in gradle.properties file if you don't like passing the property every time. Anyway check this out.
Probably not what you want, but you can add behaviour to your build if a certain task is present in the build graph (in the example additional logic is executed when graph contains release task).
Good luck

Resources