Maven: Bind plugin execution to the execution of another plugin, not to a lifecycle phase
Asked Answered
U

2

27

Note regarding the accepted answer: I accepted the answer because of strong circumstantial evidence. Nonetheless, this is circumstantial evidence, so take it with a grain of salt.


How can I have a plugin be triggered when the user runs a plugin goal, not a lifecycle phase? (This has been asked before, but the answer was to use a lifecycle phase.)

Case in point: I need release:branch to invoke regex-plugin to generate a branch with the current version as its name, minus the -SNAPSHOT suffix. This is what I have, which requires the developer to activate a profile and invoke the verify phase. I need the developer to simply invoke release:branch, which in turn should cause regex-plugin to run. In a bit of a marriage to Gitflow.

<profile>
    <id>Release Branch</id>
    <build>
        <plugins>
            <!-- On validate, compute the current version without -SNAPSHOT. -->
            <!-- Put the result in a property. -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <version>1.7</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>regex-property</goal>
                        </goals>
                        <configuration>
                            <value>${project.version}</value>
                            <regex>^(.*)-SNAPSHOT$</regex>
                            <replacement>$1</replacement>
                            <name>project.unqualifiedVersion</name>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- Also on validate, run the branch plugin, and use -->
            <!-- the non-SNAPSHOT version thus computed in the branch name. -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-release-plugin</artifactId>
                <version>2.3.2</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>branch</goal>
                        </goals>
                        <configuration>
                            <branchName>release/${project.unqualifiedVersion}</branchName>
                            <updateWorkingCopyVersions>true</updateWorkingCopyVersions>
                            <updateBranchVersions>false</updateBranchVersions>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>

The intent is for release:branch to move the current snapshot version (say, 1.0.5-SNAPSHOT) into a new branch, which should be named after the version but without the superfluous -SNAPSHOT suffix (1.0.5). The current branch should then take on a new snapshot version (1.1.0-SNAPSHOT, not 1.0.6-SNAPSHOT, because we want release 1.0.x to have room for hotfixes, so we reserve it for the branch) (I don't have the automatic computation of the next snapshot version figured out yet, so, if you run the Maven configuration above with validate, you will have to enter it at a prompt).

Unwish answered 28/4, 2013 at 14:47 Comment(15)
I second your remark that it cannot be done, but I'm waiting to be surprised :)Peasecod
Yeah, it doesn't look good. Here's another answer claiming that it's not doable: https://mcmap.net/q/535152/-maven-release-goals-binding. Sounds like a job for a custom lifecycle, or maybe I should take this away from Maven entirely and use something like Ant instead, since Maven is so unfriendly with this scenario. If they had a dummy phase that always runs, even when we only run a plugin goal, that would have been enough to solve this problem without headaches.Unwish
The entire Maven release plugin may even be goals that you'd normally not bind to lifecycle phases. As such they may've been designed exclusively with passing parameters on the command-line along in mind. Oddly enough, the prepare goal supports preparationGoals, that sounds like what you'd want for the branch goal.Peasecod
That would do the job, though I don't like preparationGoals, as it lacks structure in an otherwise highly structured file format.Unwish
I think it wouldn't do the job in this case, as it does not pertain to the branch goal (rather to the prepare goal).Peasecod
Agreed. I mean, if preparationGoals were available to branch, it would be enough to solve my problem, albeit a shortsighted solution. completionGoals should also be included with it, to allow post-processing. In any case, it seems like Maven is meant to expose only highly controlled entry points (barring writing your custom Mojos), so it may not be the most adapted tool for managing Gitflow activities.Unwish
A lot of things let themselves be overridden, but I don't see how that'd work for this one. I was thinking, though, that you'd typically want to branch off of a tag, in which case you have the SNAPSHOT stripped to begin with, assuming it's a branch for a release that was done with prepare.Peasecod
In Gitflow, you would frequently branch off of develop, which is always on a -SNAPSHOT version.Unwish
I have posted this question on the Maven developer list, but no answer yet.Unwish
Mihai... Would combining multiple maven goals with Exec Maven Plugin help you? See maba answer here. You could run regex-plugin and release:branch with exec:exec, no profiles or binding to custom phases required.Wulfe
Anthony: an interesting proposition, that I will have to think about. Nonetheless, my first preference would be not to touch the entry point, but rather just adjust its behavior. In other words, I prefer release:branch over exec:exec. Moreover, there will be other operations that will need to be overloaded in order to marry Maven's branching model with Gitflow, and I only have one exec:exec to use.Unwish
@MihaiDanila - I'm facing a similar situation, however I have the issue where I want to run another plugin prior to the execution of the release:prepare goal but within the same context. Specifically, run the properties-maven-plugin to load properties from a file to be available to the release plugin. What did you end up deciding/doing in the end?Utgardloki
@EricB. I haven't used Maven in over a year now, and the details are foggy. I would ask a question. I suspect your problem has to do specifically with how parts of the release stage are executed in a separate process.Unwish
@MihaiDanila Acutally - no. It's b/c I want to call the properties-maven-plugin during the context of my release:prepare/perform goals, but given that the release plugin is called directly (specifying the plugin:goal), there is no way to call the other plugin in the same context, short of specifying the specific goal in the properties plugin within the same mvn cmd. Basically, looking for a custom lifecycle in which I can map the different plugins and goals myself but without having to create a custom lifecycle....Utgardloki
You might be hitting on the same problem as me. It may just not be possible without that custom lifecycle. There were, nonetheless, some interesting ideas put forth in this thread and in others, if you're willing to do away with some purity. Sorry that I can't be of more help. If you insist that I partake in the brainstorming, I will have to read up on Maven again :), because I'm not in a Java shop anymore, as of over a year ago.Unwish
C
8

No, you can't bind to a plugin to another plugin. Only to a phase.

In Maven-internal terms, a "Mojo" is the thing that does work. A "plugin" is a collection of mojos wrapped up so you can reference them from the POM. Mojos bind to phases only.

From the plugin development documentation:

Each Mojo specified inside a plugin descriptor must provide the following

...

phase ... Defines a default phase to bind a mojo execution to if the user does not explicitly set a phase in the POM. Note: This annotation will not automagically make a mojo run when the plugin declaration is added to the POM. It merely enables the user to omit the <phase> element from the surrounding <execution> element.

For further confirmation, see the source of MojoExecution (the JavaDoc for this class isn't helpful) and notice that there are two possible sources of execution enumerated:

An execution that originates from the direct invocation of a goal from the CLI

and

An execution that originates from a goal bound to a lifecycle phase

No other way to kick off an execution means you're out of luck (barring extraordinary measures like rolling your own plugin that combines the effects of the two plugins you want to link and then using your custom plugin).

Cordelia answered 7/5, 2013 at 17:30 Comment(3)
You seem to be correct that there is no standard straightforward way to do achieve what I need without writing a plugin, but how about a pre-existing "aggregator" plugin like jetspeed:mvn? The site also does a good job of explaining the standard ways to chain. portals.apache.org/jetspeed-2/buildguide/…Unwish
There is strong circumstantial evidence that you are right, but your answer still does not prove it. Firstly, the default phase pertains only to phase bound executions, not CLI executions. The requirement does not preclude the execution of multiple goals from a CLI invocation any more than it precludes the execution of a single goal from a CLI invocation. Second, the source code mentions the direct invocation of a goal, not of the goal in question. Who is to say multiple goals triggered by the CLI are not represented by the same Source?Unwish
@MihaiDanila True, which is why I hedged a little at the end. My assumption is that you want to be using plugins and not developing them. You could write new plugins, or get a plugin that would call some external script which would then run another Maven instance, etc. But when you get to this point, you probably really should be using Ant or something else, rather than building a pile of kludges on top of Maven.Cordelia
U
9

The evidence presented so far is rather circumstantial. I've done some research of my own, so it's best I share it here. The below are either more of the same "it's not possible", or the building blocks for alternatives.

jetspeed:mvn plugin --- run a specified sequence of plugins; the configuration to run can be varied via a system property; IDE integration concerns


Executing goals before plugin runs (StackOverflow) --- same question answered in the context of a custom Mojo


Make Mojo run other goals (StackOverflow) --- again, from the context of a custom Mojo


Configuring default Mojo executions --- Maven page describing how Mojos run - more circumstantial evidence


Triggering phases before goal execution (StackOverflow) --- roundabout solution to my problem, unfortunately answered in the negative


INTERESTING: Guide to Ant plugin development --- appealing to me, because, while it requires writing a custom plugin, it's all Ant + Maven configuration, no code to compile; presumably a lower barrier to entry


Creating a parallel lifecycle --- appealing approach, because I could fully control the contents of the lifecycle to where it would use Gitflow verbs; unclear how IDEs would integrate this; learning curve and adoption barrier concerns exist

Unwish answered 8/5, 2013 at 4:39 Comment(0)
C
8

No, you can't bind to a plugin to another plugin. Only to a phase.

In Maven-internal terms, a "Mojo" is the thing that does work. A "plugin" is a collection of mojos wrapped up so you can reference them from the POM. Mojos bind to phases only.

From the plugin development documentation:

Each Mojo specified inside a plugin descriptor must provide the following

...

phase ... Defines a default phase to bind a mojo execution to if the user does not explicitly set a phase in the POM. Note: This annotation will not automagically make a mojo run when the plugin declaration is added to the POM. It merely enables the user to omit the <phase> element from the surrounding <execution> element.

For further confirmation, see the source of MojoExecution (the JavaDoc for this class isn't helpful) and notice that there are two possible sources of execution enumerated:

An execution that originates from the direct invocation of a goal from the CLI

and

An execution that originates from a goal bound to a lifecycle phase

No other way to kick off an execution means you're out of luck (barring extraordinary measures like rolling your own plugin that combines the effects of the two plugins you want to link and then using your custom plugin).

Cordelia answered 7/5, 2013 at 17:30 Comment(3)
You seem to be correct that there is no standard straightforward way to do achieve what I need without writing a plugin, but how about a pre-existing "aggregator" plugin like jetspeed:mvn? The site also does a good job of explaining the standard ways to chain. portals.apache.org/jetspeed-2/buildguide/…Unwish
There is strong circumstantial evidence that you are right, but your answer still does not prove it. Firstly, the default phase pertains only to phase bound executions, not CLI executions. The requirement does not preclude the execution of multiple goals from a CLI invocation any more than it precludes the execution of a single goal from a CLI invocation. Second, the source code mentions the direct invocation of a goal, not of the goal in question. Who is to say multiple goals triggered by the CLI are not represented by the same Source?Unwish
@MihaiDanila True, which is why I hedged a little at the end. My assumption is that you want to be using plugins and not developing them. You could write new plugins, or get a plugin that would call some external script which would then run another Maven instance, etc. But when you get to this point, you probably really should be using Ant or something else, rather than building a pile of kludges on top of Maven.Cordelia

© 2022 - 2024 — McMap. All rights reserved.