0

My problem: versions-maven-plugin helps me to up version in some module (let's call it A) in my multi-module maven project.

Some modules (let's call it B and C) in this project have in dependencies module A. I need to up versions for this modules (B and C) too. Sometimes, i also need to up version in other module (B-parent) where B (or C) in dependencies (A version up -> B version up -> B-parent version up). Other problem is the modules can be at different levels of nesting.

Example:

root:
  ---B-parent: 
       ---B (A in dependencies)
  ---C-parent
       ---C (A in dependencies)
  ---A-parent: 
       ---A

Process: A version up -> A-parent version up, C version-up -> C-parent version-up, B version-up -> B-parent version up.

This plugin can't do this.

Is there any idea how this can be done? Or my strategy of updating versions is not good enough?

mchernyakov
  • 196
  • 3
  • 14
  • 1
    You can use LATEST in module B & C for specifying a version module A. BUT LATEST is **DEPRECATED** future. – Eugene Roldukhin Jan 06 '18 at 14:49
  • You should not use `LATEST` anymore cause yes it's deprecated and starting with Maven 3.5.2 you will get WARNINGs about that...Furthermore I assume that those projects are within a single multi module build? If yes than you shouldn't have that problem..maybe I misunderstand your question..Usually you use maven-release-plugin and all versions are in line and there shouldn't be an issue using the version of A (should be defined by `${project.version}`? Or are we talking about a dependency which is not a module ? – khmarbaise Jan 06 '18 at 15:21
  • @khmarbaise this dependecy (A) are nested module in multi-module project. And yes, it is single build. If possible, I want to avoid using maven-release-plugin. – mchernyakov Jan 07 '18 at 13:13
  • Ok than you can use `versions-maven-plugin` to set the version or use things like `${revision}` see detail in [Release Notes](http://maven.apache.org/docs/3.5.0/release-notes.html). Apart from that if it's nested module than there shouldn't be problem using `${project.version}`... – khmarbaise Jan 07 '18 at 18:34
  • @khmarbaise ok, thank you, but i think, my update strategy is not good. I will leave the question open, maybe someone will offer more options. – mchernyakov Jan 09 '18 at 07:55

1 Answers1

1

I've made a script for increasing version numbers in all dependent modules recursively with a versions-maven-plugin.

Algorithm is as follows:

  1. Run versions:set in target module
  2. Run versions:set in all modules which have been updated by versions:set from previous step. If the module has been already processed - skip it.
  3. Repeat step 2

Python 2.7 code

#!/usr/bin/env python
# -*- coding: utf-8 -*- #

# How To
#
# Run script and pass module path as a first argument.
# Or run it without arguments in module dir.
#
# Script will request the new version number for each module.
# If no version provided - last digit will be incremented (1.0.0 -> 1.0.1).
# cd <module-path>
# <project-dir>/increment-version.py
# ...
# review changes and commit

from subprocess import call, Popen, PIPE, check_output
import os
import re
import sys

getVersionCommand = "mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate " \
                    "-Dexpression=project.version 2>/dev/null | grep -v '\['"


def getCurrentModuleVersion():
    return check_output(getVersionCommand, shell=True).decode("utf-8").split("\n")[0]


def incrementLastDigit(version):
    digits = version.split(".")
    lastDigit = int(digits[-1])
    digits[-1] = str(lastDigit+1)
    return ".".join(digits)


def isUpdatedVersionInFile(version, file):
    return "<version>" + version + "</version>" in \
           check_output("git diff HEAD --no-ext-diff --unified=0 --exit-code -a --no-prefix {} "
                        "| egrep \"^\\+\"".format(file), shell=True).decode("utf-8")


def runVersionSet(version):
    process = Popen(["mvn", "versions:set", "-DnewVersion="+version, "-DgenerateBackupPoms=false"], stdout=PIPE)
    (output, err) = process.communicate()
    exitCode = process.wait()
    if exitCode is not 0:
        print "Error setting the version"
        exit(1)
    return output, err, exitCode


def addChangedPoms(version, dirsToVisit, visitedDirs):
    changedFiles = check_output(["git", "ls-files", "-m"]) \
        .decode("utf-8").split("\n")
    changedPoms = [f for f in changedFiles if f.endswith("pom.xml")]
    changedDirs = [os.path.dirname(os.path.abspath(f)) for f in changedPoms if isUpdatedVersionInFile(version, f)]
    changedDirs = [d for d in changedDirs if d not in visitedDirs and d not in dirsToVisit]
    print "New dirs to visit:", changedDirs
    return changedDirs


if __name__ == "__main__":
    visitedDirs = []
    dirsToVisit = []

    if len(sys.argv) > 1:
        if os.path.exists(os.path.join(sys.argv[1], "pom.xml")):
            dirsToVisit.append(os.path.abspath(sys.argv[1]))
        else:
            print "Error. No pom.xml file in dir", sys.argv[1]
            exit(1)
    else:
        dirsToVisit.append(os.path.abspath(os.getcwd()))

    pattern = re.compile("aggregation root: (.*)")
    while len(dirsToVisit) > 0:
        dirToVisit = dirsToVisit.pop()
        print "Visiting dir", dirToVisit
        os.chdir(dirToVisit)
        currentVersion = getCurrentModuleVersion()
        defaultVersion = incrementLastDigit(currentVersion)
        version = raw_input("New version for {}:{} ({}):".format(dirToVisit, currentVersion, defaultVersion))
        if not version.strip():
            version = defaultVersion
        print "New version:", version
        output, err, exitcode = runVersionSet(version)
        rootDir = pattern.search(output).group(1)
        visitedDirs = visitedDirs + [dirToVisit]
        os.chdir(rootDir)
        print "Adding new dirs to visit"
        dirsToVisit = dirsToVisit + addChangedPoms(version, dirsToVisit, visitedDirs)
Anton
  • 11
  • 1