From c4d692c98f3e06d39cf80bf8fa2035c2e398646b Mon Sep 17 00:00:00 2001 From: df89 <df89@me.com> Date: Sun, 10 Oct 2021 18:24:20 +0200 Subject: [PATCH] refactor: separated script into different files --- commitBody.py | 49 ++++++ /dev/null | 235 ----------------------------- scope.py | 7 commitTag.py | 22 ++ main.py | 107 +++++++++++++ functions.py | 20 ++ rawcommit.py | 6 commit.py | 12 + 8 files changed, 223 insertions(+), 235 deletions(-) diff --git a/commit.py b/commit.py new file mode 100644 index 0000000..5272465 --- /dev/null +++ b/commit.py @@ -0,0 +1,12 @@ +from commitBody import CommitBody +from commitTag import CommitTag + +class Commit: + def __init__(self, rawCommit): + self.body = CommitBody(rawCommit.body) + self.tag = CommitTag(rawCommit.tag) + self.hash = rawCommit.hash + + def appendShortHash(self): + """return the first digits from the hash as string""" + return " (" + self.hash[:6] + ")" \ No newline at end of file diff --git a/commitBody.py b/commitBody.py new file mode 100644 index 0000000..438f22f --- /dev/null +++ b/commitBody.py @@ -0,0 +1,49 @@ +class CommitBody: + commitTypes = ("build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "style", "test") + def __init__(self, completeMessage): + self.completeMessage = completeMessage + + self.setSubjectAndBody() + self.setScope() + self.setCommitType() + + def setSubjectAndBody(self): + """set commit message subject and body (not in use yet)""" + try: # find start point of commit message + subStart = self.completeMessage.index(": ")+2 + except: + try: + subStart = self.completeMessage.index("\n") + except: + subStart = 0 + try: # find end point of commit message + subEnd = self.completeMessage.index("\n") + except: + self.subject = self.completeMessage[subStart:] + self.body = None + else: + self.subject = self.completeMessage[subStart:subEnd] + self.body = self.completeMessage[subEnd:].strip() + + def setScope(self): + """set commit scope if contained in message""" + try: + start = self.completeMessage.index("(")+1 + end = self.completeMessage.index("):") + except: + self.scope = None + else: + self.scope = self.completeMessage[start:end].strip().lower() + + def setCommitType(self): + """set commit type according to type list from conventional commits""" + for commitType in self.commitTypes: + if (self.completeMessage.startswith((commitType + ": "))) or (self.completeMessage.startswith((commitType + "("))) or (self.completeMessage.startswith((commitType + " ("))): + self.commitType = commitType + break + else: + self.commitType = "nonconform" + + def getCommitMessageWithType(self): + """get commit type and message subject as concatenated string""" + return self.commitType + ": " + self.subject \ No newline at end of file diff --git a/commitTag.py b/commitTag.py new file mode 100644 index 0000000..521e645 --- /dev/null +++ b/commitTag.py @@ -0,0 +1,22 @@ +class CommitTag: + def __init__(self, completeTag): + if not ("tag: " in completeTag): + self.completeTag = None + self.tagAsString = None + self.major = None + self.minor = None + self.bugfix = None + else: + self.completeTag = completeTag + self.setTagAsString() + self.setMajorMinorBugfix() + + def setTagAsString(self): + """set only the version number from tag as string""" + try: + self.tagAsString = self.completeTag[(self.completeTag.rindex(": v.")+4):-1] + except: + try: + self.tagAsString = self.completeTag[(self.completeTag.rindex(": v")+3):-1] + except: + self.tagAsString = self.completeTag[(self.completeTag.rindex(": ")+2):-1] diff --git a/functions.py b/functions.py new file mode 100644 index 0000000..ec0bb4a --- /dev/null +++ b/functions.py @@ -0,0 +1,20 @@ +import os.path + +from rawcommit import RawCommit +from commit import Commit + +def getCommitList(repo): + """returns a list of commits from a repository log""" + try: + stream = os.popen("git -C {} log --format=%B--SEP--%H--SEP--%d--END--".format(repo)) # formatted log + except: + raise ValueError("Not a valid git-repository!") + else: + gitLog = stream.read() + commitList = gitLog.split("--END--") # separation of individual commits + del commitList[-1] # deletes empty last element + + rawCommitList = [] + for commit in commitList: # convert every commit into Commit via RawCommit + rawCommitList.append(Commit(RawCommit(commit))) + return commitList \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..27c0420 --- /dev/null +++ b/main.py @@ -0,0 +1,107 @@ +import os.path +import sys + +from functions import getCommitList +from rawcommit import RawCommit +from commit import Commit +from scope import Scope +from commitBody import CommitBody + + +# Compute user input of repository path via console +inputPath = input("Please enter the base path of the repository: ").strip() +userDecision = input("Should the generated changelog be stored in another location (y/n)? ").lower().strip() +if userDecision == "y": + outputPath = input("Please enter the output path: ").strip() +elif userDecision == "n": + print("The changelog will be stored in the same location as the repository.") + outputPath = inputPath +else: + print("invalid input") + sys.exit(1) + + +# create a list of separate commits in chronological order (new to old) +commitHistory = getCommitList(inputPath) + + +# Create a two-dimensional list by tags: [[tag, [commits]],[tag, [commits]],...] +taggedHistory = [] +for commit in commitHistory: + if commit.tag.tagAsString: + taggedHistory.append([commit.tag, commit]) + else: + if len(taggedHistory) == 0: + taggedHistory.append([None, commit]) + else: + taggedHistory[-1].append(commit) + + +# Construction of the changelog-file +fileTemplate = ["# Changelog"] +for tag in taggedHistory: + ## If latest commit has no tag: + if not tag[0]: + fileTemplate.append("\n## Without version number") + else: + fileTemplate.append("\n## Version " + tag[0].tagAsString) + + + ## Grouping by Type + featType = ["Features"] + fixType = ["Fixes"] + otherType = ["Other"] + nonconformCommits = [] + + for commit in tag[1:]: + if commit.body.commitType == CommitBody.commitTypes[5]: # fix + fixType.append(commit) + elif commit.body.commitType == CommitBody.commitTypes[4]: # feat + featType.append(commit) + elif commit.body.commitType == "nonconform": + nonconformCommits.append(commit) + else: + otherType.append(commit) + + ## Sub-Grouping by Scopes within Types + commitlistByType = [featType, fixType, otherType] + for commitsByType in commitlistByType: + if len(commitsByType) == 1: + continue + commitlistByScope = {} + noScope = [] + for commit in commitsByType: + if type(commit) == str: + continue + if commit.body.scope == None: + noScope.append(commit) + elif commit.body.scope in commitlistByScope: + commitlistByScope[commit.body.scope].append(commit) + else: + commitlistByScope[commit.body.scope] = [commit] + + fileTemplate.append("\n### " + commitsByType[0]) + while len(commitlistByScope) > 0: + scope, commits = commitlistByScope.popitem() + fileTemplate.append("- *" + str(scope) + "*") + for commit in commits: + if commitsByType[0] == "Other": + fileTemplate.append(" - (" + commit.body.commitType + ") " + commit.body.subject + commit.appendShortHash()) + else: + fileTemplate.append(" - " + commit.body.subject + commit.appendShortHash()) + if len(noScope) > 0: + fileTemplate.append("- *no scope*") + for commit in noScope: + fileTemplate.append(" - " + commit.body.subject + commit.appendShortHash()) + + ## nonconform commits + if len(nonconformCommits) > 0: + fileTemplate.append("\n### Non-conform commits") + for commit in nonconformCommits: + fileTemplate.append("- " + commit.body.subject + commit.appendShortHash()) + + +# write into changelog.md file +with open(outputPath + "/changelog.md", "w") as file: + for line in fileTemplate: + file.write(line + "\n") \ No newline at end of file diff --git a/oop_changelog.py b/oop_changelog.py deleted file mode 100644 index fe19006..0000000 --- a/oop_changelog.py +++ /dev/null @@ -1,205 +0,0 @@ -import os.path - -## To Do -# - Breaking Changes -# - Merge Commits -# - Error Handling - -def getSeparatedGitLog(repo): - try: - stream = os.popen("git -C {} log --format=%B--SEP--%H--SEP--%d--END--".format(repo)) - except: - raise ValueError("Not a valid git-repository!") - else: - gitLog = stream.read() - commitList = gitLog.split("--END--") - del commitList[-1] - return commitList - - -class RawCommit: - def __init__(self, completeCommit): - self.raw = completeCommit.split("--SEP--") - self.body = self.raw[0].strip() - self.hash = self.raw[1].strip() - self.tag = self.raw[2].strip() - - -class CommitBody: - commitTypes = ("build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "style", "test") - def __init__(self, completeMessage): - self.completeMessage = completeMessage - #self.subject = None - #self.body = None - #self.scope = None - #self.commitType = None - - self.setSubjectAndBody() - self.setScope() - self.setCommitType() - - def setSubjectAndBody(self): - try: - subStart = self.completeMessage.index(": ")+2 - except: - try: - subStart = self.completeMessage.index("\n") - except: - subStart = 0 - try: - subEnd = self.completeMessage.index("\n") - except: - self.subject = self.completeMessage[subStart:] - self.body = None - else: - self.subject = self.completeMessage[subStart:subEnd] - self.body = self.completeMessage[subEnd:].strip() - - def setScope(self): - try: - start = self.completeMessage.index("(")+1 - end = self.completeMessage.index(")") - except: - self.scope = None - else: - self.scope = self.completeMessage[start:end] - - def setCommitType(self): - for commitType in self.commitTypes: - if (self.completeMessage.startswith((commitType + ": "))) or (self.completeMessage.startswith((commitType + "("))) or (self.completeMessage.startswith((commitType + " ("))): - self.commitType = commitType - break - else: - self.commitType = "nonconform" - - def getCommitMessageWithType(self): - return self.commitType + ": " + self.subject - - -class CommitTag: - def __init__(self, completeTag): - if not ("tag: " in completeTag): - self.completeTag = None - self.tagAsString = None - self.major = None - self.minor = None - self.bugfix = None - else: - self.completeTag = completeTag - self.setTagAsString() - self.setMajorMinorBugfix() - - def setTagAsString(self): - try: ## this one is temporary - self.tagAsString = self.completeTag[(self.completeTag.rindex(": v.")+4):-1] - except: - try: - self.tagAsString = self.completeTag[(self.completeTag.rindex(": v")+3):-1] - except: - self.tagAsString = self.completeTag[(self.completeTag.rindex(": ")+2):-1] - - def setMajorMinorBugfix(self): - versionList = self.tagAsString.split(".") - self.major = versionList[0] - self.minor = versionList[1] - self.bugfix = versionList[2] - - @staticmethod - def getUpdateType(newTag, previousTag): - if newTag.major > previousTag.major: - return "major" - elif newTag.minor > previousTag.minor: - return "minor" - elif newTag.bugfix > previousTag.bugfix: - return "bugfix" - - -class Commit: - def __init__(self, rawCommit): - self.body = CommitBody(rawCommit.body) - self.tag = CommitTag(rawCommit.tag) - self.hash = rawCommit.hash - - def appendShortHash(self): - return " (" + self.hash[:6] + ")" - - - -#### Main #### - -pathToRepo = "/Users/daniel/Developer/Repos/HfM/schumacher/Prisma-Binauralize" -#pathToRepo = "/Users/daniel/Desktop/testrepo" - -commitList = getSeparatedGitLog(pathToRepo) - -# Create a list of commits -commitHistory = [] -for commit in commitList: - commitHistory.append(Commit(RawCommit(commit))) - -# Create a two-dimensional list by tags: [[tag, [commits]],[tag, [commits]],...] -taggedHistory = [] -for commit in commitHistory: - if commit.tag.tagAsString: - taggedHistory.append([commit.tag, commit]) - else: - if len(taggedHistory) == 0: - taggedHistory.append([None, commit]) - else: - taggedHistory[-1].append(commit) - - -# Construction of the changelog-file -fileTemplate = ["# Changelog"] -for tag in taggedHistory: - # A Dictionairy to store grouped commits - commitsByType = {"fix":[], "feat":[], "Other":[], "Nonconform":[]} - - # If latest commit has no tag: - if not tag[0]: - fileTemplate.append("\n## No version number yet") - else: - fileTemplate.append("\n## Version " + tag[0].tagAsString) - - # Grouping by CommitTypes - for commit in tag[1:]: - if commit.body.commitType == CommitBody.commitTypes[5]: # fix - commitsByType["fix"].append(commit) - elif commit.body.commitType == CommitBody.commitTypes[4]: # feat - commitsByType["feat"].append(commit) - elif commit.body.commitType == "nonconform": - commitsByType["Nonconform"].append(commit) - else: - commitsByType["Other"].append(commit) - - if len(commitsByType["feat"]) != 0: - fileTemplate.append("### Features") - for feature in commitsByType["feat"]: - if feature.body.scope: - fileTemplate.append("- **" + feature.body.scope + "**: " + feature.body.subject + feature.appendShortHash()) - else: - fileTemplate.append("- " + feature.body.subject + feature.appendShortHash()) - if len(commitsByType["fix"]) != 0: - fileTemplate.append("### Fixes") - for fix in commitsByType["fix"]: - if fix.body.scope: - fileTemplate.append("- **" + fix.body.scope + "**: " + fix.body.scope + fix.appendShortHash()) - else: - fileTemplate.append("- " + fix.body.subject + fix.appendShortHash()) - if len(commitsByType["Other"]) != 0: - fileTemplate.append("### Other") - for other in commitsByType["Other"]: - if other.body.scope: - fileTemplate.append("- **" + other.body.scope + "**: " + other.body.getCommitMessageWithType() + other.appendShortHash()) - else: - fileTemplate.append("- " + other.body.getCommitMessageWithType() + other.appendShortHash()) - if len(commitsByType["Nonconform"]) != 0: - fileTemplate.append("### Non-conventional") - for nonconform in commitsByType["Nonconform"]: - fileTemplate.append("- " + nonconform.body.subject + nonconform.appendShortHash()) - - -# write into changelog -with open(pathToRepo + "/changelog.md", "w") as file: - for line in fileTemplate: - file.write(line + "\n") \ No newline at end of file diff --git a/oop_changelog_scope.py b/oop_changelog_scope.py deleted file mode 100644 index 050dbd7..0000000 --- a/oop_changelog_scope.py +++ /dev/null @@ -1,235 +0,0 @@ -import os.path -import sys - -## To Do -# - Breaking Changes -# - Merge Commits -# - Deal with wrong user input (spelling, no repo) - -def getSeparatedGitLog(repo): - try: - stream = os.popen("git -C {} log --format=%B--SEP--%H--SEP--%d--END--".format(repo)) - except: - raise ValueError("Not a valid git-repository!") - else: - gitLog = stream.read() - commitList = gitLog.split("--END--") - del commitList[-1] - return commitList - - -class RawCommit: - def __init__(self, completeCommit): - self.raw = completeCommit.split("--SEP--") - self.body = self.raw[0].strip() - self.hash = self.raw[1].strip() - self.tag = self.raw[2].strip() - - -class CommitBody: - commitTypes = ("build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "style", "test") - def __init__(self, completeMessage): - self.completeMessage = completeMessage - #self.subject = None - #self.body = None - #self.scope = None - #self.commitType = None - - self.setSubjectAndBody() - self.setScope() - self.setCommitType() - - def setSubjectAndBody(self): - try: - subStart = self.completeMessage.index(": ")+2 - except: - try: - subStart = self.completeMessage.index("\n") - except: - subStart = 0 - try: - subEnd = self.completeMessage.index("\n") - except: - self.subject = self.completeMessage[subStart:] - self.body = None - else: - self.subject = self.completeMessage[subStart:subEnd] - self.body = self.completeMessage[subEnd:].strip() - - def setScope(self): - try: - start = self.completeMessage.index("(")+1 - end = self.completeMessage.index("):") - except: - self.scope = None - else: - self.scope = self.completeMessage[start:end].strip().lower() - - def setCommitType(self): - for commitType in self.commitTypes: - if (self.completeMessage.startswith((commitType + ": "))) or (self.completeMessage.startswith((commitType + "("))) or (self.completeMessage.startswith((commitType + " ("))): - self.commitType = commitType - break - else: - self.commitType = "nonconform" - - def getCommitMessageWithType(self): - return self.commitType + ": " + self.subject - -class Scope: - def __init__(self, name): - self.name = name.strip().lower() - - @staticmethod - def createScope(name): - return Scope(name) - -class CommitTag: - def __init__(self, completeTag): - if not ("tag: " in completeTag): - self.completeTag = None - self.tagAsString = None - self.major = None - self.minor = None - self.bugfix = None - else: - self.completeTag = completeTag - self.setTagAsString() - self.setMajorMinorBugfix() - - def setTagAsString(self): - try: ## this one is temporary - self.tagAsString = self.completeTag[(self.completeTag.rindex(": v.")+4):-1] - except: - try: - self.tagAsString = self.completeTag[(self.completeTag.rindex(": v")+3):-1] - except: - self.tagAsString = self.completeTag[(self.completeTag.rindex(": ")+2):-1] - - def setMajorMinorBugfix(self): - versionList = self.tagAsString.split(".") - self.major = versionList[0] - self.minor = versionList[1] - self.bugfix = versionList[2] - - @staticmethod - def getUpdateType(newTag, previousTag): - if newTag.major > previousTag.major: - return "major" - elif newTag.minor > previousTag.minor: - return "minor" - elif newTag.bugfix > previousTag.bugfix: - return "bugfix" - - -class Commit: - def __init__(self, rawCommit): - self.body = CommitBody(rawCommit.body) - self.tag = CommitTag(rawCommit.tag) - self.hash = rawCommit.hash - - def appendShortHash(self): - return " (" + self.hash[:6] + ")" - - - -#### Main #### - -inputPath = input("Please enter the base path of the repository: ").strip() -userDecision = input("Should the generated changelog be stored in another location (y/n)? ").lower().strip() -if userDecision == "y": - outputPath = input("Please enter the output path: ").strip() -elif userDecision == "n": - print("The changelog will be stored in the same location as the repository.") - outputPath = inputPath -else: - print("invalid input") - sys.exit(1) - -commitList = getSeparatedGitLog(inputPath) - -# Create a list of commits -commitHistory = [] -for commit in commitList: - commitHistory.append(Commit(RawCommit(commit))) - -# Create a two-dimensional list by tags: [[tag, [commits]],[tag, [commits]],...] -taggedHistory = [] -for commit in commitHistory: - if commit.tag.tagAsString: - taggedHistory.append([commit.tag, commit]) - else: - if len(taggedHistory) == 0: - taggedHistory.append([None, commit]) - else: - taggedHistory[-1].append(commit) - - -# Construction of the changelog-file -fileTemplate = ["# Changelog"] -for tag in taggedHistory: - # If latest commit has no tag: - if not tag[0]: - fileTemplate.append("\n## Without version number") - else: - fileTemplate.append("\n## Version " + tag[0].tagAsString) - - - # Grouping by Type - featType = ["Features"] - fixType = ["Fixes"] - otherType = ["Other"] - nonconformCommits = [] - - for commit in tag[1:]: - if commit.body.commitType == CommitBody.commitTypes[5]: # fix - fixType.append(commit) - elif commit.body.commitType == CommitBody.commitTypes[4]: # feat - featType.append(commit) - elif commit.body.commitType == "nonconform": - nonconformCommits.append(commit) - else: - otherType.append(commit) - - # Sub-Grouping by Scopes within Types - commitlistByType = [featType, fixType, otherType] - for commitsByType in commitlistByType: - if len(commitsByType) == 1: - continue - commitlistByScope = {} - noScope = [] - for commit in commitsByType: - if type(commit) == str: - continue - if commit.body.scope == None: - noScope.append(commit) - elif commit.body.scope in commitlistByScope: - commitlistByScope[commit.body.scope].append(commit) - else: - commitlistByScope[commit.body.scope] = [commit] - - fileTemplate.append("\n### " + commitsByType[0]) - while len(commitlistByScope) > 0: - scope, commits = commitlistByScope.popitem() - fileTemplate.append("- *" + str(scope) + "*") - for commit in commits: - if commitsByType[0] == "Other": - fileTemplate.append(" - (" + commit.body.commitType + ") " + commit.body.subject + commit.appendShortHash()) - else: - fileTemplate.append(" - " + commit.body.subject + commit.appendShortHash()) - if len(noScope) > 0: - fileTemplate.append("- *no scope*") - for commit in noScope: - fileTemplate.append(" - " + commit.body.subject + commit.appendShortHash()) - - # nonconform commits - if len(nonconformCommits) > 0: - fileTemplate.append("\n### Non-conform commits") - for commit in nonconformCommits: - fileTemplate.append("- " + commit.body.subject + commit.appendShortHash()) - - -# write into changelog -with open(outputPath + "/changelog.md", "w") as file: - for line in fileTemplate: - file.write(line + "\n") \ No newline at end of file diff --git a/rawcommit.py b/rawcommit.py new file mode 100644 index 0000000..e9a80f4 --- /dev/null +++ b/rawcommit.py @@ -0,0 +1,6 @@ +class RawCommit: + def __init__(self, completeCommit): + self.raw = completeCommit.split("--SEP--") + self.body = self.raw[0].strip() + self.hash = self.raw[1].strip() + self.tag = self.raw[2].strip() diff --git a/scope.py b/scope.py new file mode 100644 index 0000000..088f48d --- /dev/null +++ b/scope.py @@ -0,0 +1,7 @@ +class Scope: + def __init__(self, name): + self.name = name.strip().lower() + + @staticmethod + def createScope(name): + return Scope(name) \ No newline at end of file -- Gitblit v1.9.1