You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by "James Blewitt (JIRA)" <ji...@codehaus.org> on 2010/05/17 18:46:13 UTC

[jira] Commented: (MRELEASE-526) release:prepare 2.0 goal tags at the wrong level, tagging project/ instead of project/trunk

    [ http://jira.codehaus.org/browse/MRELEASE-526?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=221490#action_221490 ] 

James Blewitt commented on MRELEASE-526:
----------------------------------------


There is a bug in the way the release plugin calculates the path to use as the tag base directory. We have also had this problem and have modified the release plugin (locally) to solve the problem. The cause of the problem is a little bit tricky to explain, but I'll try my best:

*The trigger for this problem is as follows:*

Suppose we have projects A, B, C and D
{noformat}
    A
    |-B
    |-C
    \-D
{noformat}
	
    * Projects B, C and D are all in the <modules> list of project A.
    * Projects C and D have A as parent.
    * Project B has no parent (or a parent other than A).

Because project B does not depend on A, it may appear before A in the reactor build order. This can easily be tested for by looking at the "Reactor build order" that appears when you do "release:prepare". Usually you would expect project A to be the first entry in this list.

*The program fault:*

The faulty code is in the "maven-release-manager" (a module used by the "maven-release-helper").
The file *org.apache.maven.shared.release.util.ReleaseUtil* in method *getCommonBasedir* is where the error lies.

This method should find the base directory shared by all projects in the reactor. This directory will be used as the base directory from which to perform the tag.

It works by looking at all paths for all projects in the reactor and finding the "prefix" that is common to all path strings.
E.g.
c:/path/to/projectA-1.5
c:/path/to/projectB-2.1
c:/path/to/projectC-1.0

The "common prefix" would be "c:/path/to/project". Because this is not a valid path (there is no "project" directory) it cuts off the string from the last "/" leaving "c:/path/to".

Returning to our example above: we would have the following input for this method:

c:/path/to/projectA
c:/path/to/projectA/projectB
c:/path/to/projectA/projectC
c:/path/to/projectA/projectD

Because the method needs to return "c:/path/to/projectA" (and not "c/path/to") as the base directory, the algorithm adds an additional "/" to the end of paths to ensure that the "common suffix" is a valid path (i.e. doesn't get shortened as in the first example).
This works fine, but as soon as the project order looks like the following it doesn't work correctly:

c:/path/to/projectA/projectB
c:/path/to/projectA
c:/path/to/projectA/projectC
c:/path/to/projectA/projectD

This is exactly the sequence that you get when B doesn't have A for a parent (the trigger condition).
The algorithm fails to append "/" to the second path and the returned path is "c:/path/to" instead of "c:/path/to/projectA" and this is then used as the base directory for the tag. This is why the generated tag is one level too high in the directory tree.

*The fix:*

This method at the moment is as follows:

{noformat}
 public static String getCommonBasedir( List reactorProjects, char separator )
    {
        String basedir = null;
        for ( Iterator i = reactorProjects.iterator(); i.hasNext(); )
        {
            MavenProject p = (MavenProject) i.next();

            // we can only normalize paths with /
            String dir = FileUtils.normalize( p.getBasedir().getPath().replace( '\\', '/' ) );

            if ( basedir == null )
            {
                basedir = dir;
            }
            else
            {
                // always end in / so that we know what is a path and what is a partial directory name in the next call 
                if ( !basedir.endsWith( "/" ) )
                {
                    basedir = basedir + "/";
                }

                basedir = StringUtils.getCommonPrefix( new String[]{dir, basedir} );

                if ( !basedir.endsWith( "/" ) )
                {
                    basedir = basedir.substring( 0, basedir.lastIndexOf( "/" ) );
                }
            }
        }

        if ( basedir != null )
        {
            if ( basedir.endsWith( "/" ) && basedir.length() > 1 )
            {
                basedir = basedir.substring( 0, basedir.length() - 1 );
            }
            basedir = basedir.replace( '/', separator );
        }

        return basedir;
    }
{noformat}

It can be changed to the following, which correctly appends "/" to the end of both "basedir" AND "dir", which solves the problem.

{noformat}
    public static String getCommonBasedir(List reactorProjects, char separator) {
        String basedir = null;
        for (Iterator i = reactorProjects.iterator(); i.hasNext();) {
            MavenProject p = (MavenProject) i.next();

            // we can only normalize paths with /
            String dir = FileUtils.normalize(p.getBasedir().getPath().replace('\\', '/'));

            // always end in / so that we know what is a path and what is a partial directory name in the next call
            if (!dir.endsWith("/")) {
                dir = dir + "/";
            }

            if (basedir == null) {
                basedir = dir;
            } else {

                basedir = StringUtils.getCommonPrefix(new String[] { dir, basedir });

                if (!basedir.endsWith("/")) {
                    basedir = basedir.substring(0, basedir.lastIndexOf("/"));
                }
            }
        }

        if (basedir != null) {
            if (basedir.endsWith("/") && basedir.length() > 1) {
                basedir = basedir.substring(0, basedir.length() - 1);
            }
            basedir = basedir.replace('/', separator);
        }

        return basedir;
    }
{noformat}


Sorry for the long post!

> release:prepare 2.0 goal tags at the wrong level, tagging project/ instead of project/trunk
> -------------------------------------------------------------------------------------------
>
>                 Key: MRELEASE-526
>                 URL: http://jira.codehaus.org/browse/MRELEASE-526
>             Project: Maven 2.x Release Plugin
>          Issue Type: Bug
>          Components: prepare
>    Affects Versions: 2.0
>         Environment: Maven 2.2.1
>            Reporter: Damien Coraboeuf
>            Priority: Critical
>             Fix For: 2.1
>
>         Attachments: export.zip
>
>
> We have switched to the release plug-in 2.0 and are using the prepare goal as we did before using version 2.0-beta-9. Unfortunately, the tag which is now created is copied from the project level, and from the trunk. With version 2.0-beta-9, the tag was correctly copied from the trunk.
> With 2.0-beta-9:
> {noformat}
>  /project
>    |-- trunk/
>          |-- pom.xml
>          |-- src/
>    |-- tags/
>          |-- 4.0.1/ (<-- copied from trunk
>               |-- pom.xml
>               |-- src/
> {noformat}
> With 2.0:
> {noformat}
>  /project
>    |-- trunk/
>          |-- pom.xml
>          |-- src/
>    |-- tags/
>          |-- 4.0.1/ (<-- copied from trunk
>               |-- trunk/
>                    |-- pom.xml
>                    |-- src/
>               |-- tags/
>               |-- branches/
> {noformat}
> Our _pom.xml_ SCM information is declared as follow:
> {noformat}
> <scm>
> 	<developerConnection>scm:svn:svn://host/path/project/trunk</developerConnection>
> </scm>
> {noformat}

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.codehaus.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira