Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute a specific plugin/Mojo from a pom.xml programmatically?

I'm the author of one of the Maven plugins (not Apache/Codehaus, completely indie). Sometimes I get support requests or test cases where I'd really need to debug the execution of my plugin with an existing pom.xml. Basically the test cases I get are sample/test project (pom.xml with src/main/resoures, src/main/java and so on).

What I need is a way to:

  • Load an existing pom.xml.
  • Find a specific execution of my plugin there (usually it's the only one).
  • Get an instance of MyMojo - fully initialized/condigured, with all the components and parameters corectly injected.
  • Execute MyMojo.
  • What's important is that test projects are separate projects, I don't want to copy them into the Maven module of my plugin.
  • I'd like to be able to do this without remote debugging.

By debugging I mean to be able to set and halt on breakpoints (also conditional), step in/out/over on the source code.

Ideally I'd like to be able to executeMyMojoFrom(new File("pom.xml")) - for instance in a JUnit test or a main method of some class. (I can supply groupId, artifactId etc. All other definitions should just be loaded from that pom.xml.)

How can I achieve this?


What I've tried so far:

  • Debug As... on pom.xml in Eclipse - does not work well enough (source code not found, breakpoint don't work as its not a Java project context)
  • Maven Embedder/Invoker solutions - spawn things in separate processes via CLI. Forget breakpoints, no debugging.
  • Remote debugging with mvnDebug and then remote debugging from Eclipse as suggested by Pascal Thivent here. This is so far the best option. However, remote debugging means starting mvnDebug separately, and there's also not guarantee that the JARs I have in Eclipse are exactly the same that mvnDebug is using. So there's a certain distance here.
  • maven-plugin-testing-harness - I actually thought this this will do the task. But first I was jumping through hoops for a few hours just to make it start. All of the important dependencies are "provided" so I first had to figure out the right combination of versions of these artifacts. And then - only to discover that AbstractMojoTestCase only works within the plugin module you want to test. Probably I was mistaken when I thought that maven-plugin-testing-harness was a testing harness for Maven plugins. It seems that it's a testing harness for the plugin from that plugin's module. Which is not illogical but does not help my case. I'd like to test my plugin in other modules.

So right now I've got the best results with the remote debugging solution. But what I'm looking for is really something like maven-plugin-testing-harness but not hardwired to the plugin module. Does anyone happen to have a hint, if such a method exists somewhere in Maven artifacts?

To be even more specific, I'd like to write something like:

 public void testSomething()
        throws Exception
    {
        File pom = getTestFile( "pom.xml" );
        assertNotNull( pom );
        assertTrue( pom.exists() );

        MyMojo myMojo = (MyMojo) lookupMojo( "myGroupId", "myArtifactid", ...,
                                             "myGoal", pom );
        assertNotNull( myMojo );
        myMojo.execute();

        ...
    }

Compare it to the MyMojoTest here - it's almost there. Should just not be hardwired into the mymojo Maven module (as it is in maven-plugin-testing-harness).


Update

Few answers to the questions in comments:

You mean you don't want such a test class, i.e MyMojoTest to reside inside the same project as the MyMojo, i.e your plugin project? Why is that?

Exactly. I want to debug the plugin execution in an existing Maven project, I don't want to move that project to my plugin project first to be able to run a test. I want to be able to test/debug an existing project. Ideally, I'd just need to add my-maven-plugin-testing dependency and subclass MyMojoTest in the project's src/test/jaca. This would be a good instrument to debug executions. Dragging the target project into my Mojo project ist just too much overhead - and mostly these aren't really the test cases I want to keep long-term. I hope, this answers, why.

Anyway, it's merely a convention to keep the project-to-test/pom.xml inside the src/test/resources of your plugin module, not a rule...

My problem is not the location of the pom.xml of the project-to-test, that is easily configurable. My difficulty is that maven-plugin-testing-harness is is somehow hardcoded to be in the Mojo's project. It uses the pom.xml of the Mojo, looks for other special files/descriptors in the containing project. So I somehow can't use it in a non-Mojo project, or can I? This is my question.

And I'm not sure why Debug as... didn't help you...

Not sure either, but (1) breakpoints did not work and (2) the source code was not "attached" for some reason.

like image 773
lexicore Avatar asked Dec 13 '14 21:12

lexicore


People also ask

What is the correct syntax for executing a Maven plugin?

Usage of a Maven Plugin xml you can use the shorthand notation to execute the plugin: mvn <prefix>:<goal> , commonly the “prefix” is the artifact ID minus the “-maven-plugin”. For example mvn example:version .

Where do plugins go in POM xml?

They execute during the build process and should be configured in the <build/> element of pom. xml. They execute during the site generation process and they should be configured in the <reporting/> element of the pom.

What is Maven compiler plugin in POM xml?

The compiler plugin is used to compile the source code of a Maven project. This plugin has two goals, which are already bound to specific phases of the default lifecycle: compile – compile main source files. testCompile – compile test source files.


1 Answers

If the Debug as didn't work for you as well as it should, you can try to use the mojo-executor with a bit of work.

https://github.com/TimMoore/mojo-executor

This is how you would execute the copy-dependencies goal of the Maven Dependency Plugin programmatically:

executeMojo(
    plugin(
        groupId("org.apache.maven.plugins"),
        artifactId("maven-dependency-plugin"),
        version("2.0")
    ),
    goal("copy-dependencies"),
    configuration(
        element(name("outputDirectory"), "${project.build.directory}/foo")
    ),
    executionEnvironment(
        mavenProject,
        mavenSession,
        pluginManager
    )
);

The project, session, and pluginManager variables should be injected via the normal Mojo injection. Yes, that means this should be executed from the context of another maven plugin. Now that I think about it, whether this would help you in any way is still a question because this still relies on injection of such components by the underlying plexus container.

My original idea was though to have you build a maven plugin that would invoke your jaxb2 plugin thru the mojo-executor like above, then serialize the mavenProject, mavenSession, pluginManager, i.e, all the plexus injected components and then use those objects to invoke your jaxb2 plugin in future from a standalone class without the plugin that you built.

like image 192
mystarrocks Avatar answered Sep 16 '22 16:09

mystarrocks