def test_diff_pull_request(self): """ Test pagure.lib.git.diff_pull_request """ gitrepo = os.path.join(self.path, 'repos', 'test.git') gitrepo2 = os.path.join(self.path, 'repos', 'forks', 'pingou', 'test.git') request = pagure.lib.query.search_pull_requests(self.session, requestid=1, project_id=1) diff_commits, diff = pagure.lib.git.diff_pull_request( self.session, request=request, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), with_diff=True) self.assertEqual(len(diff_commits), 2) self.assertEqual( diff_commits[0].message, 'Second edit on side branch of the file sources for testing') self.assertEqual( diff_commits[1].message, 'New edition on side branch of the file sources for testing') # Check that the PR has its PR refs # we don't know the task id but we'll give it 30 sec to finish cnt = 0 repo = PagureRepo(gitrepo) self.assertIn('refs/pull/1/head', list(repo.listall_references())) self.assertTrue(cnt < 60) pr_ref = repo.lookup_reference('refs/pull/1/head') commit = pr_ref.get_object() self.assertEqual(commit.oid.hex, diff_commits[0].oid.hex)
def get_git_tags_objects(project): """ Returns the list of references of the tags created in the git repositorie the specified project. The list is sorted using the time of the commit associated to the tag """ repopath = pagure.get_repo_path(project) repo_obj = PagureRepo(repopath) tags = {} for tag in repo_obj.listall_references(): if 'refs/tags/' in tag and repo_obj.lookup_reference(tag): commit_time = "" theobject = repo_obj[repo_obj.lookup_reference(tag).target] objecttype = "" if isinstance(theobject, pygit2.Tag): commit_time = theobject.get_object().commit_time objecttype = "tag" elif isinstance(theobject, pygit2.Commit): commit_time = theobject.commit_time objecttype = "commit" tags[commit_time] = { "object": repo_obj[repo_obj.lookup_reference(tag).target], "tagname": tag.replace("refs/tags/", ""), "date": commit_time, "objecttype": objecttype } sorted_tags = [] for tag in sorted(tags, reverse=True): sorted_tags.append(tags[tag]) return sorted_tags
def get_git_tags_objects(project): """ Returns the list of references of the tags created in the git repositorie the specified project. """ repopath = pagure.get_repo_path(project) repo_obj = PagureRepo(repopath) tags = [ repo_obj.lookup_reference(tag) for tag in repo_obj.listall_references() if 'refs/tags/' in tag ] return tags
def get_git_tags(project): """ Returns the list of tags created in the git repositorie of the specified project. """ repopath = pagure.get_repo_path(project) repo_obj = PagureRepo(repopath) tags = [ tag.split('refs/tags/')[1] for tag in repo_obj.listall_references() if 'refs/tags/' in tag ] return tags
def test_get_pr_info_raises(self): """ Test pagure.ui.fork._get_pr_info """ gitrepo = os.path.join(self.path, 'repos', 'test.git') gitrepo2 = os.path.join(self.path, 'repos', 'forks', 'pingou', 'test.git') self.assertRaises(pagure.exceptions.BranchNotFoundException, pagure.lib.git.get_diff_info, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), branch_from='feature', branch_to='master') self.assertRaises(pagure.exceptions.BranchNotFoundException, pagure.lib.git.get_diff_info, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), branch_from='feature_foo', branch_to='bar')
def test_get_pr_info(self): """ Test pagure.ui.fork._get_pr_info """ gitrepo = os.path.join(self.path, 'repos', 'test.git') gitrepo2 = os.path.join(self.path, 'repos', 'forks', 'pingou', 'test.git') diff, diff_commits, orig_commit = pagure.lib.git.get_diff_info( repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), branch_from='feature_foo', branch_to='master') self.assertEqual(len(diff_commits), 2) self.assertEqual( diff_commits[0].message, 'Second edit on side branch of the file sources for testing') self.assertEqual( diff_commits[1].message, 'New edition on side branch of the file sources for testing') self.assertEqual(orig_commit.message, 'Editing the file sources for testing #5')
def test_two_diff_pull_request_sequentially(self): """ Test calling pagure.lib.git.diff_pull_request twice returns the same data """ gitrepo = os.path.join(self.path, 'repos', 'test.git') gitrepo2 = os.path.join(self.path, 'repos', 'forks', 'pingou', 'test.git') request = pagure.lib.query.search_pull_requests(self.session, requestid=1, project_id=1) # Get the diff corresponding to the PR and check its ref diff_commits, diff = pagure.lib.git.diff_pull_request( self.session, request=request, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), with_diff=True) self.assertEqual(len(diff_commits), 2) # Check that the PR has its PR refs # we don't know the task id but we'll give it 30 sec to finish cnt = 0 repo = PagureRepo(gitrepo) self.assertIn('refs/pull/1/head', list(repo.listall_references())) self.assertTrue(cnt < 60) pr_ref = repo.lookup_reference('refs/pull/1/head') commit = pr_ref.get_object() self.assertEqual(commit.oid.hex, diff_commits[0].oid.hex) # Run diff_pull_request a second time diff_commits2, diff = pagure.lib.git.diff_pull_request( self.session, request=request, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), with_diff=True) self.assertEqual(len(diff_commits2), 2) self.assertEqual([d.oid.hex for d in diff_commits2], [d.oid.hex for d in diff_commits]) # Check that the PR has its PR refs # we don't know the task id but we'll give it 30 sec to finish cnt = 0 repo = PagureRepo(gitrepo) self.assertIn('refs/pull/1/head', list(repo.listall_references())) self.assertTrue(cnt < 60) pr_ref = repo.lookup_reference('refs/pull/1/head') commit2 = pr_ref.get_object() self.assertEqual(commit2.oid.hex, diff_commits[0].oid.hex) self.assertEqual(commit.oid.hex, commit2.oid.hex)
def test_get_pr_info_raises(self): """ Test pagure.ui.fork._get_pr_info """ gitrepo = os.path.join(self.path, "repos", "test.git") gitrepo2 = os.path.join(self.path, "repos", "forks", "pingou", "test.git") self.assertRaises( pagure.exceptions.BranchNotFoundException, pagure.lib.git.get_diff_info, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), branch_from="feature", branch_to="master", ) self.assertRaises( pagure.exceptions.BranchNotFoundException, pagure.lib.git.get_diff_info, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), branch_from="feature_foo", branch_to="bar", )
def test_get_pr_info(self): """ Test pagure.ui.fork._get_pr_info """ gitrepo = os.path.join(self.path, "repos", "test.git") gitrepo2 = os.path.join(self.path, "repos", "forks", "pingou", "test.git") diff, diff_commits, orig_commit = pagure.lib.git.get_diff_info( repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), branch_from="feature_foo", branch_to="master", ) self.assertEqual(len(diff_commits), 2) self.assertEqual( diff_commits[0].message, "Second edit on side branch of the file sources for testing", ) self.assertEqual( diff_commits[1].message, "New edition on side branch of the file sources for testing", ) self.assertEqual(orig_commit.message, "Editing the file sources for testing #5")
def get_git_tags_objects(project): """ Returns the list of references of the tags created in the git repositorie the specified project. The list is sorted using the time of the commit associated to the tag """ repopath = pagure.get_repo_path(project) repo_obj = PagureRepo(repopath) tags = {} for tag in repo_obj.listall_references(): if 'refs/tags/' in tag and repo_obj.lookup_reference(tag): commit_time = "" theobject = repo_obj[repo_obj.lookup_reference(tag).target] objecttype = "" if isinstance(theobject, pygit2.Tag): commit_time = theobject.get_object().commit_time objecttype = "tag" elif isinstance(theobject, pygit2.Commit): commit_time = theobject.commit_time objecttype = "commit" tags[commit_time] = { "object": repo_obj[repo_obj.lookup_reference(tag).target], "tagname": tag.replace("refs/tags/", ""), "date": commit_time, "objecttype": objecttype, "head_msg": None, "body_msg": None, } if objecttype == 'tag': head_msg, _, body_msg = tags[commit_time][ "object"].message.partition('\n') if body_msg.strip().endswith('\n-----END PGP SIGNATURE-----'): body_msg = body_msg.rsplit('-----BEGIN PGP SIGNATURE-----', 1)[0].strip() tags[commit_time]["head_msg"] = head_msg tags[commit_time]["body_msg"] = body_msg sorted_tags = [] for tag in sorted(tags, reverse=True): sorted_tags.append(tags[tag]) return sorted_tags
def merge_pull_request(session, request, username, request_folder, domerge=True): ''' Merge the specified pull-request. ''' 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) fork_obj = PagureRepo(repopath) # Get the original repo parentpath = pagure.get_repo_path(request.project) # Clone the original repo into a temp folder newpath = tempfile.mkdtemp(prefix='pagure-pr-merge') new_repo = pygit2.clone_repository(parentpath, newpath) # Update the start and stop commits in the DB, one last time diff_commits = diff_pull_request(session, request, PagureRepo(parentpath), fork_obj, requestfolder=request_folder, with_diff=False)[0] if request.project.settings.get( 'Enforce_signed-off_commits_in_pull-request', False): for commit in diff_commits: if 'signed-off-by' not in commit.message.lower(): raise pagure.exceptions.PagureException( 'This repo enforces that all commits are ' 'signed off by their author. ') # Checkout the correct branch branch_ref = get_branch_ref(new_repo, request.branch) if not branch_ref: shutil.rmtree(newpath) raise pagure.exceptions.BranchNotFoundException( 'Branch %s could not be found in the repo %s' % (request.branch, request.project.fullname)) new_repo.checkout(branch_ref) branch = get_branch_ref(fork_obj, request.branch_from) if not branch: shutil.rmtree(newpath) raise pagure.exceptions.BranchNotFoundException( 'Branch %s could not be found in the repo %s' % (request.branch_from, request.project_from.fullname if request.project_from else request.remote_git)) repo_commit = fork_obj[branch.get_object().hex] ori_remote = new_repo.remotes[0] # Add the fork as remote repo reponame = '%s_%s' % (request.user.user, request.uid) remote = new_repo.create_remote(reponame, repopath) # Fetch the commits remote.fetch() merge = new_repo.merge(repo_commit.oid) if merge is None: mergecode = new_repo.merge_analysis(repo_commit.oid)[0] refname = '%s:refs/heads/%s' % (branch_ref.name, request.branch) if ((merge is not None and merge.is_uptodate) or (merge is None and mergecode & pygit2.GIT_MERGE_ANALYSIS_UP_TO_DATE)): if domerge: pagure.lib.close_pull_request(session, request, username, requestfolder=request_folder) try: session.commit() except SQLAlchemyError as err: # pragma: no cover session.rollback() pagure.APP.logger.exception(err) shutil.rmtree(newpath) raise pagure.exceptions.PagureException( 'Could not close this pull-request') raise pagure.exceptions.PagureException( 'Nothing to do, changes were already merged') else: request.merge_status = 'NO_CHANGE' session.commit() return 'NO_CHANGE' elif ( (merge is not None and merge.is_fastforward) or (merge is None and mergecode & pygit2.GIT_MERGE_ANALYSIS_FASTFORWARD)): if domerge: if merge is not None: # This is depending on the pygit2 version branch_ref.target = merge.fastforward_oid elif merge is None and mergecode is not None: branch_ref.set_target(repo_commit.oid.hex) PagureRepo.push(ori_remote, refname) else: request.merge_status = 'FFORWARD' session.commit() return 'FFORWARD' else: tree = None try: tree = new_repo.index.write_tree() except pygit2.GitError: shutil.rmtree(newpath) if domerge: raise pagure.exceptions.PagureException('Merge conflicts!') else: request.merge_status = 'CONFLICTS' session.commit() return 'CONFLICTS' if not domerge: request.merge_status = 'MERGE' session.commit() return 'MERGE' head = new_repo.lookup_reference('HEAD').get_object() new_repo.create_commit('refs/heads/%s' % request.branch, repo_commit.author, repo_commit.committer, 'Merge #%s `%s`' % (request.id, request.title), tree, [head.hex, repo_commit.oid.hex]) PagureRepo.push(ori_remote, refname) # Update status pagure.lib.close_pull_request( session, request, username, requestfolder=request_folder, ) try: # Reset the merge_status of all opened PR to refresh their cache pagure.lib.reset_status_pull_request(session, request.project) session.commit() except SQLAlchemyError as err: # pragma: no cover session.rollback() pagure.APP.logger.exception(err) shutil.rmtree(newpath) raise pagure.exceptions.PagureException( 'Could not update this pull-request in the database') shutil.rmtree(newpath) return 'Changes merged!'
def test_diff_pull_request_updated(self): """ Test that calling pagure.lib.git.diff_pull_request on an updated PR updates the PR reference """ gitrepo = os.path.join(self.path, 'repos', 'test.git') gitrepo2 = os.path.join(self.path, 'repos', 'forks', 'pingou', 'test.git') request = pagure.lib.search_pull_requests(self.session, requestid=1, project_id=1) # Get the diff corresponding to the PR and check its ref diff_commits, diff = pagure.lib.git.diff_pull_request( self.session, request=request, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), requestfolder=None, with_diff=True) self.assertEqual(len(diff_commits), 2) # Check that the PR has its PR refs # we don't know the task id but we'll give it 30 sec to finish cnt = 0 repo = PagureRepo(gitrepo) while 1: if 'refs/pull/1/head' in list(repo.listall_references()): break cnt += 1 if cnt == 60: break time.sleep(0.5) self.assertTrue(cnt < 60) pr_ref = repo.lookup_reference('refs/pull/1/head') commit = pr_ref.get_object() self.assertEqual(commit.oid.hex, diff_commits[0].oid.hex) # Add a new commit on the fork repopath = os.path.join(self.path, 'pingou_test2') clone_repo = pygit2.clone_repository(gitrepo2, repopath, checkout_branch='feature_foo') with open(os.path.join(repopath, 'sources'), 'w') as stream: stream.write('foo\n bar\nbaz\nhey there\n') clone_repo.index.add('sources') clone_repo.index.write() last_commit = clone_repo.lookup_branch('feature_foo').get_object() # Commits the files added tree = clone_repo.index.write_tree() author = pygit2.Signature('Alice Author', '*****@*****.**') committer = pygit2.Signature('Cecil Committer', '*****@*****.**') last_commit = clone_repo.create_commit( 'refs/heads/feature_foo', # the name of the reference to update author, committer, 'Third edit on side branch of the file sources for testing', # binary string representing the tree object ID tree, # list of binary strings representing parents of the new commit [last_commit.oid.hex]) # Push to the fork repo ori_remote = clone_repo.remotes[0] refname = 'refs/heads/feature_foo:refs/heads/feature_foo' PagureRepo.push(ori_remote, refname) # Get the new diff for that PR and check its new ref diff_commits, diff = pagure.lib.git.diff_pull_request( self.session, request=request, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), requestfolder=None, with_diff=True) self.assertEqual(len(diff_commits), 3) # Check that the PR has its PR refs # we don't know the task id but we'll give it 30 sec to finish cnt = 0 repo = PagureRepo(gitrepo) while 1: if 'refs/pull/1/head' in list(repo.listall_references()): break cnt += 1 if cnt == 60: break time.sleep(0.5) self.assertTrue(cnt < 60) pr_ref = repo.lookup_reference('refs/pull/1/head') commit2 = pr_ref.get_object() self.assertEqual(commit2.oid.hex, diff_commits[0].oid.hex) self.assertNotEqual( commit.oid.hex, commit2.oid.hex, )
def test_diff_pull_request_updated(self): """ Test that calling pagure.lib.git.diff_pull_request on an updated PR updates the PR reference """ gitrepo = os.path.join(self.path, "repos", "test.git") gitrepo2 = os.path.join(self.path, "repos", "forks", "pingou", "test.git") request = pagure.lib.query.search_pull_requests(self.session, requestid=1, project_id=1) # Get the diff corresponding to the PR and check its ref diff_commits, diff = pagure.lib.git.diff_pull_request( self.session, request=request, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), with_diff=True, ) self.assertEqual(len(diff_commits), 2) # Check that the PR has its PR refs # we don't know the task id but we'll give it 30 sec to finish cnt = 0 repo = PagureRepo(gitrepo) self.assertIn("refs/pull/1/head", list(repo.listall_references())) self.assertTrue(cnt < 60) pr_ref = repo.lookup_reference("refs/pull/1/head") commit = pr_ref.peel() self.assertEqual(commit.oid.hex, diff_commits[0].oid.hex) # Add a new commit on the fork repopath = os.path.join(self.path, "pingou_test2") clone_repo = pygit2.clone_repository(gitrepo2, repopath, checkout_branch="feature_foo") with open(os.path.join(repopath, "sources"), "w") as stream: stream.write("foo\n bar\nbaz\nhey there\n") clone_repo.index.add("sources") clone_repo.index.write() last_commit = clone_repo.lookup_branch("feature_foo").peel() # Commits the files added tree = clone_repo.index.write_tree() author = pygit2.Signature("Alice Author", "*****@*****.**") committer = pygit2.Signature("Cecil Committer", "*****@*****.**") last_commit = clone_repo.create_commit( "refs/heads/feature_foo", # the name of the reference to update author, committer, "Third edit on side branch of the file sources for testing", # binary string representing the tree object ID tree, # list of binary strings representing parents of the new commit [last_commit.oid.hex], ) # Push to the fork repo ori_remote = clone_repo.remotes[0] refname = "refs/heads/feature_foo:refs/heads/feature_foo" PagureRepo.push(ori_remote, refname) # Get the new diff for that PR and check its new ref diff_commits, diff = pagure.lib.git.diff_pull_request( self.session, request=request, repo_obj=PagureRepo(gitrepo2), orig_repo=PagureRepo(gitrepo), with_diff=True, ) self.assertEqual(len(diff_commits), 3) # Check that the PR has its PR refs # we don't know the task id but we'll give it 30 sec to finish cnt = 0 repo = PagureRepo(gitrepo) self.assertIn("refs/pull/1/head", list(repo.listall_references())) self.assertTrue(cnt < 60) pr_ref = repo.lookup_reference("refs/pull/1/head") commit2 = pr_ref.peel() self.assertEqual(commit2.oid.hex, diff_commits[0].oid.hex) self.assertNotEqual(commit.oid.hex, commit2.oid.hex)