Skip to content

Instantly share code, notes, and snippets.

@gaponcec
Created December 6, 2018 16:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gaponcec/99f19e2bc972761e11ccba2260622d10 to your computer and use it in GitHub Desktop.
Save gaponcec/99f19e2bc972761e11ccba2260622d10 to your computer and use it in GitHub Desktop.
Script to create Release Notes/Change Log from two ISO manifests
"""
Script to create release notes from project manifests
"""
#!/usr/bin/env python3
from json import dumps, loads
from os.path import basename
from sys import exit
from xml.etree.ElementTree import fromstringlist
from argparse import ArgumentParser
from git import Repo, repo, Git
from git.exc import GitError
from prettytable import PrettyTable, NONE
from xmljson import gdata
import dictdiffer
def load_manifest_to_dict(manifest):
"""
Loads manifest file into a dictionary and returns it
manifest -- manifest file path/name
"""
with open(manifest, "r") as file_desc:
data = file_desc.readlines()
return loads(dumps(gdata.data(fromstringlist(data))))
def check_dict_diff(o_re, n_re):
"""
Checks differences between dictionaries and returns a list of them
o_re -- old dictionary
n_re -- new dictionary
"""
return list(dictdiffer.diff(o_re, n_re))
def get_remotes_dict(remotes):
"""
Creates a dictionary with the remotes names and URLS and returns it
remotes -- remotes dictionary created from manifest xml
"""
rem_dict = {}
for i in remotes:
rem_dict[i['name']] = i['fetch']
return rem_dict
def clone_repo(repo_url, directory):
"""
Clones a git repo and returns an object to manipulate it
repo_url -- URL to git repository
directory -- directory to clone the repo
"""
try:
Repo.clone_from(repo_url, directory)
except GitError:
return Repo(directory)
return Repo(directory)
def create_argument_parser():
"""
Creates an argument parser
"""
parser = ArgumentParser('Compares changes between ISOs using manifest')
parser.add_argument('-o', '--old', type=str, nargs=1, required=True,
metavar='manifest.xml', help='Old manifest path')
parser.add_argument('-n', '--new', type=str, nargs=1, required=True,
metavar='manifest.xml', help='Old manifest path')
return parser
ARG_PARSE = create_argument_parser().parse_args()
OLD_MANIFEST_NAME = ARG_PARSE.old[0]
NEW_MANIFEST_NAME = ARG_PARSE.new[0]
OLD_MAN = load_manifest_to_dict(OLD_MANIFEST_NAME)
NEW_MAN = load_manifest_to_dict(NEW_MANIFEST_NAME)
DIFF = check_dict_diff(OLD_MAN['manifest']['remote'],
NEW_MAN['manifest']['remote'])
if DIFF != []:
print("something changed on the remotes")
exit(1)
REMOTES_DICT = get_remotes_dict(OLD_MAN['manifest']['remote'])
DIFF = check_dict_diff(OLD_MAN['manifest']['project'],
NEW_MAN['manifest']['project'])
RELEASE_NOTES = "RELEASE NOTES FROM " + basename(OLD_MANIFEST_NAME)
RELEASE_NOTES += " TO " + basename(NEW_MANIFEST_NAME) + "\n"
if DIFF != []:
FOR_RELEASE = []
DIFF2 = dict()
for _, k, l in DIFF:
if k[0] in DIFF2.keys():
if DIFF2[k[0]] == 'upstream':
DIFF2[k[0]] = {k[1]: l}
else:
DIFF2[k[0]] = {k[1]: l}
for m in DIFF2:
b = DIFF2[m].popitem()[1]
if 'remote' not in NEW_MAN['manifest']['project'][m].keys():
NEW_MAN['manifest']['project'][m]['remote'] = \
NEW_MAN['manifest']['default']['remote']
FOR_RELEASE.append({
'name': NEW_MAN['manifest']['project'][m]['name'],
'remote': REMOTES_DICT[NEW_MAN['manifest']['project'][m]['remote']],
'old_rev': b[0],
'new_rev': b[1]
})
for r in FOR_RELEASE:
TEMP = ''
try:
TEMP += "\n\nFrom repo: " + r['name'] + "\n"
repo = clone_repo("{}/{}".format(r['remote'], r['name']), r['name'])
git = Git(r['name'])
repo.head.reference = repo.commit(r['old_rev'])
old_logs = git.log('--pretty=%ai$%h$%s$%aE').split('\n')
repo.head.reference = repo.commit(r['new_rev'])
new_logs = git.log('--pretty=%ai$%h$%s$%aE').split('\n')
diff_logs = set(new_logs) - set(old_logs)
if list(diff_logs) == []:
raise ValueError('No changes were found.')
p_table = PrettyTable(header_style="upper", vrules=NONE)
p_table.field_names = ['Date', 'Commit', 'Message', 'Author']
for d in diff_logs:
p_table.add_row(d.split('$'))
p_table.sortby = "Date"
p_table.align = "l"
TEMP += p_table.get_string()
except:
TEMP = ''
RELEASE_NOTES += TEMP
else:
RELEASE_NOTES += "NO CHANGES"
print(RELEASE_NOTES)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment