test_pagure_lib_git_diff_pr.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2017 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. from __future__ import unicode_literals, absolute_import
  8. import json # noqa
  9. import unittest # noqa
  10. import shutil # noqa
  11. import sys # noqa
  12. import tempfile # noqa
  13. import time # noqa
  14. import os # noqa
  15. import pygit2 # noqa
  16. from mock import patch, MagicMock # noqa
  17. sys.path.insert(
  18. 0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
  19. )
  20. import pagure.lib.query # noqa
  21. import tests # noqa
  22. from pagure.lib.repo import PagureRepo # noqa
  23. class PagureFlaskForkPrtests(tests.Modeltests):
  24. """ Tests for flask fork controller of pagure regarding diffing PRs """
  25. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  26. def setUp(self):
  27. """ Set up the environnment, ran before every tests. """
  28. super(PagureFlaskForkPrtests, self).setUp()
  29. # Create the main project in the DB
  30. item = pagure.lib.model.Project(
  31. user_id=1, # pingou
  32. name="test",
  33. description="test project #1",
  34. hook_token="aaabbbccc",
  35. )
  36. item.close_status = [
  37. "Invalid",
  38. "Insufficient data",
  39. "Fixed",
  40. "Duplicate",
  41. ]
  42. self.session.add(item)
  43. self.session.commit()
  44. # Create the fork
  45. item = pagure.lib.model.Project(
  46. user_id=1, # pingou
  47. name="test",
  48. description="test project #1",
  49. hook_token="aaabbbcccdd",
  50. parent_id=1,
  51. is_fork=True,
  52. )
  53. item.close_status = [
  54. "Invalid",
  55. "Insufficient data",
  56. "Fixed",
  57. "Duplicate",
  58. ]
  59. self.session.add(item)
  60. self.session.commit()
  61. # Create two git repos, one has 6 commits, the other 4 of which only
  62. # 1 isn't present in the first repo
  63. gitrepo = os.path.join(self.path, "repos", "test.git")
  64. pygit2.init_repository(gitrepo, bare=True)
  65. gitrepo2 = os.path.join(
  66. self.path, "repos", "forks", "pingou", "test.git"
  67. )
  68. pygit2.init_repository(gitrepo2, bare=True)
  69. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  70. repopath = os.path.join(newpath, "test")
  71. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  72. # Do 3 commits to the main repo
  73. for i in range(3):
  74. with open(os.path.join(repopath, "sources"), "w") as stream:
  75. stream.write("foo%s\n bar%s\n" % (i, i))
  76. clone_repo.index.add("sources")
  77. clone_repo.index.write()
  78. parents = []
  79. try:
  80. last_commit = clone_repo.revparse_single("HEAD")
  81. parents = [last_commit.oid.hex]
  82. except KeyError:
  83. pass
  84. # Commits the files added
  85. tree = clone_repo.index.write_tree()
  86. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  87. committer = pygit2.Signature(
  88. "Cecil Committer", "cecil@committers.tld"
  89. )
  90. clone_repo.create_commit(
  91. "refs/heads/master", # the name of the reference to update
  92. author,
  93. committer,
  94. "Editing the file sources for testing #%s" % i,
  95. # binary string representing the tree object ID
  96. tree,
  97. # list of binary strings representing parents of the new commit
  98. parents,
  99. )
  100. # Push to the main repo
  101. refname = "refs/heads/master:refs/heads/master"
  102. ori_remote = clone_repo.remotes[0]
  103. PagureRepo.push(ori_remote, refname)
  104. # Push to the fork repo
  105. remote = clone_repo.create_remote("pingou_fork", gitrepo2)
  106. PagureRepo.push(remote, refname)
  107. # Do another 3 commits to the main repo
  108. for i in range(3, 6):
  109. with open(os.path.join(repopath, "sources"), "w") as stream:
  110. stream.write("foo%s\n bar%s\n" % (i, i))
  111. clone_repo.index.add("sources")
  112. clone_repo.index.write()
  113. last_commit = clone_repo.revparse_single("HEAD")
  114. # Commits the files added
  115. tree = clone_repo.index.write_tree()
  116. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  117. committer = pygit2.Signature(
  118. "Cecil Committer", "cecil@committers.tld"
  119. )
  120. clone_repo.create_commit(
  121. "refs/heads/master", # the name of the reference to update
  122. author,
  123. committer,
  124. "Editing the file sources for testing #%s" % i,
  125. # binary string representing the tree object ID
  126. tree,
  127. # list of binary strings representing parents of the new commit
  128. [last_commit.oid.hex],
  129. )
  130. # Push to the main repo
  131. refname = "refs/heads/master:refs/heads/master"
  132. ori_remote = clone_repo.remotes[0]
  133. PagureRepo.push(ori_remote, refname)
  134. # Add two commits to the fork repo
  135. repopath = os.path.join(newpath, "pingou_test")
  136. clone_repo = pygit2.clone_repository(gitrepo2, repopath)
  137. with open(os.path.join(repopath, "sources"), "w") as stream:
  138. stream.write("foo\n bar\n")
  139. clone_repo.index.add("sources")
  140. clone_repo.index.write()
  141. last_commit = clone_repo.revparse_single("HEAD")
  142. # Commits the files added
  143. tree = clone_repo.index.write_tree()
  144. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  145. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  146. last_commit = clone_repo.create_commit(
  147. "refs/heads/feature_foo", # the name of the reference to update
  148. author,
  149. committer,
  150. "New edition on side branch of the file sources for testing",
  151. # binary string representing the tree object ID
  152. tree,
  153. # list of binary strings representing parents of the new commit
  154. [last_commit.oid.hex],
  155. )
  156. with open(os.path.join(repopath, "sources"), "w") as stream:
  157. stream.write("foo\n bar\nbaz\n")
  158. clone_repo.index.add("sources")
  159. clone_repo.index.write()
  160. # Commits the files added
  161. tree = clone_repo.index.write_tree()
  162. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  163. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  164. last_commit = clone_repo.create_commit(
  165. "refs/heads/feature_foo", # the name of the reference to update
  166. author,
  167. committer,
  168. "Second edit on side branch of the file sources for testing",
  169. # binary string representing the tree object ID
  170. tree,
  171. # list of binary strings representing parents of the new commit
  172. [last_commit.hex],
  173. )
  174. # Push to the fork repo
  175. ori_remote = clone_repo.remotes[0]
  176. refname = "refs/heads/feature_foo:refs/heads/feature_foo"
  177. PagureRepo.push(ori_remote, refname)
  178. shutil.rmtree(newpath)
  179. # Create the PR between the two repos
  180. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  181. forked_repo = pagure.lib.query.get_authorized_project(
  182. self.session, "test", user="pingou"
  183. )
  184. req = pagure.lib.query.new_pull_request(
  185. session=self.session,
  186. repo_from=forked_repo,
  187. branch_from="feature_foo",
  188. repo_to=repo,
  189. branch_to="master",
  190. title="test pull-request",
  191. user="pingou",
  192. )
  193. self.assertEqual(req.id, 1)
  194. self.assertEqual(req.title, "test pull-request")
  195. def test_get_pr_info(self):
  196. """ Test pagure.ui.fork._get_pr_info """
  197. gitrepo = os.path.join(self.path, "repos", "test.git")
  198. gitrepo2 = os.path.join(
  199. self.path, "repos", "forks", "pingou", "test.git"
  200. )
  201. diff, diff_commits, orig_commit = pagure.lib.git.get_diff_info(
  202. repo_obj=PagureRepo(gitrepo2),
  203. orig_repo=PagureRepo(gitrepo),
  204. branch_from="feature_foo",
  205. branch_to="master",
  206. )
  207. self.assertEqual(len(diff_commits), 2)
  208. self.assertEqual(
  209. diff_commits[0].message,
  210. "Second edit on side branch of the file sources for testing",
  211. )
  212. self.assertEqual(
  213. diff_commits[1].message,
  214. "New edition on side branch of the file sources for testing",
  215. )
  216. self.assertEqual(
  217. orig_commit.message, "Editing the file sources for testing #5"
  218. )
  219. def test_get_pr_info_raises(self):
  220. """ Test pagure.ui.fork._get_pr_info """
  221. gitrepo = os.path.join(self.path, "repos", "test.git")
  222. gitrepo2 = os.path.join(
  223. self.path, "repos", "forks", "pingou", "test.git"
  224. )
  225. self.assertRaises(
  226. pagure.exceptions.BranchNotFoundException,
  227. pagure.lib.git.get_diff_info,
  228. repo_obj=PagureRepo(gitrepo2),
  229. orig_repo=PagureRepo(gitrepo),
  230. branch_from="feature",
  231. branch_to="master",
  232. )
  233. self.assertRaises(
  234. pagure.exceptions.BranchNotFoundException,
  235. pagure.lib.git.get_diff_info,
  236. repo_obj=PagureRepo(gitrepo2),
  237. orig_repo=PagureRepo(gitrepo),
  238. branch_from="feature_foo",
  239. branch_to="bar",
  240. )
  241. def test_diff_pull_request(self):
  242. """ Test pagure.lib.git.diff_pull_request """
  243. gitrepo = os.path.join(self.path, "repos", "test.git")
  244. gitrepo2 = os.path.join(
  245. self.path, "repos", "forks", "pingou", "test.git"
  246. )
  247. request = pagure.lib.query.search_pull_requests(
  248. self.session, requestid=1, project_id=1
  249. )
  250. diff_commits, diff = pagure.lib.git.diff_pull_request(
  251. self.session,
  252. request=request,
  253. repo_obj=PagureRepo(gitrepo2),
  254. orig_repo=PagureRepo(gitrepo),
  255. with_diff=True,
  256. )
  257. self.assertEqual(len(diff_commits), 2)
  258. self.assertEqual(
  259. diff_commits[0].message,
  260. "Second edit on side branch of the file sources for testing",
  261. )
  262. self.assertEqual(
  263. diff_commits[1].message,
  264. "New edition on side branch of the file sources for testing",
  265. )
  266. # Check that the PR has its PR refs
  267. # we don't know the task id but we'll give it 30 sec to finish
  268. cnt = 0
  269. repo = PagureRepo(gitrepo)
  270. self.assertIn("refs/pull/1/head", list(repo.listall_references()))
  271. self.assertTrue(cnt < 60)
  272. pr_ref = repo.lookup_reference("refs/pull/1/head")
  273. commit = pr_ref.peel()
  274. self.assertEqual(commit.oid.hex, diff_commits[0].oid.hex)
  275. def test_diff_pull_request_updated(self):
  276. """ Test that calling pagure.lib.git.diff_pull_request on an updated
  277. PR updates the PR reference
  278. """
  279. gitrepo = os.path.join(self.path, "repos", "test.git")
  280. gitrepo2 = os.path.join(
  281. self.path, "repos", "forks", "pingou", "test.git"
  282. )
  283. request = pagure.lib.query.search_pull_requests(
  284. self.session, requestid=1, project_id=1
  285. )
  286. # Get the diff corresponding to the PR and check its ref
  287. diff_commits, diff = pagure.lib.git.diff_pull_request(
  288. self.session,
  289. request=request,
  290. repo_obj=PagureRepo(gitrepo2),
  291. orig_repo=PagureRepo(gitrepo),
  292. with_diff=True,
  293. )
  294. self.assertEqual(len(diff_commits), 2)
  295. # Check that the PR has its PR refs
  296. # we don't know the task id but we'll give it 30 sec to finish
  297. cnt = 0
  298. repo = PagureRepo(gitrepo)
  299. self.assertIn("refs/pull/1/head", list(repo.listall_references()))
  300. self.assertTrue(cnt < 60)
  301. pr_ref = repo.lookup_reference("refs/pull/1/head")
  302. commit = pr_ref.peel()
  303. self.assertEqual(commit.oid.hex, diff_commits[0].oid.hex)
  304. # Add a new commit on the fork
  305. repopath = os.path.join(self.path, "pingou_test2")
  306. clone_repo = pygit2.clone_repository(
  307. gitrepo2, repopath, checkout_branch="feature_foo"
  308. )
  309. with open(os.path.join(repopath, "sources"), "w") as stream:
  310. stream.write("foo\n bar\nbaz\nhey there\n")
  311. clone_repo.index.add("sources")
  312. clone_repo.index.write()
  313. last_commit = clone_repo.lookup_branch("feature_foo").peel()
  314. # Commits the files added
  315. tree = clone_repo.index.write_tree()
  316. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  317. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  318. last_commit = clone_repo.create_commit(
  319. "refs/heads/feature_foo", # the name of the reference to update
  320. author,
  321. committer,
  322. "Third edit on side branch of the file sources for testing",
  323. # binary string representing the tree object ID
  324. tree,
  325. # list of binary strings representing parents of the new commit
  326. [last_commit.oid.hex],
  327. )
  328. # Push to the fork repo
  329. ori_remote = clone_repo.remotes[0]
  330. refname = "refs/heads/feature_foo:refs/heads/feature_foo"
  331. PagureRepo.push(ori_remote, refname)
  332. # Get the new diff for that PR and check its new ref
  333. diff_commits, diff = pagure.lib.git.diff_pull_request(
  334. self.session,
  335. request=request,
  336. repo_obj=PagureRepo(gitrepo2),
  337. orig_repo=PagureRepo(gitrepo),
  338. with_diff=True,
  339. )
  340. self.assertEqual(len(diff_commits), 3)
  341. # Check that the PR has its PR refs
  342. # we don't know the task id but we'll give it 30 sec to finish
  343. cnt = 0
  344. repo = PagureRepo(gitrepo)
  345. self.assertIn("refs/pull/1/head", list(repo.listall_references()))
  346. self.assertTrue(cnt < 60)
  347. pr_ref = repo.lookup_reference("refs/pull/1/head")
  348. commit2 = pr_ref.peel()
  349. self.assertEqual(commit2.oid.hex, diff_commits[0].oid.hex)
  350. self.assertNotEqual(commit.oid.hex, commit2.oid.hex)
  351. def test_two_diff_pull_request_sequentially(self):
  352. """ Test calling pagure.lib.git.diff_pull_request twice returns
  353. the same data
  354. """
  355. gitrepo = os.path.join(self.path, "repos", "test.git")
  356. gitrepo2 = os.path.join(
  357. self.path, "repos", "forks", "pingou", "test.git"
  358. )
  359. request = pagure.lib.query.search_pull_requests(
  360. self.session, requestid=1, project_id=1
  361. )
  362. # Get the diff corresponding to the PR and check its ref
  363. diff_commits, diff = pagure.lib.git.diff_pull_request(
  364. self.session,
  365. request=request,
  366. repo_obj=PagureRepo(gitrepo2),
  367. orig_repo=PagureRepo(gitrepo),
  368. with_diff=True,
  369. )
  370. self.assertEqual(len(diff_commits), 2)
  371. # Check that the PR has its PR refs
  372. # we don't know the task id but we'll give it 30 sec to finish
  373. cnt = 0
  374. repo = PagureRepo(gitrepo)
  375. self.assertIn("refs/pull/1/head", list(repo.listall_references()))
  376. self.assertTrue(cnt < 60)
  377. pr_ref = repo.lookup_reference("refs/pull/1/head")
  378. commit = pr_ref.peel()
  379. self.assertEqual(commit.oid.hex, diff_commits[0].oid.hex)
  380. # Run diff_pull_request a second time
  381. diff_commits2, diff = pagure.lib.git.diff_pull_request(
  382. self.session,
  383. request=request,
  384. repo_obj=PagureRepo(gitrepo2),
  385. orig_repo=PagureRepo(gitrepo),
  386. with_diff=True,
  387. )
  388. self.assertEqual(len(diff_commits2), 2)
  389. self.assertEqual(
  390. [d.oid.hex for d in diff_commits2],
  391. [d.oid.hex for d in diff_commits],
  392. )
  393. # Check that the PR has its PR refs
  394. # we don't know the task id but we'll give it 30 sec to finish
  395. cnt = 0
  396. repo = PagureRepo(gitrepo)
  397. self.assertIn("refs/pull/1/head", list(repo.listall_references()))
  398. self.assertTrue(cnt < 60)
  399. pr_ref = repo.lookup_reference("refs/pull/1/head")
  400. commit2 = pr_ref.peel()
  401. self.assertEqual(commit2.oid.hex, diff_commits[0].oid.hex)
  402. self.assertEqual(commit.oid.hex, commit2.oid.hex)
  403. if __name__ == "__main__":
  404. unittest.main(verbosity=2)