Skip to content

Migrate GitHub OAuth App to GitHub App #11942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 111 commits into from
Closed
Show file tree
Hide file tree
Changes from 96 commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
926f95d
Migrate GitHub OAuth App to GitHub App
stsewd Jan 22, 2025
9c5746c
Merge branch 'main' into migrate-to-gh-apps
stsewd Jan 28, 2025
1314a9c
wip
stsewd Jan 30, 2025
22de5d6
Migration and stuff
stsewd Feb 3, 2025
5119e48
Fixes
stsewd Feb 3, 2025
a854c7e
More hooks!
stsewd Feb 4, 2025
7235cd8
Bug fixes and refactor
stsewd Feb 4, 2025
632e2e5
Format
stsewd Feb 4, 2025
b0e2181
More events
stsewd Feb 4, 2025
ba47293
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 4, 2025
91d23aa
More hooks and fixes
stsewd Feb 5, 2025
ddadee1
Implement members hook
stsewd Feb 5, 2025
2c4c0cc
Dead code
stsewd Feb 5, 2025
3c61db6
Delete code
stsewd Feb 5, 2025
88b0021
Poor man implementation
stsewd Feb 6, 2025
2987cf8
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 6, 2025
ad5655e
Stash
stsewd Feb 6, 2025
fa53c1c
Git service: depend on the project instead of users
stsewd Feb 7, 2025
f031b4b
Fix name
stsewd Feb 7, 2025
f7a3917
Fix tests
stsewd Feb 10, 2025
083cfa0
Small updates
stsewd Feb 10, 2025
8e6caa3
Format
stsewd Feb 10, 2025
4671a46
Merge branch 'refactor-services' into migrate-to-gh-apps
stsewd Feb 10, 2025
6d686f3
Format
stsewd Feb 10, 2025
d771092
Refactor
stsewd Feb 10, 2025
0d0511c
Fix import
stsewd Feb 10, 2025
4308bbf
Check for None
stsewd Feb 10, 2025
7065003
refactor
stsewd Feb 10, 2025
b2a8a2b
Fix import
stsewd Feb 10, 2025
b0d9dcc
Full feature!
stsewd Feb 11, 2025
54e7ec6
More refactor
stsewd Feb 11, 2025
4d5a229
More fixes and updates
stsewd Feb 11, 2025
12aab79
Docstrings and updates
stsewd Feb 11, 2025
c2ffe7d
Note on GH user access tokens
stsewd Feb 11, 2025
56b024f
Remove code
stsewd Feb 11, 2025
c09186b
Error handling and logging
stsewd Feb 12, 2025
0b2c686
Validate when trying to connect to an existing account
stsewd Feb 12, 2025
a7f1cb7
Less indentation
stsewd Feb 12, 2025
50637b5
And both apps lived happy forever after.
stsewd Feb 12, 2025
7fc1466
Updates from review
stsewd Feb 12, 2025
27ad8c6
Skip incompatible integrations
stsewd Feb 12, 2025
6ea1655
Format
stsewd Feb 12, 2025
5daf4da
Check for attribute instead
stsewd Feb 13, 2025
8e73ab4
Fix querysets
stsewd Feb 13, 2025
1289298
Git service: attach each service to a allauth provider
stsewd Feb 13, 2025
5319608
Missed this file
stsewd Feb 13, 2025
c9eb355
Use just the hostname for the base_api_url
stsewd Feb 13, 2025
c7b259b
Merge branch 'abstract-allauth-from-services' into migrate-to-gh-apps
stsewd Feb 13, 2025
e031477
Stash
stsewd Feb 14, 2025
bf5014c
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 14, 2025
6165e4c
Format
stsewd Feb 14, 2025
37738df
stash
stsewd Feb 17, 2025
160d41f
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 17, 2025
cd5015c
Basic migration page
stsewd Feb 18, 2025
f67e028
Don't use the ID to get the organization
stsewd Feb 18, 2025
933658c
Docstring
stsewd Feb 18, 2025
346cc34
Fix template
stsewd Feb 18, 2025
cac9567
Cleanup
stsewd Feb 18, 2025
db1950f
More updates
stsewd Feb 18, 2025
75cc864
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 19, 2025
87dad06
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 19, 2025
4b84536
Check for githuapp
stsewd Feb 19, 2025
3899104
Uninstalling the app from a repository, means unlinking it from the p…
stsewd Feb 19, 2025
acfda4c
Format
stsewd Feb 19, 2025
d1e3cb4
Add a sync repositories permissions method
stsewd Feb 20, 2025
de06013
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 24, 2025
b3ad1a2
Add tests for webhook
stsewd Feb 25, 2025
3fb1083
Stash
stsewd Feb 26, 2025
34052b3
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 26, 2025
c5ea8a1
Merge branch 'main' into migrate-to-gh-apps
stsewd Feb 26, 2025
eacf058
Tests
stsewd Feb 27, 2025
33d6151
Merge branch 'main' into migrate-to-gh-apps
stsewd Mar 10, 2025
619858c
Tests
stsewd Mar 10, 2025
80e6c88
More tests
stsewd Mar 10, 2025
926ed6d
Tests for tasks
stsewd Mar 10, 2025
0c338ab
stash
stsewd Mar 11, 2025
616166e
Format to avoid conflicts
stsewd Mar 11, 2025
2c81a2a
Merge branch 'main' into migrate-to-gh-apps
stsewd Mar 11, 2025
b58c3b8
Format
stsewd Mar 11, 2025
d106277
Update migration
stsewd Mar 11, 2025
c2a89d7
Remove suspended installations
stsewd Mar 11, 2025
7fffcea
Delete installation when suspended
stsewd Mar 11, 2025
0adc4b4
Handle authorization event
stsewd Mar 11, 2025
7e3f3f4
Tests
stsewd Mar 12, 2025
5c1ce0b
Merge branch 'main' into migrate-to-gh-apps
stsewd Mar 12, 2025
fa1b70c
Small changes
stsewd Mar 12, 2025
339cf73
Complete migrate view
stsewd Mar 18, 2025
7ff1e96
Create notifications when an error happens during the migration
stsewd Mar 18, 2025
9b14e95
Fixes
stsewd Mar 18, 2025
704ecb4
Check for users with multiple GH accounts
stsewd Mar 19, 2025
19dc240
Better default for accounts linked to multiple GH accounts
stsewd Mar 19, 2025
5a5d532
Rollback changes to avoid merge conflicts
stsewd Mar 20, 2025
26ef7eb
Re-add pygithub
stsewd Mar 20, 2025
34ddb25
Merge branch 'main' into migrate-to-gh-apps
stsewd Mar 20, 2025
33893de
Clean up and docstrings
stsewd Mar 20, 2025
5964ff1
Merge branch 'main' into migrate-to-gh-apps
stsewd Mar 20, 2025
8f23fa4
Docs about local dev
stsewd Mar 24, 2025
192f3ac
Add tests for migration page
stsewd Mar 25, 2025
66fdd95
Merge branch 'main' into migrate-to-gh-apps
stsewd Mar 25, 2025
08f9d2c
Fix merge conflict
stsewd Mar 25, 2025
ce6c2da
Match changes
stsewd Mar 25, 2025
c489137
Decouple migration from current GH account
stsewd Mar 27, 2025
3a88a62
More decoupling
stsewd Mar 27, 2025
928984b
Very WIP docs
stsewd Mar 27, 2025
6227ea3
Update docs
stsewd Mar 31, 2025
c962205
Add old_github_accounts so we can use it as a listing
stsewd Apr 14, 2025
6c5eefb
Add type
stsewd Apr 14, 2025
60a5228
Merge branch 'main' into migrate-to-gh-apps
stsewd Apr 15, 2025
f2d5498
Fix merge conflicts
stsewd Apr 15, 2025
34d7ed6
Format
stsewd Apr 15, 2025
225c640
Fix reference
stsewd Apr 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions readthedocs/api/v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class Meta(ProjectSerializer.Meta):
"environment_variables",
"max_concurrent_builds",
"readthedocs_yaml_path",
"clone_token",
)


Expand Down
46 changes: 39 additions & 7 deletions readthedocs/core/views/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
log = structlog.get_logger(__name__)


def _build_version(project, slug, already_built=()):
def _build_version(project, version):
"""
Where we actually trigger builds for a project and slug.

Expand All @@ -27,24 +27,27 @@ def _build_version(project, slug, already_built=()):
# Previously we were building the latest version (inactive or active)
# when building the default version,
# some users may have relied on this to update the version list #4450
version = project.versions.filter(active=True, slug=slug).first()
if version and slug not in already_built:
if version.active:
log.info(
"Building.",
project_slug=project.slug,
version_slug=version.slug,
)
trigger_build(project=project, version=version)
return slug
return version.slug

log.info("Not building.", version_slug=slug)
log.info("Not building.", version_slug=version.slug)
return None


def build_branches(project, branch_list):
"""
Build the branches for a specific project.

.. warning::

Deprecated, use ``build_versions_from_names`` instead.

Returns:
to_build - a list of branches that were built
not_building - a list of branches that we won't build
Expand All @@ -59,14 +62,43 @@ def build_branches(project, branch_list):
project_slug=project.slug,
version_slug=version.slug,
)
ret = _build_version(project, version.slug, already_built=to_build)
if version.slug in to_build:
continue
ret = _build_version(project, version)
if ret:
to_build.add(ret)
else:
not_building.add(version.slug)
return (to_build, not_building)


def build_versions_from_names(project, version_names: list[tuple[str, str]]):
"""
Build the branches or tags from the project.

:param project: Project instance
:param version_names: A list of tuples with the version name and type.
:returns: A tuple with the versions that were built and the versions that were not built.
"""
to_build = set()
not_building = set()
for version_name, version_type in version_names:
for version in project.versions_from_name(version_name, version_type):
log.debug(
"Processing.",
project_slug=project.slug,
version_slug=version.slug,
)
if version.slug in to_build:
continue
triggered = _build_version(project, version)
if triggered:
to_build.add(triggered)
else:
not_building.add(version.slug)
return to_build, not_building


def trigger_sync_versions(project):
"""
Sync the versions of a repo using its latest version.
Expand Down Expand Up @@ -150,6 +182,7 @@ def get_or_create_external_version(project, version_data):
external_version.identifier = version_data.commit
# If the PR was previously closed it was marked as closed
external_version.state = EXTERNAL_VERSION_STATE_OPEN
external_version.active = True
external_version.save()
log.info(
"External version updated.",
Expand All @@ -175,7 +208,6 @@ def close_external_version(project, version_data):
project.versions(manager=EXTERNAL)
.filter(
verbose_name=version_data.id,
identifier=version_data.commit,
)
.first()
)
Expand Down
10 changes: 10 additions & 0 deletions readthedocs/oauth/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@

from django.contrib import admin

from .models import GitHubAppInstallation
from .models import RemoteOrganization
from .models import RemoteOrganizationRelation
from .models import RemoteRepository
from .models import RemoteRepositoryRelation


@admin.register(GitHubAppInstallation)
class GitHubAppInstallationAdmin(admin.ModelAdmin):
list_display = (
"installation_id",
"target_type",
"target_id",
)


@admin.register(RemoteRepository)
class RemoteRepositoryAdmin(admin.ModelAdmin):
"""Admin configuration for the RemoteRepository model."""
Expand Down
15 changes: 15 additions & 0 deletions readthedocs/oauth/clients.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from datetime import datetime

import structlog
from django.conf import settings
from django.utils import timezone
from github import Auth
from github import GithubIntegration
from requests_oauthlib import OAuth2Session


Expand Down Expand Up @@ -70,3 +73,15 @@ def get_oauth2_client(account):
token_updater=_get_token_updater(token),
)
return session


def get_gh_app_client() -> GithubIntegration:
"""Return a client authenticated as the GitHub App to interact with the API."""
app_auth = Auth.AppAuth(
app_id=settings.GITHUB_APP_CLIENT_ID,
private_key=settings.GITHUB_APP_PRIVATE_KEY,
# 10 minutes is the maximum allowed by GitHub.
# PyGithub will handle the token expiration and renew it automatically.
jwt_expiry=60 * 10,
)
return GithubIntegration(auth=app_auth)
2 changes: 2 additions & 0 deletions readthedocs/oauth/constants.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
GITHUB = "github"
GITHUB_APP = "githubapp"
GITLAB = "gitlab"
BITBUCKET = "bitbucket"

VCS_PROVIDER_CHOICES = (
(GITHUB, "GitHub"),
(GITHUB_APP, "GitHub"),
(GITLAB, "GitLab"),
(BITBUCKET, "Bitbucket"),
)
Loading