28

In maven it is very easy to set properties in a pom with the following syntax:

...
<properties>
  <myValue>4.06.17.6</myValue>
 </properties>
...

Now I need to build a property which depends on the version of my pom. For creating the property i want to do the following (java pseudo code):

String[] parts = version.split("\\.");
String.format("V%s_%s_%s_P%s", splitted[0],  splitted[1],splitted[2],splitted[3]);
// example: 4.06.17.6 => V_4_06_17_P6

It should be dynamic, because it is used as a tag name in our repository and must always be in sync with the version of the artifact.

Any ideas how to create that "dynamic" properties?

Peter Mularien
  • 2,578
  • 1
  • 25
  • 34

3 Answers3

42

Mojo's Build-Helper Maven Plugin can help you out here.

There are a number of goals that can be used to help transform properties.

There is

Probably regex-property is the one you want, but if your version numbers conform to the "standards" the other two might save you.

To use the regex-property goal you would do something like

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <version>1.7</version>
        <executions>
          <execution>
            <id>regex-property</id>
            <goals>
              <goal>regex-property</goal>
            </goals>
            <configuration>
              <name>tag.version</name>
              <value>${project.version}</value>
              <regex>^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)\.(-SNAPSHOT)?$</regex>
              <replacement>V$1_$2_$3_P$4</replacement>
              <failIfNoMatch>true</failIfNoMatch>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

Note: my regex might be slightly off so you should test the above.

Note: The property value will only be available for executions after the phase that this execution is bound to. The default phase that it is bound to is validate but if you are on a different lifecycle (e.g. the site lifecycle) the value will not be available.

Oliver
  • 3,815
  • 8
  • 35
  • 63
Stephen Connolly
  • 13,872
  • 6
  • 41
  • 63
  • And if I do not bind the plugin to a phase. I am using maven release plugin and call the goal release:prepare. How do make it available here? – EhmKah a.k.a. Michael Krauße Aug 17 '12 at 09:52
  • if you do not specify a phase, by default it is bound to the `validate` phase, so the code snippet above will execute the goal when the validate phase is active. when you invoke a goal directly, e.g. `release:prepare`, what happens is that maven runs the goal directly skipping any lifecycle phases, so the `release:prepare` goal itself will not see the property *but* the lifecycle *forked* by `release:prepare` will see it. So `release:prepare` will not be able to use the property for tagging SCM, but the property will be present in the forked build that the release plugin runs – Stephen Connolly Aug 17 '12 at 09:59
  • 1
    If you want to have the SCM tag based on the property (you should update your question to reflect that this is your aim, or start a second question) then you might need to use something like http://maven.apache.org/plugins/maven-release-plugin/prepare-mojo.html#tagNameFormat though that will not give you the `_` substitution you want nor the `_P` injection. I recommend changing the tag name requirements rather than trying to bend Maven ;-) – Stephen Connolly Aug 17 '12 at 10:02
  • 1
    OK. I created a new question. Maybe better luck. I am not able to change the tag-name-definition because to many are departments would have to change there tagging behavior. :-( – EhmKah a.k.a. Michael Krauße Aug 17 '12 at 10:55
  • Wow... 24 lines of XML to replace 2 lines of Java. Is there an option a little less... verbose? – bacar May 13 '13 at 16:33
  • @bacar That's a glib comparison. There are about 9-10 lines of actual information, 3 define what code base to use, 2 define when to run, and 5 define the behaviour. Your "2 lines" of java do not cover when to run in life cycle nor failure modes and some other stuff... Add that in and you're likely up near the 9-10 LoC count... – Stephen Connolly May 13 '13 at 17:04
  • @StephenConnolly Kinda fair, but it's still crazy verbose... that's just maven I guess. Also it's not _that_ glib. What's the incremental effort to add 1 new property for a different regex, with a (currently fictional...) more expressive solution vs. the maven one? I think the maven one requires a whole additional `` block (stop me if I'm wrong!) – bacar May 13 '13 at 17:15
  • @bacar I'm not saying the xml isn't verbose, and if you had a load of properties to set that way I'd change the plugin to make it easier... Plugin designed for the use case of single property... A multi-property plugin goal would need more than 24 lines for setting just one. Question asked for one property only... And BTW properties are a but of an anti-pattern because they are only of use during the build itself – Stephen Connolly May 13 '13 at 18:36
  • Properties can be exported so that's not what makes them antipatterns. I wouldn't consider them anti-patterns in themselves either; some of the anti-patternness comes from Maven's craziness of pushing everything into a deeply nested XML structure, some comes from Maven's caziness of a fixed, not-easily-extensible lifecycle (so the standard lifecycle keeps sprouting new phases). BTW those crazinesses are what's pushing Maven users to Gradle, where other crazinesses exist but at least these are fixable. – toolforger Jul 12 '18 at 07:58
5

You can use maven build-helper plugin, in particular its regex-property mojo. Take a look at usage examples (scroll to Set a property by applying a regex replacement to a value section).

Basically you want something like that in your pom to get myVersionTag property inferred from myValue:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <version>1.7</version>
        <executions>
          <execution>
            <id>regex-property</id>
            <goals>
              <goal>regex-property</goal>
            </goals>
            <configuration>
              <name>myVersionTag</name>
              <value>$\{myValue}</value>
              <regex>(\d+)\.(\d+)\.(\d+)\.(\d+)</regex>
              <replacement>V_$1_$2_$3_P$4</replacement>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>
Ihor Kaharlichenko
  • 5,944
  • 1
  • 26
  • 32
  • I would have marked this answer as accepted too because its the same is the one above. Thank you. – EhmKah a.k.a. Michael Krauße Aug 17 '12 at 10:57
  • 1
    Not quite. Ihor's example puts a '\' between the '$' and the '{' in the element. This is how the Codehaus document says to do it but it's wrong. The regex-property goal will not work with the backslash and does work without it. And Codehaus is out of business. – Steve Cohen Nov 16 '15 at 23:01
  • @SteveCohen If the docs are wrong please open an issue https://github.com/mojohaus/build-helper-maven-plugin/issues – khmarbaise Sep 02 '16 at 08:25
3

Ihor Kaharlichenko's answer is basically correct except that it copies an error from the Codehaus documentation. There should be no '\' between the '$' and the '{'. The mojo works without it and doesn't work with it. Truly, with a basic understanding of regex and Maven, I couldn't see what the backslash was supposed to do and indeed it's wrong.

Stephen Connolly's answer correctly omits the backslash. Be careful.
This error has proliferated throughout SO and with Codehaus out of business will probably never get fixed.

Steve Cohen
  • 4,679
  • 9
  • 51
  • 89