Skip to content

Commit

Permalink
GHE support
Browse files Browse the repository at this point in the history
  • Loading branch information
gaborbernat committed Mar 29, 2018
1 parent 4e43caf commit 6ae1f32
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 26 deletions.
57 changes: 57 additions & 0 deletions docs/custom_installs/github_enterprise.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
Connecting with an Enterprise Github
====================================

Github integration is provided via the `django-allauth`_ package, and by default connected with `github.com`_.
To swap out this connection with an enterprise edition of Github you need to:

1. Change the social account provider settings to point the Enterprise Github (value of ``{{github_url}}`` in the
``local_settings.py``):

.. code-block:: python
SOCIALACCOUNT_PROVIDERS = {'github': {'SCOPE': ['user:email', 'read:org',
'admin:repo_hook', 'repo:status'],
'GITHUB_URL': '{{github_url}}'}}
2. Create an OAuth Github Application by following the `official guide <https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/>`_. Note here you must provide the address of the readthedocs
instance you're setting up. This will give you a Github application ``client id`` and ``secret``.

3. Use these two, plus the domain name of the readthedocs instance to register a site, and a social account provider.
This could be done from the admin dashboard of readthedocs instance, or by running the following script:

.. code-block:: python
# config_github.py
from __future__ import unicode_literals
from allauth.socialaccount.providers.github.provider import GitHubProvider
from allauth.socialaccount.models import SocialApp
from django.contrib.sites.models import Site
from django.conf import settings
# create a site for the authentication system
PRODUCTION_DOMAIN = getattr(settings, 'PRODUCTION_DOMAIN')
SITE_ID = getattr(settings, 'SITE_ID')
site, _ = Site.objects.update_or_create(id=SITE_ID,
defaults=dict(name=PRODUCTION_DOMAIN,
domain=PRODUCTION_DOMAIN))
# change the github social account provider to link to the enterprise Github
GITHUB_APP_CLIENT_ID = '{{github_app_client_id}}'
GITHUB_APP_SECRET = '{{github_app_secret}}'
app, _ = SocialApp.objects.update_or_create(provider=GitHubProvider.id, name='github',
defaults=dict(client_id=GITHUB_APP_CLIENT_ID,
secret=GITHUB_APP_SECRET, key=''))
app.sites.add(site) # enable th enterprise Github on the current domain
Make sure to replace ``{{github_app_client_id}}`` with the Github application client id, and
``{{github_app_secret}}`` wit the Github application secret. Then run from a shell:

.. code-block:: python
cat config_github.py | python manage.py shell
.. _django-allauth: https://github.com/pennersr/django-allauth
.. _github.com: https://github.com/
7 changes: 5 additions & 2 deletions readthedocs/builds/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@
from builtins import object
from shutil import rmtree

from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _
from guardian.shortcuts import assign
from taggit.managers import TaggableManager

from readthedocs.core.utils import broadcast
from readthedocs.projects.constants import (
BITBUCKET_URL, GITHUB_URL, GITLAB_URL, PRIVACY_CHOICES, PRIVATE)
BITBUCKET_URL, GITLAB_URL, PRIVACY_CHOICES, PRIVATE)
from readthedocs.projects.models import APIProject, Project

from .constants import (
Expand All @@ -36,6 +37,8 @@

DEFAULT_VERSION_PRIVACY_LEVEL = getattr(
settings, 'DEFAULT_VERSION_PRIVACY_LEVEL', 'public')
_GITHUB_URL_ARGS = '/{user}/{repo}/{action}/{version}{docroot}{path}{source_suffix}'
GITHUB_URL = GitHubOAuth2Adapter.web_url + _GITHUB_URL_ARGS

log = logging.getLogger(__name__)

Expand Down
11 changes: 9 additions & 2 deletions readthedocs/builds/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@
from __future__ import (
absolute_import, division, print_function, unicode_literals)

from readthedocs.projects.constants import (
BITBUCKET_REGEXS, GITHUB_REGEXS, GITLAB_REGEXS)
import re

from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter
from six.moves import urllib

from readthedocs.projects.constants import BITBUCKET_REGEXS, GITHUB_REGEX_BASES, GITLAB_REGEXS

_GITHUB_NO_PROTOCOL = urllib.parse.urlparse(GitHubOAuth2Adapter.web_url).netloc
GITHUB_REGEXS = [re.compile(b.format(re.escape(_GITHUB_NO_PROTOCOL))) for b in GITHUB_REGEX_BASES]


def get_github_username_repo(url):
Expand Down
18 changes: 8 additions & 10 deletions readthedocs/core/management/commands/import_github_language.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
from __future__ import absolute_import
from __future__ import print_function
import os
import requests

from django.core.management.base import BaseCommand
import requests
from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter
from django.core.cache import cache
from django.core.management.base import BaseCommand

from readthedocs.builds.utils import get_github_username_repo
from readthedocs.projects.constants import PROGRAMMING_LANGUAGES
from readthedocs.projects.models import Project
from readthedocs.projects.constants import GITHUB_REGEXS, PROGRAMMING_LANGUAGES

PL_DICT = {}

Expand All @@ -41,13 +43,8 @@ def handle(self, *args, **options):
).filter(
repo__contains='github'
):
user = repo = ''
repo_url = project.repo
for regex in GITHUB_REGEXS:
match = regex.search(repo_url)
if match:
user, repo = match.groups()
break
user, repo = get_github_username_repo(repo_url)

if not user:
print('No GitHub repo for %s' % repo_url)
Expand All @@ -56,7 +53,8 @@ def handle(self, *args, **options):
cache_key = '%s-%s' % (user, repo)
top_lang = cache.get(cache_key, None)
if not top_lang:
url = 'https://api.github.com/repos/{user}/{repo}/languages'.format(
url = '{github_api_url}/repos/{user}/{repo}/languages'.format(
github_api_url=GitHubOAuth2Adapter.api_url,
user=user,
repo=repo,
)
Expand Down
10 changes: 5 additions & 5 deletions readthedocs/oauth/services/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class GitHubService(Service):

adapter = GitHubOAuth2Adapter
# TODO replace this with a less naive check
url_pattern = re.compile(r'github\.com')
url_pattern = re.compile(re.escape(GitHubOAuth2Adapter.web_url))

def sync(self):
"""Sync repositories and organizations."""
Expand All @@ -37,7 +37,7 @@ def sync(self):

def sync_repositories(self):
"""Sync repositories from GitHub API."""
repos = self.paginate('https://api.github.com/user/repos?per_page=100')
repos = self.paginate('{}/repos?per_page=100'.format(GitHubOAuth2Adapter.profile_url))
try:
for repo in repos:
self.create_repository(repo)
Expand All @@ -50,7 +50,7 @@ def sync_repositories(self):
def sync_organizations(self):
"""Sync organizations from GitHub API."""
try:
orgs = self.paginate('https://api.github.com/user/orgs')
orgs = self.paginate('{}/orgs'.format(GitHubOAuth2Adapter.profile_url))
for org in orgs:
org_resp = self.get_session().get(org['url'])
org_obj = self.create_organization(org_resp.json())
Expand Down Expand Up @@ -196,8 +196,8 @@ def setup_webhook(self, project):
resp = None
try:
resp = session.post(
('https://api.github.com/repos/{owner}/{repo}/hooks'
.format(owner=owner, repo=repo)),
('{url}/repos/{owner}/{repo}/hooks'
.format(owner=owner, repo=repo, url=GitHubOAuth2Adapter.api_url)),
data=data,
headers={'content-type': 'application/json'}
)
Expand Down
11 changes: 4 additions & 7 deletions readthedocs/projects/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,10 @@
PROJECT_PK_REGEX = '(?:[-\w]+)'
PROJECT_SLUG_REGEX = '(?:[-\w]+)'

GITHUB_REGEXS = [
re.compile('github.com/(.+)/(.+)(?:\.git){1}$'),
re.compile('github.com/(.+)/(.+)'),
re.compile('github.com:(.+)/(.+)\.git$'),
GITHUB_REGEX_BASES = [
'{}/(.+)/(.+)(?:\.git){{1}}$',
'{}/(.+)/(.+)',
'{}:(.+)/(.+)\.git$',
]
BITBUCKET_REGEXS = [
re.compile('bitbucket.org/(.+)/(.+)\.git$'),
Expand All @@ -307,9 +307,6 @@
re.compile('gitlab.com/(.+)/(.+)'),
re.compile('gitlab.com:(.+)/(.+)\.git$'),
]
GITHUB_URL = (
'https://github.com/{user}/{repo}/'
'{action}/{version}{docroot}{path}{source_suffix}')
BITBUCKET_URL = (
'https://bitbucket.org/{user}/{repo}/'
'src/{version}{docroot}{path}{source_suffix}')
Expand Down

0 comments on commit 6ae1f32

Please sign in to comment.