Repository: ishepard/pydriller

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


Comments:

Patch:
diff --git a/pydriller/domain/commit.py b/pydriller/domain/commit.py
index 50e8f53..98701d5 100644
--- a/pydriller/domain/commit.py
+++ b/pydriller/domain/commit.py
@@ -230,7 +230,7 @@ class Modification:  # pylint: disable=R0902
         Languages are derived from the file  extension.
         Supported languages are those supported by Lizard.
 
-        :return: True iff language  of this Modification can be analyzed.
+        :return: True iff language of this Modification can be analyzed.
         """
         return lizard_languages.get_reader_for(self.filename) is not None
 
@@ -242,7 +242,6 @@ class Modification:  # pylint: disable=R0902
         :return: LOC of the file
         """
         self._calculate_metrics()
-        assert self._nloc is not None
         return self._nloc
 
     @property
@@ -253,7 +252,6 @@ class Modification:  # pylint: disable=R0902
         :return: Cyclomatic Complexity of the file
         """
         self._calculate_metrics()
-        assert self._complexity is not None
         return self._complexity
 
     @property
@@ -264,7 +262,6 @@ class Modification:  # pylint: disable=R0902
         :return: token count
         """
         self._calculate_metrics()
-        assert self._token_count is not None
         return self._token_count
 
     @property
@@ -311,8 +308,7 @@ class Modification:  # pylint: disable=R0902
         token = line.split(" ")
         numbers_old_file = token[1]
         numbers_new_file = token[2]
-        delete_line_number = int(numbers_old_file.split(",")[0]
-                                 .replace("-", "")) - 1
+        delete_line_number = int(numbers_old_file.split(",")[0].replace("-", "")) - 1
         additions_line_number = int(numbers_new_file.split(",")[0]) - 1
         return delete_line_number, additions_line_number
 
@@ -396,9 +392,12 @@ class Modification:  # pylint: disable=R0902
         :param include_before: either to compute the metrics
         for source_code_before, i.e. before the change happened
         """
+        if not self.language_supported:
+            return
+
         if self.source_code and self._nloc is None:
-            analysis = lizard.analyze_file.analyze_source_code(
-                self.filename, self.source_code)
+            analysis = lizard.analyze_file.analyze_source_code(self.filename,
+                                                               self.source_code)
             self._nloc = analysis.nloc
             self._complexity = analysis.CCN
             self._token_count = analysis.token_count
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
diff --git a/tests/test_commit.py b/tests/test_commit.py
index b52c1aa..be3feb1 100644
--- a/tests/test_commit.py
+++ b/tests/test_commit.py
@@ -197,8 +197,7 @@ def test_metrics_not_supported_file():
                       "test-repos/lizard/NotSupported.pdf",
                       ModificationType.MODIFY, diff_and_sc)
 
-    assert m1.nloc == 2
-    assert len(m1.methods) == 0
+    assert m1.nloc is None
 
 
 @pytest.mark.parametrize('path', ['test-repos/files_in_directories'])