Repository: ishepard/pydriller (python)

Issue:
from_tag/to_tag + multiple repos is broken
**Describe the bug**
I want to analyse multiple repos and I want to anyalze between tags (present in all repos).

**To Reproduce**
```
import re

from pydriller import RepositoryMining

repos = [
    "C:/jcb/code/montagel",
    "C:/jcb/code/Xrf",
]
print(repos)

starttag="com.jcbachmann.xrf.suite/v11"
endtag="com.jcbachmann.xrf.suite/v12"

for commit in RepositoryMining(path_to_repo=repos[0], from_tag=starttag, to_tag=endtag).traverse_commits():
    pass
print("repo 0 OK")

for commit in RepositoryMining(path_to_repo=repos[1], from_tag=starttag, to_tag=endtag).traverse_commits():
    pass
print("repo 1 OK")

for commit in RepositoryMining(path_to_repo=repos).traverse_commits():
    pass
print("repos untagged OK")

for commit in RepositoryMining(path_to_repo=repos, from_tag=starttag, to_tag=endtag).traverse_commits():
    pass
print("repos tagged OK")
```

```
C:\jcb\venvs\Xrf\Scripts\python.exe C:/jcb/code/Xrf-Python/Documentation/chapters/software/bug.py
['C:/jcb/code/montagel', 'C:/jcb/code/Xrf']
repo 0 OK
repo 1 OK
repos untagged OK
Traceback (most recent call last):
  File "C:/jcb/code/Xrf-Python/Documentation/chapters/software/bug.py", line 26, in <module>
    for commit in RepositoryMining(path_to_repo=repos, from_tag=starttag, to_tag=endtag).traverse_commits():
  File "C:\jcb\venvs\Xrf\lib\site-packages\pydriller\repository_mining.py", line 168, in traverse_commits
    self._conf.sanity_check_filters()
  File "C:\jcb\venvs\Xrf\lib\site-packages\pydriller\utils\conf.py", line 71, in sanity_check_filters
    self._check_correct_filters_order()
  File "C:\jcb\venvs\Xrf\lib\site-packages\pydriller\utils\conf.py", line 110, in _check_correct_filters_order
    self.get('git_repo').get_commit(self.get('from_commit')),
  File "C:\jcb\venvs\Xrf\lib\site-packages\pydriller\git_repository.py", line 144, in get_commit
    gp_commit = self.repo.commit(commit_id)
  File "C:\jcb\venvs\Xrf\lib\site-packages\git\repo\base.py", line 480, in commit
    return self.rev_parse(str(rev) + "^0")
  File "C:\jcb\venvs\Xrf\lib\site-packages\git\repo\fun.py", line 213, in rev_parse
    obj = name_to_object(repo, rev[:start])
  File "C:\jcb\venvs\Xrf\lib\site-packages\git\repo\fun.py", line 147, in name_to_object
    raise BadName(name)
gitdb.exc.BadName: Ref '['' did not resolve to an object

Process finished with exit code 1
```

**OS Version:**
Python 3.7 on Windows


Pull request:
Fix error for multiple repos using the tag filter
Fix #116.

For simplicity reasons, I was translating from/to_tag into from/to_commit and saving this info into an object. This doesn't work if the user passes multiple repos, since the second time pydriller will run will find both from_tag and from_commit saved in the object, and will raise an Error.

Now I don't save this info in the object, I just calculate it at runtime.

Patch:
diff --git a/pydriller/utils/conf.py b/pydriller/utils/conf.py
index 740c1a5..e8d1530 100644
--- a/pydriller/utils/conf.py
+++ b/pydriller/utils/conf.py
@@ -63,14 +63,26 @@ class Conf:
                 not isinstance(path_to_repo, list):
             raise Exception("The path to the repo has to be of type 'string' or 'list of strings'!")
 
+    def _check_only_one_from_commit(self):
+        if not self.only_one_filter([self.get('since'),
+                                     self.get('from_commit'),
+                                     self.get('from_tag')]):
+            raise Exception('You can only specify one filter between since, from_tag and from_commit')
+
+    def _check_only_one_to_commit(self):
+        if not self.only_one_filter([self.get('to'),
+                                     self.get('to_commit'),
+                                     self.get('to_tag')]):
+            raise Exception('You can only specify one between since, from_tag and from_commit')
+
     def sanity_check_filters(self):
         """
         Check if the values passed by the user are correct.
 
         """
         self._check_correct_filters_order()
-        self.check_starting_commit()
-        self.check_ending_commit()
+        self._check_only_one_from_commit()
+        self._check_only_one_to_commit()
         self._check_timezones()
 
         # Check if from_commit and to_commit point to the same commit, in which case
@@ -94,8 +106,7 @@ class Conf:
                 raise Exception('You can not specify a single commit with '
                                 'other filters')
             try:
-                self.set_value('single', self.get("git_repo").get_commit(
-                    self.get('single')).hash)
+                self.set_value('single', self.get("git_repo").get_commit(self.get('single')).hash)
             except BadName:
                 raise Exception("The commit {} defined in "
                                 "the 'single' filtered does "
@@ -129,47 +140,41 @@ class Conf:
             return True
         return False
 
-    def check_starting_commit(self):
+    def get_starting_commit(self):
         """
         Get the starting commit from the 'since', 'from_commit' or 'from_tag'
         filter.
         """
-        if not self.only_one_filter([self.get('since'),
-                                     self.get('from_commit'),
-                                     self.get('from_tag')]):
-            raise Exception('You can only specify one between since, from_tag and from_commit')
-        if self.get('from_tag') is not None:
-            tagged_commit = self.get("git_repo").get_commit_from_tag(self.get('from_tag'))
-            self.set_value('from_commit', tagged_commit.hash)
-        if self.get('from_commit'):
+        from_tag = self.get('from_tag')
+        from_commit = self.get('from_commit')
+        if from_tag is not None:
+            tagged_commit = self.get("git_repo").get_commit_from_tag(from_tag)
+            from_commit = tagged_commit.hash
+        if from_commit is not None:
             try:
-                commit = self.get("git_repo").get_commit(self.get('from_commit'))
+                commit = self.get("git_repo").get_commit(from_commit)
                 if len(commit.parents) == 0:
-                    self.set_value('from_commit', [commit.hash])
+                    return [commit.hash]
                 elif len(commit.parents) == 1:
-                    self.set_value('from_commit', ['^' + commit.hash + '^'])
+                    return ['^' + commit.hash + '^']
                 else:
-                    commits = ['^' + x for x in commit.parents]
-                    self.set_value('from_commit', commits)
+                    return ['^' + x for x in commit.parents]
             except Exception:
                 raise Exception("The commit {} defined in the 'from_tag' or 'from_commit' filter does "
                                 "not exist".format(self.get('from_commit')))
 
-    def check_ending_commit(self):
+    def get_ending_commit(self):
         """
         Get the ending commit from the 'to', 'to_commit' or 'to_tag' filter.
         """
-        if not self.only_one_filter([self.get('to'),
-                                     self.get('to_commit'),
-                                     self.get('to_tag')]):
-            raise Exception('You can only specify one between since, from_tag and from_commit')
-        if self.get('to_tag') is not None:
-            tagged_commit = self.get("git_repo").get_commit_from_tag(self.get('to_tag'))
-            self.set_value('to_commit', tagged_commit.hash)
-        if self.get('to_commit'):
+        to_tag = self.get('to_tag')
+        to_commit = self.get('to_commit')
+        if to_tag is not None:
+            tagged_commit = self.get("git_repo").get_commit_from_tag(to_tag)
+            to_commit = tagged_commit.hash
+        if to_commit is not None:
             try:
-                commit = self.get("git_repo").get_commit(self.get('to_commit'))
-                self.set_value('to_commit', commit.hash)
+                return self.get("git_repo").get_commit(to_commit).hash
             except Exception:
                 raise Exception("The commit {} defined in the 'to_tag' or 'to_commit' filter does "
                                 "not exist".format(self.get('to_commit')))
@@ -193,8 +198,8 @@ class Conf:
         single = self.get('single')
         since = self.get('since')
         until = self.get('to')
-        from_commit = self.get('from_commit')
-        to_commit = self.get('to_commit')
+        from_commit = self.get_starting_commit()
+        to_commit = self.get_ending_commit()
         include_refs = self.get('include_refs')
         remotes = self.get('include_remotes')
         branch = self.get('only_in_branch')


Test patch:
diff --git a/tests/integration/test_between_tags.py b/tests/integration/test_between_tags.py
index 84da66d..30ee863 100644
--- a/tests/integration/test_between_tags.py
+++ b/tests/integration/test_between_tags.py
@@ -33,3 +33,17 @@ def test_between_revisions():
     assert '4638730126d40716e230c2040751a13153fb1556' == lc[2].hash
     assert 'a26f1438bd85d6b22497c0e5dae003812becd0bc' == lc[3].hash
     assert '627e1ad917a188a861c9fedf6e5858b79edbe439' == lc[4].hash
+
+
+def test_multiple_repos_with_tags():
+    from_tag = 'tag2'
+    to_tag = 'tag3'
+    repos = [
+        'test-repos/tags',
+        'test-repos/tags',
+        'test-repos/tags'
+    ]
+    lc = list(RepositoryMining(path_to_repo=repos,
+                               from_tag=from_tag,
+                               to_tag=to_tag).traverse_commits())
+    assert len(lc) == 9