Last active
July 13, 2022 14:26
-
-
Save nickgr6/a6837b0c01a4f230bc26 to your computer and use it in GitHub Desktop.
Merge pom's via python git driver. This code is highly specific for my own project structure. Use at your own risk.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env python | |
import sys | |
import subprocess | |
import shlex | |
import codecs | |
import xml.dom.minidom as dom | |
class PomProperty: | |
"""__init__() functions as the class constructor""" | |
def __init__(self, pomFile, propertKey): | |
self.propertyKey = propertKey | |
self.initialValue = get_property_value(propertKey, pomFile) | |
def change_property(fileContents, propertyKey, old_value, new_value): | |
propertyOpenTag = "<{0}>".format(propertyKey) | |
propertyCloseTag = "</{0}>".format(propertyKey) | |
# Can be uncommented for debug purposes. | |
# print "Replace: " + propertyOpenTag + old_value + propertyCloseTag | |
# print "- with:" + propertyOpenTag + new_value + propertyCloseTag | |
# | |
# print "" | |
return fileContents.replace( | |
propertyOpenTag + old_value + propertyCloseTag, | |
propertyOpenTag + new_value + propertyCloseTag | |
) | |
def get_project_version(f): | |
try: | |
tree = dom.parse(f) | |
version = None | |
parent_version = None | |
for entry in tree.documentElement.childNodes: | |
if entry.nodeName == "version": | |
version = entry.firstChild.data | |
if entry.nodeName == "parent": | |
for entry2 in entry.childNodes: | |
if entry2.nodeName == 'version': | |
parent_version = entry2.firstChild.data | |
if version is not None: | |
# version has a priority over parent version | |
return version | |
else: | |
# may return None | |
return parent_version | |
except: | |
print(sys.argv[0] + ': error while parsing pom.xml') | |
return None | |
def get_property_value(propertyName, file): | |
try: | |
tree = dom.parse(file) | |
version = None | |
parent_version = None | |
for entry in tree.documentElement.childNodes: | |
if entry.nodeName == "properties": | |
for entry2 in entry.childNodes: | |
if entry2.nodeName == propertyName: | |
parent_version = entry2.firstChild.data | |
if version is not None: | |
# version has a priority over parent version | |
return version | |
else: | |
# may return None | |
return parent_version | |
except: | |
print('Error while parsing pom.xml') | |
return None | |
if (len(sys.argv) < 4 or len(sys.argv) > 5): | |
print("Wrong number of arguments: " + str(len(sys.argv))) | |
sys.exit(-1) | |
baseFile = sys.argv[1] | |
oursFile = sys.argv[2] | |
theirsFile = sys.argv[3] | |
current_branch_version = get_project_version(oursFile) # Ours | |
other_branch_version = get_project_version(theirsFile) # Theirs | |
pomPropertiesToKeep = [ | |
PomProperty(oursFile, "module1.version"), | |
PomProperty(oursFile, "module2.version"), | |
PomProperty(oursFile, "module3.version"), | |
PomProperty(oursFile, "module4.version") | |
] | |
# Change the 'ours' pom version (including the properties as defined in the 'properties map' above | |
# to the pom version of the incoming file to avoid merge conflicts. | |
# Later in the process, the 'ours' pom version is restored. | |
with codecs.open(oursFile, 'r', 'utf-8') as f: | |
newTempOursPomContent = f.read() | |
newTempOursPomContent = change_property(newTempOursPomContent, "version", current_branch_version, other_branch_version) | |
for pomProperty in pomPropertiesToKeep: | |
theirsVersion = get_property_value(pomProperty.propertyKey, theirsFile) | |
if (pomProperty.initialValue != None and theirsVersion != None): | |
newTempOursPomContent = change_property( | |
newTempOursPomContent, | |
pomProperty.propertyKey, | |
pomProperty.initialValue, | |
theirsVersion | |
) | |
with codecs.open(oursFile, 'w', 'utf-8') as f: | |
f.write(newTempOursPomContent) | |
# Start merge the files -> the -p value makes sure, the merge is not performed on the actual files, | |
# but printed to the terminal. This way we can check if other merge conflicts will occur, | |
# before restoring our original version values we'd like to keep.. | |
testMergeCommand = "git merge-file -p -L mine -L base -L theirs " + oursFile + " " + baseFile + " " + theirsFile | |
process = subprocess.Popen(shlex.split(testMergeCommand), stdout=subprocess.PIPE) | |
git_merge_res = process.communicate()[0] | |
mergeReturnCode = process.returncode | |
gitMergeResultPomContents = git_merge_res.strip().decode('utf-8') | |
# Revert the 'ours' pom version back to it's own original version.. | |
gitMergeResultPomContents = change_property(gitMergeResultPomContents, "version", other_branch_version, | |
current_branch_version) | |
# Change all the defined propertie 'versions' back to the original branch value, BUT only | |
# if the property has the same value as the pom's main <version> value. Or if the 'theirs' value contains '1.feature_', | |
# because we don't want to take over 'feature specific' dependency versions.. | |
# We do this because: | |
# - When developing a feature over multiple projects, we can keep this branches 'coupled' | |
# - But when, for example, the main project doesn't need a specific feature branch, we can update it | |
# with whatever value the branch is merged with (probably the master branch). | |
for pomProperty in pomPropertiesToKeep: | |
theirsVersion = get_property_value(pomProperty.propertyKey, theirsFile) | |
if (pomProperty.initialValue != None and ( | |
(pomProperty.initialValue == current_branch_version and theirsVersion != None) | |
or "1.feature_" in theirsVersion | |
)): | |
gitMergeResultPomContents = change_property(gitMergeResultPomContents, | |
pomProperty.propertyKey, | |
theirsVersion, | |
pomProperty.initialValue | |
) | |
# Write the new contents to 'ours' file as merge result. | |
with codecs.open(oursFile, 'w', 'utf-8') as f: | |
f.write(gitMergeResultPomContents) | |
print "git merge result code: " + str(mergeReturnCode) | |
## Uncomment following line to always force merge conflict | |
# sys.exit(5) | |
sys.exit(mergeReturnCode) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment