Repository: WeblateOrg/weblate

Issue:
Github integration
It would be nice to have better integration with Github, so even when users don't give Weblate access to push directly to the repository, it would create pull request for the translations.



Discussion:
Actually it could be implemented as another VCS backend, that would do fork/pull request instead of pushing changes upstream.


Resolving patch:
diff --git a/weblate/appsettings.py b/weblate/appsettings.py
--- a/weblate/appsettings.py
+++ b/weblate/appsettings.py
@@ -194,6 +194,9 @@ def getvalue(name, default):
 # Hiding repository credentials
 HIDE_REPO_CREDENTIALS = getvalue('HIDE_REPO_CREDENTIALS', True)
 
+# GitHub username for sending pull requests
+GITHUB_USERNAME = getvalue('GITHUB_USERNAME', None)
+
 # Whiteboard
 ENABLE_WHITEBOARD = getvalue('ENABLE_WHITEBOARD', False)
 
diff --git a/weblate/settings_example.py b/weblate/settings_example.py
--- a/weblate/settings_example.py
+++ b/weblate/settings_example.py
@@ -177,6 +177,10 @@
     )),
 )
 
+# GitHub username for sending pull requests.
+# Please see the documentation for more details.
+GITHUB_USERNAME = None
+
 # Authentication configuration
 AUTHENTICATION_BACKENDS = (
     'social.backends.email.EmailAuth',
diff --git a/weblate/trans/vcs.py b/weblate/trans/vcs.py
--- a/weblate/trans/vcs.py
+++ b/weblate/trans/vcs.py
@@ -21,6 +21,7 @@
 Minimal distributed version control system abstraction for Weblate needs.
 """
 import subprocess
+import os
 import os.path
 import email.utils
 import re
@@ -32,6 +33,7 @@
 from dateutil import parser
 from weblate.trans.util import get_clean_env, add_configuration_error
 from weblate.trans.ssh import ssh_file, SSH_WRAPPER
+from weblate import appsettings
 
 VCS_REGISTRY = {}
 VCS_CHOICES = []
@@ -629,6 +631,63 @@ def push(self, branch):
             raise
 
 
+@register_vcs
+class GithubRepository(GitRepository):
+
+    name = 'GitHub'
+
+    _cmd = 'hub'
+    _hub_user = appsettings.GITHUB_USERNAME
+
+    if _hub_user is None:
+        _is_supported = False
+    else:
+        _cmd_push = ['push', _hub_user]
+
+    def create_pull_request(self, origin_branch, fork_branch):
+        """
+        Creates pull request to merge branch in forked repository into
+        branch of remote repository.
+        """
+        cmd = [
+            'pull-request',
+            '-h', '{0}:{1}'.format(self._hub_user, fork_branch),
+            '-b', origin_branch,
+            '-m', 'Update from Weblate.'.encode('utf-8'),
+        ]
+        self.execute(cmd)
+
+    def push_to_fork(self, local_branch, fork_branch):
+        """
+        Pushes given local branch to branch in forked repository.
+        """
+        self.execute(self._cmd_push + ['{0}:{1}'.format(local_branch,
+                                                        fork_branch)])
+
+    def fork(self):
+        """
+        Creates fork of original repository if one doesn't exist yet.
+        """
+        if self._hub_user not in self.execute(['remote']).splitlines():
+            self.execute(['fork'])
+
+    def push(self, branch):
+        """
+        Forks repository on Github, pushes changes to *-weblate branch
+        on fork and creates pull request against original repository.
+        """
+        self.fork()
+        fork_branch = '{0}-weblate'.format(branch)
+        self.push_to_fork(branch, fork_branch)
+        try:
+            self.create_pull_request(branch, fork_branch)
+        except RepositoryException as error:
+            if error.retcode == 1:
+                # Pull request already exists.
+                return
+            raise
+
+
 @register_vcs
 class HgRepository(Repository):
     """


Test patch: