Skip to content

Commit

Permalink
feat: update github mirror on publish
Browse files Browse the repository at this point in the history
* now only attempt to create github releases if they don't already exist
* fixed bug where local_releases were being overwritten with only the
  last updated releases instead of adding to the set
  • Loading branch information
sgfost committed Sep 6, 2024
1 parent 0e9d82b commit ca4ade6
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 22 deletions.
2 changes: 1 addition & 1 deletion django/library/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ def build(self) -> Repo:
self.mirror.update_local_releases(releases)
return Repo(self.repo_dir)

def get_or_build(self) -> Repo:
def update_or_build(self) -> Repo:
if self.repo_dir.exists() and self.repo_dir.joinpath(".git").exists():
return self.append_releases()
else:
Expand Down
25 changes: 16 additions & 9 deletions django/library/github.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from github import GithubIntegration, Auth, Github, Repository as GithubRepo
from github import GithubIntegration, Auth, Github
from github.Repository import Repository as GithubRepo
from git import Repo as GitRepo
from django.conf import settings
from django.core.cache import cache
Expand Down Expand Up @@ -114,15 +115,21 @@ def push(self, local_repo: GitRepo):
self._push_to_url(local_repo, push_url)

def create_releases(self, local_repo: GitRepo):
"""create Github releases for each tag in the local repository"""
"""create Github releases for each tag in the local repository that
does not already have a corresponding release in the remote repository"""
for tag in local_repo.tags:
self.github_repo.create_git_release(
tag.name,
name=tag.name,
message=tag.commit.message,
draft=False,
prerelease=False,
)
try:
existing_release = self.github_repo.get_release(tag.name)
except:
existing_release = None
if not existing_release:
self.github_repo.create_git_release(
tag.name,
name=tag.name,
message=tag.commit.message,
draft=False,
prerelease=False,
)

def _get_existing_repo(self):
"""attempt to get an existing repository for the authenticated user or organization"""
Expand Down
10 changes: 8 additions & 2 deletions django/library/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,11 @@ def unmirrored_remote_releases(self):
id__in=self.remote_releases.values_list("id", flat=True)
)

def update_local_releases(self, releases: models.QuerySet | list):
self.local_releases.set(releases)
def update_local_releases(self, new_releases: models.QuerySet | list):
if self.local_releases.exists():
self.local_releases.add(*new_releases)
else:
self.local_releases.set(new_releases)
self.last_local_update = timezone.now()
self.save()

Expand Down Expand Up @@ -1772,6 +1775,9 @@ def add_contributor(self, contributor: Contributor, role=Role.AUTHOR, index=None
def publish(self):
self.validate_publishable()
self._publish()
if self.codebase.git_mirror:
from .tasks import update_mirrored_codebase
update_mirrored_codebase(self.codebase.id)

def _publish(self):
if not self.live:
Expand Down
32 changes: 28 additions & 4 deletions django/library/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,50 @@ def mirror_codebase(codebase_id: int, is_user_repo=False, code=None, debug=False
if is_user_repo:
if not code:
raise ValueError("User repo requires a code")
mirror.user_access_token = GithubApi.get_user_access_token(code)
else:
mirror.organization_login = settings.GITHUB_MODEL_LIBRARY_ORG_NAME
mirror.save()

git_fs_api = CodebaseGitRepositoryApi(codebase)
local_repo = git_fs_api.get_or_build()
local_repo = git_fs_api.update_or_build()

gh_api = GithubApi(
codebase=codebase,
local_repo=local_repo,
repo_name=mirror.repository_name,
is_user_repo=is_user_repo,
organization_login=mirror.organization_login,
user_access_token=(
GithubApi.get_user_access_token(code) if is_user_repo else None
),
user_access_token=mirror.user_access_token,
debug=debug,
)
repo = gh_api.get_or_create_repo()
mirror.remote_url = repo.html_url
gh_api.push(local_repo)
gh_api.create_releases(local_repo)
mirror.update_remote_releases()


@db_task(retries=3, retry_delay=30)
def update_mirrored_codebase(codebase_id: int):
"""asynchronous task that updates a mirrored codebase by pushing new releases to Github"""
codebase = Codebase.objects.get(id=codebase_id)
mirror = codebase.git_mirror
if not mirror:
raise ValueError("Codebase does not have a git mirror")
if not mirror.remote_url:
raise ValueError("Codebase git mirror does not have a remote url")

git_fs_api = CodebaseGitRepositoryApi(codebase)
local_repo = git_fs_api.append_releases()
gh_api = GithubApi(
codebase=codebase,
local_repo=local_repo,
repo_name=mirror.repository_name,
is_user_repo=bool(mirror.user_access_token),
organization_login=mirror.organization_login,
user_access_token=mirror.user_access_token,
)
gh_api.push(local_repo)
gh_api.create_releases(local_repo)
mirror.update_remote_releases()
9 changes: 5 additions & 4 deletions django/library/tests/test_fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
StagingDirectories,
MessageLevels,
import_archive,
CodebaseGitRepositoryApi,
)
from library.tests.base import CodebaseFactory, TEST_SAMPLES_DIR
from library.models import License
Expand Down Expand Up @@ -113,7 +114,7 @@ def test_repo_build(self):
self.release_1.publish()
public_release_count = self.codebase.public_releases().count()
self.assertEqual(public_release_count, 1)
api = self.git_mirror.get_repo_api()
api = CodebaseGitRepositoryApi(self.codebase)
api.build()
# check that the mirror model is updated and the repo is built
self.assertIsNotNone(self.git_mirror.last_local_update)
Expand Down Expand Up @@ -143,7 +144,7 @@ def test_repo_append_releases(self):
self.release_1, self.release_1_dir, version_number="1.0.0"
)
self.release_1.publish()
api = self.git_mirror.get_repo_api()
api = CodebaseGitRepositoryApi(self.codebase)
api.build()
self.release_2 = self.codebase.create_release()
update_release_from_sample(
Expand Down Expand Up @@ -183,7 +184,7 @@ def test_will_not_append_lower_version(self):
self.release_2, self.release_2_dir, version_number="2.0.0"
)
self.release_2.publish()
api = self.git_mirror.get_repo_api()
api = CodebaseGitRepositoryApi(self.codebase)
api.build()
# now publish release 1.0.0
self.release_1.publish()
Expand All @@ -194,7 +195,7 @@ def test_repo_rebuild(self):
self.release_1, self.release_1_dir, version_number="1.0.0"
)
self.release_1.publish()
api = self.git_mirror.get_repo_api()
api = CodebaseGitRepositoryApi(self.codebase)
api.build()
self.release_2 = self.codebase.create_release()
update_release_from_sample(
Expand Down
15 changes: 13 additions & 2 deletions django/library/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
PeerReviewFeedbackEditorSerializer,
PeerReviewEventLogSerializer,
)
from .tasks import mirror_codebase
from .tasks import mirror_codebase, update_mirrored_codebase

import logging
import pathlib
Expand Down Expand Up @@ -452,7 +452,18 @@ def github_mirror(self, request, *args, **kwargs):
repo_name = request.data.get("repo_name")
codebase.create_git_mirror(repo_name)
mirror_codebase(codebase.id, debug=True)
return Response(data={"job_id": "1234"}, status=status.HTTP_202_ACCEPTED)
return Response(status=status.HTTP_202_ACCEPTED)

@action(detail=True, methods=["post"])
def update_github_mirror(self, request, *args, **kwargs):
codebase = self.get_object()
if not codebase.git_mirror:
return Response(
data={"error": "This codebase is not mirrored to a GitHub repo"},
status=status.HTTP_400_BAD_REQUEST,
)
update_mirrored_codebase(codebase.id)
return Response(status=status.HTTP_202_ACCEPTED)


class DevelopmentCodebaseDeleteView(mixins.DestroyModelMixin, CodebaseViewSet):
Expand Down

0 comments on commit ca4ade6

Please sign in to comment.