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