Repository: pymedusa/Medusa

Issue:
Cannot push error on github automatically
**Branch/Commit:**
```
branch: master
Commit: b16e0e5eb4ded727eebd2ab2cd9683ab597662f5
Version: v0.1.17
Database: 44.8
--
Python Version: | 2.7.13 (default, Apr 20 2017, 12:13:37) [GCC 6.3.0]
SSL Version: | LibreSSL 2.5.5
OS: | Linux-3.16.0-4-amd64-x86_64-with
Locale: | Unknown.Unknown
```
**OS:**
`Using the linuxserver.io docker image.`
**What you did:**
```
I configured the github setting in the config.
I am using the "Personal access token" because I have 2FA on github.
Then, in the error message page on Medusa, I pushed the submit errors button.
```
**What happened:**
`
The notification tell me I have to setup my username and password first
`

**Logs:**
```
2017-10-31 21:50:05 WARNING  Thread-16 :: [b16e0e5] Please set your GitHub username and password in the config and enable debug. Unable to submit issue ticket to GitHub.
```



Discussion:
Same here, I'm unable to report an issue using the "Submit errors" button
`2017-11-01 16:49:32 WARNING  Thread-17 :: [b16e0e5] Please set your GitHub username and password in the config and enable debug. Unable to submit issue ticket to GitHub.`
At the risk of AOLing, it's giving me the same error, even though a username and password are set.  (I don't use 2FA with GitHub.)

Resolving patch:
diff --git a/medusa/issue_submitter.py b/medusa/issue_submitter.py
--- a/medusa/issue_submitter.py
+++ b/medusa/issue_submitter.py
@@ -22,7 +22,8 @@
 class IssueSubmitter(object):
     """GitHub issue submitter."""
 
-    INVALID_CONFIG = 'Please set your GitHub username and password in the config and enable debug. Unable to submit issue ticket to GitHub.'
+    MISSING_CREDENTIALS = 'Please set your GitHub Username and Passowrd in the config.  Unable to submit issue ticket to GitHub.'
+    DEBUG_NOT_ENABLED = 'Please enable Debug mode in the config.  Unable to submit issue ticket to GitHub.'
     NO_ISSUES = 'No issue to be submitted to GitHub.'
     UNSUPPORTED_VERSION = 'Please update Medusa, unable to submit issue ticket to GitHub with an outdated version.'
     ALREADY_RUNNING = 'An issue is already being submitted, please wait for it to complete.'
@@ -41,15 +42,7 @@ def __init__(self):
 
     @staticmethod
     def create_gist(github, logline):
-        """Create a private gist with log data for the specified logline.
-
-        :param github:
-        :type github: Github
-        :param logline:
-        :type logline: medusa.logger.LogLine
-        :return:
-        :rtype: github.Gist.Gist
-        """
+        """Create a private gist with log data for the specified log line."""
         context_loglines = logline.get_context_loglines()
         if context_loglines:
             content = '\n'.join([str(ll) for ll in context_loglines])
@@ -57,15 +50,7 @@ def create_gist(github, logline):
 
     @staticmethod
     def create_issue_data(logline, log_url):
-        """Create the issue data expected by github api to be submitted.
-
-        :param logline:
-        :type logline: medusa.logger.LogLine
-        :param log_url:
-        :type log_url: str
-        :return:
-        :rtype: str
-        """
+        """Create the issue data expected by github api to be submitted."""
         try:
             locale_name = locale.getdefaultlocale()[1]
         except ValueError:
@@ -77,46 +62,41 @@ def create_issue_data(logline, log_url):
 
         commit = app.CUR_COMMIT_HASH
         base_url = '../blob/{commit}'.format(commit=commit) if commit else None
-        return '\n'.join([
-            '### INFO',
-            '**Python Version**: `{python_version}`'.format(python_version=sys.version[:120].replace('\n', '')),
-            '**Operating System**: `{os}`'.format(os=platform.platform()),
-            '**Locale**: `{locale}`'.format(locale=locale_name),
-            '**Branch**: [{branch}](../tree/{branch})'.format(branch=app.BRANCH),
-            '**Database**: `{0}.{1}`'.format(cur_branch_major_db_version, cur_branch_minor_db_version),
-            '**Commit**: {org}/{repo}@{commit}'.format(org=app.GIT_ORG, repo=app.GIT_REPO, commit=commit),
-            '**Link to Log**: {log_url}'.format(log_url=log_url) if log_url else '**No Log available**',
-            '### ERROR',
-            logline.format_to_html(base_url=base_url),
-            '---',
-            '_STAFF NOTIFIED_: @{org}/support @{org}/moderators'.format(org=app.GIT_ORG),
-        ])
-
-    @staticmethod
-    def find_similar_issues(github_repo, loglines, max_age=timedelta(days=180)):
-        """Find similar issues in GitHub repo.
-
-        :param github_repo:
-        :type github_repo: github.Repository.Repository
-        :param loglines:
-        :type loglines: list of medusa.logger.LogLine
-        :param max_age:
-        :type max_age: timedelta
-        :return:
-        :rtype: dict(str, github.Issue.Issue)
-        """
+        return """
+        ### INFO
+        **Python Version**: `{python_version}
+        **Operating System**: `{os}`
+        **Locale**: `{locale}`
+        **Branch**: [{branch}](../tree/{branch})
+        **Database**: `{db_major_version}.{db_minor_version}`
+        **Commit**: {org}/{repo}@{commit}
+        **Link to Log**: {log_url}
+        ### ERROR
+        {log_line}
+        ---
+        _STAFF NOTIFIED_: @{org}/support @{org}/moderators
+        """.format(
+            python_version=sys.version[:120].replace('\n', ''), os=platform.platform(), locale=locale_name,
+            branch=app.BRANCH, org=app.GIT_ORG, repo=app.GIT_REPO, commit=commit,
+            db_major_version=cur_branch_major_db_version, db_minor_version=cur_branch_minor_db_version,
+            log_url=log_url or '**No Log available**', log_line=logline.format_to_html(base_url=base_url),
+        )
+
+    @classmethod
+    def find_similar_issues(cls, github_repo, loglines, max_age=timedelta(days=180)):
+        """Find similar issues in the GitHub repository."""
         results = dict()
         issues = github_repo.get_issues(state='all', since=datetime.now() - max_age)
         for issue in issues:
             if hasattr(issue, 'pull_request') and issue.pull_request:
                 continue
             issue_title = issue.title
-            if issue_title.startswith(IssueSubmitter.TITLE_PREFIX):
-                issue_title = issue_title[len(IssueSubmitter.TITLE_PREFIX):]
+            if issue_title.startswith(cls.TITLE_PREFIX):
+                issue_title = issue_title[len(cls.TITLE_PREFIX):]
 
             for logline in loglines:
                 log_title = logline.issue_title
-                if IssueSubmitter.similar(log_title, issue_title):
+                if cls.similar(log_title, issue_title):
                     results[logline.key] = issue
 
             if len(results) >= len(loglines):
@@ -126,109 +106,76 @@ def find_similar_issues(github_repo, loglines, max_age=timedelta(days=180)):
 
     @staticmethod
     def similar(title1, title2, ratio=0.9):
-        """Return wheter the title1 is similar to title2.
-
-        :param title1:
-        :type title1: str
-        :param title2:
-        :type title2: str
-        :param ratio:
-        :type ratio: float
-        :return:
-        :rtype: bool
-        """
+        """Compare title similarity."""
         return difflib.SequenceMatcher(None, title1, title2).ratio() >= ratio
 
     def submit_github_issue(self, version_checker, max_issues=500):
-        """Submit errors to github.
-
-        :param version_checker:
-        :type version_checker: CheckVersion
-        :param max_issues:
-        :type max_issues: int
-        :return: user message and issue number
-        :rtype: list of tuple(str, str)
-        """
-        if app.GIT_AUTH_TYPE == 0:
-            if not app.DEBUG or not app.GIT_USERNAME or not app.GIT_PASSWORD:
-                log.warning(IssueSubmitter.INVALID_CONFIG)
-                return [(IssueSubmitter.INVALID_CONFIG, None)]
-        else:
-            if not app.DEBUG or not app.GIT_TOKEN:
-                log.warning(IssueSubmitter.INVALID_CONFIG)
-                return [(IssueSubmitter.INVALID_CONFIG, None)]
+        """Submit errors to github."""
+        def result(message, level=logging.WARNING):
+            log.log(level, message)
+            return [(message, None)]
+
+        if not app.DEBUG:
+            return result(self.DEBUG_NOT_ENABLED)
+
+        if not (app.GIT_USERNAME and app.GIT_PASSWORD) or app.GIT_TOKEN:
+            return result(self.MISSING_CREDENTIALS)
+
         if not ErrorViewer.errors:
-            log.info(IssueSubmitter.NO_ISSUES)
-            return [(IssueSubmitter.NO_ISSUES, None)]
+            return result(self.NO_ISSUES, logging.INFO)
 
         if not app.DEVELOPER and version_checker.need_update():
-            log.warning(IssueSubmitter.UNSUPPORTED_VERSION)
-            return [(IssueSubmitter.UNSUPPORTED_VERSION, None)]
+            return result(self.UNSUPPORTED_VERSION)
 
         if self.running:
-            log.warning(IssueSubmitter.ALREADY_RUNNING)
-            return [(IssueSubmitter.ALREADY_RUNNING, None)]
+            return result(self.ALREADY_RUNNING)
 
         self.running = True
         try:
-            if app.GIT_AUTH_TYPE == 0:
-                github = authenticate(app.GIT_USERNAME, app.GIT_PASSWORD)
-            else:
+            if app.GIT_AUTH_TYPE:
                 github = token_authenticate(app.GIT_TOKEN)
+            else:
+                github = authenticate(app.GIT_USERNAME, app.GIT_PASSWORD)
             if not github:
-                return [(IssueSubmitter.BAD_CREDENTIALS, None)]
+                return result(self.BAD_CREDENTIALS)
 
             github_repo = get_github_repo(app.GIT_ORG, app.GIT_REPO, gh=github)
             loglines = ErrorViewer.errors[:max_issues]
-            similar_issues = IssueSubmitter.find_similar_issues(github_repo, loglines)
+            similar_issues = self.find_similar_issues(github_repo, loglines)
 
-            return IssueSubmitter.submit_issues(github, github_repo, loglines, similar_issues)
+            return self.submit_issues(github, github_repo, loglines, similar_issues)
         except RateLimitExceededException:
-            log.warning(IssueSubmitter.RATE_LIMIT)
-            return [(IssueSubmitter.RATE_LIMIT, None)]
+            return result(self.RATE_LIMIT)
         except (GithubException, IOError):
-            log.warning(IssueSubmitter.GITHUB_EXCEPTION)
-            return [(IssueSubmitter.GITHUB_EXCEPTION, None)]
+            return result(self.GITHUB_EXCEPTION)
         finally:
             self.running = False
 
-    @staticmethod
-    def submit_issues(github, github_repo, loglines, similar_issues):
-        """Submit issues to github.
-
-        :param github:
-        :type github: Github
-        :param github_repo:
-        :type github_repo: github.Repository.Repository
-        :param loglines:
-        :type loglines: list of medusa.logger.LogLine
-        :param similar_issues:
-        :type similar_issues: dict(str, github.Issue.Issue)
-        :return:
-        :rtype: list of tuple(str, str)
-        """
+    @classmethod
+    def submit_issues(cls, github, github_repo, loglines, similar_issues):
+        """Submit issues to github."""
         results = []
-        for logline in loglines:
-            gist = IssueSubmitter.create_gist(github, logline)
-            message = IssueSubmitter.create_issue_data(logline, log_url=gist.html_url if gist else None)
-            similar_issue = similar_issues.get(logline.key)
+        for line in loglines:
+            gist = cls.create_gist(github, line)
+            message = cls.create_issue_data(line, log_url=gist.html_url if gist else None)
+            similar_issue = similar_issues.get(line.key)
             issue_id = None
             if similar_issue:
                 if similar_issue.raw_data['locked']:
-                    submitter_result = IssueSubmitter.EXISTING_ISSUE_LOCKED.format(number=similar_issue.number)
+                    submitter_result = cls.EXISTING_ISSUE_LOCKED.format(number=similar_issue.number)
                     log.warning(submitter_result)
                 else:
                     similar_issue.create_comment(message)
                     issue_id = similar_issue.number
-                    submitter_result = IssueSubmitter.COMMENTED_EXISTING_ISSUE.format(number=issue_id)
+                    submitter_result = cls.COMMENTED_EXISTING_ISSUE.format(number=issue_id)
                     log.info(submitter_result)
-                    ErrorViewer.remove(logline)
+                    ErrorViewer.remove(line)
             else:
-                issue = github_repo.create_issue('{prefix}{title}'.format(prefix=IssueSubmitter.TITLE_PREFIX, title=logline.issue_title), message)
+                issue = github_repo.create_issue('{prefix}{title}'.format(prefix=cls.TITLE_PREFIX, title=line.issue_title), message)
                 issue_id = issue.number
-                submitter_result = IssueSubmitter.ISSUE_CREATED.format(number=issue_id)
+                submitter_result = cls.ISSUE_CREATED.format(number=issue_id)
                 log.info(submitter_result)
-                ErrorViewer.remove(logline)
+                ErrorViewer.remove(line)
             results.append((submitter_result, issue_id))
 
         return results


Test patch:
diff --git a/tests/test_issuesubmitter.py b/tests/test_issuesubmitter.py
--- a/tests/test_issuesubmitter.py
+++ b/tests/test_issuesubmitter.py
@@ -16,28 +16,34 @@
 @pytest.mark.parametrize('p', [
     {  # p0: debug not enabled
         'debug': False,
-        'expected': [(IssueSubmitter.INVALID_CONFIG, None)]
+        'expected': [(IssueSubmitter.DEBUG_NOT_ENABLED, None)]
     },
     {  # p1: debug not set
-        'expected': [(IssueSubmitter.INVALID_CONFIG, None)]
+        'expected': [(IssueSubmitter.DEBUG_NOT_ENABLED, None)]
     },
-    {  # p2: debug enabled, but no username
+    {  # p2: username and password set, but debug not enabled
+        'debug': False,
+        'username': 'user',
+        'password': 'pass',
+        'expected': [(IssueSubmitter.DEBUG_NOT_ENABLED, None)]
+    },
+    {  # p3: debug enabled, but no username
         'debug': True,
         'password': 'pass',
-        'expected': [(IssueSubmitter.INVALID_CONFIG, None)]
+        'expected': [(IssueSubmitter.MISSING_CREDENTIALS, None)]
     },
-    {  # p3: debug enabled, but no password
+    {  # p4: debug enabled, but no password
         'debug': True,
         'username': 'user',
-        'expected': [(IssueSubmitter.INVALID_CONFIG, None)]
+        'expected': [(IssueSubmitter.MISSING_CREDENTIALS, None)]
     },
-    {  # p4: debug enabled, username and password set, but no errors to report
+    {  # p5: debug enabled, username and password set, but no errors to report
         'debug': True,
         'username': 'user',
         'password': 'pass',
         'expected': [(IssueSubmitter.NO_ISSUES, None)]
     },
-    {  # p5: debug enabled, username and password set, errors to report but update is needed
+    {  # p6: debug enabled, username and password set, errors to report but update is needed
         'debug': True,
         'username': 'user',
         'password': 'pass',
@@ -45,7 +51,7 @@
         'need_update': True,
         'expected': [(IssueSubmitter.UNSUPPORTED_VERSION, None)]
     },
-    {  # p6: debug enabled, username and password set, errors to report, no update is needed, but it's already running
+    {  # p7: debug enabled, username and password set, errors to report, no update is needed, but it's already running
         'debug': True,
         'username': 'user',
         'password': 'pass',
@@ -53,7 +59,7 @@
         'running': True,
         'expected': [(IssueSubmitter.ALREADY_RUNNING, None)]
     },
-    {  # p7: debug enabled, username and password set, errors to report, update is needed but I'M A DEVELOPER :-)
+    {  # p8: debug enabled, username and password set, errors to report, update is needed but I'M A DEVELOPER :-)
         'debug': True,
         'username': 'user',
         'password': 'pass',
@@ -63,7 +69,7 @@
         'exception': [BadCredentialsException, 401],
         'expected': [(IssueSubmitter.BAD_CREDENTIALS, None)]
     },
-    {  # p8: debug enabled, username and password set, errors to report, update is not needed but rate limit exception happened
+    {  # p9: debug enabled, username and password set, errors to report, update is not needed but rate limit exception happened
         'debug': True,
         'username': 'user',
         'password': 'pass',