Maven is overly strict with version numbers. The release plugin expects either numbers or alphas, but not both, with or without the -SNAPSHOT extension. Another problem is that release:prepare does not change plugin configuration if it depends on a version thats being built in the reactor build.
Maven plugins can be buggy at the best of times so I prefer to do this stuff myself anyway ;)
With all that in mind, I took to Groovy to solve my problems. Firstly, I needed a class to hold my pom data:
package branch.modify.transform
import java.io.File;
class PomData{
def root
File pomFile
String artifactId
String groupId
boolean persistFile
}
... and then I went on to use DOMCategory to create this little beauty:
class PomTransformer {
def skipDirectories = ['.svn', 'src', '.metadata']
def updateDependencies = { findIn, pomData, newValue ->
println "updating dependencies for ${pomData.artifactId}, ${pomData.groupId}"
use(DOMCategory){
pomData.root.'**'.findAll {
(it.artifactId.text() == findIn.artifactId && it.groupId.text() == findIn.groupId)
}.each{
pomData.persistFile = changeVersion(it.version, newValue, pomData.persistFile)
}
}
return pomData
}
def transform(workingDirectory, version){
File startDir = new File(workingDirectory)
assert "File is not a directory", startDir.isDirectory()
List pomList = []
startDir.eachFileRecurse { File file ->
if(file.isDirectory() && skipDirectories.any{ it == file.name } ){
return
}
if(file.name == "pom.xml"){
println "reading file ${file.path}"
def doc = DOMBuilder.parse(new FileReader(file))
def project = doc.documentElement
use(DOMCategory){
def artifact = project.artifactId[0]?.text()
def group = project.groupId[0]?.text()
println "adding group $group and artifact $artifact to list"
PomData data = new PomData(root: project, artifactId:artifact, groupId: group, pomFile: file)
pomList.add(data)
}
}
}
replaceValues(pomList, version)
for (PomData it : pomList) {
File f = new File(it.pomFile.path).asWritable()
if(f.canWrite() && it.persistFile){
String xml = XmlUtil.serialize(it.root)
println "writing $f.path"
f.write(xml)
}else{
println "${it.persistFile ? 'cannot' : 'no version change, not going to'} write to file ${f.path}"
}
}
}
def replaceValues(list, ver){
use(DOMCategory){
new ArrayList(list).each{
it.persistFile = changeVersion(it.root.version, ver, it.persistFile)
new ArrayList(list).each{ data ->
updateDependencies(it, data, ver) // update dependencies in other poms
}
}
}
}
def changeVersion(versionElements, ver, persistFile){
if(!versionElements){
println "no element found"
return
}
persistFile = ((versionElements[0]?.text() != ver) || persistFile)
if(persistFile){
versionElements[0]?.value = ver
}
return persistFile
}
}
Firstly, you obviously need to check out your dependent projects into a folder. I am assuming here that each project you check out is part of a multi-module build, and that each project is in some way dependent on the others.
To run the transformer, call "transform" with the working directory (the folder you checked all the projects out in to), and a version (such as 3.1.2-SNAPSHOT). Transform moves through the entire workspace directory by directory, and gathers the poms it needs to change in a list.
Once it has gathered these, it calls replaceValues. This method goes through each of the gathered poms and changes the version in that pom file, and also any reference to the same module in the other pom files in any element it finds.
The only thing this does not do is change any scm information, which it can be modified to do but I have not done (yet) - I do it another more convoluted way.
Hope this is useful :)

0 comments:
Post a Comment