From acd3eb0fc263ab10ad2168b1caa6dfafb6e851e5 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Chibon Date: Jun 22 2017 10:50:54 +0000 Subject: Create references for pull-request in the git repo for local checkout This will allow checking out locally a PR opened against a given project without having to add and manage a new remote. One note: while existing clone will not get the objects coming from the fork, new clones will download them, so git show will find the commits coming from forks even though they are not merged and even if the user did not fetch the corresponding pull/ references. Fixes https://pagure.io/pagure/issue/443 Signed-off-by: Pierre-Yves Chibon --- diff --git a/pagure/lib/git.py b/pagure/lib/git.py index c50c27f..7f0a207 100644 --- a/pagure/lib/git.py +++ b/pagure/lib/git.py @@ -27,6 +27,8 @@ import pygit2 import werkzeug from sqlalchemy.exc import SQLAlchemyError +from pygit2.remote import RemoteCollection + import pagure import pagure.exceptions import pagure.lib @@ -1600,6 +1602,14 @@ def diff_pull_request( request.commit_stop = diff_commits[0].oid.hex session.add(request) session.commit() + + tasks.sync_pull_ref.delay( + request.project.name, + request.project.namespace, + request.project.user.username if request.project.is_fork else None, + request.id + ) + if commenttext: pagure.lib.add_pull_request_comment( session, request, @@ -1620,6 +1630,28 @@ def diff_pull_request( return diff_commits +def update_pull_ref(request, repo): + """ Create or update the refs/pull/ reference in the git repo. + """ + + repopath = pagure.get_repo_path(request.project) + reponame = '%s_%s' % (request.user.user, request.uid) + + _log.info( + ' Adding remote: %s pointing to: %s', reponame, repopath) + rc = RemoteCollection(repo) + remote = rc.create(reponame, repopath) + try: + _log.info( + ' Pushing refs/heads/%s to refs/pull/%s', + request.branch_from, request.id) + refname = 'refs/heads/%s:refs/pull/%s/head' % ( + request.branch_from, request.id) + PagureRepo.push(remote, refname) + finally: + rc.delete(reponame) + + def get_git_tags(project): """ Returns the list of tags created in the git repositorie of the specified project. diff --git a/pagure/lib/tasks.py b/pagure/lib/tasks.py index 411dee0..ed713da 100644 --- a/pagure/lib/tasks.py +++ b/pagure/lib/tasks.py @@ -417,3 +417,36 @@ def project_dowait(name, namespace, user): gc_clean() return ret('view_repo', repo=name, username=user, namespace=namespace) + + +@conn.task +def sync_pull_ref(name, namespace, user, requestid): + """ Synchronize a pull/ reference from the content in the forked repo, + allowing local checkout of the pull-request. + """ + session = pagure.lib.create_session() + + project = pagure.lib._get_project( + session, namespace=namespace, name=name, user=user) + + with project.lock('WORKER'): + request = pagure.lib.search_pull_requests( + session, project_id=project.id, requestid=requestid) + _log.debug( + 'Update pull refs of: %s#%s', + request.project.fullname, request.id) + + if request.remote: + # Get the fork + repopath = pagure.get_remote_repo_path( + request.remote_git, request.branch_from) + else: + # Get the fork + repopath = pagure.get_repo_path(request.project_from) + _log.debug(' working on the repo in: %s', repopath) + + repo_obj = pygit2.Repository(repopath) + pagure.lib.git.update_pull_ref(request, repo_obj) + + session.remove() + gc_clean()