Plugin task executes after configuration phase - gradle

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.

Related

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

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.

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.

how to flip between local and remote repo in gradle with old maven plugin?

I am not using the new maven-publish plugin which looks awesome and would work perfectly for this use case because I keep reading how no one can get the signing of the jars to work (though I am open to an answer that explains that as well as I haven't found a blog on that saying it would work at this point).
Soooo, I would like easily to switch between publishing locally for testing and remotely. My current build.gradle file is
https://github.com/deanhiller/webpieces/blob/master/build.gradle
which has a commented out local repo and I keep flipping commenting on and off and would rather like to avoid that. ie. these repos...
//repository(url: "file://localhost/tmp/myRepo/")
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication(userName: sonatypeUsername, password: sonatypePassword)
}
I read a post on doing something here but this failed with cryptic closure errors...
Configuring multiple upload repositories in Gradle build
I put that in my subprojects section but that didn't work at all. Ideally, using the graph whenReady sounds the best as it would be cool to only use remote repo if I am doing the release target. I can't seem to get any of this to work though.
thanks,
Dean
EDIT: I was wrong, the below is only half working right now as when I ./gradlew jar, then I get this error... (so some targets work and others not...ouch)
Cannot cast object 'task ':uploadArchives'' with class 'org.gradle.api.DefaultTask_Decorated' to class 'org.gradle.api.tasks.Upload'
I did figure out a work around though it seems weird as targets in running tasks list are hidden now depending on if a variable is set which seems a little odd. I would think there is probably a better way of doing this so all tasks are still listed, but for now my build file works by just doing a
if(project.hasProperty('projVersion')) {
//task I want to be able to run
} else {
//other task I want to run when no projVersion
}
so it works...the tasks are just invisible now until I do ./gradlew -PprojVersion=X to view them.

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