Utilize ant in settings.gradle during configuration phase - gradle

I want to apply a shared gradle file to my projects settings.gradle. The shared file is located in a jar which must be downloaded and extracted during the configuration phase. This is because is applies a plugin which must be applied in the configuration phase. I found this related question: How to share a common build.gradle via a repository? My preferred way is described in this answer: https://stackoverflow.com/a/39228611/987860
However, this appears to be working in build.gradle only. I tried to move the buildscript block to my settings.gradle.
settings.gradle
buildscript {
ext {
dependencyVersion = '0.1.2'
}
repositories {
maven {
credentials {
username 'user'
password 'password'
}
url 'https://my-private-maven-repo.com'
}
}
dependencies {
classpath "my.group:myartifact:$dependencyVersion"
}
dependencies {
def gradleScripts = new File(rootDir, '/build/gradle')
delete gradleScripts
def jars = configurations.classpath.files as List<File>
ant.unjar(src: jars.find { it.name.matches '.*myartifact.*' }, dest: gradleScripts) {
patternset {
include(name:'*.gradle')
}
}
}
}
apply from: new File(rootDir, '/build/gradle/myscript.gradle')
But this results in the following exception:
FAILURE: Build failed with an exception.
* Where:
Settings file 'settings.gradle' line: 24
* What went wrong:
A problem occurred evaluating settings 'journal'.
> Could not get unknown property 'ant' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 0.019 secs
Could not get unknown property 'ant' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
Is there any way to utilize ant int the confiuration phase before my settings.gradle is evaluated? I need to have the dependency downloaded and extractet before the to-be-downloaded file gets applied.

This is a really unusual way to do things. I'd really recommend not doing what you're trying to do because it'll make your build much slower than it should be. You're deleting build/gradle and extracting the contents of the plugin's jar on every build.
Everything inside a build.gradle (or settings.gradle) can be put into a plugin and distributed that way. You already have a jar that needs to be downloaded, so converting myscript.gradle into a plugin is very easy to roughly convert.
Put this in src/main/groovy/some/package/MyPlugin.groovy in the project that's producing the plugin jar already:
package some.package
import org.gradle.api.*
class MyPlugin implements Plugin<Project> {
void apply(Project project) {
project.with {
// contents of script
}
}
}
For plugins applied to settings.gradle:
package some.package
import org.gradle.api.*
class MyPlugin implements Plugin<Settings> {
void apply(Settings settings) {
settings.with {
// contents of script
}
}
}
Then you can just add the dependency to the plugin and use apply plugin: some.package.MyPlugin.
There are a lot of other advantages of developing/distributing plugins in this way. You can find more information on plugin development in the Gradle Guides.
Alternatively, if you absolutely must keep the separate .gradle script. If you can serve it separately (outside of the jar), you can do:
apply from: "http://example.com/some/url/myscript.gradle"
The downside with this is that it'll download the file on every build (this is fixed in Gradle 4.2).

Related

How can I configure a Gradle plugin externally to the build?

How can I apply a plugin configuration to a Gradle project externally of the build so that it does not get included in Git source control?
Details
I have a Gradle project which uses the gradle-git-properties plugin to generate a git.properties file based on the project's Git details.
plugins {
id 'java'
id 'com.gorylenko.gradle-git-properties'
}
// Rest of build.gradle goes here
Additionally, I'm checking out my project to multiple locations locally using git working trees. However, projects using gradle-git-properties fail when run from a linked working tree, per gradle-git-properties#14.
$ ./gradlew generateGitProperties
> Task :subproject:generateGitProperties FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':subproject:generateGitProperties'.
> Error while evaluating property 'generatedProperties' of task ':subproject:generateGitProperties'
> gradlegitproperties.org.eclipse.jgit.errors.RepositoryNotFoundException: repository not found: /Users/Me/my-project/.git/worktrees/my-project
I have been using a plugin configuration to work around the issue, allowing the project to build successfully when run from the linked working tree:
gitProperties {
Path dotGitPath = rootProject.layout.projectDirectory.asFile.toPath().resolve(".git")
if (Files.isRegularFile(dotGitPath)) {
Files.lines(dotGitPath).withCloseable { ditGitFileLines ->
dotGitDirectory = ditGitFileLines
.filter { it.startsWith("gitdir: ") }
.map { it.substring('gitdir: '.length(), it.lastIndexOf('/.git/')) }
.map { project.objects.directoryProperty().convention(project.layout.projectDirectory.dir(it)) }
.findFirst()
.orElse(project.objects.directoryProperty().convention(project.layout.projectDirectory.dir(".git")))
}
}
}
The problem with this solution is that it requires modifying the build file. This is a shared repository, and I'm the only person accessing it who uses multiple git working trees. Therefore, I don't want to include this workaround in the build itself.
Is there a way I can automatically apply this plugin configuration externally to the build file or any other file that would be committed with the project?
A Gradle initialization script can be used, putting the plugin configuration into an external file.
There are several ways to use an init script:
Specify a file on the command line. The command line option is -I or --init-script followed by the path to the script. […]
Put a file called init.gradle (or init.gradle.kts for Kotlin) in the USER_HOME/.gradle/ directory.
Put a file that ends with .gradle (or .init.gradle.kts for Kotlin) in the USER_HOME/.gradle/init.d/ directory.
Put a file that ends with .gradle (or .init.gradle.kts for Kotlin) in the GRADLE_HOME/init.d/ directory, in the Gradle distribution. […]
~/.gradle/init.d/git-worktree-fix.gradle
import java.nio.file.Files
import java.nio.file.Path
allprojects {
plugins.withId('com.gorylenko.gradle-git-properties') {
gitProperties {
Path dotGitPath = rootProject.layout.projectDirectory.asFile.toPath().resolve(".git")
if (Files.isRegularFile(dotGitPath)) {
Files.lines(dotGitPath).withCloseable { ditGitFileLines ->
dotGitDirectory = ditGitFileLines
.filter { it.startsWith("gitdir: ") }
.map { it.substring('gitdir: '.length(), it.lastIndexOf('/.git/')) }
.map { project.objects.directoryProperty().convention(project.layout.projectDirectory.dir(it)) }
.findFirst()
.orElse(project.objects.directoryProperty().convention(project.layout.projectDirectory.dir(".git")))
}
}
}
}
}
The gitProperties configuration is wrapped in a plugins.withId('com.gorylenko.gradle-git-properties') check, since otherwise projects not using the gradle-git-properties plugin would fail when using this script.

Unable to resolve a plugin using the new plugin mechanism in Gradle

While trying to upgrade some of our scripts to Gradle 4.0.1 on of the plugins we are using is failing and I thought of fixing that plugin first. The plugin is a third party open source project.
So I have cloned the project and tried to compile it. However it fails with following message:
c:\source\gradle-xld-plugin>gradlew build
FAILURE: Build failed with an exception.
* Where:
Build file 'C:\source\gradle-xld-plugin\build.gradle' line: 2
* What went wrong:
Plugin [id: 'com.gradle.plugin-publish', version: '0.9.7'] was not found in
any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- maven(https://artifactory/java-v) (Could not resolve plugin artifact 'com.gradle.plugin-publish:com.gradle.plugin-publish.gradle.plugin:0.9.7')
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --
debug option to get more log output.
BUILD FAILED in 0s
The build.gradle script for the plugin starts like this:
plugins {
id "com.gradle.plugin-publish" version "0.9.7"
id "com.github.hierynomus.license" version "0.11.0"
id 'nebula.nebula-release' version '4.0.1'
id "com.jfrog.bintray" version "1.7.3"
}
In addition to this the company policy dictates we have to go through an internal artifactory server, so following has been added to the settings.gradle file:
pluginManagement {
repositories {
maven {
url "https://artifactory/java-v"
}
}
}
The jar file exists at following location: https://artifactory/java-v/com/gradle/publish/plugin-publish-plugin/0.9.7/plugin-publish-plugin-0.9.7.jar
but when I look at the error message I am a little puzzled that it says that it cannot find com.gradle.plugin-publish:com.gradle.plugin-publish.gradle.plugin:0.9.7.
It seems to have suffixed the id with .gradle.plugin.
Does anyone know whether I am looking at the wrong location or how come it is suffixing the id with .gradle.plugin. And shouldn't it look at a location that has the GAV like this: com.gradle.plugin-publish:com.gradle.plugin-publish:0.9.7?
And does anyone know about how the resolution mechanism for the new plugin mechanism in Gradle works.
Thanks in advance
Edit
Thanks to Mateusz Chrzaszcz I was able to progress.
The only caveat I have with the solution is that it seems like a workaround rather than a solution. But it works!
In addition to his solution you had to resolve the plugins. I was able to hack my way to actually resolve the appropriate names.
In order to do so one has to do as follows:
In a webbrowser go for the plugin: id "com.github.hierynomus.license" version "0.11.0" go to following URL: https://plugins.gradle.org/api/gradle/4.0.1/plugin/use/com.github.hierynomus.license/0.11.0
The json returned contains the GAV needed in the useModule call. Use that
The following serves as an example:
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == 'com.gradle' && requested.id.name == 'plugin-publish') {
useModule('com.gradle.publish:plugin-publish-plugin:0.9.7')
} else if(requested.id.namespace == 'com.github.hierynomus' && requested.id.name == 'license') {
useModule('nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0')
}
}
}
Try to implement Plugin Resolution Rules.
According to gradle documentation:
Plugin resolution rules allow you to modify plugin requests made in plugins {} blocks, e.g. changing the requested version or explicitly specifying the implementation artifact coordinates.
To add resolution rules, use the resolutionStrategy {} inside the pluginManagement {} block
like that:
pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == 'com.gradle.plugin-publish') {
useModule('com.gradle.plugin-publish:0.9.7') //try a few combinations
}
}
}
repositories {
maven {
url 'https://artifactory/java-v'
}
}
}
Keep in mind this is incubating feature though.

Changing configuration with the gretty plugin?

I haven't done anything with Gradle for a while, so it appears I've forgotten how configuration resolution works.
I'm trying to use the gretty plugin (instead of core, deprecated jetty), but I cannot seem to create a custom configuration.
I've boiled it down to a very short, simple script (using Gradle 3.4):
buildscript {
repositories {
maven {
url 'https://plugins.gradle.org/m2/'
}
}
dependencies {
classpath 'org.akhikhl.gretty:gretty:1.4.0'
}
}
plugins {
id 'org.akhikhl.gretty' version '1.4.0'
}
configurations {
fooTest
}
configurations.fooTest.each {
println it.toString()
}
It seems to not like me iterating over the fooTest configuration.
Assuming I need to know the dependencies for that configuration (I stripped that part from the code above)
What am I doing wrong here?
The script above gives me this:
org.gradle.api.InvalidUserDataException: Cannot change strategy of configuration ':fooTest' after it has been resolved.
The key point here was that I needed an unresolved configuration to loop over. Admittedly this information was neglected in the initial description as I didn't know it was critical information. We needed to loop over the files in the dependency and copy/unzip them into certain locations.
However, we cannot do that with a resolved configuration. That said, we can copy the configuration into a unresolved one, and loop over that instead:
configurations.fooTest.copy().each {
println it.toString()
}
This will successfully print out the files involved in the dependency (or unzip them, as my case needs).

Execute Gradle task after subprojects are configured

I have a multi-project Gradle build where subprojects are assigned version numbers independent of the root project. I'd like to inject this version number into a few resource files in each subproject. Normally, I'd do this by configuring the processResources task for each subproject in the root build. However, the problem is that Gradle appears to be executing the processResources task before loading the subprojects' build files and is injecting "unspecified" as the version.
Currently, my project looks like this:
/settings.gradle
include 'childA' // ... and many others
/build.gradle
subprojects {
apply plugin: 'java'
apply plugin: 'com.example.exampleplugin'
}
subprojects {
// This has to be configured before processResources
customPlugin {
baseDir = "../common"
}
processResources {
// PROBLEM: version is "unspecified" here
inputs.property "version", project.version
// Inject the version:
from(sourceSets.main.resources.srcDirs) {
include 'res1.txt', 'res2.txt', 'res3.txt'
expand 'version':project.version
}
// ...
}
}
/childA/build.gradle
version = "0.5.424"
I looked into adding evaluationDependsOnChildren() at the beginning of root's build.gradle, but that causes an error because childA/build.gradle runs before customPlugin { ... }. I've tried using dependsOn, mustRunAfter, and other techniques, but none seem have the desired effect. (Perhaps I don't fully understand the lifecycle, but it seems like the root project is configured and executed before the subprojects. Shouldn't it configure root, then configure subprojects, and then execute?)
How can I get inject the version of each subproject into the appropriate resource files without a lot of copy/paste or boilerplate?
You could try using this method, with a hook:
gradle.projectsEvaluated({
// your code
})
I got this figured out for myself. I'm using a init.gradle file to apply something to the rootProject, but I need data from a subproject.
First option was to evaluate each subproject before I modified it:
rootProject {
project.subprojects { sub ->
sub.evaluate()
//Put your code here
But I wasn't sure what side effects forcing the sub project to evaluate would have so I did the following:
allprojects {
afterEvaluate { project ->
//Put your code here
Try doing it like this:
subprojects { project ->
// your code
}
Otherwise project will refer to your root project where no version has been specified.

gradle: how to share a build.gradle which contains information I am the only one to have?

My build.gradle file contains a section like this to upload archives to SonaType:
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment {
MavenDeployment deployment -> signing.signPom(deployment);
}
// HERE
repository(url: sonatypeRepoURI) {
authentication(userName: sonatypeUsername,
password: sonatypePassword);
}
pom.project {
// etc etc
}
}
}
}
At the point marked HERE, other users wishing to use my build file will fail, because at least the first variable is not defined:
FAILURE: Build failed with an exception.
* Where:
Build file '/path/to/build.gradle' line: 144
* What went wrong:
A problem occurred evaluating root project 'whateverTheProject'.
> No such property: sonatypeRepoURI for class:
org.gradle.api.publication.maven.internal.ant.DefaultGroovyMavenDeployer
How do I modify the section above so that users are not affected by these variables not being defined for them?
You could try to add all the needed properties to your gradle.properties file, which you add to version control, but leave the values empty.
Eg:
version=1.0
signing.keyId=
signing.password=
signing.secretKeyRingFile=
sonatypeUsername=
sonatypePassword=
Then you override these in your own ${USER}/.gradle/gradle.properties.
As an example take a look at a working project https://github.com/judoole/monitorino. Should be able to run all tasks at any machine except snapshot, stage and build.
Edit: I would not do it like this today. Follow the Gradle guide, using required. Just as the example from #jb-nizet Gradle ref 53.3.3 Conditional Signing: http://www.gradle.org/docs/current/userguide/signing_plugin.html
Very simple just create the "gradle.properties" file in "~/.gradle" with the following contents:
sonatypeUsername=
sonatypePassword=
After run your project. Its running properly.

Resources