Maven 3.0's "mvn release:perform" doesn't like a pom.xml that isn't in its git repo's root directory
Asked Answered
F

4

10

I have a question about Maven, the maven-release-plugin, git integration, pom.xml's, and having pom.xml's in subdirectories of the repo's local copy rather than in the root.

Here's the setup:

  • I have a github account with a limited number of private repositories
  • I want to (am just learning to) use Maven to organize my builds/releases
  • I might need to create many Maven "projects", several projects per git repository
  • Each maven project requires a "pom.xml" to define its characteristics
  • I can't, or at least it's not convenient to, put all project pom.xml files in the root of the git repository
  • So I end up with this folder layout for projects:
    • git_repo_root_dir
      • project_A folder
        • pom.xml
        • other_code
      • project_B folder
        • pom.xml
        • other_code
      • etc.
      • ...
  • I can successfully go to directory git_repo_root_dir/project_A and do an "mvn release:prepare"
  • I fail with this step in git_repo_root_dir/project_A: "mvn release:perform"
    • The problem seems to be that the git-tagged code is successfully checked out to git_repo_root_dir/project_A/target/checkout/project_A in preparation for the release build, but then after the checkout the "maven-release" plugin goes to directory git_repo_root_dir/project_A/target/checkout/. instead of git_repo_root_dir/project_A/target/checkout/project_A/. to do the actual build, and there's no way to tell the "maven-release" plugin to step into a subdirectory of the special tagged copy of the source before trying to mess with the pom.xml
  • QUESTION: is there a way around this? Is there an option to somehow tell "mvn release:perform" to go to the subdirectory?

Here's the actual error I get during this process:

[INFO] --- maven-release-plugin:2.0:perform (default-cli) @ standard_parent_project ---
[INFO] Checking out the project to perform the release ...
[INFO] Executing: /bin/sh -c cd "/Users/___/DEV c8ion 01/maven_based_code/0maven/standard_parent_project/target" && git clone [email protected]:clarafaction/0maven.git '/Users/___/DEV c8ion 01/maven_based_code/0maven/standard_parent_project/target/checkout'
...
/* note, the pom.xml the build should go out of at this point is at
   '/Users/___/DEV c8ion 01/maven_based_code/0maven/standard_parent_project/target/checkout/standard_parent_project/pom.xml'
*/
...
[INFO] [ERROR] The goal you specified requires a project to execute but
    there is no POM in this directory
    (/Users/___/DEV c8ion 01/maven_based_code/0maven/standard_parent_project/target/checkout).
    Please verify you invoked Maven from the correct directory. -> [Help 1]

Thanks.

Futurity answered 21/5, 2012 at 23:58 Comment(0)
F
11

This should do the trick:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-release-plugin</artifactId>
    <version>2.3.2</version>
    <executions>
        <execution>
            <id>default</id>
            <goals>
                <goal>perform</goal>
            </goals>
            <configuration>
                <pomFileName>your_path/your_pom.xml</pomFileName>
            </configuration>
        </execution>
    </executions>
</plugin>
Felicio answered 11/10, 2012 at 14:42 Comment(1)
So we must write inside the pom.xml file to tell Maven where that same pom.xml is to be found? Well...Calandra
P
7

You can do it in the same way you normally tell Maven to run from a POM that's somewhere else: the -f option. mvn --help describes it thusly:

-f,--file <arg>    Force the use of an alternate POM
                   file.

To do that in a release, you just need to pass the appropriate option to the release plugin. You can use the perform goal's "arguments" property to do that. This property just tells the release plugin some additional arguments to append to the mvn command it runs when doing the release. You can set it from the command line by appending -D arguments="-f path/to/pom" or set it permanently in the pom in the release plugin's configuration, something like

<plugin>
    <artifactId>maven-release-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <arguments>-f path/to/pom</arguments>
    </configuration>
</plugin>
Principally answered 22/5, 2012 at 3:24 Comment(4)
Thanks for the tip. I'll be trying this soon, but a further question: can the link be relative, i.e., when release plugin tries to run Maven with the checked-out-tagged-version of the code, present directory is .../project_A/target/checkout, but the POM is at .../project_A/target/checkout/project_A/pom.xml, so would using <arguments>-f ./project_A/pom.xml</arguments> tend to work?Futurity
(An aside: the first "project" I'm trying to compile is the "standard parent pom.xml I'll be using for all other projects. It will be inherited by all other projects across all git repositories.) In any case, once I ran "mvn versions:display-plugin-updates" and explicit listed all plugins, and then cleaned up the project, and then did an "mvn release:prepare" and "mvn release:perform", the build worked as expected even without the need for your tip -- apparently I was using older versions of various plugins -- more recent versions account for this situation quite well, apparently. Thanks!Futurity
Yes, either ./project_A/pom.ml or just project_A/pom.xml is fine. You obviously already know about inheritance. You might also find aggregation useful. I recently answered another question on this topic.Principally
It's worth noting this doesn't work in earlier versions of the maven release plugin. I testes this with 2.3.2 and it didn't work. It worked fine with 2.5.3 however.Flied
S
1

This question was asked over 10 years ago so I wanted to provide a more up-to-date answer.

As of Oct 2022, the current/modern Maven works without any problems in a sub-directory. The current version of the maven plugin release is version: 3.0.0-M6

All that is needed is the normal elements defined in your POM that the maven release plugin needs:

NOTE: It's also possible to pass these arguments via a command line, but I prefer having them in a file (in pom.xml, parent for <distributionManagement>, or even settings.xml to better document the process and make it easier for other devs on the team to deploy.

NOTE: I used maven version 3.8.5 with Java 11, but AFAIK the version of Java does not matter. The latest version of maven is 3.8.6 (at this time). I believe it would work with Java 8. And at this time, maven 4 is in alpha.

How it works

Assumptions

In this example the following is used:

Each of the apps or libraries are in a separate directory with no parent POM being used (in this example). So you can't type mvn clean install from the top level directory. This is similar to the original OP question. As one commenter said, this is type of problem happens in a polyglot repo where multiple languages and technologies are used.

Explanation of POM configuration needed

In lib1, the pom has the following defined (only showing settings for maven release plugin). NOTE: This is the SAME information that will be in all of the POMs for this repository.

    <scm>
        <connection>scm:[email protected]:user123/proj456.git</connection>
        <developerConnection>scm:[email protected]:user123/proj456.git</developerConnection>
        <tag>HEAD</tag>
    </scm>
    <distributionManagement>
        <downloadUrl>https://mynexus.example.com/repository/maven-public</downloadUrl>
        <repository>
            <id>proj456-release</id>
            <name>proj456 release distro</name>
            <url>https://mynexus.example.com/repository/proj456-release</url>
        </repository>
        <snapshotRepository>
            <uniqueVersion>true</uniqueVersion>
            <id>proj456-snapshot</id>
            <name>proj456 snapshot</name>
            <url>https://mynexus.example.com/repository/proj456-snapshot</url>
        </snapshotRepository>
    </distributionManagement>

NOTE: Your settings.xml file needs to contain your login or auth-credentials so that might look like:

    <servers>
        <server>
            <id>proj456-releases</id>
            <username>user123</username>
            <password>not-shown</password>
        </server>
        <server>
            <id>proj456-snapshot</id>
            <username>user123</username>
            <password>not-shown</password>
        </server>
    </servers>


When you have a separate git repo for each maven artifact you are working on, the <scm> tag will be different for each of them.

Creating a release

The normal maven release commands are used, just from the sub-directory:

cd $HOME/work/proj456
ls -1
app1
app2
lib1
lib2

# Now CD to the directory you want to create a release for
cd lib1
mvn release:clean
mvn release:prepare release:perform

At the end of this process, the maven release plugin will do all the things it normally does. For example,

  1. The -SNAPSHOT version in the POM is replaced with a release version (that you specify).
  2. A git commit is created with the release version.
  3. A maven build and package is created with that release.
  4. The maven package is pushed (uploaded) to the NEXUS repo (or maven central).
  5. The pom.xml is bumped to the next version (with -SNAPSHOT added) and git commit is made so future development occurs on next SNAPSHOT version.

See maven docs for maven release plugin for a complete list of the steps.

Stigmatism answered 27/10, 2022 at 15:1 Comment(0)
A
-2

The first thing is to understand git which has it's convention that every project has it's own repository. The next thing is that Maven has it's conventions and putting the pom.xml into the root of it's project is the most obvious one. Furthermore you are trying to fight against Maven and i will predict that you will lose the combat and make your life not easy. If your projects A and B are related (same versio number or same release times) in some kind you should think about a multi-module build which results in a structure like this:

root (Git Repos)
  +-- pom.xml
       +--- projectA (pom.xml)
       +--- projectB (pom.xml)

and you can do a release of both projectA (better calling it a module) and module b in a single step from the root.

Aftergrowth answered 22/5, 2012 at 6:29 Comment(1)
There are use cases for this kind of setup, e.g. if you have a distributed system consisting of a lot of different services. Having them all in the same repo allows to make a single commit across services. But you don't want to necessarily release them all at once since then they all have a new version number which might force you to update services you didn't touch.Brynnbrynna

© 2022 - 2024 — McMap. All rights reserved.