Execute action in Gradle after all plugins applied, but before "afterEvaluate()" - gradle

I try to configure my project from a custom plugin. I want to set a default URL and credentials for the publishing extension if plugin maven-publish is applied. I need know whether the plugin is applied or not.
In a function of my custom plugin I want to write something like this (not actual code)
project.afterPluginApply {
if (project.pluginc.any("maven-publish")) {
setDefaultUrl()
}
}
I don't want use project.pluginManager.withPlugin("maven-publish")
because I want see all applied plugins for the project (I want to configure many extensions and some value may change if whether or not other plugins are applied).
I don't want use subProject.afterEvaluate {} because, if I configured a field in build.gradle.kts I would overwrite it with my plugin.
I could write some dirty code like this
(it.pluginManager as DefaultPluginManager).idMappings[DefaultPluginId.unvalidated("maven-publish")] != null
But I'd rather like to find a better solution.

Related

How do you set the --frames option for a Javadoc task in Gradle?

We recently updated to JDK 11 and the javadoc team has seen fit to remove frame generation from the javadocs in favor of a search box. Our community is comprised heavily of students who don't know what keywords to search for, but who can browse a sidebar and find what they need. For them a search box is useless. They require discovery through browsing. For that reason, we would like to turn frames back on by adding the --frames option to the javadoc task, and then we'll just never move off of JDK 11.
We are using Gradle 7.4.2 and there doesn't appear to be a method exposing the --frames option in the StandardJavadocDocletOptions class.
If the options section of my Javadoc task looks like this:
options.memberLevel = JavadocMemberLevel.PROTECTED
options.links "https://developer.android.com/references"
options.encoding = 'UTF-8'
Then I see those options in gradle's generated options file.
Adding...
options.setStringOption('-frames')
...does not result in any new option appearing in the generated options file. To be honest I have no idea what setStringOption() without the second string parameter actually does.
Adding...
options.setStringOption('-frames', '')
... results in --frames '' appearing on the generated options file, but that confuses javadoc.
I don't see anything in the Gradle documentation that indicates how one might add simply '--frames' to the command line of the javadoc executable. Or any other option that javadoc might expose, but the gradle version one is sitting on does not expose for that matter.
To set flags use addBooleanOption()
// build.gradle.kts
tasks.javadoc {
options {
require(this is StandardJavadocDocletOptions) // workaround https://github.com/gradle/gradle/issues/7038
addBooleanOption("frames", true)
}
}
Note that the Kotlin DSL requires a workaround https://github.com/gradle/gradle/issues/7038#issuecomment-448294937

Display gradle property in readme.md file

I have a gradle project with a gradle.properties file. One of the properties displays the current version of my project and I would like to include this proprerty in the project's README.md on github. How can I do this?
The Gradle Copy task is capable of such functionality. Simply use its expand method to specify the values to insert. Of course you'll need to define a template somewhere in your project:
task copy(type: Copy) {
from 'src/templates'
into "$buildDir"
include 'projectinfo.html.template'
rename { file -> 'projectinfo.html' }
expand(project: project, title: 'ProjectInfo', generated: new Date())
}
I took this example from a post of Mr. Hakis Blog.
This functionality is based on the Groovy SimpleTemplateEngine. Of course you can simply use this class or any other templating engine to implement the required functionality in your build script on your own.
#KrispyK,
I believe this would be possible. You could write a simple serverless script using webtask (or similar service) that reads your gradle properties file and creates a custom status badge using a badge service like shields.io. Finally, you would only need to add this badge to your markdown file.
Please refer to this webtask script that I created. This calls an external API and uses the data returned by that API to create a custom Shields badge.
I've then used this badge in my readme file.
Hope this helps.

Plugin task executes after configuration phase

I am building a whole suite of plugins for a new build pipeline. I have certain metadata that if it is not present in the build file, i want it to fail. for example
inventory_link: '124djsj39r'
This links the build back to our inventory system. If that tag is not present in the build, I don't want the developer to be able to do squat. no tests, no compiles, no builds, no nothing. I want the project to be a worthless group of files.
Now reading the docs, i understand the build lifecycle, sorta. There's an init, config, execute, clean. basically How do I configure a custom plugin (writing it as an independant jar) so that a validation task executes automatically that checks to make sure this tag is present at the end of the configuration phase of the build lifecycle?
how does multi-project builds effect this? each individual project of a multiproject build must have this tag as well.
EDIT
I was able to get back to this. I got this to run and it executes the closure, problem is project_hash always null. Now granted, I'm using testkit so i may be dealing with something weird in testkit. see anything wrong?:
#Override
void apply(Project project) {
this.project = project
def metadata = new Metadata()
// Create and install the extension object
project.extensions.create('metadata', MetadataExtension, metadata)
def ignore = project.tasks.create(METADATA_REPORT, MetadataReportTask)
ignore.group = PLUGIN_GROUP
ignore.description = 'Gets the detailed information for this project and formats it into a user readable report'
project.afterEvaluate {
throw new InvalidUserDataException(project.metadata.metadata.project_hash)
}
}
Any code you put in the main body of your build.gradle script will run during the configuration phase. If you want it done last, just put it at the bottom.
if (inventory_link == null) //or whatever check makes sense
throw new GradleException('Hey, you need to set the inventory_link')
Note that clean is not a "phase" in the gradle build lifecycle like init, config, execute. It is achieved via a task.

Getting settings object from the buildscript

I am trying to access the settings object from the root project's build script.
The reason is I want to define a list in the settings.gradle file which will be a list of subprojects, kind of:
settings.gradle
projectNames = ['prjA', 'prjB']
Would like to do something like:
build.gradle (root project)
projectNames = settings.projectNames
// Use projectName in tasks
And then access it in build.gradle for various tasks, such as resolving those names into URLs to git-clone them. However I can't seem to find a way to declare some arbitrary groovy object which is visible between these two scripts. Note I may potentially like that list to be related but not equal to the project names. I guess the question sums up to sharing POGOs between those two files and accessing the settings object.
I'm pretty new to Gradle.
There isn't a way to get to the settings object from a build script. However, both scripts share a gradle object, which you could use to set an extra property in the settings script (e.g. gradle.ext.foo = "bar"), and read it in the build script (e.g. println gradle.foo).
If you need access to the Settings instance from your build.gradle file after the
settings have been loaded and evaluated, you can register a lifecycle closure or listener.
A great place to start is the method Gradle#settingsEvaluated(Closure)
that provides the Settings object as a closure parameter.

Correct way to modify maven plugin configuration from mojo

I know this is subjective question and it will be closed most probably. But I don't know where to ask this question to get answer.
There is one small annoying thing with maven android plugin - it modifies original manifest file and if you are running maven in working folder your vcs is proposing you to commit these changes.
Example: we have several environments to run if I build build with beta environment it will modify app name in AndroidManifest.xml.
This is could be easily solved by copying original manifest and give reference to the copy to the android maven plugin. But I've decided to make it's more easy for developer so plugin will do this automatically except situation when developer specifies that he wants this update to be done under original manifest.
It was easy to modify functionality (copy file and replace property that keeps reference to the File) but the problem is that I need to pass this property to other mojos.
The property defined in abstract mojo AbstractAndroidMojo which doesn't have execute method. And all other mojos extend this class. The definition look like this:
/**
* The <code>AndroidManifest.xml</code> file.
*
* #parameter default-value="${project.basedir}/AndroidManifest.xml"
*/
protected File androidManifestFile;
I followed this answer:
private void updatePluginConfiguration ( String newManifestFileValue )
{
for ( Plugin plugin : project.getBuild().getPlugins() )
{
if ( plugin.getArtifactId().equals( "android-maven-plugin" ) )
{
Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
Xpp3Dom manifestFileParameter = configuration.getChild( "androidManifestFile" );
if ( manifestFileParameter == null )
{
manifestFileParameter = new Xpp3Dom( "androidManifestFile" );
configuration.addChild( manifestFileParameter );
}
manifestFileParameter.setValue( newManifestFileValue );
break;
}
}
}
But unfortunately this doesn't work. There are many explicit ways to make it working but all of them will require to change all current mojos.
I wonder if someone knows why the answer doesn't work or how to make it working.
The code of updated plugin could be found here:
https://github.com/emartynov/maven-android-plugin/tree/keep-android-manifest
Thanks for everyone who read till the end.
Are you running your goal within the same lifecycle phase? If not, in the post you provided it's written:
Note: Any configuration changes are discarded at the end of the current phase.
The other thing to consider: are the goals run in order you expect? Have a look at this post: http://www.mkyong.com/maven/maven-plugin-execution-order-in-same-phase/ - Perhaps it's the ordering of plugins that you're having problems with.
Other thing to consider: perhaps you'd prefer a cleaner solution - to add such feature to the android-maven-plugin? Manfred Moser is usually open to proposals backed by pull requests ;)
I'll be most propably doing the very same thing in my plugin. The only difference is that I'm reusing goals from maven-dependency-plugin to copy dependencies within my custom plugin lifecycle. I'm trying to make a plugin for InstallShield projects building.

Resources