test_pagure_flask_rebase.py 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2018 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. from __future__ import unicode_literals, absolute_import
  8. import datetime
  9. import unittest
  10. import shutil
  11. import sys
  12. import os
  13. import json
  14. import pagure_messages
  15. from fedora_messaging import api, testing
  16. from mock import ANY, patch, MagicMock
  17. sys.path.insert(
  18. 0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
  19. )
  20. import pagure.lib.query
  21. import pagure.lib.tasks
  22. import tests
  23. class PagureRebaseBasetests(tests.Modeltests):
  24. """ Tests rebasing pull-request in pagure """
  25. maxDiff = None
  26. config_values = {"authbackend": "pagure"}
  27. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  28. def setUp(self):
  29. """ Set up the environnment, ran before every tests. """
  30. super(PagureRebaseBasetests, self).setUp()
  31. pagure.config.config["REQUESTS_FOLDER"] = None
  32. tests.create_projects(self.session)
  33. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  34. tests.create_projects_git(
  35. os.path.join(self.path, "requests"), bare=True
  36. )
  37. tests.add_content_to_git(
  38. os.path.join(self.path, "repos", "test.git"),
  39. branch="master",
  40. content="foobarbaz",
  41. filename="testfile",
  42. )
  43. project = pagure.lib.query.get_authorized_project(self.session, "test")
  44. # Fork the project
  45. task = pagure.lib.query.fork_project(
  46. session=self.session, user="foo", repo=project
  47. )
  48. self.session.commit()
  49. self.assertEqual(
  50. task.get(),
  51. {
  52. "endpoint": "ui_ns.view_repo",
  53. "repo": "test",
  54. "username": "foo",
  55. "namespace": None,
  56. },
  57. )
  58. tests.add_content_to_git(
  59. os.path.join(self.path, "repos", "forks", "foo", "test.git"),
  60. branch="test",
  61. content="foobar",
  62. filename="sources",
  63. )
  64. fork_repo = pagure.lib.query.get_authorized_project(
  65. self.session, "test", user="foo"
  66. )
  67. tests.add_readme_git_repo(os.path.join(self.path, "repos", "test.git"))
  68. # Create a PR for these changes
  69. req = pagure.lib.query.new_pull_request(
  70. session=self.session,
  71. repo_from=fork_repo,
  72. branch_from="test",
  73. repo_to=project,
  74. branch_to="master",
  75. title="PR from the test branch",
  76. user="foo",
  77. allow_rebase=True,
  78. )
  79. self.session.commit()
  80. self.assertEqual(req.id, 1)
  81. self.assertEqual(req.title, "PR from the test branch")
  82. self.project = pagure.lib.query.get_authorized_project(
  83. self.session, "test"
  84. )
  85. self.assertEqual(len(project.requests), 1)
  86. self.request = self.project.requests[0]
  87. class PagureRebasetests(PagureRebaseBasetests):
  88. """ Tests rebasing pull-request in pagure """
  89. def test_merge_status_merge(self):
  90. """ Test that the PR can be merged with a merge commit. """
  91. user = tests.FakeUser(username="pingou")
  92. with tests.user_set(self.app.application, user):
  93. data = {
  94. "requestid": self.request.uid,
  95. "csrf_token": self.get_csrf(),
  96. }
  97. output = self.app.post("/pv/pull-request/merge", data=data)
  98. self.assertEqual(output.status_code, 200)
  99. data = json.loads(output.get_data(as_text=True))
  100. self.assertEqual(
  101. data,
  102. {
  103. "code": "MERGE",
  104. "message": "The pull-request can be merged with a "
  105. "merge commit",
  106. "short_code": "With merge",
  107. },
  108. )
  109. def test_merge_status_needsrebase(self):
  110. """Test that the PR is marked as needing a rebase if the project
  111. disables non-fast-forward merges."""
  112. self.project = pagure.lib.query.get_authorized_project(
  113. self.session, "test"
  114. )
  115. settings = self.project.settings
  116. settings["disable_non_fast-forward_merges"] = True
  117. self.project.settings = settings
  118. self.session.add(self.project)
  119. self.session.commit()
  120. user = tests.FakeUser(username="pingou")
  121. with tests.user_set(self.app.application, user):
  122. data = {
  123. "requestid": self.request.uid,
  124. "csrf_token": self.get_csrf(),
  125. }
  126. output = self.app.post("/pv/pull-request/merge", data=data)
  127. self.assertEqual(output.status_code, 200)
  128. data = json.loads(output.get_data(as_text=True))
  129. self.assertEqual(
  130. data,
  131. {
  132. "code": "NEEDSREBASE",
  133. "message": "The pull-request must be rebased before "
  134. "merging",
  135. "short_code": "Needs rebase",
  136. },
  137. )
  138. def test_rebase_task(self):
  139. """ Test the rebase PR task and its outcome. """
  140. pagure.lib.tasks.rebase_pull_request(
  141. "test",
  142. namespace=None,
  143. user=None,
  144. requestid=self.request.id,
  145. user_rebaser="pingou",
  146. )
  147. user = tests.FakeUser(username="pingou")
  148. with tests.user_set(self.app.application, user):
  149. data = {
  150. "requestid": self.request.uid,
  151. "csrf_token": self.get_csrf(),
  152. }
  153. output = self.app.post("/pv/pull-request/merge", data=data)
  154. self.assertEqual(output.status_code, 200)
  155. data = json.loads(output.get_data(as_text=True))
  156. self.assertEqual(
  157. data,
  158. {
  159. "code": "FFORWARD",
  160. "message": "The pull-request can be merged and "
  161. "fast-forwarded",
  162. "short_code": "Ok",
  163. },
  164. )
  165. def test_rebase_api_ui_logged_in_different_user(self):
  166. """Test the rebase PR API endpoint when logged in from the UI and
  167. its outcome."""
  168. # Add 'bar' to the project 'test' so 'bar' can rebase the PR
  169. item = pagure.lib.model.User(
  170. user="bar",
  171. fullname="bar foo",
  172. password=b"foo",
  173. default_email="bar@foo.com",
  174. )
  175. self.session.add(item)
  176. item = pagure.lib.model.UserEmail(user_id=2, email="bar@foo.com")
  177. self.session.add(item)
  178. self.session.commit()
  179. repo = pagure.lib.query._get_project(self.session, "test")
  180. msg = pagure.lib.query.add_user_to_project(
  181. session=self.session, project=repo, new_user="bar", user="pingou"
  182. )
  183. self.session.commit()
  184. self.assertEqual(msg, "User added")
  185. user = tests.FakeUser(username="bar")
  186. with tests.user_set(self.app.application, user):
  187. # Get the merge status first so it's cached and can be refreshed
  188. csrf_token = self.get_csrf()
  189. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  190. output = self.app.post("/pv/pull-request/merge", data=data)
  191. self.assertEqual(output.status_code, 200)
  192. data = json.loads(output.get_data(as_text=True))
  193. self.assertEqual(
  194. data,
  195. {
  196. "code": "MERGE",
  197. "message": "The pull-request can be merged with "
  198. "a merge commit",
  199. "short_code": "With merge",
  200. },
  201. )
  202. output = self.app.post("/api/0/test/pull-request/1/rebase")
  203. self.assertEqual(output.status_code, 200)
  204. data = json.loads(output.get_data(as_text=True))
  205. self.assertEqual(data, {"message": "Pull-request rebased"})
  206. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  207. output = self.app.post("/pv/pull-request/merge", data=data)
  208. self.assertEqual(output.status_code, 200)
  209. data = json.loads(output.get_data(as_text=True))
  210. self.assertEqual(
  211. data,
  212. {
  213. "code": "FFORWARD",
  214. "message": "The pull-request can be merged and "
  215. "fast-forwarded",
  216. "short_code": "Ok",
  217. },
  218. )
  219. output = self.app.get("/test/pull-request/1")
  220. self.assertEqual(output.status_code, 200)
  221. output_text = output.get_data(as_text=True)
  222. self.assertIn("rebased onto", output_text)
  223. repo = pagure.lib.query._get_project(self.session, "test")
  224. self.assertEqual(repo.requests[0].comments[0].user.username, "bar")
  225. def test_rebase_api_ui_logged_in_pull_request_author(self):
  226. """Test the rebase PR API endpoint when logged in from the UI and
  227. its outcome."""
  228. user = tests.FakeUser(username="foo")
  229. with tests.user_set(self.app.application, user):
  230. # Get the merge status first so it's cached and can be refreshed
  231. csrf_token = self.get_csrf()
  232. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  233. output = self.app.post("/pv/pull-request/merge", data=data)
  234. self.assertEqual(output.status_code, 200)
  235. data = json.loads(output.get_data(as_text=True))
  236. self.assertEqual(
  237. data,
  238. {
  239. "code": "MERGE",
  240. "message": "The pull-request can be merged with "
  241. "a merge commit",
  242. "short_code": "With merge",
  243. },
  244. )
  245. output = self.app.post("/api/0/test/pull-request/1/rebase")
  246. self.assertEqual(output.status_code, 200)
  247. data = json.loads(output.get_data(as_text=True))
  248. self.assertEqual(data, {"message": "Pull-request rebased"})
  249. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  250. output = self.app.post("/pv/pull-request/merge", data=data)
  251. self.assertEqual(output.status_code, 200)
  252. data = json.loads(output.get_data(as_text=True))
  253. self.assertEqual(
  254. data,
  255. {
  256. "code": "FFORWARD",
  257. "message": "The pull-request can be merged and "
  258. "fast-forwarded",
  259. "short_code": "Ok",
  260. },
  261. )
  262. output = self.app.get("/test/pull-request/1")
  263. self.assertEqual(output.status_code, 200)
  264. output_text = output.get_data(as_text=True)
  265. self.assertIn("rebased onto", output_text)
  266. repo = pagure.lib.query._get_project(self.session, "test")
  267. self.assertEqual(repo.requests[0].comments[0].user.username, "foo")
  268. def test_rebase_api_api_logged_in(self):
  269. """Test the rebase PR API endpoint when using an API token and
  270. its outcome."""
  271. tests.create_tokens(self.session)
  272. tests.create_tokens_acl(self.session)
  273. headers = {"Authorization": "token aaabbbcccddd"}
  274. output = self.app.post(
  275. "/api/0/test/pull-request/1/rebase", headers=headers
  276. )
  277. self.assertEqual(output.status_code, 200)
  278. data = json.loads(output.get_data(as_text=True))
  279. self.assertEqual(data, {"message": "Pull-request rebased"})
  280. user = tests.FakeUser(username="pingou")
  281. with tests.user_set(self.app.application, user):
  282. data = {
  283. "requestid": self.request.uid,
  284. "csrf_token": self.get_csrf(),
  285. }
  286. output = self.app.post("/pv/pull-request/merge", data=data)
  287. self.assertEqual(output.status_code, 200)
  288. data = json.loads(output.get_data(as_text=True))
  289. self.assertEqual(
  290. data,
  291. {
  292. "code": "FFORWARD",
  293. "message": "The pull-request can be merged and "
  294. "fast-forwarded",
  295. "short_code": "Ok",
  296. },
  297. )
  298. def test_rebase_api_conflicts(self):
  299. """Test the rebase PR API endpoint when logged in from the UI and
  300. its outcome."""
  301. tests.add_content_to_git(
  302. os.path.join(self.path, "repos", "test.git"),
  303. branch="master",
  304. content="foobar baz",
  305. )
  306. user = tests.FakeUser(username="pingou")
  307. with tests.user_set(self.app.application, user):
  308. output = self.app.post("/api/0/test/pull-request/1/rebase")
  309. self.assertEqual(output.status_code, 400)
  310. data = json.loads(output.get_data(as_text=True))
  311. self.assertEqual(
  312. data,
  313. {
  314. "error": "Did not manage to rebase this pull-request",
  315. "error_code": "ENOCODE",
  316. },
  317. )
  318. data = {
  319. "requestid": self.request.uid,
  320. "csrf_token": self.get_csrf(),
  321. }
  322. output = self.app.post("/pv/pull-request/merge", data=data)
  323. self.assertEqual(output.status_code, 200)
  324. data = json.loads(output.get_data(as_text=True))
  325. self.assertEqual(
  326. data,
  327. {
  328. "code": "CONFLICTS",
  329. "message": "The pull-request cannot be merged due "
  330. "to conflicts",
  331. "short_code": "Conflicts",
  332. },
  333. )
  334. def test_rebase_api_api_logged_in_unknown_project(self):
  335. """ Test the rebase PR API endpoint when the project doesn't exist """
  336. tests.create_tokens(self.session)
  337. tests.create_tokens_acl(self.session)
  338. headers = {"Authorization": "token aaabbbcccddd"}
  339. output = self.app.post(
  340. "/api/0/unknown/pull-request/1/rebase", headers=headers
  341. )
  342. self.assertEqual(output.status_code, 404)
  343. data = json.loads(output.get_data(as_text=True))
  344. self.assertEqual(
  345. data, {"error": "Project not found", "error_code": "ENOPROJECT"}
  346. )
  347. def test_rebase_api_api_logged_in_unknown_pr(self):
  348. """ Test the rebase PR API endpoint when the PR doesn't exist """
  349. tests.create_tokens(self.session)
  350. tests.create_tokens_acl(self.session)
  351. headers = {"Authorization": "token aaabbbcccddd"}
  352. output = self.app.post(
  353. "/api/0/test/pull-request/404/rebase", headers=headers
  354. )
  355. self.assertEqual(output.status_code, 404)
  356. data = json.loads(output.get_data(as_text=True))
  357. self.assertEqual(
  358. data, {"error": "Pull-Request not found", "error_code": "ENOREQ"}
  359. )
  360. def test_rebase_api_api_logged_in_unknown_token(self):
  361. """ Test the rebase PR API endpoint with an invalid API token """
  362. tests.create_tokens(self.session)
  363. tests.create_tokens_acl(self.session)
  364. headers = {"Authorization": "token unknown"}
  365. output = self.app.post(
  366. "/api/0/test/pull-request/1/rebase", headers=headers
  367. )
  368. self.assertEqual(output.status_code, 401)
  369. data = json.loads(output.get_data(as_text=True))
  370. self.assertEqual(
  371. data,
  372. {
  373. "error": "Invalid or expired token. Please visit "
  374. "http://localhost.localdomain/settings#nav-api-tab to get "
  375. "or renew your API token.",
  376. "error_code": "EINVALIDTOK",
  377. "errors": "Invalid token",
  378. },
  379. )
  380. class PagureRebaseNoHooktests(PagureRebaseBasetests):
  381. """ Tests rebasing pull-request in pagure """
  382. config_values = {"authbackend": "pagure", "nogithooks": True}
  383. @patch.dict(
  384. "pagure.config.config",
  385. {
  386. "FEDORA_MESSAGING_NOTIFICATIONS": True,
  387. },
  388. )
  389. def test_rebase_api_ui_logged_in(self):
  390. """Test the rebase PR API endpoint when logged in from the UI and
  391. its outcome."""
  392. user = tests.FakeUser(username="pingou")
  393. with tests.user_set(self.app.application, user):
  394. # Get the merge status first so it's cached and can be refreshed
  395. csrf_token = self.get_csrf()
  396. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  397. output = self.app.post("/pv/pull-request/merge", data=data)
  398. self.assertEqual(output.status_code, 200)
  399. data = json.loads(output.get_data(as_text=True))
  400. self.assertEqual(
  401. data,
  402. {
  403. "code": "MERGE",
  404. "message": "The pull-request can be merged with "
  405. "a merge commit",
  406. "short_code": "With merge",
  407. },
  408. )
  409. with testing.mock_sends(
  410. pagure_messages.PullRequestRebasedV1(
  411. topic="pagure.pull-request.rebased",
  412. body={
  413. "pullrequest": {
  414. "id": 1,
  415. "uid": ANY,
  416. "title": "PR from the test branch",
  417. "full_url": "http://localhost.localdomain/test/pull-request/1",
  418. "branch": "master",
  419. "project": {
  420. "id": 1,
  421. "name": "test",
  422. "fullname": "test",
  423. "url_path": "test",
  424. "full_url": "http://localhost.localdomain/test",
  425. "description": "test project #1",
  426. "namespace": None,
  427. "parent": None,
  428. "date_created": ANY,
  429. "date_modified": ANY,
  430. "user": {
  431. "name": "pingou",
  432. "fullname": "PY C",
  433. "url_path": "user/pingou",
  434. "full_url": "http://localhost.localdomain/user/pingou",
  435. },
  436. "access_users": {
  437. "owner": ["pingou"],
  438. "admin": [],
  439. "commit": [],
  440. "collaborator": [],
  441. "ticket": [],
  442. },
  443. "access_groups": {
  444. "admin": [],
  445. "commit": [],
  446. "collaborator": [],
  447. "ticket": [],
  448. },
  449. "tags": [],
  450. "priorities": {},
  451. "custom_keys": [],
  452. "close_status": [
  453. "Invalid",
  454. "Insufficient data",
  455. "Fixed",
  456. "Duplicate",
  457. ],
  458. "milestones": {},
  459. },
  460. "branch_from": "test",
  461. "repo_from": {
  462. "id": 4,
  463. "name": "test",
  464. "fullname": "forks/foo/test",
  465. "url_path": "fork/foo/test",
  466. "full_url": "http://localhost.localdomain/fork/foo/test",
  467. "description": "test project #1",
  468. "namespace": None,
  469. "parent": {
  470. "id": 1,
  471. "name": "test",
  472. "fullname": "test",
  473. "url_path": "test",
  474. "full_url": "http://localhost.localdomain/test",
  475. "description": "test project #1",
  476. "namespace": None,
  477. "parent": None,
  478. "date_created": ANY,
  479. "date_modified": ANY,
  480. "user": {
  481. "name": "pingou",
  482. "fullname": "PY C",
  483. "url_path": "user/pingou",
  484. "full_url": "http://localhost.localdomain/user/pingou",
  485. },
  486. "access_users": {
  487. "owner": ["pingou"],
  488. "admin": [],
  489. "commit": [],
  490. "collaborator": [],
  491. "ticket": [],
  492. },
  493. "access_groups": {
  494. "admin": [],
  495. "commit": [],
  496. "collaborator": [],
  497. "ticket": [],
  498. },
  499. "tags": [],
  500. "priorities": {},
  501. "custom_keys": [],
  502. "close_status": [
  503. "Invalid",
  504. "Insufficient data",
  505. "Fixed",
  506. "Duplicate",
  507. ],
  508. "milestones": {},
  509. },
  510. "date_created": ANY,
  511. "date_modified": ANY,
  512. "user": {
  513. "name": "foo",
  514. "fullname": "foo bar",
  515. "url_path": "user/foo",
  516. "full_url": "http://localhost.localdomain/user/foo",
  517. },
  518. "access_users": {
  519. "owner": ["foo"],
  520. "admin": [],
  521. "commit": [],
  522. "collaborator": [],
  523. "ticket": [],
  524. },
  525. "access_groups": {
  526. "admin": [],
  527. "commit": [],
  528. "collaborator": [],
  529. "ticket": [],
  530. },
  531. "tags": [],
  532. "priorities": {},
  533. "custom_keys": [],
  534. "close_status": [],
  535. "milestones": {},
  536. },
  537. "remote_git": None,
  538. "date_created": ANY,
  539. "updated_on": ANY,
  540. "last_updated": ANY,
  541. "closed_at": None,
  542. "user": {
  543. "name": "foo",
  544. "fullname": "foo bar",
  545. "url_path": "user/foo",
  546. "full_url": "http://localhost.localdomain/user/foo",
  547. },
  548. "assignee": None,
  549. "status": "Open",
  550. "commit_start": ANY,
  551. "commit_stop": ANY,
  552. "closed_by": None,
  553. "initial_comment": None,
  554. "cached_merge_status": "unknown",
  555. "threshold_reached": None,
  556. "tags": [],
  557. "comments": [],
  558. },
  559. "agent": "pagure",
  560. },
  561. ),
  562. pagure_messages.PullRequestCommentAddedV1(
  563. topic="pagure.pull-request.comment.added",
  564. body={
  565. "pullrequest": {
  566. "id": 1,
  567. "uid": ANY,
  568. "title": "PR from the test branch",
  569. "full_url": "http://localhost.localdomain/test/pull-request/1",
  570. "branch": "master",
  571. "project": {
  572. "id": 1,
  573. "name": "test",
  574. "fullname": "test",
  575. "url_path": "test",
  576. "full_url": "http://localhost.localdomain/test",
  577. "description": "test project #1",
  578. "namespace": None,
  579. "parent": None,
  580. "date_created": ANY,
  581. "date_modified": ANY,
  582. "user": {
  583. "name": "pingou",
  584. "fullname": "PY C",
  585. "url_path": "user/pingou",
  586. "full_url": "http://localhost.localdomain/user/pingou",
  587. },
  588. "access_users": {
  589. "owner": ["pingou"],
  590. "admin": [],
  591. "commit": [],
  592. "collaborator": [],
  593. "ticket": [],
  594. },
  595. "access_groups": {
  596. "admin": [],
  597. "commit": [],
  598. "collaborator": [],
  599. "ticket": [],
  600. },
  601. "tags": [],
  602. "priorities": {},
  603. "custom_keys": [],
  604. "close_status": [
  605. "Invalid",
  606. "Insufficient data",
  607. "Fixed",
  608. "Duplicate",
  609. ],
  610. "milestones": {},
  611. },
  612. "branch_from": "test",
  613. "repo_from": {
  614. "id": 4,
  615. "name": "test",
  616. "fullname": "forks/foo/test",
  617. "url_path": "fork/foo/test",
  618. "full_url": "http://localhost.localdomain/fork/foo/test",
  619. "description": "test project #1",
  620. "namespace": None,
  621. "parent": {
  622. "id": 1,
  623. "name": "test",
  624. "fullname": "test",
  625. "url_path": "test",
  626. "full_url": "http://localhost.localdomain/test",
  627. "description": "test project #1",
  628. "namespace": None,
  629. "parent": None,
  630. "date_created": ANY,
  631. "date_modified": ANY,
  632. "user": {
  633. "name": "pingou",
  634. "fullname": "PY C",
  635. "url_path": "user/pingou",
  636. "full_url": "http://localhost.localdomain/user/pingou",
  637. },
  638. "access_users": {
  639. "owner": ["pingou"],
  640. "admin": [],
  641. "commit": [],
  642. "collaborator": [],
  643. "ticket": [],
  644. },
  645. "access_groups": {
  646. "admin": [],
  647. "commit": [],
  648. "collaborator": [],
  649. "ticket": [],
  650. },
  651. "tags": [],
  652. "priorities": {},
  653. "custom_keys": [],
  654. "close_status": [
  655. "Invalid",
  656. "Insufficient data",
  657. "Fixed",
  658. "Duplicate",
  659. ],
  660. "milestones": {},
  661. },
  662. "date_created": ANY,
  663. "date_modified": ANY,
  664. "user": {
  665. "name": "foo",
  666. "fullname": "foo bar",
  667. "url_path": "user/foo",
  668. "full_url": "http://localhost.localdomain/user/foo",
  669. },
  670. "access_users": {
  671. "owner": ["foo"],
  672. "admin": [],
  673. "commit": [],
  674. "collaborator": [],
  675. "ticket": [],
  676. },
  677. "access_groups": {
  678. "admin": [],
  679. "commit": [],
  680. "collaborator": [],
  681. "ticket": [],
  682. },
  683. "tags": [],
  684. "priorities": {},
  685. "custom_keys": [],
  686. "close_status": [],
  687. "milestones": {},
  688. },
  689. "remote_git": None,
  690. "date_created": ANY,
  691. "updated_on": ANY,
  692. "last_updated": ANY,
  693. "closed_at": None,
  694. "user": {
  695. "name": "foo",
  696. "fullname": "foo bar",
  697. "url_path": "user/foo",
  698. "full_url": "http://localhost.localdomain/user/foo",
  699. },
  700. "assignee": None,
  701. "status": "Open",
  702. "commit_start": ANY,
  703. "commit_stop": ANY,
  704. "closed_by": None,
  705. "initial_comment": None,
  706. "cached_merge_status": "unknown",
  707. "threshold_reached": None,
  708. "tags": [],
  709. "comments": [
  710. {
  711. "id": 1,
  712. "commit": None,
  713. "tree": None,
  714. "filename": None,
  715. "line": None,
  716. "comment": ANY,
  717. "parent": None,
  718. "date_created": ANY,
  719. "user": {
  720. "name": "pingou",
  721. "fullname": "PY C",
  722. "url_path": "user/pingou",
  723. "full_url": "http://localhost.localdomain/user/pingou",
  724. },
  725. "edited_on": None,
  726. "editor": None,
  727. "notification": True,
  728. "reactions": {},
  729. }
  730. ],
  731. },
  732. "agent": "pingou",
  733. },
  734. ),
  735. ):
  736. output = self.app.post("/api/0/test/pull-request/1/rebase")
  737. self.assertEqual(output.status_code, 200)
  738. data = json.loads(output.get_data(as_text=True))
  739. self.assertEqual(data, {"message": "Pull-request rebased"})
  740. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  741. output = self.app.post("/pv/pull-request/merge", data=data)
  742. self.assertEqual(output.status_code, 200)
  743. data = json.loads(output.get_data(as_text=True))
  744. self.assertEqual(
  745. data,
  746. {
  747. "code": "FFORWARD",
  748. "message": "The pull-request can be merged and "
  749. "fast-forwarded",
  750. "short_code": "Ok",
  751. },
  752. )
  753. output = self.app.get("/test/pull-request/1")
  754. self.assertEqual(output.status_code, 200)
  755. output_text = output.get_data(as_text=True)
  756. self.assertIn("rebased onto", output_text)
  757. repo = pagure.lib.query._get_project(self.session, "test")
  758. self.assertEqual(
  759. repo.requests[0].comments[0].user.username, "pingou"
  760. )
  761. class PagureRebaseNotAllowedtests(tests.Modeltests):
  762. """ Tests rebasing pull-request in pagure """
  763. maxDiff = None
  764. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  765. def setUp(self):
  766. """ Set up the environnment, ran before every tests. """
  767. super(PagureRebaseNotAllowedtests, self).setUp()
  768. pagure.config.config["REQUESTS_FOLDER"] = None
  769. tests.create_projects(self.session)
  770. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  771. tests.create_projects_git(
  772. os.path.join(self.path, "requests"), bare=True
  773. )
  774. tests.add_content_to_git(
  775. os.path.join(self.path, "repos", "test.git"),
  776. branch="master",
  777. content="foobarbaz",
  778. filename="testfile",
  779. )
  780. project = pagure.lib.query.get_authorized_project(self.session, "test")
  781. # Fork the project
  782. task = pagure.lib.query.fork_project(
  783. session=self.session, user="foo", repo=project
  784. )
  785. self.session.commit()
  786. self.assertEqual(
  787. task.get(),
  788. {
  789. "endpoint": "ui_ns.view_repo",
  790. "repo": "test",
  791. "username": "foo",
  792. "namespace": None,
  793. },
  794. )
  795. tests.add_content_to_git(
  796. os.path.join(self.path, "repos", "forks", "foo", "test.git"),
  797. branch="test",
  798. content="foobar",
  799. filename="sources",
  800. )
  801. fork_repo = pagure.lib.query.get_authorized_project(
  802. self.session, "test", user="foo"
  803. )
  804. tests.add_readme_git_repo(os.path.join(self.path, "repos", "test.git"))
  805. # Create a PR for these changes
  806. project = pagure.lib.query.get_authorized_project(self.session, "test")
  807. req = pagure.lib.query.new_pull_request(
  808. session=self.session,
  809. repo_from=fork_repo,
  810. branch_from="test",
  811. repo_to=project,
  812. branch_to="master",
  813. title="PR from the test branch",
  814. user="foo",
  815. allow_rebase=False,
  816. )
  817. self.session.commit()
  818. self.assertEqual(req.id, 1)
  819. self.assertEqual(req.title, "PR from the test branch")
  820. self.project = pagure.lib.query.get_authorized_project(
  821. self.session, "test"
  822. )
  823. self.assertEqual(len(project.requests), 1)
  824. self.request = self.project.requests[0]
  825. def test_rebase_api_ui_logged_in(self):
  826. """Test the rebase PR API endpoint when logged in from the UI and
  827. its outcome."""
  828. user = tests.FakeUser(username="pingou")
  829. with tests.user_set(self.app.application, user):
  830. # Get the merge status first so it's cached and can be refreshed
  831. csrf_token = self.get_csrf()
  832. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  833. output = self.app.post("/pv/pull-request/merge", data=data)
  834. self.assertEqual(output.status_code, 200)
  835. data = json.loads(output.get_data(as_text=True))
  836. self.assertEqual(
  837. data,
  838. {
  839. "code": "MERGE",
  840. "message": "The pull-request can be merged with "
  841. "a merge commit",
  842. "short_code": "With merge",
  843. },
  844. )
  845. output = self.app.post("/api/0/test/pull-request/1/rebase")
  846. self.assertEqual(output.status_code, 403)
  847. data = json.loads(output.get_data(as_text=True))
  848. self.assertEqual(
  849. data,
  850. {
  851. "error": "You are not authorized to rebase this pull-request",
  852. "error_code": "EREBASENOTALLOWED",
  853. },
  854. )
  855. # Add pingou to fork repo so he can rebase while allow_rebase = False
  856. fork = pagure.lib.query.get_authorized_project(
  857. self.session, "test", user="foo"
  858. )
  859. msg = pagure.lib.query.add_user_to_project(
  860. session=self.session,
  861. project=fork,
  862. new_user="pingou",
  863. user="foo",
  864. )
  865. self.session.commit()
  866. self.assertEqual(msg, "User added")
  867. output = self.app.post("/api/0/test/pull-request/1/rebase")
  868. self.assertEqual(output.status_code, 200)
  869. data = json.loads(output.get_data(as_text=True))
  870. self.assertEqual(data, {"message": "Pull-request rebased"})
  871. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  872. output = self.app.post("/pv/pull-request/merge", data=data)
  873. self.assertEqual(output.status_code, 200)
  874. data = json.loads(output.get_data(as_text=True))
  875. self.assertEqual(
  876. data,
  877. {
  878. "code": "FFORWARD",
  879. "message": "The pull-request can be merged and "
  880. "fast-forwarded",
  881. "short_code": "Ok",
  882. },
  883. )
  884. output = self.app.get("/test/pull-request/1")
  885. self.assertEqual(output.status_code, 200)
  886. output_text = output.get_data(as_text=True)
  887. self.assertIn("rebased onto", output_text)
  888. repo = pagure.lib.query._get_project(self.session, "test")
  889. self.assertEqual(
  890. repo.requests[0].comments[0].user.username, "pingou"
  891. )
  892. def test_rebase_api_ui_logged_in_different_user(self):
  893. """Test the rebase PR API endpoint when logged in from the UI and
  894. its outcome."""
  895. # Add 'bar' to the project 'test' so 'bar' can rebase the PR
  896. item = pagure.lib.model.User(
  897. user="bar",
  898. fullname="bar foo",
  899. password=b"foo",
  900. default_email="bar@foo.com",
  901. )
  902. self.session.add(item)
  903. item = pagure.lib.model.UserEmail(user_id=2, email="bar@foo.com")
  904. self.session.add(item)
  905. self.session.commit()
  906. repo = pagure.lib.query._get_project(self.session, "test")
  907. msg = pagure.lib.query.add_user_to_project(
  908. session=self.session, project=repo, new_user="bar", user="pingou"
  909. )
  910. self.session.commit()
  911. self.assertEqual(msg, "User added")
  912. user = tests.FakeUser(username="bar")
  913. with tests.user_set(self.app.application, user):
  914. # Get the merge status first so it's cached and can be refreshed
  915. csrf_token = self.get_csrf()
  916. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  917. output = self.app.post("/pv/pull-request/merge", data=data)
  918. self.assertEqual(output.status_code, 200)
  919. data = json.loads(output.get_data(as_text=True))
  920. self.assertEqual(
  921. data,
  922. {
  923. "code": "MERGE",
  924. "message": "The pull-request can be merged with "
  925. "a merge commit",
  926. "short_code": "With merge",
  927. },
  928. )
  929. output = self.app.post("/api/0/test/pull-request/1/rebase")
  930. self.assertEqual(output.status_code, 403)
  931. data = json.loads(output.get_data(as_text=True))
  932. self.assertEqual(
  933. data,
  934. {
  935. "error": "You are not authorized to rebase this pull-request",
  936. "error_code": "EREBASENOTALLOWED",
  937. },
  938. )
  939. # Add bar to fork repo so he can rebase while allow_rebase = False
  940. fork = pagure.lib.query.get_authorized_project(
  941. self.session, "test", user="foo"
  942. )
  943. msg = pagure.lib.query.add_user_to_project(
  944. session=self.session, project=fork, new_user="bar", user="foo"
  945. )
  946. self.session.commit()
  947. self.assertEqual(msg, "User added")
  948. output = self.app.post("/api/0/test/pull-request/1/rebase")
  949. self.assertEqual(output.status_code, 200)
  950. data = json.loads(output.get_data(as_text=True))
  951. self.assertEqual(data, {"message": "Pull-request rebased"})
  952. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  953. output = self.app.post("/pv/pull-request/merge", data=data)
  954. self.assertEqual(output.status_code, 200)
  955. data = json.loads(output.get_data(as_text=True))
  956. self.assertEqual(
  957. data,
  958. {
  959. "code": "FFORWARD",
  960. "message": "The pull-request can be merged and "
  961. "fast-forwarded",
  962. "short_code": "Ok",
  963. },
  964. )
  965. output = self.app.get("/test/pull-request/1")
  966. self.assertEqual(output.status_code, 200)
  967. output_text = output.get_data(as_text=True)
  968. self.assertIn("rebased onto", output_text)
  969. repo = pagure.lib.query._get_project(self.session, "test")
  970. self.assertEqual(repo.requests[0].comments[0].user.username, "bar")
  971. def test_rebase_api_api_logged_in(self):
  972. """Test the rebase PR API endpoint when using an API token and
  973. its outcome."""
  974. tests.create_tokens(self.session)
  975. tests.create_tokens_acl(self.session)
  976. headers = {"Authorization": "token aaabbbcccddd"}
  977. output = self.app.post(
  978. "/api/0/test/pull-request/1/rebase", headers=headers
  979. )
  980. self.assertEqual(output.status_code, 403)
  981. data = json.loads(output.get_data(as_text=True))
  982. self.assertEqual(
  983. data,
  984. {
  985. "error": "You are not authorized to rebase this pull-request",
  986. "error_code": "EREBASENOTALLOWED",
  987. },
  988. )
  989. # Add pingou to fork repo so he can rebase while allow_rebase = False
  990. fork = pagure.lib.query.get_authorized_project(
  991. self.session, "test", user="foo"
  992. )
  993. msg = pagure.lib.query.add_user_to_project(
  994. session=self.session, project=fork, new_user="pingou", user="foo"
  995. )
  996. self.session.commit()
  997. self.assertEqual(msg, "User added")
  998. output = self.app.post(
  999. "/api/0/test/pull-request/1/rebase", headers=headers
  1000. )
  1001. self.assertEqual(output.status_code, 200)
  1002. data = json.loads(output.get_data(as_text=True))
  1003. self.assertEqual(data, {"message": "Pull-request rebased"})
  1004. user = tests.FakeUser(username="pingou")
  1005. with tests.user_set(self.app.application, user):
  1006. data = {
  1007. "requestid": self.request.uid,
  1008. "csrf_token": self.get_csrf(),
  1009. }
  1010. output = self.app.post("/pv/pull-request/merge", data=data)
  1011. self.assertEqual(output.status_code, 200)
  1012. data = json.loads(output.get_data(as_text=True))
  1013. self.assertEqual(
  1014. data,
  1015. {
  1016. "code": "FFORWARD",
  1017. "message": "The pull-request can be merged and "
  1018. "fast-forwarded",
  1019. "short_code": "Ok",
  1020. },
  1021. )
  1022. def test_rebase_api_ui_logged_in_pull_request_author(self):
  1023. """Test the rebase PR API endpoint when logged in from the UI and
  1024. its outcome."""
  1025. user = tests.FakeUser(username="foo")
  1026. with tests.user_set(self.app.application, user):
  1027. # Get the merge status first so it's cached and can be refreshed
  1028. csrf_token = self.get_csrf()
  1029. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  1030. output = self.app.post("/pv/pull-request/merge", data=data)
  1031. self.assertEqual(output.status_code, 200)
  1032. data = json.loads(output.get_data(as_text=True))
  1033. self.assertEqual(
  1034. data,
  1035. {
  1036. "code": "MERGE",
  1037. "message": "The pull-request can be merged with "
  1038. "a merge commit",
  1039. "short_code": "With merge",
  1040. },
  1041. )
  1042. output = self.app.post("/api/0/test/pull-request/1/rebase")
  1043. self.assertEqual(output.status_code, 200)
  1044. data = json.loads(output.get_data(as_text=True))
  1045. self.assertEqual(data, {"message": "Pull-request rebased"})
  1046. data = {"requestid": self.request.uid, "csrf_token": csrf_token}
  1047. output = self.app.post("/pv/pull-request/merge", data=data)
  1048. self.assertEqual(output.status_code, 200)
  1049. data = json.loads(output.get_data(as_text=True))
  1050. self.assertEqual(
  1051. data,
  1052. {
  1053. "code": "FFORWARD",
  1054. "message": "The pull-request can be merged and "
  1055. "fast-forwarded",
  1056. "short_code": "Ok",
  1057. },
  1058. )
  1059. output = self.app.get("/test/pull-request/1")
  1060. self.assertEqual(output.status_code, 200)
  1061. output_text = output.get_data(as_text=True)
  1062. self.assertIn("rebased onto", output_text)
  1063. repo = pagure.lib.query._get_project(self.session, "test")
  1064. self.assertEqual(repo.requests[0].comments[0].user.username, "foo")
  1065. if __name__ == "__main__":
  1066. unittest.main(verbosity=2)