Maven plugin development: goal dependency - java

It's vary hard to find proper search query for my question so I hope it's not a duplicate.
I'm developing maven plugin with few goals. I'd like to combine two of them in the chain (lifecycle?). Before clean-checkout goal is executed I would like to execute checkout goal first. I'm using annotation approach and tried using #Execute annotation to point which goal should be executed. The plugin compiles but is not executed in the way I assumed, cause there is no preceeding checkout goal while executing clean-checkout.
#Mojo(name = "checkout", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class Checkout extends AbstractMojo {
#Mojo(name = "clean-checkout", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
#Execute(goal = "checkout", phase = LifecyclePhase.GENERATE_SOURCES)
public class CleanCheckout extends AbstractMojo {
Without defaultPhase and phase properties, the build was failing.
Where I'm doing mistake?

Defining a custom lifecycle might help you.
Two years ago I analyzed the maven-release-plugin in more details and noticed that they use their own lifecycle.
Here you can find their lifecycle definition:
http://svn.apache.org/viewvc/maven/release/tags/maven-release-2.3.2/maven-release-manager/src/main/components-fragment.xml?view=markup
Additionally I found details inside Sonatype's Mavenbook:
http://www.sonatype.com/books/mvnref-book/reference/writing-plugins-sect-plugins-lifecycle.html
This interesting blog might also help you:
http://www.sonatype.com/people/2009/08/create-a-customized-build-process-in-maven/

Related

How to define gradle tasks dependency in a task in custom gradle plugin

I'm writing a custom gradle plugin in which I want to have a bunch of common for several of my projects tasks and a sort of a 'main' task to control which of these tasks to turn on.
Regular tasks in the plugin are e.g.:
CopyDockerResourcesTask
CopyContainerFilesTask
PerformAnalysisTask
and the 'main' task is:
BaseProjectTask
so then in the project in build.gradle I'd like to be able to do this:
BaseProjectTask {
copyDockerResources = true
copyContainerFiles = true
performAnalysis = true
}
I want the default behaviour of the plugin to be to not to do anything, only add certain tasks if they are turned on in BaseProjectTask.
I wanted to achieve this with adding task dependency in #TaskAction method of BaseProjectTask:
class BaseProjectTask extends DefaultTask {
private final BaseProjectExtension extension
private final Project project
#Optional
#Input
Boolean copyContainerFiles = false
...
#Inject
BaseProjectTask(Project project, BaseProjectExtension extension) {
this.project = project
this.extension = extension
}
#TaskAction
def execute() {
if (copyContainerFiles) {
project.tasks.assemble.dependsOn(project.tasks.copyContainerFiles)
}
...
}
}
Creating task dependency, this line:
project.tasks.assemble.dependsOn(project.tasks.copyContainerFiles)
doesn't work.
Edit:
My current findings are that defining task dependency in #TaskAction is too late as this is execution phase. I could do it in the constructor (this way it works) but its too early as property copyContainerFiles isn't set yet.
Does anyone know a way of adding code in the task class that would be fired in the configuration phase? I think this is what I'm missing.
You need to configure task dependencies during the build configuration phase, as you surmised.
It's not possible to do it in the #TaskAction method. It's fundamental to the way Gradle works that it needs to know how tasks depend on each other before it starts executing the build. That allows Gradle to do some useful things, such as only executing the tasks that are not up to date, or working out what tasks will execute without actually executing them.
In general, tasks should not be aware of one another1.
When you are trying to do this in a plugin using values in a project extension, you must wait until after the project has evaluated so that the build script code executes first. You can do this with project.afterEvaluate()2.
So you can do the following (using Kotlin DSL3):
project.afterEvaluate {
tasks.register("baseTask") {
if (baseProjectExtension.copyDockerResources)
dependsOn(tasks.getByName("copyDockerResources"))
if (baseProjectExtension.copyContainerFiles)
dependsOn(tasks.getByName("copyContainerFiles"))
if (baseProjectExtension.performAnalysis)
dependsOn(tasks.getByName("performAnalysis"))
}
}
1See How to declare dependencies of a Gradle custom task?
2See https://docs.gradle.org/current/userguide/build_lifecycle.html#sec:project_evaluation
3What I am familiar with. Hopefully not too much trouble to convert to Groovy.

Casting issue with maven but not eclipse

I am facing a type casting issue I can't figure out a workaround for.
The context is a legacy project developed in java 6 which has project B depending on project A.
Currently the build process involves generating .class for project A and copy them manually into project B before building it. It is very awkward but it works.
The issue arise when I tried to define the dependencies into the pom so that we can get rid of the manual process and let maven deal with the dependencies.
Here is the code that cause the error:
List<RowFilter<MyTableModel, Integer>> filters = new ArrayList<RowFilter<MyTableModel, Integer>>();
myTable.setFilter(RowFilter.andFilter(filters);
with setFilter defined as:
public void setFilter(RowFilter<MyTableModel, Integer> filter)
The error I get is:
setFilter(javax.swing.RowFilter<javax.swing.table.TableModel,java.lang.Integer>)
cannot be applied to
(javax.swing.RowFilter<java.lang.Object,java.lang.Object>)
I need to understand why is it working in the current build process but not when using maven dependencies? And how to fix it.
Thanks
After playing a little bit with casts I found the following to work:
Do it in each call to setFilter (more than a dozen)
myTable.setFilter((RowFilter<TableModel, Integer>) (Object) RowFilter.andFilter(filters));
Or redefine the setFilter signature like this
public void setFilter(RowFilter<?, ?> filter)
Or like this
public void setFilter(RowFilter filter)
Can anyone explain why it was not working in the first place and why this is working? Or if there is a better workaround?
In the meantime, i opted for the second option.

DependONGroups annotation testng

I am using DependOnGroups parameter in #test annotation.the code looks like,
#Test(groups={"datacompare"},dependsOnGroups = {"AzkabanFlow"})
Now the requirement is we need to run the test only for the group datacompare which is done by specifying the maven parameter,
clean test site -DtestGroup=datacompare
Since the above group has dependency with the group azkban flow, i am getting the error
[ERROR] DependencyMap::Method "DataValidationTestSuite.data_Comparison(java.lang.reflect.Method)[pri:0, instance:com.kohls.test.automation.framework.testsuite.DataValidationTestSuite#1608e1a]" depends on nonexistent group "AzkabanFlow"
Can someone suggest me a way to run the test for datacompare without removing the parameter DependOnGroups and also not calling the particular group mentioned in dependOnGroup parameter in maven parameter for test run.
You might want to change your #Test annotation to something like below
#Test(groups={"datacompare"},dependsOnGroups = {"AzkabanFlow"}, ignoreMissingDependencies=true)
This would cause TestNG to ignore missing dependencies and hopefully it should solve your problem as well.
Javadocs for the same can be referred here.

SonarQube: Custom Java Rules Not Visible in UI

I've been trying for quite some time to implement my own custom Java rule(s) on SonarQube. However, it seems like no matter what I try, I can't get the new rule to show up on the SonarQube UI.
I only have one rule at the moment, a security rule that checks to see if text output is sanitized. The rule extends BaseTreeVisitor and implements JavaFileScanner. It overrides visitMethodInvocation to do some checks on String arguments for the relevant methods. Here is the rule definition annotation:
#Rule(key = "Sanitize_HTML",
name = "HTML Responses Should be Sanitized",
tags = {"security", "owasp-a3"},
priority = Priority.CRITICAL)
#ActivatedByDefault
#SqaleSubCharacteristic(RulesDefinition.SubCharacteristics.SECURITY_FEATURES)
#SqaleConstantRemediation("10min")
public class SanitizeHTMLCheck extends BaseTreeVisitor implements JavaFileScanner{...}
After writing the rule, I wanted to test it, but quickly realized I had to wrap it in a plugin in order to do so. I wrote three additional classes for this, based entirely on the provided example plugin. Here's the base class:
public class SecurityPlugin extends SonarPlugin{
public List getExtensions(){
return Arrays.asList(
JavaClasspath.class,
JavaTestClasspath.class,
Java.class,
SecurityRulesDefinition.class,
SonarComponents.class,
DefaultJavaResourceLocator.class);
}
}
The classes in the list are all irrelevant (added in desperation) except for SecurityRulesDefinition. It mirrors the structure of the MyJavaRulesDefinition class from the example:
public class SecurityRulesDefinition implements RulesDefinition{
public void define(Context context){
NewRepository repository = context
.createRepository(RulesList.REPOSITORY_KEY, Java.KEY)
.setName("Security Rules");
AnnotationBasedRulesDefinition.load(repository, Java.KEY, RulesList.getChecks());
for(NewRule rule : repository.rules()){
rule.setInternalKey(rule.key());
}
repository.done();
}
}
Finally, just like the example, here's RulesList, where all of my rule classes are supposed to go:
public class RulesList {
public static final String REPOSITORY_KEY = "security_java";
private RulesList(){}
public static List<Class> getChecks(){
return ImmutableList.<Class>builder().addAll(getJavaChecks()).addAll(getJavaTestChecks()).build();
}
//Add all checks to here...
public static List<Class<? extends JavaCheck>> getJavaChecks(){
return ImmutableList.<Class<? extends JavaCheck>>builder()
.add(SanitizeHTMLCheck.class)
.build();
}
//Put all test checks here
public static List<Class<? extends JavaCheck>> getJavaTestChecks(){
return ImmutableList.<Class<? extends JavaCheck>>builder()
.build();
}
}
Like I said, these are all pretty much ripped from the example plugin, so I have no idea what could be wrong with them.
I'm using Eclipse with M2E to try and build the plugin. As suggested by the documentation's Coding A Plugin page, I've added the following plugin tag to my POM.xml:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-packaging-maven-plugin</artifactId>
<version>1.13</version>
<extensions>true</extensions>
<configuration>
<pluginKey>securityrules</pluginKey>
<pluginClass>org.myOrg.sonar_analysis.security_rules_java.SecurityPlugin</pluginClass>
<pluginName>Sonar Java Custom Security Rules</pluginName>
<pluginDescription>Implements several checks against OWASP-Top-10 vulnerabilities.</pluginDescription>
</configuration>
</plugin>
</plugins>
</build>
Now, according to everything I've read, I should be able to build the project (right-click on the project > Run As > Maven Build (with goal "package") and drop the resulting .jar into SONAR_HOME/extensions/plugins, and when I restart the server, the rule (and repository) should be there. However, no matter what I try, it's never there. I've spent hours combing the internet and trying anything I find, but the rule never shows up in the UI.
Am I missing something? Have I done something wrong? Is my code incorrect or missing anything?
Thank you for reading this monster post. Any advice you have is valuable, as I'm out of ideas.
The structure of the code seems right for me (more or less).
In the SecurityPlugin class, you return many classes (JavaClasspath.class, JavaTestClasspath.class and so on)... What are they for? What do they implement/extend?
In my expirience you need to return there:
- a "RulesDefinition" (to see the rule in SonarQube) and
- a CheckRegistrar (to let the checks being used).
Maybe my small rules project will give you some ideas (https://github.com/arxes-tolina/sonar-plugins ; one rule with two checks).
If you are still struggling with the rules try to set the sonar.log.level-property (./conf/sonar.properties) to DEBUG and watch the start-up of SonarQube.

How to mock maven plugin environment and or project configuration

I want to write unit tests (junit4) for my maven-plugin. All examples i found use "AbstractMojoTestCase" (junit3 :-(). To get rid of this i got answer here. But the problem is how Mojos get instantiated:
MyMojo myMojo = (MyMojo) lookupMojo( "touch", pom );
That means i need a pom for every test case - the pom is the tests input data. But is there a way to mock (i would use Mockito) the project model some how?
Could lookupMojo(String groupId, String artifactId, String version, String goal, PlexusConfiguration pluginConfiguration) be a good starting point? In this case i would mock "PlexusConfiguration", but what methods?
Some maven-plugin testing doku uses classes like "MavenProjectStub". But i can't get a consistent picture of how a mojo is created and to what intefaces it talks on creation.
A perfect solution would be if i could just
#inject
MyMojo testObject;
and just mock all the stuff it need to get it working (primary i need #Parameters)
Based on my experience writing Maven plugin, there are two levels of testing a plugin: via unit test (using mocks) and via integration tests (using the maven-invoker-plugin).
For the integration tests, the maven archetype for new maven plugins already provide a good example out of the box, just execute the following and have a look at it:
mvn archetype:generate \
-DgroupId=sample.plugin \
-DartifactId=hello-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-plugin
By default you will get integration tests in a profile to start with. An example maven project will also be available (under src\it\simple-it\pom.xml) which can execute your plugin goals. What I suggest is also to enforce the result of your integration test via additional constraints in that pom.xml. For instance: you can add the Maven Enforcer Plugin rule to check against created files, if that makes sense for your plugin.
To answer more specifically to your question on how to write unit tests for custom maven plugins, this is the approach I'm using:
JUnit + Mockito.
Test case running using #RunWith(MockitoJUnitRunner.class)
Mock Maven specific classes (MavenProject, Log, Build, DependencyNode, etc.) using #Mock annotations
Initiate and link your mock objects in a #Before method (typically setUp() method)
Test your plugin :)
As an example, you might have the following mocked objects as class variable of your unit test:
#Mock
private MavenProject project;
#Mock
private Log log;
#Mock
Build build;
Then, in your #Before method you need to add a big of glue code as following:
Mockito.when(this.project.getBuild()).thenReturn(this.build);
For instance, I use to write some custom Enforcer Plugin rules, hence I need
#Mock
private EnforcerRuleHelper helper;
And in the #Before method:
Mockito.when(this.helper.evaluate("${project}")).thenReturn(this.project);
Mockito.when(this.helper.getLog()).thenReturn(this.log);
Mockito.when(this.project.getBuild()).thenReturn(this.build);
Mockito.when(this.helper.getComponent(DependencyGraphBuilder.class)).thenReturn(this.graphBuilder);
Mockito.when(this.graphBuilder.buildDependencyGraph(this.project, null)).thenReturn(this.node);
As such, it will be easy to use these mock objects into your tests. For instance, a must have first dummy test is to test it against an empty build as following (below testing a custom Enforcer rule):
#Test
public void testEmptyBuild() throws Exception {
try {
this.rule.execute(this.helper);
} catch (EnforcerRuleException e) {
Assert.fail("Rule should not fail");
}
}
If you need to test against dependencies of your build, for instance, you might end up writing utility methods as following:
private static DependencyNode generateNode(String groupId, String artifactId, String version) {
DependencyNode node = Mockito.mock(DependencyNode.class);
Artifact artifact = Mockito.mock(Artifact.class);
Mockito.when(node.getArtifact()).thenReturn(artifact);
// mock artifact
Mockito.when(artifact.getGroupId()).thenReturn(groupId);
Mockito.when(artifact.getArtifactId()).thenReturn(artifactId);
Mockito.when(artifact.getVersion()).thenReturn(version);
return node;
}
In order to easily create dependencies into the dependency graph of your build, as following:
List<DependencyNode> nodes = new ArrayList<DependencyNode>();
nodes.add(generateNode("junit", "junit", "4.12"));
Mockito.when(node.getChildren()).thenReturn(nodes);
NOTE: you can improve the utility method if you need further details (like scope or classifier for a dependency).
If you also need to mock configuration of a plugin, because you need to scan existing plugins and their configuration, for instance, you can do it as following:
List<Plugin> plugins = new ArrayList<Plugin>();
Plugin p = new Plugin(); // no need to mock it
p.setArtifactId("maven-surefire-plugin");
Xpp3Dom conf = new Xpp3Dom("configuration");
Xpp3Dom skip = new Xpp3Dom("skip");
skip.setValue("true");
conf.addChild(skip);
p.setConfiguration(conf);
plugins.add(p);
Mockito.when(this.build.getPlugins()).thenReturn(plugins);
I will obviously not cover all the possible cases, but I am sure you got an understanding about approach and usage. Hope it helps.

Categories

Resources