1
0

test_pagure_flask_internal.py 109 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-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 datetime
  9. import json
  10. import unittest
  11. import shutil
  12. import sys
  13. import time
  14. import os
  15. import pygit2
  16. from mock import patch, MagicMock, Mock
  17. sys.path.insert(
  18. 0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
  19. )
  20. import pagure.lib.query
  21. import tests
  22. from pagure.lib.repo import PagureRepo
  23. class PagureFlaskInternaltests(tests.Modeltests):
  24. """ Tests for flask Internal controller of pagure """
  25. maxDiff = None
  26. def setUp(self):
  27. """ Set up the environnment, ran before every tests. """
  28. super(PagureFlaskInternaltests, self).setUp()
  29. pagure.config.config["IP_ALLOWED_INTERNAL"] = list(
  30. set(pagure.config.config["IP_ALLOWED_INTERNAL"] + [None])
  31. )
  32. pagure.config.config["GIT_FOLDER"] = os.path.join(self.path, "repos")
  33. @patch.dict("pagure.config.config", {"IP_ALLOWED_INTERNAL": []})
  34. def test_internal_access_only(self):
  35. output = self.app.post("/pv/ssh/lookupkey/")
  36. self.assertEqual(output.status_code, 403)
  37. # no internal IP addresses => will fail
  38. output = self.app.post("/pv/ssh/lookupkey/")
  39. self.assertEqual(output.status_code, 403)
  40. # wrong token => will fail
  41. output = self.app.post(
  42. "/pv/ssh/lookupkey/",
  43. headers={"Authorization": "token doesntexist"},
  44. )
  45. self.assertEqual(output.status_code, 401)
  46. # correct token => will work
  47. exp_date = datetime.date.today() + datetime.timedelta(days=300)
  48. pagure.lib.query.add_token_to_user(
  49. self.session, None, ["internal_access"], "pingou", exp_date
  50. )
  51. token = pagure.lib.query.search_token(
  52. self.session, acls=["internal_access"], user="pingou"
  53. )
  54. output = self.app.post(
  55. "/pv/ssh/lookupkey/",
  56. headers={"Authorization": "token %s" % token[0].id},
  57. )
  58. self.assertEqual(output.status_code, 400)
  59. @patch("pagure.lib.notify.send_email")
  60. def test_pull_request_add_comment(self, send_email):
  61. """ Test the pull_request_add_comment function. """
  62. send_email.return_value = True
  63. tests.create_projects(self.session)
  64. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  65. req = pagure.lib.query.new_pull_request(
  66. session=self.session,
  67. repo_from=repo,
  68. branch_from="feature",
  69. repo_to=repo,
  70. branch_to="master",
  71. title="PR from the feature branch",
  72. user="pingou",
  73. )
  74. self.session.commit()
  75. self.assertEqual(req.id, 1)
  76. self.assertEqual(req.title, "PR from the feature branch")
  77. request = repo.requests[0]
  78. self.assertEqual(len(request.comments), 0)
  79. self.assertEqual(len(request.discussion), 0)
  80. data = {"objid": "foo"}
  81. # Wrong http request
  82. output = self.app.post("/pv/pull-request/comment/", data=data)
  83. self.assertEqual(output.status_code, 405)
  84. # Invalid request
  85. output = self.app.put("/pv/pull-request/comment/", data=data)
  86. self.assertEqual(output.status_code, 400)
  87. data = {"objid": "foo", "useremail": "foo@pingou.com"}
  88. # Invalid objid
  89. output = self.app.put("/pv/pull-request/comment/", data=data)
  90. self.assertEqual(output.status_code, 404)
  91. data = {"objid": request.uid, "useremail": "foo@pingou.com"}
  92. # Valid objid, in-complete data for a comment
  93. output = self.app.put("/pv/pull-request/comment/", data=data)
  94. self.assertEqual(output.status_code, 400)
  95. data = {
  96. "objid": request.uid,
  97. "useremail": "foo@pingou.com",
  98. "comment": "Looks good to me!",
  99. }
  100. # Add comment
  101. output = self.app.put("/pv/pull-request/comment/", data=data)
  102. self.assertEqual(output.status_code, 200)
  103. js_data = json.loads(output.get_data(as_text=True))
  104. self.assertDictEqual(js_data, {"message": "Comment added"})
  105. self.session.commit()
  106. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  107. request = repo.requests[0]
  108. self.assertEqual(len(request.comments), 1)
  109. self.assertEqual(len(request.discussion), 1)
  110. # Check the @internal_access_only
  111. before = pagure.config.config["IP_ALLOWED_INTERNAL"][:]
  112. pagure.config.config["IP_ALLOWED_INTERNAL"] = []
  113. output = self.app.put("/pv/pull-request/comment/", data=data)
  114. self.assertEqual(output.status_code, 403)
  115. pagure.config.config["IP_ALLOWED_INTERNAL"] = before[:]
  116. @patch("pagure.lib.notify.send_email")
  117. def test_ticket_add_comment(self, send_email):
  118. """ Test the ticket_add_comment function. """
  119. send_email.return_value = True
  120. tests.create_projects(self.session)
  121. # Create issues to play with
  122. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  123. msg = pagure.lib.query.new_issue(
  124. session=self.session,
  125. repo=repo,
  126. title="Test issue",
  127. content="We should work on this",
  128. user="pingou",
  129. )
  130. self.session.commit()
  131. self.assertEqual(msg.title, "Test issue")
  132. issue = repo.issues[0]
  133. self.assertEqual(len(issue.comments), 0)
  134. data = {"objid": "foo"}
  135. # Wrong http request
  136. output = self.app.post("/pv/ticket/comment/", data=data)
  137. self.assertEqual(output.status_code, 405)
  138. # Invalid request
  139. output = self.app.put("/pv/ticket/comment/", data=data)
  140. self.assertEqual(output.status_code, 400)
  141. data = {"objid": "foo", "useremail": "foo@pingou.com"}
  142. # Invalid objid
  143. output = self.app.put("/pv/ticket/comment/", data=data)
  144. self.assertEqual(output.status_code, 404)
  145. data = {"objid": issue.uid, "useremail": "foo@pingou.com"}
  146. # Valid objid, in-complete data for a comment
  147. output = self.app.put("/pv/ticket/comment/", data=data)
  148. self.assertEqual(output.status_code, 400)
  149. data = {
  150. "objid": issue.uid,
  151. "useremail": "foo@pingou.com",
  152. "comment": "Looks good to me!",
  153. }
  154. # Add comment
  155. output = self.app.put("/pv/ticket/comment/", data=data)
  156. self.assertEqual(output.status_code, 200)
  157. js_data = json.loads(output.get_data(as_text=True))
  158. self.assertDictEqual(js_data, {"message": "Comment added"})
  159. self.session.commit()
  160. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  161. issue = repo.issues[0]
  162. self.assertEqual(len(issue.comments), 1)
  163. # Check the @internal_access_only
  164. pagure.config.config["IP_ALLOWED_INTERNAL"].remove(None)
  165. before = pagure.config.config["IP_ALLOWED_INTERNAL"][:]
  166. pagure.config.config["IP_ALLOWED_INTERNAL"] = []
  167. output = self.app.put("/pv/ticket/comment/", data=data)
  168. self.assertEqual(output.status_code, 403)
  169. pagure.config.config["IP_ALLOWED_INTERNAL"] = before[:]
  170. @patch("pagure.lib.notify.send_email")
  171. def test_private_ticket_add_comment(self, send_email):
  172. """ Test the ticket_add_comment function on a private ticket. """
  173. send_email.return_value = True
  174. tests.create_projects(self.session)
  175. # Create issues to play with
  176. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  177. msg = pagure.lib.query.new_issue(
  178. session=self.session,
  179. repo=repo,
  180. title="Test issue",
  181. content="We should work on this, really",
  182. user="pingou",
  183. private=True,
  184. )
  185. self.session.commit()
  186. self.assertEqual(msg.title, "Test issue")
  187. issue = repo.issues[0]
  188. self.assertEqual(len(issue.comments), 0)
  189. data = {"objid": "foo"}
  190. # Wrong http request
  191. output = self.app.post("/pv/ticket/comment/", data=data)
  192. self.assertEqual(output.status_code, 405)
  193. # Invalid request
  194. output = self.app.put("/pv/ticket/comment/", data=data)
  195. self.assertEqual(output.status_code, 400)
  196. data = {"objid": "foo", "useremail": "foo@pingou.com"}
  197. # Invalid objid
  198. output = self.app.put("/pv/ticket/comment/", data=data)
  199. self.assertEqual(output.status_code, 404)
  200. data = {"objid": issue.uid, "useremail": "foo@bar.com"}
  201. # Valid objid, un-allowed user for this (private) ticket
  202. output = self.app.put("/pv/ticket/comment/", data=data)
  203. self.assertEqual(output.status_code, 403)
  204. data = {"objid": issue.uid, "useremail": "foo@pingou.com"}
  205. # Valid objid, un-allowed user for this (private) ticket
  206. output = self.app.put("/pv/ticket/comment/", data=data)
  207. self.assertEqual(output.status_code, 400)
  208. data = {
  209. "objid": issue.uid,
  210. "useremail": "foo@pingou.com",
  211. "comment": "Looks good to me!",
  212. }
  213. # Add comment
  214. output = self.app.put("/pv/ticket/comment/", data=data)
  215. self.assertEqual(output.status_code, 200)
  216. js_data = json.loads(output.get_data(as_text=True))
  217. self.assertDictEqual(js_data, {"message": "Comment added"})
  218. self.session.commit()
  219. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  220. issue = repo.issues[0]
  221. self.assertEqual(len(issue.comments), 1)
  222. # Check the @internal_access_only
  223. before = pagure.config.config["IP_ALLOWED_INTERNAL"][:]
  224. pagure.config.config["IP_ALLOWED_INTERNAL"] = []
  225. output = self.app.put("/pv/ticket/comment/", data=data)
  226. self.assertEqual(output.status_code, 403)
  227. pagure.config.config["IP_ALLOWED_INTERNAL"] = before[:]
  228. @patch("pagure.lib.notify.send_email")
  229. def test_private_ticket_add_comment_acl(self, send_email):
  230. """ Test the ticket_add_comment function on a private ticket. """
  231. send_email.return_value = True
  232. tests.create_projects(self.session)
  233. # Create issues to play with
  234. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  235. msg = pagure.lib.query.new_issue(
  236. session=self.session,
  237. repo=repo,
  238. title="Test issue",
  239. content="We should work on this, really",
  240. user="pingou",
  241. private=True,
  242. )
  243. self.session.commit()
  244. self.assertEqual(msg.title, "Test issue")
  245. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  246. issue = repo.issues[0]
  247. self.assertEqual(len(issue.comments), 0)
  248. # Currently, he is just an average user,
  249. # He doesn't have any access in this repo
  250. data = {
  251. "objid": issue.uid,
  252. "useremail": "foo@bar.com",
  253. "comment": "Looks good to me!",
  254. }
  255. # Valid objid, un-allowed user for this (private) ticket
  256. output = self.app.put("/pv/ticket/comment/", data=data)
  257. self.assertEqual(output.status_code, 403)
  258. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  259. # Let's promote him to be a ticketer
  260. # He shoudn't be able to comment even then though
  261. msg = pagure.lib.query.add_user_to_project(
  262. self.session,
  263. project=repo,
  264. new_user="foo",
  265. user="pingou",
  266. access="ticket",
  267. )
  268. self.session.commit()
  269. self.assertEqual(msg, "User added")
  270. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  271. self.assertEqual(sorted([u.username for u in repo.users]), ["foo"])
  272. self.assertEqual(sorted([u.username for u in repo.committers]), [])
  273. self.assertEqual(sorted([u.username for u in repo.admins]), [])
  274. output = self.app.put("/pv/ticket/comment/", data=data)
  275. self.assertEqual(output.status_code, 403)
  276. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  277. # Let's promote him to be a committer
  278. # He should be able to comment
  279. msg = pagure.lib.query.add_user_to_project(
  280. self.session,
  281. project=repo,
  282. new_user="foo",
  283. user="pingou",
  284. access="commit",
  285. )
  286. self.session.commit()
  287. self.assertEqual(msg, "User access updated")
  288. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  289. self.assertEqual(sorted([u.username for u in repo.users]), ["foo"])
  290. self.assertEqual(
  291. sorted([u.username for u in repo.committers]), ["foo"]
  292. )
  293. self.assertEqual(sorted([u.username for u in repo.admins]), [])
  294. # Add comment
  295. output = self.app.put("/pv/ticket/comment/", data=data)
  296. self.assertEqual(output.status_code, 200)
  297. js_data = json.loads(output.get_data(as_text=True))
  298. self.assertDictEqual(js_data, {"message": "Comment added"})
  299. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  300. issue = repo.issues[0]
  301. self.assertEqual(len(issue.comments), 1)
  302. # Let's promote him to be a admin
  303. # He should be able to comment
  304. msg = pagure.lib.query.add_user_to_project(
  305. self.session,
  306. project=repo,
  307. new_user="foo",
  308. user="pingou",
  309. access="admin",
  310. )
  311. self.session.commit()
  312. self.assertEqual(msg, "User access updated")
  313. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  314. self.assertEqual(sorted([u.username for u in repo.users]), ["foo"])
  315. self.assertEqual(
  316. sorted([u.username for u in repo.committers]), ["foo"]
  317. )
  318. self.assertEqual(sorted([u.username for u in repo.admins]), ["foo"])
  319. # Add comment
  320. output = self.app.put("/pv/ticket/comment/", data=data)
  321. self.assertEqual(output.status_code, 200)
  322. js_data = json.loads(output.get_data(as_text=True))
  323. self.assertDictEqual(js_data, {"message": "Comment added"})
  324. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  325. issue = repo.issues[0]
  326. self.assertEqual(len(issue.comments), 2)
  327. # Check the @internal_access_only
  328. before = pagure.config.config["IP_ALLOWED_INTERNAL"][:]
  329. pagure.config.config["IP_ALLOWED_INTERNAL"] = []
  330. output = self.app.put("/pv/ticket/comment/", data=data)
  331. self.assertEqual(output.status_code, 403)
  332. pagure.config.config["IP_ALLOWED_INTERNAL"] = before[:]
  333. @patch("pagure.lib.notify.send_email")
  334. def test_mergeable_request_pull_FF(self, send_email):
  335. """ Test the mergeable_request_pull endpoint with a fast-forward
  336. merge.
  337. """
  338. send_email.return_value = True
  339. # Create a git repo to play with
  340. origgitrepo = os.path.join(self.path, "repos", "test.git")
  341. self.assertFalse(os.path.exists(origgitrepo))
  342. os.makedirs(origgitrepo)
  343. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  344. os.makedirs(os.path.join(self.path, "repos_tmp"))
  345. gitrepo = os.path.join(self.path, "repos_tmp", "test.git")
  346. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  347. # Create a file in that git repo
  348. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  349. stream.write("foo\n bar")
  350. repo.index.add("sources")
  351. repo.index.write()
  352. # Commits the files added
  353. tree = repo.index.write_tree()
  354. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  355. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  356. repo.create_commit(
  357. "refs/heads/master", # the name of the reference to update
  358. author,
  359. committer,
  360. "Add sources file for testing",
  361. # binary string representing the tree object ID
  362. tree,
  363. # list of binary strings representing parents of the new commit
  364. [],
  365. )
  366. first_commit = repo.revparse_single("HEAD")
  367. refname = "refs/heads/master:refs/heads/master"
  368. ori_remote = repo.remotes[0]
  369. PagureRepo.push(ori_remote, refname)
  370. # Edit the sources file again
  371. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  372. stream.write("foo\n bar\nbaz\n boose")
  373. repo.index.add("sources")
  374. repo.index.write()
  375. # Commits the files added
  376. tree = repo.index.write_tree()
  377. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  378. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  379. repo.create_commit(
  380. "refs/heads/feature", # the name of the reference to update
  381. author,
  382. committer,
  383. "Add baz and boose to the sources\n\n There are more objects to "
  384. "consider",
  385. # binary string representing the tree object ID
  386. tree,
  387. # list of binary strings representing parents of the new commit
  388. [first_commit.oid.hex],
  389. )
  390. second_commit = repo.revparse_single("HEAD")
  391. refname = "refs/heads/feature:refs/heads/feature"
  392. ori_remote = repo.remotes[0]
  393. PagureRepo.push(ori_remote, refname)
  394. # Create a PR for these changes
  395. tests.create_projects(self.session)
  396. project = pagure.lib.query.get_authorized_project(self.session, "test")
  397. req = pagure.lib.query.new_pull_request(
  398. session=self.session,
  399. repo_from=project,
  400. branch_from="feature",
  401. repo_to=project,
  402. branch_to="master",
  403. title="PR from the feature branch",
  404. user="pingou",
  405. )
  406. self.session.commit()
  407. self.assertEqual(req.id, 1)
  408. self.assertEqual(req.title, "PR from the feature branch")
  409. # Check if the PR can be merged
  410. data = {"objid": "blah"}
  411. # Missing CSRF
  412. output = self.app.post("/pv/pull-request/merge", data=data)
  413. self.assertEqual(output.status_code, 400)
  414. user = tests.FakeUser()
  415. user.username = "pingou"
  416. with tests.user_set(self.app.application, user):
  417. output = self.app.get("/test/adduser")
  418. csrf_token = (
  419. output.get_data(as_text=True)
  420. .split('name="csrf_token" type="hidden" value="')[1]
  421. .split('">')[0]
  422. )
  423. # Missing request identifier
  424. data = {"csrf_token": csrf_token}
  425. output = self.app.post("/pv/pull-request/merge", data=data)
  426. self.assertEqual(output.status_code, 404)
  427. # With all the desired information
  428. project = pagure.lib.query.get_authorized_project(
  429. self.session, "test"
  430. )
  431. data = {
  432. "csrf_token": csrf_token,
  433. "requestid": project.requests[0].uid,
  434. }
  435. output = self.app.post("/pv/pull-request/merge", data=data)
  436. self.assertEqual(output.status_code, 200)
  437. exp = {
  438. "code": "FFORWARD",
  439. "message": "The pull-request can be merged and fast-forwarded",
  440. "short_code": "Ok",
  441. }
  442. js_data = json.loads(output.get_data(as_text=True))
  443. self.assertDictEqual(js_data, exp)
  444. @patch("pagure.lib.notify.send_email")
  445. def test_mergeable_request_pull_no_change(self, send_email):
  446. """ Test the mergeable_request_pull endpoint when there are no
  447. changes to merge.
  448. """
  449. send_email.return_value = True
  450. # Create a git repo to play with
  451. gitrepo = os.path.join(self.path, "repos", "test.git")
  452. self.assertFalse(os.path.exists(gitrepo))
  453. os.makedirs(gitrepo)
  454. repo = pygit2.init_repository(gitrepo)
  455. # Create a file in that git repo
  456. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  457. stream.write("foo\n bar")
  458. repo.index.add("sources")
  459. repo.index.write()
  460. # Commits the files added
  461. tree = repo.index.write_tree()
  462. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  463. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  464. repo.create_commit(
  465. "refs/heads/master", # the name of the reference to update
  466. author,
  467. committer,
  468. "Add sources file for testing",
  469. # binary string representing the tree object ID
  470. tree,
  471. # list of binary strings representing parents of the new commit
  472. [],
  473. )
  474. first_commit = repo.revparse_single("HEAD")
  475. # Edit the sources file again
  476. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  477. stream.write("foo\n bar\nbaz\n boose")
  478. repo.index.add("sources")
  479. repo.index.write()
  480. # Commits the files added
  481. tree = repo.index.write_tree()
  482. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  483. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  484. repo.create_commit(
  485. "refs/heads/master", # the name of the reference to update
  486. author,
  487. committer,
  488. "Add baz and boose to the sources\n\n There are more objects to "
  489. "consider",
  490. # binary string representing the tree object ID
  491. tree,
  492. # list of binary strings representing parents of the new commit
  493. [first_commit.oid.hex],
  494. )
  495. second_commit = repo.revparse_single("HEAD")
  496. # Create a PR for these changes
  497. tests.create_projects(self.session)
  498. project = pagure.lib.query.get_authorized_project(self.session, "test")
  499. req = pagure.lib.query.new_pull_request(
  500. session=self.session,
  501. repo_from=project,
  502. branch_from="master",
  503. repo_to=project,
  504. branch_to="master",
  505. title="PR from the feature branch",
  506. user="pingou",
  507. )
  508. self.session.commit()
  509. self.assertEqual(req.id, 1)
  510. self.assertEqual(req.title, "PR from the feature branch")
  511. # Check if the PR can be merged
  512. data = {"objid": "blah"}
  513. # Missing CSRF
  514. output = self.app.post("/pv/pull-request/merge", data=data)
  515. self.assertEqual(output.status_code, 400)
  516. user = tests.FakeUser()
  517. user.username = "pingou"
  518. with tests.user_set(self.app.application, user):
  519. output = self.app.get("/test/adduser")
  520. csrf_token = (
  521. output.get_data(as_text=True)
  522. .split('name="csrf_token" type="hidden" value="')[1]
  523. .split('">')[0]
  524. )
  525. # Missing request identifier
  526. data = {"csrf_token": csrf_token}
  527. output = self.app.post("/pv/pull-request/merge", data=data)
  528. self.assertEqual(output.status_code, 404)
  529. # With all the desired information
  530. project = pagure.lib.query.get_authorized_project(
  531. self.session, "test"
  532. )
  533. data = {
  534. "csrf_token": csrf_token,
  535. "requestid": project.requests[0].uid,
  536. }
  537. output = self.app.post("/pv/pull-request/merge", data=data)
  538. self.assertEqual(output.status_code, 200)
  539. exp = {
  540. "code": "NO_CHANGE",
  541. "message": "Nothing to change, git is up to date",
  542. "short_code": "No changes",
  543. }
  544. js_data = json.loads(output.get_data(as_text=True))
  545. self.assertDictEqual(js_data, exp)
  546. @patch("pagure.lib.notify.send_email")
  547. def test_mergeable_request_pull_merge(self, send_email):
  548. """ Test the mergeable_request_pull endpoint when the changes can
  549. be merged with a merge commit.
  550. """
  551. send_email.return_value = True
  552. # Create a git repo to play with
  553. origgitrepo = os.path.join(self.path, "repos", "test.git")
  554. self.assertFalse(os.path.exists(origgitrepo))
  555. os.makedirs(origgitrepo)
  556. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  557. os.makedirs(os.path.join(self.path, "repos_tmp"))
  558. gitrepo = os.path.join(self.path, "repos_tmp", "test.git")
  559. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  560. # Create a file in that git repo
  561. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  562. stream.write("foo\n bar")
  563. repo.index.add("sources")
  564. repo.index.write()
  565. # Commits the files added
  566. tree = repo.index.write_tree()
  567. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  568. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  569. repo.create_commit(
  570. "refs/heads/master", # the name of the reference to update
  571. author,
  572. committer,
  573. "Add sources file for testing",
  574. # binary string representing the tree object ID
  575. tree,
  576. # list of binary strings representing parents of the new commit
  577. [],
  578. )
  579. first_commit = repo.revparse_single("HEAD")
  580. refname = "refs/heads/master:refs/heads/master"
  581. ori_remote = repo.remotes[0]
  582. PagureRepo.push(ori_remote, refname)
  583. # Edit the sources file again
  584. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  585. stream.write("foo\n bar\nbaz\n boose")
  586. repo.index.add("sources")
  587. repo.index.write()
  588. # Commits the files added
  589. tree = repo.index.write_tree()
  590. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  591. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  592. repo.create_commit(
  593. "refs/heads/feature", # the name of the reference to update
  594. author,
  595. committer,
  596. "Add baz and boose to the sources\n\n There are more objects to "
  597. "consider",
  598. # binary string representing the tree object ID
  599. tree,
  600. # list of binary strings representing parents of the new commit
  601. [first_commit.oid.hex],
  602. )
  603. refname = "refs/heads/feature:refs/heads/feature"
  604. ori_remote = repo.remotes[0]
  605. PagureRepo.push(ori_remote, refname)
  606. # Create another file in the master branch
  607. with open(os.path.join(gitrepo, ".gitignore"), "w") as stream:
  608. stream.write("*~")
  609. repo.index.add(".gitignore")
  610. repo.index.write()
  611. # Commits the files added
  612. tree = repo.index.write_tree()
  613. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  614. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  615. repo.create_commit(
  616. "refs/heads/master", # the name of the reference to update
  617. author,
  618. committer,
  619. "Add .gitignore file for testing",
  620. # binary string representing the tree object ID
  621. tree,
  622. # list of binary strings representing parents of the new commit
  623. [first_commit.oid.hex],
  624. )
  625. refname = "refs/heads/master:refs/heads/master"
  626. ori_remote = repo.remotes[0]
  627. PagureRepo.push(ori_remote, refname)
  628. # Create a PR for these changes
  629. tests.create_projects(self.session)
  630. project = pagure.lib.query.get_authorized_project(self.session, "test")
  631. req = pagure.lib.query.new_pull_request(
  632. session=self.session,
  633. repo_from=project,
  634. branch_from="feature",
  635. repo_to=project,
  636. branch_to="master",
  637. title="PR from the feature branch",
  638. user="pingou",
  639. )
  640. self.session.commit()
  641. self.assertEqual(req.id, 1)
  642. self.assertEqual(req.title, "PR from the feature branch")
  643. # Check if the PR can be merged
  644. data = {}
  645. # Missing CSRF
  646. output = self.app.post("/pv/pull-request/merge", data=data)
  647. self.assertEqual(output.status_code, 400)
  648. user = tests.FakeUser()
  649. user.username = "pingou"
  650. with tests.user_set(self.app.application, user):
  651. output = self.app.get("/test/adduser")
  652. csrf_token = (
  653. output.get_data(as_text=True)
  654. .split('name="csrf_token" type="hidden" value="')[1]
  655. .split('">')[0]
  656. )
  657. # Missing request identifier
  658. data = {"csrf_token": csrf_token}
  659. output = self.app.post("/pv/pull-request/merge", data=data)
  660. self.assertEqual(output.status_code, 404)
  661. # With all the desired information
  662. project = pagure.lib.query.get_authorized_project(
  663. self.session, "test"
  664. )
  665. data = {
  666. "csrf_token": csrf_token,
  667. "requestid": project.requests[0].uid,
  668. "force": True,
  669. }
  670. output = self.app.post("/pv/pull-request/merge", data=data)
  671. self.assertEqual(output.status_code, 200)
  672. exp = {
  673. "code": "MERGE",
  674. "message": "The pull-request can be merged with a merge commit",
  675. "short_code": "With merge",
  676. }
  677. js_data = json.loads(output.get_data(as_text=True))
  678. self.assertDictEqual(js_data, exp)
  679. # Asking a second time will trigger the cache
  680. data = {
  681. "csrf_token": csrf_token,
  682. "requestid": project.requests[0].uid,
  683. }
  684. output = self.app.post("/pv/pull-request/merge", data=data)
  685. self.assertEqual(output.status_code, 200)
  686. exp = {
  687. "code": "MERGE",
  688. "message": "The pull-request can be merged with a merge commit",
  689. "short_code": "With merge",
  690. }
  691. js_data = json.loads(output.get_data(as_text=True))
  692. self.assertDictEqual(js_data, exp)
  693. @patch("pagure.lib.notify.send_email")
  694. def test_mergeable_request_pull_conflicts(self, send_email):
  695. """ Test the mergeable_request_pull endpoint when the changes cannot
  696. be merged due to conflicts.
  697. """
  698. send_email.return_value = True
  699. # Create a git repo to play with
  700. origgitrepo = os.path.join(self.path, "repos", "test.git")
  701. self.assertFalse(os.path.exists(origgitrepo))
  702. os.makedirs(origgitrepo)
  703. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  704. os.makedirs(os.path.join(self.path, "repos_tmp"))
  705. gitrepo = os.path.join(self.path, "repos_tmp", "test.git")
  706. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  707. # Create a file in that git repo
  708. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  709. stream.write("foo\n bar")
  710. repo.index.add("sources")
  711. repo.index.write()
  712. # Commits the files added
  713. tree = repo.index.write_tree()
  714. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  715. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  716. repo.create_commit(
  717. "refs/heads/master", # the name of the reference to update
  718. author,
  719. committer,
  720. "Add sources file for testing",
  721. # binary string representing the tree object ID
  722. tree,
  723. # list of binary strings representing parents of the new commit
  724. [],
  725. )
  726. first_commit = repo.revparse_single("HEAD")
  727. refname = "refs/heads/master:refs/heads/master"
  728. ori_remote = repo.remotes[0]
  729. PagureRepo.push(ori_remote, refname)
  730. # Edit the sources file again
  731. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  732. stream.write("foo\n bar\nbaz\n boose")
  733. repo.index.add("sources")
  734. repo.index.write()
  735. # Commits the files added
  736. tree = repo.index.write_tree()
  737. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  738. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  739. repo.create_commit(
  740. "refs/heads/feature", # the name of the reference to update
  741. author,
  742. committer,
  743. "Add baz and boose to the sources\n\n There are more objects to "
  744. "consider",
  745. # binary string representing the tree object ID
  746. tree,
  747. # list of binary strings representing parents of the new commit
  748. [first_commit.oid.hex],
  749. )
  750. refname = "refs/heads/feature:refs/heads/feature"
  751. ori_remote = repo.remotes[0]
  752. PagureRepo.push(ori_remote, refname)
  753. # Create another file in the master branch
  754. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  755. stream.write("foo\n bar\nbaz\n")
  756. repo.index.add("sources")
  757. repo.index.write()
  758. # Commits the files added
  759. tree = repo.index.write_tree()
  760. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  761. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  762. repo.create_commit(
  763. "refs/heads/master", # the name of the reference to update
  764. author,
  765. committer,
  766. "Add .gitignore file for testing",
  767. # binary string representing the tree object ID
  768. tree,
  769. # list of binary strings representing parents of the new commit
  770. [first_commit.oid.hex],
  771. )
  772. refname = "refs/heads/master:refs/heads/master"
  773. ori_remote = repo.remotes[0]
  774. PagureRepo.push(ori_remote, refname)
  775. # Create a PR for these changes
  776. tests.create_projects(self.session)
  777. project = pagure.lib.query.get_authorized_project(self.session, "test")
  778. req = pagure.lib.query.new_pull_request(
  779. session=self.session,
  780. repo_from=project,
  781. branch_from="feature",
  782. repo_to=project,
  783. branch_to="master",
  784. title="PR from the feature branch",
  785. user="pingou",
  786. )
  787. self.session.commit()
  788. self.assertEqual(req.id, 1)
  789. self.assertEqual(req.title, "PR from the feature branch")
  790. # Check if the PR can be merged
  791. data = {}
  792. # Missing CSRF
  793. output = self.app.post("/pv/pull-request/merge", data=data)
  794. self.assertEqual(output.status_code, 400)
  795. user = tests.FakeUser()
  796. user.username = "pingou"
  797. with tests.user_set(self.app.application, user):
  798. output = self.app.get("/test/adduser")
  799. csrf_token = (
  800. output.get_data(as_text=True)
  801. .split('name="csrf_token" type="hidden" value="')[1]
  802. .split('">')[0]
  803. )
  804. # Missing request identifier
  805. data = {"csrf_token": csrf_token}
  806. output = self.app.post("/pv/pull-request/merge", data=data)
  807. self.assertEqual(output.status_code, 404)
  808. # With all the desired information
  809. project = pagure.lib.query.get_authorized_project(
  810. self.session, "test"
  811. )
  812. data = {
  813. "csrf_token": csrf_token,
  814. "requestid": project.requests[0].uid,
  815. }
  816. output = self.app.post("/pv/pull-request/merge", data=data)
  817. self.assertEqual(output.status_code, 200)
  818. exp = {
  819. "code": "CONFLICTS",
  820. "message": "The pull-request cannot be merged due to conflicts",
  821. "short_code": "Conflicts",
  822. }
  823. js_data = json.loads(output.get_data(as_text=True))
  824. self.assertDictEqual(js_data, exp)
  825. @patch("pagure.lib.notify.send_email")
  826. def test_mergeable_request_pull_merge_no_nonff_merges(self, send_email):
  827. """ Test the mergeable_request_pull endpoint when the changes can
  828. be merged with a merge commit, but project settings prohibit this.
  829. """
  830. send_email.return_value = True
  831. # Create a git repo to play with
  832. origgitrepo = os.path.join(self.path, "repos", "test.git")
  833. self.assertFalse(os.path.exists(origgitrepo))
  834. os.makedirs(origgitrepo)
  835. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  836. os.makedirs(os.path.join(self.path, "repos_tmp"))
  837. gitrepo = os.path.join(self.path, "repos_tmp", "test.git")
  838. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  839. # Create a file in that git repo
  840. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  841. stream.write("foo\n bar")
  842. repo.index.add("sources")
  843. repo.index.write()
  844. # Commits the files added
  845. tree = repo.index.write_tree()
  846. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  847. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  848. repo.create_commit(
  849. "refs/heads/master", # the name of the reference to update
  850. author,
  851. committer,
  852. "Add sources file for testing",
  853. # binary string representing the tree object ID
  854. tree,
  855. # list of binary strings representing parents of the new commit
  856. [],
  857. )
  858. first_commit = repo.revparse_single("HEAD")
  859. refname = "refs/heads/master:refs/heads/master"
  860. ori_remote = repo.remotes[0]
  861. PagureRepo.push(ori_remote, refname)
  862. # Edit the sources file again
  863. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  864. stream.write("foo\n bar\nbaz\n boose")
  865. repo.index.add("sources")
  866. repo.index.write()
  867. # Commits the files added
  868. tree = repo.index.write_tree()
  869. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  870. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  871. repo.create_commit(
  872. "refs/heads/feature", # the name of the reference to update
  873. author,
  874. committer,
  875. "Add baz and boose to the sources\n\n There are more objects to "
  876. "consider",
  877. # binary string representing the tree object ID
  878. tree,
  879. # list of binary strings representing parents of the new commit
  880. [first_commit.oid.hex],
  881. )
  882. refname = "refs/heads/feature:refs/heads/feature"
  883. ori_remote = repo.remotes[0]
  884. PagureRepo.push(ori_remote, refname)
  885. # Create another file in the master branch
  886. with open(os.path.join(gitrepo, ".gitignore"), "w") as stream:
  887. stream.write("*~")
  888. repo.index.add(".gitignore")
  889. repo.index.write()
  890. # Commits the files added
  891. tree = repo.index.write_tree()
  892. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  893. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  894. repo.create_commit(
  895. "refs/heads/master", # the name of the reference to update
  896. author,
  897. committer,
  898. "Add .gitignore file for testing",
  899. # binary string representing the tree object ID
  900. tree,
  901. # list of binary strings representing parents of the new commit
  902. [first_commit.oid.hex],
  903. )
  904. refname = "refs/heads/master:refs/heads/master"
  905. ori_remote = repo.remotes[0]
  906. PagureRepo.push(ori_remote, refname)
  907. # Create a PR for these changes
  908. tests.create_projects(self.session)
  909. project = pagure.lib.query.get_authorized_project(self.session, "test")
  910. req = pagure.lib.query.new_pull_request(
  911. session=self.session,
  912. repo_from=project,
  913. branch_from="feature",
  914. repo_to=project,
  915. branch_to="master",
  916. title="PR from the feature branch",
  917. user="pingou",
  918. )
  919. settings = {"disable_non_fast-forward_merges": True}
  920. project.settings = settings
  921. self.session.commit()
  922. self.assertEqual(req.id, 1)
  923. self.assertEqual(req.title, "PR from the feature branch")
  924. # Check if the PR can be merged
  925. data = {}
  926. user = tests.FakeUser()
  927. user.username = "pingou"
  928. with tests.user_set(self.app.application, user):
  929. output = self.app.get("/test/adduser")
  930. csrf_token = (
  931. output.get_data(as_text=True)
  932. .split('name="csrf_token" type="hidden" value="')[1]
  933. .split('">')[0]
  934. )
  935. # With all the desired information
  936. project = pagure.lib.query.get_authorized_project(
  937. self.session, "test"
  938. )
  939. data = {
  940. "csrf_token": csrf_token,
  941. "requestid": project.requests[0].uid,
  942. "force": True,
  943. }
  944. output = self.app.post("/pv/pull-request/merge", data=data)
  945. self.assertEqual(output.status_code, 200)
  946. exp = {
  947. "code": "NEEDSREBASE",
  948. "message": "The pull-request must be rebased before merging",
  949. "short_code": "Needs rebase",
  950. }
  951. js_data = json.loads(output.get_data(as_text=True))
  952. self.assertDictEqual(js_data, exp)
  953. # Asking a second time will trigger the cache
  954. data = {
  955. "csrf_token": csrf_token,
  956. "requestid": project.requests[0].uid,
  957. }
  958. output = self.app.post("/pv/pull-request/merge", data=data)
  959. self.assertEqual(output.status_code, 200)
  960. exp = {
  961. "code": "NEEDSREBASE",
  962. "message": "The pull-request must be rebased before merging",
  963. "short_code": "Needs rebase",
  964. }
  965. js_data = json.loads(output.get_data(as_text=True))
  966. self.assertDictEqual(js_data, exp)
  967. @patch("pagure.lib.notify.send_email")
  968. def test_mergeable_request_pull_minimum_score(self, send_email):
  969. """ Test the mergeable_request_pull endpoint when the changes can
  970. be merged with a merge FF, but project settings enforces vote on
  971. the PR.
  972. """
  973. send_email.return_value = True
  974. # Create a git repo to play with
  975. origgitrepo = os.path.join(self.path, "repos", "test.git")
  976. self.assertFalse(os.path.exists(origgitrepo))
  977. os.makedirs(origgitrepo)
  978. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  979. os.makedirs(os.path.join(self.path, "repos_tmp"))
  980. gitrepo = os.path.join(self.path, "repos_tmp", "test.git")
  981. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  982. # Create a file in that git repo
  983. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  984. stream.write("foo\n bar")
  985. repo.index.add("sources")
  986. repo.index.write()
  987. # Commits the files added
  988. tree = repo.index.write_tree()
  989. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  990. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  991. repo.create_commit(
  992. "refs/heads/master", # the name of the reference to update
  993. author,
  994. committer,
  995. "Add sources file for testing",
  996. # binary string representing the tree object ID
  997. tree,
  998. # list of binary strings representing parents of the new commit
  999. [],
  1000. )
  1001. first_commit = repo.revparse_single("HEAD")
  1002. refname = "refs/heads/master:refs/heads/master"
  1003. ori_remote = repo.remotes[0]
  1004. PagureRepo.push(ori_remote, refname)
  1005. # Edit the sources file again
  1006. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1007. stream.write("foo\n bar\nbaz\n boose")
  1008. repo.index.add("sources")
  1009. repo.index.write()
  1010. # Commits the files added
  1011. tree = repo.index.write_tree()
  1012. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1013. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1014. repo.create_commit(
  1015. "refs/heads/feature", # the name of the reference to update
  1016. author,
  1017. committer,
  1018. "Add baz and boose to the sources\n\n There are more objects to "
  1019. "consider",
  1020. # binary string representing the tree object ID
  1021. tree,
  1022. # list of binary strings representing parents of the new commit
  1023. [first_commit.oid.hex],
  1024. )
  1025. refname = "refs/heads/feature:refs/heads/feature"
  1026. ori_remote = repo.remotes[0]
  1027. PagureRepo.push(ori_remote, refname)
  1028. # Create a PR for these changes
  1029. tests.create_projects(self.session)
  1030. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1031. req = pagure.lib.query.new_pull_request(
  1032. session=self.session,
  1033. repo_from=project,
  1034. branch_from="feature",
  1035. repo_to=project,
  1036. branch_to="master",
  1037. title="PR from the feature branch",
  1038. user="pingou",
  1039. )
  1040. settings = {"Minimum_score_to_merge_pull-request": 2}
  1041. project.settings = settings
  1042. self.session.commit()
  1043. self.assertEqual(req.id, 1)
  1044. self.assertEqual(req.title, "PR from the feature branch")
  1045. # Check if the PR can be merged
  1046. data = {}
  1047. user = tests.FakeUser()
  1048. user.username = "pingou"
  1049. with tests.user_set(self.app.application, user):
  1050. output = self.app.get("/test/adduser")
  1051. csrf_token = (
  1052. output.get_data(as_text=True)
  1053. .split('name="csrf_token" type="hidden" value="')[1]
  1054. .split('">')[0]
  1055. )
  1056. # With all the desired information
  1057. project = pagure.lib.query.get_authorized_project(
  1058. self.session, "test"
  1059. )
  1060. data = {
  1061. "csrf_token": csrf_token,
  1062. "requestid": project.requests[0].uid,
  1063. "force": True,
  1064. }
  1065. output = self.app.post("/pv/pull-request/merge", data=data)
  1066. self.assertEqual(output.status_code, 400)
  1067. exp = {
  1068. "code": "CONFLICTS",
  1069. "message": "Pull-Request does not meet the minimal number "
  1070. "of review required: 0/2",
  1071. }
  1072. js_data = json.loads(output.get_data(as_text=True))
  1073. self.assertDictEqual(js_data, exp)
  1074. # Verify we get a valid merge_status (not 'unknown')
  1075. pub_api_call = self.app.get("/api/0/test/pull-request/1")
  1076. data = json.loads(pub_api_call.get_data(as_text=True))
  1077. self.assertIn(data["cached_merge_status"], ("MERGE", "FFORWARD"))
  1078. # Asking a second time will trigger the cache
  1079. data = {
  1080. "csrf_token": csrf_token,
  1081. "requestid": project.requests[0].uid,
  1082. }
  1083. output = self.app.post("/pv/pull-request/merge", data=data)
  1084. self.assertEqual(output.status_code, 400)
  1085. exp = {
  1086. "code": "CONFLICTS",
  1087. "message": "Pull-Request does not meet the minimal number "
  1088. "of review required: 0/2",
  1089. }
  1090. js_data = json.loads(output.get_data(as_text=True))
  1091. self.assertDictEqual(js_data, exp)
  1092. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  1093. @patch(
  1094. "pagure.lib.git.merge_pull_request",
  1095. MagicMock(side_effect=pagure.exceptions.PagureException("error")),
  1096. )
  1097. def test_mergeable_request_pull_merge_pagureerror(self):
  1098. """ Test the mergeable_request_pull endpoint when the backend
  1099. raises an GitError exception.
  1100. """
  1101. # Create a git repo to play with
  1102. origgitrepo = os.path.join(self.path, "repos", "test.git")
  1103. self.assertFalse(os.path.exists(origgitrepo))
  1104. os.makedirs(origgitrepo)
  1105. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  1106. os.makedirs(os.path.join(self.path, "repos_tmp"))
  1107. gitrepo = os.path.join(self.path, "repos_tmp", "test.git")
  1108. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  1109. # Create a file in that git repo
  1110. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1111. stream.write("foo\n bar")
  1112. repo.index.add("sources")
  1113. repo.index.write()
  1114. # Commits the files added
  1115. tree = repo.index.write_tree()
  1116. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1117. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1118. repo.create_commit(
  1119. "refs/heads/master", # the name of the reference to update
  1120. author,
  1121. committer,
  1122. "Add sources file for testing",
  1123. # binary string representing the tree object ID
  1124. tree,
  1125. # list of binary strings representing parents of the new commit
  1126. [],
  1127. )
  1128. first_commit = repo.revparse_single("HEAD")
  1129. refname = "refs/heads/master:refs/heads/master"
  1130. ori_remote = repo.remotes[0]
  1131. PagureRepo.push(ori_remote, refname)
  1132. # Edit the sources file again
  1133. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1134. stream.write("foo\n bar\nbaz\n boose")
  1135. repo.index.add("sources")
  1136. repo.index.write()
  1137. # Commits the files added
  1138. tree = repo.index.write_tree()
  1139. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1140. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1141. repo.create_commit(
  1142. "refs/heads/feature", # the name of the reference to update
  1143. author,
  1144. committer,
  1145. "Add baz and boose to the sources\n\n There are more objects to "
  1146. "consider",
  1147. # binary string representing the tree object ID
  1148. tree,
  1149. # list of binary strings representing parents of the new commit
  1150. [first_commit.oid.hex],
  1151. )
  1152. refname = "refs/heads/feature:refs/heads/feature"
  1153. ori_remote = repo.remotes[0]
  1154. PagureRepo.push(ori_remote, refname)
  1155. # Create another file in the master branch
  1156. with open(os.path.join(gitrepo, ".gitignore"), "w") as stream:
  1157. stream.write("*~")
  1158. repo.index.add(".gitignore")
  1159. repo.index.write()
  1160. # Commits the files added
  1161. tree = repo.index.write_tree()
  1162. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1163. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1164. repo.create_commit(
  1165. "refs/heads/master", # the name of the reference to update
  1166. author,
  1167. committer,
  1168. "Add .gitignore file for testing",
  1169. # binary string representing the tree object ID
  1170. tree,
  1171. # list of binary strings representing parents of the new commit
  1172. [first_commit.oid.hex],
  1173. )
  1174. refname = "refs/heads/master:refs/heads/master"
  1175. ori_remote = repo.remotes[0]
  1176. PagureRepo.push(ori_remote, refname)
  1177. # Create a PR for these changes
  1178. tests.create_projects(self.session)
  1179. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1180. req = pagure.lib.query.new_pull_request(
  1181. session=self.session,
  1182. repo_from=project,
  1183. branch_from="feature",
  1184. repo_to=project,
  1185. branch_to="master",
  1186. title="PR from the feature branch",
  1187. user="pingou",
  1188. )
  1189. self.session.commit()
  1190. self.assertEqual(req.id, 1)
  1191. self.assertEqual(req.title, "PR from the feature branch")
  1192. # Check if the PR can be merged
  1193. data = {}
  1194. user = tests.FakeUser()
  1195. user.username = "pingou"
  1196. with tests.user_set(self.app.application, user):
  1197. output = self.app.get("/test/adduser")
  1198. csrf_token = self.get_csrf(output=output)
  1199. # With all the desired information
  1200. project = pagure.lib.query.get_authorized_project(
  1201. self.session, "test"
  1202. )
  1203. data = {
  1204. "csrf_token": csrf_token,
  1205. "requestid": project.requests[0].uid,
  1206. "force": True,
  1207. }
  1208. output = self.app.post("/pv/pull-request/merge", data=data)
  1209. self.assertEqual(output.status_code, 500)
  1210. exp = {"code": "CONFLICTS", "message": "error"}
  1211. js_data = json.loads(output.get_data(as_text=True))
  1212. self.assertDictEqual(js_data, exp)
  1213. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  1214. @patch(
  1215. "pagure.lib.git.merge_pull_request",
  1216. MagicMock(side_effect=pygit2.GitError("git error")),
  1217. )
  1218. def test_mergeable_request_pull_merge_giterror(self):
  1219. """ Test the mergeable_request_pull endpoint when the backend
  1220. raises an GitError exception.
  1221. """
  1222. # Create a git repo to play with
  1223. origgitrepo = os.path.join(self.path, "repos", "test.git")
  1224. self.assertFalse(os.path.exists(origgitrepo))
  1225. os.makedirs(origgitrepo)
  1226. orig_repo = pygit2.init_repository(origgitrepo, bare=True)
  1227. os.makedirs(os.path.join(self.path, "repos_tmp"))
  1228. gitrepo = os.path.join(self.path, "repos_tmp", "test.git")
  1229. repo = pygit2.clone_repository(origgitrepo, gitrepo)
  1230. # Create a file in that git repo
  1231. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1232. stream.write("foo\n bar")
  1233. repo.index.add("sources")
  1234. repo.index.write()
  1235. # Commits the files added
  1236. tree = repo.index.write_tree()
  1237. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1238. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1239. repo.create_commit(
  1240. "refs/heads/master", # the name of the reference to update
  1241. author,
  1242. committer,
  1243. "Add sources file for testing",
  1244. # binary string representing the tree object ID
  1245. tree,
  1246. # list of binary strings representing parents of the new commit
  1247. [],
  1248. )
  1249. first_commit = repo.revparse_single("HEAD")
  1250. refname = "refs/heads/master:refs/heads/master"
  1251. ori_remote = repo.remotes[0]
  1252. PagureRepo.push(ori_remote, refname)
  1253. # Edit the sources file again
  1254. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1255. stream.write("foo\n bar\nbaz\n boose")
  1256. repo.index.add("sources")
  1257. repo.index.write()
  1258. # Commits the files added
  1259. tree = repo.index.write_tree()
  1260. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1261. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1262. repo.create_commit(
  1263. "refs/heads/feature", # the name of the reference to update
  1264. author,
  1265. committer,
  1266. "Add baz and boose to the sources\n\n There are more objects to "
  1267. "consider",
  1268. # binary string representing the tree object ID
  1269. tree,
  1270. # list of binary strings representing parents of the new commit
  1271. [first_commit.oid.hex],
  1272. )
  1273. refname = "refs/heads/feature:refs/heads/feature"
  1274. ori_remote = repo.remotes[0]
  1275. PagureRepo.push(ori_remote, refname)
  1276. # Create another file in the master branch
  1277. with open(os.path.join(gitrepo, ".gitignore"), "w") as stream:
  1278. stream.write("*~")
  1279. repo.index.add(".gitignore")
  1280. repo.index.write()
  1281. # Commits the files added
  1282. tree = repo.index.write_tree()
  1283. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1284. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1285. repo.create_commit(
  1286. "refs/heads/master", # the name of the reference to update
  1287. author,
  1288. committer,
  1289. "Add .gitignore file for testing",
  1290. # binary string representing the tree object ID
  1291. tree,
  1292. # list of binary strings representing parents of the new commit
  1293. [first_commit.oid.hex],
  1294. )
  1295. refname = "refs/heads/master:refs/heads/master"
  1296. ori_remote = repo.remotes[0]
  1297. PagureRepo.push(ori_remote, refname)
  1298. # Create a PR for these changes
  1299. tests.create_projects(self.session)
  1300. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1301. req = pagure.lib.query.new_pull_request(
  1302. session=self.session,
  1303. repo_from=project,
  1304. branch_from="feature",
  1305. repo_to=project,
  1306. branch_to="master",
  1307. title="PR from the feature branch",
  1308. user="pingou",
  1309. )
  1310. self.session.commit()
  1311. self.assertEqual(req.id, 1)
  1312. self.assertEqual(req.title, "PR from the feature branch")
  1313. # Check if the PR can be merged
  1314. data = {}
  1315. user = tests.FakeUser()
  1316. user.username = "pingou"
  1317. with tests.user_set(self.app.application, user):
  1318. output = self.app.get("/test/adduser")
  1319. csrf_token = self.get_csrf(output=output)
  1320. # With all the desired information
  1321. project = pagure.lib.query.get_authorized_project(
  1322. self.session, "test"
  1323. )
  1324. data = {
  1325. "csrf_token": csrf_token,
  1326. "requestid": project.requests[0].uid,
  1327. "force": True,
  1328. }
  1329. output = self.app.post("/pv/pull-request/merge", data=data)
  1330. self.assertEqual(output.status_code, 409)
  1331. exp = {"code": "CONFLICTS", "message": "git error"}
  1332. js_data = json.loads(output.get_data(as_text=True))
  1333. self.assertDictEqual(js_data, exp)
  1334. def test_get_branches_of_commit(self):
  1335. """ Test the get_branches_of_commit from the internal API. """
  1336. tests.create_projects(self.session)
  1337. tests.create_projects_git(os.path.join(self.path, "repos"))
  1338. user = tests.FakeUser()
  1339. user.username = "pingou"
  1340. with tests.user_set(self.app.application, user):
  1341. output = self.app.get("/test/adduser")
  1342. self.assertEqual(output.status_code, 200)
  1343. csrf_token = (
  1344. output.get_data(as_text=True)
  1345. .split('name="csrf_token" type="hidden" value="')[1]
  1346. .split('">')[0]
  1347. )
  1348. # No CSRF token
  1349. data = {"repo": "fakerepo", "commit_id": "foo"}
  1350. output = self.app.post("/pv/branches/commit/", data=data)
  1351. self.assertEqual(output.status_code, 400)
  1352. js_data = json.loads(output.get_data(as_text=True))
  1353. self.assertDictEqual(
  1354. js_data, {"code": "ERROR", "message": "Invalid input submitted"}
  1355. )
  1356. # Invalid repo
  1357. data = {
  1358. "repo": "fakerepo",
  1359. "commit_id": "foo",
  1360. "csrf_token": csrf_token,
  1361. }
  1362. output = self.app.post("/pv/branches/commit/", data=data)
  1363. self.assertEqual(output.status_code, 404)
  1364. js_data = json.loads(output.get_data(as_text=True))
  1365. self.assertDictEqual(
  1366. js_data,
  1367. {
  1368. "code": "ERROR",
  1369. "message": "No repo found with the information provided",
  1370. },
  1371. )
  1372. # Rigth repo, no commit
  1373. data = {"repo": "test", "csrf_token": csrf_token}
  1374. output = self.app.post("/pv/branches/commit/", data=data)
  1375. self.assertEqual(output.status_code, 400)
  1376. js_data = json.loads(output.get_data(as_text=True))
  1377. self.assertDictEqual(
  1378. js_data, {"code": "ERROR", "message": "No commit id submitted"}
  1379. )
  1380. # Request is fine, but git repo doesn't exist
  1381. item = pagure.lib.model.Project(
  1382. user_id=1, # pingou
  1383. name="test20",
  1384. description="test project #20",
  1385. hook_token="aaabbbhhh",
  1386. )
  1387. self.session.add(item)
  1388. self.session.commit()
  1389. data = {"repo": "test20", "commit_id": "foo", "csrf_token": csrf_token}
  1390. output = self.app.post("/pv/branches/commit/", data=data)
  1391. self.assertEqual(output.status_code, 404)
  1392. js_data = json.loads(output.get_data(as_text=True))
  1393. self.assertDictEqual(
  1394. js_data,
  1395. {
  1396. "code": "ERROR",
  1397. "message": "No git repo found with the information provided",
  1398. },
  1399. )
  1400. # Create a git repo to play with
  1401. gitrepo = os.path.join(self.path, "repos", "test.git")
  1402. self.assertTrue(os.path.exists(gitrepo))
  1403. repo = pygit2.Repository(gitrepo)
  1404. # Create a file in that git repo
  1405. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1406. stream.write("foo\n bar")
  1407. repo.index.add("sources")
  1408. repo.index.write()
  1409. # Commits the files added
  1410. tree = repo.index.write_tree()
  1411. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1412. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1413. repo.create_commit(
  1414. "refs/heads/master", # the name of the reference to update
  1415. author,
  1416. committer,
  1417. "Add sources file for testing",
  1418. # binary string representing the tree object ID
  1419. tree,
  1420. # list of binary strings representing parents of the new commit
  1421. [],
  1422. )
  1423. first_commit = repo.revparse_single("HEAD")
  1424. # Edit the sources file again
  1425. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1426. stream.write("foo\n bar\nbaz\n boose")
  1427. repo.index.add("sources")
  1428. repo.index.write()
  1429. # Commits the files added
  1430. tree = repo.index.write_tree()
  1431. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1432. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1433. repo.create_commit(
  1434. "refs/heads/feature", # the name of the reference to update
  1435. author,
  1436. committer,
  1437. "Add baz and boose to the sources\n\n There are more objects to "
  1438. "consider",
  1439. # binary string representing the tree object ID
  1440. tree,
  1441. # list of binary strings representing parents of the new commit
  1442. [first_commit.oid.hex],
  1443. )
  1444. # Create another file in the master branch
  1445. with open(os.path.join(gitrepo, ".gitignore"), "w") as stream:
  1446. stream.write("*~")
  1447. repo.index.add(".gitignore")
  1448. repo.index.write()
  1449. # Commits the files added
  1450. tree = repo.index.write_tree()
  1451. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1452. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1453. commit_hash = repo.create_commit(
  1454. "refs/heads/feature_branch", # the name of the reference to update
  1455. author,
  1456. committer,
  1457. "Add .gitignore file for testing",
  1458. # binary string representing the tree object ID
  1459. tree,
  1460. # list of binary strings representing parents of the new commit
  1461. [first_commit.oid.hex],
  1462. )
  1463. # All good but the commit id
  1464. data = {"repo": "test", "commit_id": "foo", "csrf_token": csrf_token}
  1465. output = self.app.post("/pv/branches/commit/", data=data)
  1466. self.assertEqual(output.status_code, 404)
  1467. js_data = json.loads(output.get_data(as_text=True))
  1468. self.assertDictEqual(
  1469. js_data,
  1470. {
  1471. "code": "ERROR",
  1472. "message": "This commit could not be found in this repo",
  1473. },
  1474. )
  1475. # All good
  1476. data = {
  1477. "repo": "test",
  1478. "commit_id": commit_hash,
  1479. "csrf_token": csrf_token,
  1480. }
  1481. output = self.app.post("/pv/branches/commit/", data=data)
  1482. self.assertEqual(output.status_code, 200)
  1483. js_data = json.loads(output.get_data(as_text=True))
  1484. self.assertDictEqual(
  1485. js_data, {"code": "OK", "branches": ["feature_branch"]}
  1486. )
  1487. def test_get_branches_of_commit_with_unrelated_branches(self):
  1488. """ Test the get_branches_of_commit from the internal API. """
  1489. tests.create_projects(self.session)
  1490. tests.create_projects_git(os.path.join(self.path, "repos"))
  1491. user = tests.FakeUser(username="pingou")
  1492. with tests.user_set(self.app.application, user):
  1493. csrf_token = self.get_csrf()
  1494. # Create a git repo to play with
  1495. gitrepo = os.path.join(self.path, "repos", "test.git")
  1496. self.assertTrue(os.path.exists(gitrepo))
  1497. repo = pygit2.Repository(gitrepo)
  1498. # Create a file in that git repo
  1499. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1500. stream.write("foo\n bar")
  1501. repo.index.add("sources")
  1502. repo.index.write()
  1503. # Commits the files added
  1504. tree = repo.index.write_tree()
  1505. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1506. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1507. repo.create_commit(
  1508. "refs/heads/master", # the name of the reference to update
  1509. author,
  1510. committer,
  1511. "Add sources file for testing",
  1512. # binary string representing the tree object ID
  1513. tree,
  1514. # list of binary strings representing parents of the new commit
  1515. [],
  1516. )
  1517. first_commit = repo.revparse_single("HEAD")
  1518. # Edit the sources file again
  1519. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1520. stream.write("foo\n bar\nbaz\n boose")
  1521. repo.index.add("sources")
  1522. repo.index.write()
  1523. # Commits the files added, but unrelated with the first commit
  1524. tree = repo.index.write_tree()
  1525. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1526. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1527. commit = repo.create_commit(
  1528. "refs/heads/feature", # the name of the reference to update
  1529. author,
  1530. committer,
  1531. "Add baz and boose to the sources\n\n There are more objects to "
  1532. "consider",
  1533. # binary string representing the tree object ID
  1534. tree,
  1535. # list of binary strings representing parents of the new commit
  1536. [],
  1537. )
  1538. commit_hash = commit.hex
  1539. # All good
  1540. data = {
  1541. "repo": "test",
  1542. "commit_id": commit_hash,
  1543. "csrf_token": csrf_token,
  1544. }
  1545. output = self.app.post("/pv/branches/commit/", data=data)
  1546. self.assertEqual(output.status_code, 200)
  1547. js_data = json.loads(output.get_data(as_text=True))
  1548. self.assertDictEqual(js_data, {"code": "OK", "branches": ["feature"]})
  1549. def test_get_branches_head(self):
  1550. """ Test the get_branches_head from the internal API. """
  1551. tests.create_projects(self.session)
  1552. tests.create_projects_git(os.path.join(self.path, "repos"))
  1553. user = tests.FakeUser()
  1554. user.username = "pingou"
  1555. with tests.user_set(self.app.application, user):
  1556. csrf_token = self.get_csrf()
  1557. # No CSRF token
  1558. data = {"repo": "fakerepo"}
  1559. output = self.app.post("/pv/branches/heads/", data=data)
  1560. self.assertEqual(output.status_code, 400)
  1561. js_data = json.loads(output.get_data(as_text=True))
  1562. self.assertDictEqual(
  1563. js_data, {"code": "ERROR", "message": "Invalid input submitted"}
  1564. )
  1565. # Invalid repo
  1566. data = {
  1567. "repo": "fakerepo",
  1568. "commit_id": "foo",
  1569. "csrf_token": csrf_token,
  1570. }
  1571. output = self.app.post("/pv/branches/heads/", data=data)
  1572. self.assertEqual(output.status_code, 404)
  1573. js_data = json.loads(output.get_data(as_text=True))
  1574. self.assertDictEqual(
  1575. js_data,
  1576. {
  1577. "code": "ERROR",
  1578. "message": "No repo found with the information provided",
  1579. },
  1580. )
  1581. # Rigth repo, no commit
  1582. data = {"repo": "test", "csrf_token": csrf_token}
  1583. output = self.app.post("/pv/branches/heads/", data=data)
  1584. self.assertEqual(output.status_code, 200)
  1585. js_data = json.loads(output.get_data(as_text=True))
  1586. self.assertDictEqual(
  1587. js_data, {"branches": {}, "code": "OK", "heads": {}}
  1588. )
  1589. # Request is fine, but git repo doesn't exist
  1590. item = pagure.lib.model.Project(
  1591. user_id=1, # pingou
  1592. name="test20",
  1593. description="test project #20",
  1594. hook_token="aaabbbhhh",
  1595. )
  1596. self.session.add(item)
  1597. self.session.commit()
  1598. data = {"repo": "test20", "csrf_token": csrf_token}
  1599. output = self.app.post("/pv/branches/heads/", data=data)
  1600. self.assertEqual(output.status_code, 404)
  1601. js_data = json.loads(output.get_data(as_text=True))
  1602. self.assertDictEqual(
  1603. js_data,
  1604. {
  1605. "code": "ERROR",
  1606. "message": "No git repo found with the information provided",
  1607. },
  1608. )
  1609. # Create a git repo to play with
  1610. gitrepo = os.path.join(self.path, "repos", "test.git")
  1611. self.assertTrue(os.path.exists(gitrepo))
  1612. repo = pygit2.Repository(gitrepo)
  1613. # Create a file in that git repo
  1614. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1615. stream.write("foo\n bar")
  1616. repo.index.add("sources")
  1617. repo.index.write()
  1618. # Commits the files added
  1619. tree = repo.index.write_tree()
  1620. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1621. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1622. repo.create_commit(
  1623. "refs/heads/master", # the name of the reference to update
  1624. author,
  1625. committer,
  1626. "Add sources file for testing",
  1627. # binary string representing the tree object ID
  1628. tree,
  1629. # list of binary strings representing parents of the new commit
  1630. [],
  1631. )
  1632. first_commit = repo.revparse_single("HEAD")
  1633. # Edit the sources file again
  1634. with open(os.path.join(gitrepo, "sources"), "w") as stream:
  1635. stream.write("foo\n bar\nbaz\n boose")
  1636. repo.index.add("sources")
  1637. repo.index.write()
  1638. # Commits the files added
  1639. tree = repo.index.write_tree()
  1640. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1641. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1642. repo.create_commit(
  1643. "refs/heads/feature", # the name of the reference to update
  1644. author,
  1645. committer,
  1646. "Add baz and boose to the sources\n\n There are more objects to "
  1647. "consider",
  1648. # binary string representing the tree object ID
  1649. tree,
  1650. # list of binary strings representing parents of the new commit
  1651. [first_commit.oid.hex],
  1652. )
  1653. # Create another file in the master branch
  1654. with open(os.path.join(gitrepo, ".gitignore"), "w") as stream:
  1655. stream.write("*~")
  1656. repo.index.add(".gitignore")
  1657. repo.index.write()
  1658. # Commits the files added
  1659. tree = repo.index.write_tree()
  1660. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1661. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1662. commit_hash = repo.create_commit(
  1663. "refs/heads/feature_branch", # the name of the reference to update
  1664. author,
  1665. committer,
  1666. "Add .gitignore file for testing",
  1667. # binary string representing the tree object ID
  1668. tree,
  1669. # list of binary strings representing parents of the new commit
  1670. [first_commit.oid.hex],
  1671. )
  1672. # All good
  1673. data = {"repo": "test", "csrf_token": csrf_token}
  1674. output = self.app.post("/pv/branches/heads/", data=data)
  1675. self.assertEqual(output.status_code, 200)
  1676. js_data = json.loads(output.get_data(as_text=True))
  1677. # We can't test the content since the commit hash will change all
  1678. # the time, so let's just check the structure
  1679. self.assertEqual(sorted(js_data.keys()), ["branches", "code", "heads"])
  1680. self.assertEqual(js_data["code"], "OK")
  1681. self.assertEqual(len(js_data["heads"]), 3)
  1682. self.assertEqual(len(js_data["branches"]), 3)
  1683. def test_get_stats_commits_no_token(self):
  1684. """ Test the get_stats_commits from the internal API. """
  1685. # No CSRF token
  1686. data = {"repo": "fakerepo"}
  1687. output = self.app.post("/pv/stats/commits/authors", data=data)
  1688. self.assertEqual(output.status_code, 400)
  1689. js_data = json.loads(output.get_data(as_text=True))
  1690. self.assertDictEqual(
  1691. js_data, {"code": "ERROR", "message": "Invalid input submitted"}
  1692. )
  1693. def test_get_stats_commits_invalid_repo(self):
  1694. """ Test the get_stats_commits from the internal API. """
  1695. user = tests.FakeUser()
  1696. user.username = "pingou"
  1697. with tests.user_set(self.app.application, user):
  1698. csrf_token = self.get_csrf()
  1699. # Invalid repo
  1700. data = {"repo": "fakerepo", "csrf_token": csrf_token}
  1701. output = self.app.post("/pv/stats/commits/authors", data=data)
  1702. self.assertEqual(output.status_code, 404)
  1703. js_data = json.loads(output.get_data(as_text=True))
  1704. self.assertDictEqual(
  1705. js_data,
  1706. {
  1707. "code": "ERROR",
  1708. "message": "No repo found with the information provided",
  1709. },
  1710. )
  1711. def test_get_stats_commits_empty_git(self):
  1712. """ Test the get_stats_commits from the internal API. """
  1713. tests.create_projects(self.session)
  1714. tests.create_projects_git(os.path.join(self.path, "repos"))
  1715. user = tests.FakeUser()
  1716. user.username = "pingou"
  1717. with tests.user_set(self.app.application, user):
  1718. csrf_token = self.get_csrf()
  1719. # No content in git
  1720. data = {"repo": "test", "csrf_token": csrf_token}
  1721. output = self.app.post("/pv/stats/commits/authors", data=data)
  1722. self.assertEqual(output.status_code, 200)
  1723. js_data = json.loads(output.get_data(as_text=True))
  1724. self.assertEqual(
  1725. sorted(js_data.keys()), ["code", "message", "task_id", "url"]
  1726. )
  1727. self.assertEqual(js_data["code"], "OK")
  1728. self.assertEqual(js_data["message"], "Stats asked")
  1729. self.assertTrue(js_data["url"].startswith("/pv/task/"))
  1730. output = self.app.get(js_data["url"])
  1731. js_data2 = json.loads(output.get_data(as_text=True))
  1732. self.assertTrue(
  1733. js_data2
  1734. in [
  1735. {"results": "reference 'refs/heads/master' not found"},
  1736. {"results": "Reference 'refs/heads/master' not found"},
  1737. ]
  1738. )
  1739. def test_get_stats_commits_git_populated(self):
  1740. """ Test the get_stats_commits from the internal API. """
  1741. tests.create_projects(self.session)
  1742. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1743. tests.add_content_git_repo(
  1744. os.path.join(self.path, "repos", "test.git")
  1745. )
  1746. user = tests.FakeUser()
  1747. user.username = "pingou"
  1748. with tests.user_set(self.app.application, user):
  1749. csrf_token = self.get_csrf()
  1750. # Content in git
  1751. data = {"repo": "test", "csrf_token": csrf_token}
  1752. output = self.app.post("/pv/stats/commits/authors", data=data)
  1753. self.assertEqual(output.status_code, 200)
  1754. js_data = json.loads(output.get_data(as_text=True))
  1755. self.assertEqual(
  1756. sorted(js_data.keys()), ["code", "message", "task_id", "url"]
  1757. )
  1758. self.assertEqual(js_data["code"], "OK")
  1759. self.assertEqual(js_data["message"], "Stats asked")
  1760. self.assertTrue(js_data["url"].startswith("/pv/task/"))
  1761. output = self.app.get(js_data["url"])
  1762. while output.status_code == 418:
  1763. output = self.app.get(js_data["url"])
  1764. js_data2 = json.loads(output.get_data(as_text=True))
  1765. self.assertTrue(js_data2["results"][3] > 1509110062)
  1766. js_data2["results"][3] = 1509110062
  1767. self.assertTrue(
  1768. js_data2
  1769. in [
  1770. {
  1771. "results": [
  1772. 2,
  1773. [
  1774. [
  1775. 2,
  1776. [
  1777. [
  1778. "Alice Author",
  1779. "alice@authors.tld",
  1780. "https://seccdn.libravatar.org/avatar/"
  1781. "96c52c78570ffc4cfefcdadf5f8e77aeebcb11e07225df11bbf2fce381cdb8bd"
  1782. "?s=32&d=retro",
  1783. ]
  1784. ],
  1785. ]
  1786. ],
  1787. 1,
  1788. 1509110062,
  1789. ]
  1790. },
  1791. {
  1792. "results": [
  1793. 2,
  1794. [
  1795. [
  1796. 2,
  1797. [
  1798. [
  1799. "Alice Author",
  1800. "alice@authors.tld",
  1801. "https://seccdn.libravatar.org/avatar/"
  1802. "96c52c78570ffc4cfefcdadf5f8e77aeebcb11e07225df11bbf2fce381cdb8bd"
  1803. "?d=retro&s=32",
  1804. ]
  1805. ],
  1806. ]
  1807. ],
  1808. 1,
  1809. 1509110062,
  1810. ]
  1811. },
  1812. ]
  1813. )
  1814. def test_get_stats_commits_trend_no_token(self):
  1815. """ Test the get_stats_commits_trend from the internal API. """
  1816. # No CSRF token
  1817. data = {"repo": "fakerepo"}
  1818. output = self.app.post("/pv/stats/commits/trend", data=data)
  1819. self.assertEqual(output.status_code, 400)
  1820. js_data = json.loads(output.get_data(as_text=True))
  1821. self.assertDictEqual(
  1822. js_data, {"code": "ERROR", "message": "Invalid input submitted"}
  1823. )
  1824. def test_get_stats_commits_trend_invalid_repo(self):
  1825. """ Test the get_stats_commits_trend from the internal API. """
  1826. user = tests.FakeUser()
  1827. user.username = "pingou"
  1828. with tests.user_set(self.app.application, user):
  1829. csrf_token = self.get_csrf()
  1830. # Invalid repo
  1831. data = {"repo": "fakerepo", "csrf_token": csrf_token}
  1832. output = self.app.post("/pv/stats/commits/trend", data=data)
  1833. self.assertEqual(output.status_code, 404)
  1834. js_data = json.loads(output.get_data(as_text=True))
  1835. self.assertDictEqual(
  1836. js_data,
  1837. {
  1838. "code": "ERROR",
  1839. "message": "No repo found with the information provided",
  1840. },
  1841. )
  1842. def test_get_stats_commits_trend_empty_git(self):
  1843. """ Test the get_stats_commits_trend from the internal API. """
  1844. tests.create_projects(self.session)
  1845. tests.create_projects_git(os.path.join(self.path, "repos"))
  1846. user = tests.FakeUser()
  1847. user.username = "pingou"
  1848. with tests.user_set(self.app.application, user):
  1849. csrf_token = self.get_csrf()
  1850. # No content in git
  1851. data = {"repo": "test", "csrf_token": csrf_token}
  1852. output = self.app.post("/pv/stats/commits/trend", data=data)
  1853. self.assertEqual(output.status_code, 200)
  1854. js_data = json.loads(output.get_data(as_text=True))
  1855. self.assertEqual(
  1856. sorted(js_data.keys()), ["code", "message", "task_id", "url"]
  1857. )
  1858. self.assertEqual(js_data["code"], "OK")
  1859. self.assertEqual(js_data["message"], "Stats asked")
  1860. self.assertTrue(js_data["url"].startswith("/pv/task/"))
  1861. output = self.app.get(js_data["url"])
  1862. js_data2 = json.loads(output.get_data(as_text=True))
  1863. self.assertTrue(
  1864. js_data2
  1865. in [
  1866. {"results": "reference 'refs/heads/master' not found"},
  1867. {"results": "Reference 'refs/heads/master' not found"},
  1868. ]
  1869. )
  1870. def test_get_stats_commits_trend_git_populated(self):
  1871. """ Test the get_stats_commits_trend from the internal API. """
  1872. tests.create_projects(self.session)
  1873. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1874. tests.add_content_git_repo(
  1875. os.path.join(self.path, "repos", "test.git")
  1876. )
  1877. user = tests.FakeUser()
  1878. user.username = "pingou"
  1879. with tests.user_set(self.app.application, user):
  1880. csrf_token = self.get_csrf()
  1881. # Content in git
  1882. data = {"repo": "test", "csrf_token": csrf_token}
  1883. output = self.app.post("/pv/stats/commits/trend", data=data)
  1884. self.assertEqual(output.status_code, 200)
  1885. js_data = json.loads(output.get_data(as_text=True))
  1886. self.assertEqual(
  1887. sorted(js_data.keys()), ["code", "message", "task_id", "url"]
  1888. )
  1889. self.assertEqual(js_data["code"], "OK")
  1890. self.assertEqual(js_data["message"], "Stats asked")
  1891. self.assertTrue(js_data["url"].startswith("/pv/task/"))
  1892. output = self.app.get(js_data["url"])
  1893. js_data2 = json.loads(output.get_data(as_text=True))
  1894. today = datetime.datetime.utcnow().date()
  1895. self.assertDictEqual(js_data2, {"results": [[str(today), 2]]})
  1896. def test_get_project_family_no_project(self):
  1897. """ Test the get_project_family from the internal API. """
  1898. output = self.app.post("/pv/test/family")
  1899. self.assertEqual(output.status_code, 404)
  1900. def test_get_project_family_no_csrf(self):
  1901. """ Test the get_project_family from the internal API. """
  1902. tests.create_projects(self.session)
  1903. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1904. tests.add_content_git_repo(
  1905. os.path.join(self.path, "repos", "test.git")
  1906. )
  1907. output = self.app.post("/pv/test/family")
  1908. self.assertEqual(output.status_code, 400)
  1909. js_data = json.loads(output.get_data(as_text=True))
  1910. self.assertEqual(sorted(js_data.keys()), ["code", "message"])
  1911. self.assertEqual(js_data["code"], "ERROR")
  1912. self.assertEqual(js_data["message"], "Invalid input submitted")
  1913. def test_get_project_family(self):
  1914. """ Test the get_project_family from the internal API. """
  1915. tests.create_projects(self.session)
  1916. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1917. tests.add_content_git_repo(
  1918. os.path.join(self.path, "repos", "test.git")
  1919. )
  1920. user = tests.FakeUser()
  1921. user.username = "pingou"
  1922. with tests.user_set(self.app.application, user):
  1923. csrf_token = self.get_csrf()
  1924. data = {"csrf_token": csrf_token}
  1925. output = self.app.post("/pv/test/family", data=data)
  1926. self.assertEqual(output.status_code, 200)
  1927. js_data = json.loads(output.get_data(as_text=True))
  1928. self.assertEqual(sorted(js_data.keys()), ["code", "family"])
  1929. self.assertEqual(js_data["code"], "OK")
  1930. self.assertEqual(js_data["family"], ["test"])
  1931. def test_get_project_larger_family(self):
  1932. """ Test the get_project_family from the internal API. """
  1933. tests.create_projects(self.session)
  1934. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1935. # Create a 3rd user
  1936. item = pagure.lib.model.User(
  1937. user="ralph",
  1938. fullname="Ralph bar",
  1939. password="ralph_foo",
  1940. default_email="ralph@bar.com",
  1941. )
  1942. self.session.add(item)
  1943. item = pagure.lib.model.UserEmail(user_id=3, email="ralph@bar.com")
  1944. self.session.add(item)
  1945. self.session.commit()
  1946. # Create a couple of forks of the test project
  1947. item = pagure.lib.model.Project(
  1948. user_id=2, # foo
  1949. name="test",
  1950. is_fork=True,
  1951. parent_id=1, # test
  1952. description="test project #1",
  1953. hook_token="aaabbbcccddd",
  1954. )
  1955. item.close_status = [
  1956. "Invalid",
  1957. "Insufficient data",
  1958. "Fixed",
  1959. "Duplicate",
  1960. ]
  1961. self.session.add(item)
  1962. item = pagure.lib.model.Project(
  1963. user_id=3, # Ralph
  1964. name="test",
  1965. is_fork=True,
  1966. parent_id=1, # test
  1967. description="test project #1",
  1968. hook_token="aaabbbccceee",
  1969. )
  1970. item.close_status = [
  1971. "Invalid",
  1972. "Insufficient data",
  1973. "Fixed",
  1974. "Duplicate",
  1975. ]
  1976. self.session.add(item)
  1977. self.session.commit()
  1978. # Get on with testing
  1979. user = tests.FakeUser()
  1980. user.username = "pingou"
  1981. with tests.user_set(self.app.application, user):
  1982. csrf_token = self.get_csrf()
  1983. data = {"csrf_token": csrf_token}
  1984. output = self.app.post("/pv/test/family", data=data)
  1985. self.assertEqual(output.status_code, 200)
  1986. js_data = json.loads(output.get_data(as_text=True))
  1987. self.assertEqual(sorted(js_data.keys()), ["code", "family"])
  1988. self.assertEqual(js_data["code"], "OK")
  1989. self.assertEqual(
  1990. js_data["family"], ["test", "fork/foo/test", "fork/ralph/test"]
  1991. )
  1992. def test_get_project_larger_family_pr_only(self):
  1993. """ Test the get_project_family from the internal API. """
  1994. tests.create_projects(self.session)
  1995. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1996. # Create a 3rd user
  1997. item = pagure.lib.model.User(
  1998. user="ralph",
  1999. fullname="Ralph bar",
  2000. password="ralph_foo",
  2001. default_email="ralph@bar.com",
  2002. )
  2003. self.session.add(item)
  2004. item = pagure.lib.model.UserEmail(user_id=3, email="ralph@bar.com")
  2005. self.session.add(item)
  2006. self.session.commit()
  2007. # Create a couple of forks of the test project
  2008. item = pagure.lib.model.Project(
  2009. user_id=2, # foo
  2010. name="test",
  2011. is_fork=True,
  2012. parent_id=1, # test
  2013. description="test project #1",
  2014. hook_token="aaabbbcccddd",
  2015. )
  2016. item.close_status = [
  2017. "Invalid",
  2018. "Insufficient data",
  2019. "Fixed",
  2020. "Duplicate",
  2021. ]
  2022. # disable issues in this fork
  2023. default_repo_settings = item.settings
  2024. default_repo_settings["issue_tracker"] = False
  2025. item.settings = default_repo_settings
  2026. self.session.add(item)
  2027. item = pagure.lib.model.Project(
  2028. user_id=3, # Ralph
  2029. name="test",
  2030. is_fork=True,
  2031. parent_id=1, # test
  2032. description="test project #1",
  2033. hook_token="aaabbbccceee",
  2034. )
  2035. item.close_status = [
  2036. "Invalid",
  2037. "Insufficient data",
  2038. "Fixed",
  2039. "Duplicate",
  2040. ]
  2041. # disable PRs in this fork
  2042. default_repo_settings = item.settings
  2043. default_repo_settings["pull_requests"] = False
  2044. item.settings = default_repo_settings
  2045. self.session.add(item)
  2046. self.session.commit()
  2047. # Get on with testing
  2048. user = tests.FakeUser()
  2049. user.username = "pingou"
  2050. with tests.user_set(self.app.application, user):
  2051. csrf_token = self.get_csrf()
  2052. data = {"csrf_token": csrf_token, "allows_pr": "1"}
  2053. output = self.app.post("/pv/test/family", data=data)
  2054. self.assertEqual(output.status_code, 200)
  2055. js_data = json.loads(output.get_data(as_text=True))
  2056. self.assertEqual(sorted(js_data.keys()), ["code", "family"])
  2057. self.assertEqual(js_data["code"], "OK")
  2058. self.assertEqual(js_data["family"], ["test", "fork/foo/test"])
  2059. data = {"csrf_token": csrf_token, "allows_issues": "1"}
  2060. output = self.app.post("/pv/test/family", data=data)
  2061. self.assertEqual(output.status_code, 200)
  2062. js_data = json.loads(output.get_data(as_text=True))
  2063. self.assertEqual(sorted(js_data.keys()), ["code", "family"])
  2064. self.assertEqual(js_data["code"], "OK")
  2065. self.assertEqual(js_data["family"], ["test", "fork/ralph/test"])
  2066. def test_get_pull_request_ready_branch_no_csrf(self):
  2067. """Test the get_pull_request_ready_branch from the internal API
  2068. on the main repository
  2069. """
  2070. tests.create_projects(self.session)
  2071. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2072. # Query branches on the main repo
  2073. data = {"repo": "test"}
  2074. output = self.app.post("/pv/pull-request/ready", data=data)
  2075. self.assertEqual(output.status_code, 400)
  2076. js_data = json.loads(output.get_data(as_text=True))
  2077. self.assertEqual(sorted(js_data.keys()), ["code", "message"])
  2078. self.assertEqual(js_data["code"], "ERROR")
  2079. self.assertEqual(js_data["message"], "Invalid input submitted")
  2080. def test_get_pull_request_ready_branch_no_repo(self):
  2081. """Test the get_pull_request_ready_branch from the internal API
  2082. on the main repository
  2083. """
  2084. with tests.user_set(self.app.application, tests.FakeUser()):
  2085. csrf_token = self.get_csrf()
  2086. # Query branches on an invalid repo
  2087. data = {"repo": "test", "namespace": "fake", "csrf_token": csrf_token}
  2088. output = self.app.post("/pv/pull-request/ready", data=data)
  2089. self.assertEqual(output.status_code, 404)
  2090. js_data = json.loads(output.get_data(as_text=True))
  2091. self.assertEqual(sorted(js_data.keys()), ["code", "message"])
  2092. self.assertEqual(js_data["code"], "ERROR")
  2093. self.assertEqual(
  2094. js_data["message"], "No repo found with the information provided"
  2095. )
  2096. def test_get_pull_request_ready_branch_main_repo_no_branch(self):
  2097. """Test the get_pull_request_ready_branch from the internal API
  2098. on the main repository
  2099. """
  2100. tests.create_projects(self.session)
  2101. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2102. # Get on with testing
  2103. user = tests.FakeUser()
  2104. user.username = "pingou"
  2105. with tests.user_set(self.app.application, user):
  2106. csrf_token = self.get_csrf()
  2107. # Query branches on the main repo
  2108. data = {"csrf_token": csrf_token, "repo": "test"}
  2109. output = self.app.post("/pv/pull-request/ready", data=data)
  2110. self.assertEqual(output.status_code, 200)
  2111. js_data = json.loads(output.get_data(as_text=True))
  2112. self.assertEqual(sorted(js_data.keys()), ["code", "task"])
  2113. self.assertEqual(js_data["code"], "OK")
  2114. def test_get_pull_request_ready_branch_on_fork(self):
  2115. """Test the get_pull_request_ready_branch from the internal API on
  2116. a fork
  2117. """
  2118. tests.create_projects(self.session)
  2119. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2120. tests.create_projects_git(
  2121. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  2122. )
  2123. tests.add_content_git_repo(
  2124. os.path.join(self.path, "repos", "forks", "foo", "test.git"),
  2125. branch="feature",
  2126. )
  2127. # Create foo's fork of the test project
  2128. item = pagure.lib.model.Project(
  2129. user_id=2, # foo
  2130. name="test",
  2131. is_fork=True,
  2132. parent_id=1, # test
  2133. description="test project #1",
  2134. hook_token="aaabbbcccddd",
  2135. )
  2136. item.close_status = [
  2137. "Invalid",
  2138. "Insufficient data",
  2139. "Fixed",
  2140. "Duplicate",
  2141. ]
  2142. self.session.add(item)
  2143. self.session.commit()
  2144. # Get on with testing
  2145. user = tests.FakeUser()
  2146. user.username = "pingou"
  2147. with tests.user_set(self.app.application, user):
  2148. csrf_token = self.get_csrf()
  2149. # Query branches on the Ralph's fork
  2150. data = {"csrf_token": csrf_token, "repo": "test", "repouser": "foo"}
  2151. output = self.app.post("/pv/pull-request/ready", data=data)
  2152. self.assertEqual(output.status_code, 200)
  2153. js_data = json.loads(output.get_data(as_text=True))
  2154. self.assertEqual(sorted(js_data.keys()), ["code", "task"])
  2155. self.assertEqual(js_data["code"], "OK")
  2156. output = self.app.get("/pv/task/" + js_data["task"])
  2157. self.assertEqual(output.status_code, 200)
  2158. js_data = json.loads(output.get_data(as_text=True))
  2159. self.assertEqual(
  2160. js_data,
  2161. {
  2162. "results": {
  2163. "branch_w_pr": {},
  2164. "new_branch": {
  2165. "feature": {"commits": 2, "target_branch": "master"}
  2166. },
  2167. }
  2168. },
  2169. )
  2170. def test_get_pull_request_ready_branch_on_fork_no_parent_no_pr(self):
  2171. """Test the get_pull_request_ready_branch from the internal API on
  2172. a fork that has no parent repo (deleted) and doesn't allow PR
  2173. """
  2174. tests.create_projects(self.session)
  2175. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2176. tests.create_projects_git(
  2177. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  2178. )
  2179. tests.add_content_git_repo(
  2180. os.path.join(self.path, "repos", "forks", "foo", "test.git"),
  2181. branch="feature",
  2182. )
  2183. # Create foo's fork of the test project
  2184. item = pagure.lib.model.Project(
  2185. user_id=2, # foo
  2186. name="test",
  2187. is_fork=True,
  2188. parent_id=1, # test
  2189. description="test project #1",
  2190. hook_token="aaabbbcccddd",
  2191. )
  2192. item.close_status = [
  2193. "Invalid",
  2194. "Insufficient data",
  2195. "Fixed",
  2196. "Duplicate",
  2197. ]
  2198. self.session.add(item)
  2199. self.session.commit()
  2200. settings = item.settings
  2201. settings["pull_requests"] = False
  2202. item.settings = settings
  2203. self.session.add(item)
  2204. self.session.commit()
  2205. # Delete the parent project
  2206. project = pagure.lib.query.get_authorized_project(self.session, "test")
  2207. self.session.delete(project)
  2208. self.session.commit()
  2209. # Get on with testing
  2210. user = tests.FakeUser()
  2211. user.username = "pingou"
  2212. with tests.user_set(self.app.application, user):
  2213. csrf_token = self.get_csrf()
  2214. # Query branches on the Ralph's fork
  2215. data = {"csrf_token": csrf_token, "repo": "test", "repouser": "foo"}
  2216. output = self.app.post("/pv/pull-request/ready", data=data)
  2217. self.assertEqual(output.status_code, 400)
  2218. js_data = json.loads(output.get_data(as_text=True))
  2219. self.assertEqual(sorted(js_data.keys()), ["code", "message"])
  2220. self.assertEqual(js_data["code"], "ERROR")
  2221. self.assertEqual(
  2222. js_data["message"], "Pull-request have been disabled for this repo"
  2223. )
  2224. def test_get_pull_request_ready_branch_on_fork_no_parent(self):
  2225. """Test the get_pull_request_ready_branch from the internal API on
  2226. a fork that has no parent repo (deleted).
  2227. """
  2228. tests.create_projects(self.session)
  2229. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2230. tests.create_projects_git(
  2231. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  2232. )
  2233. tests.add_content_git_repo(
  2234. os.path.join(self.path, "repos", "forks", "foo", "test.git"),
  2235. branch="feature",
  2236. )
  2237. # Create foo's fork of the test project
  2238. item = pagure.lib.model.Project(
  2239. user_id=2, # foo
  2240. name="test",
  2241. is_fork=True,
  2242. parent_id=1, # test
  2243. description="test project #1",
  2244. hook_token="aaabbbcccddd",
  2245. )
  2246. item.close_status = [
  2247. "Invalid",
  2248. "Insufficient data",
  2249. "Fixed",
  2250. "Duplicate",
  2251. ]
  2252. self.session.add(item)
  2253. self.session.commit()
  2254. settings = item.settings
  2255. settings["pull_requests"] = True
  2256. item.settings = settings
  2257. self.session.add(item)
  2258. self.session.commit()
  2259. # Delete the parent project
  2260. project = pagure.lib.query.get_authorized_project(self.session, "test")
  2261. self.session.delete(project)
  2262. self.session.commit()
  2263. # Get on with testing
  2264. user = tests.FakeUser()
  2265. user.username = "pingou"
  2266. with tests.user_set(self.app.application, user):
  2267. csrf_token = self.get_csrf()
  2268. # Query branches on the Ralph's fork
  2269. data = {"csrf_token": csrf_token, "repo": "test", "repouser": "foo"}
  2270. output = self.app.post("/pv/pull-request/ready", data=data)
  2271. self.assertEqual(output.status_code, 200)
  2272. js_data = json.loads(output.get_data(as_text=True))
  2273. self.assertEqual(sorted(js_data.keys()), ["code", "task"])
  2274. self.assertEqual(js_data["code"], "OK")
  2275. output = self.app.get("/pv/task/" + js_data["task"])
  2276. self.assertEqual(output.status_code, 200)
  2277. js_data = json.loads(output.get_data(as_text=True))
  2278. self.assertEqual(
  2279. js_data,
  2280. {
  2281. "results": {
  2282. "branch_w_pr": {},
  2283. "new_branch": {
  2284. "feature": {"commits": 2, "target_branch": "master"}
  2285. },
  2286. }
  2287. },
  2288. )
  2289. def test_get_pull_request_ready_branch_matching_target_off(self):
  2290. """Test the get_pull_request_ready_branch from the internal API on
  2291. a fork while PR_TARGET_MATCHING_BRANCH is False
  2292. """
  2293. tests.create_projects(self.session)
  2294. # make sure that head is not unborn
  2295. tests.add_content_git_repo(
  2296. os.path.join(self.path, "repos", "test.git"), branch="master"
  2297. )
  2298. tests.add_content_git_repo(
  2299. os.path.join(self.path, "repos", "test.git"), branch="feature"
  2300. )
  2301. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2302. tests.create_projects_git(
  2303. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  2304. )
  2305. tests.add_content_git_repo(
  2306. os.path.join(self.path, "repos", "forks", "foo", "test.git"),
  2307. branch="feature",
  2308. )
  2309. # Create foo's fork of the test project
  2310. item = pagure.lib.model.Project(
  2311. user_id=2, # foo
  2312. name="test",
  2313. is_fork=True,
  2314. parent_id=1, # test
  2315. description="test project #1",
  2316. hook_token="aaabbbcccddd",
  2317. )
  2318. item.close_status = [
  2319. "Invalid",
  2320. "Insufficient data",
  2321. "Fixed",
  2322. "Duplicate",
  2323. ]
  2324. self.session.add(item)
  2325. self.session.commit()
  2326. # Get on with testing
  2327. user = tests.FakeUser()
  2328. user.username = "pingou"
  2329. with tests.user_set(self.app.application, user):
  2330. csrf_token = self.get_csrf()
  2331. # Query branches on the Ralph's fork
  2332. data = {"csrf_token": csrf_token, "repo": "test", "repouser": "foo"}
  2333. output = self.app.post("/pv/pull-request/ready", data=data)
  2334. self.assertEqual(output.status_code, 200)
  2335. js_data = json.loads(output.get_data(as_text=True))
  2336. self.assertEqual(sorted(js_data.keys()), ["code", "task"])
  2337. self.assertEqual(js_data["code"], "OK")
  2338. output = self.app.get("/pv/task/" + js_data["task"])
  2339. self.assertEqual(output.status_code, 200)
  2340. js_data = json.loads(output.get_data(as_text=True))
  2341. self.assertEqual(
  2342. js_data,
  2343. {
  2344. "results": {
  2345. "branch_w_pr": {},
  2346. "new_branch": {
  2347. "feature": {"commits": 2, "target_branch": "master"}
  2348. },
  2349. }
  2350. },
  2351. )
  2352. @patch.dict("pagure.config.config", {"PR_TARGET_MATCHING_BRANCH": True})
  2353. def test_get_pull_request_ready_branch_matching_target_on(self):
  2354. """Test the get_pull_request_ready_branch from the internal API on
  2355. a fork while PR_TARGET_MATCHING_BRANCH is True
  2356. """
  2357. tests.create_projects(self.session)
  2358. # make sure that head is not unborn
  2359. tests.add_content_git_repo(
  2360. os.path.join(self.path, "repos", "test.git"), branch="master"
  2361. )
  2362. tests.add_content_git_repo(
  2363. os.path.join(self.path, "repos", "test.git"), branch="feature"
  2364. )
  2365. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2366. tests.create_projects_git(
  2367. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  2368. )
  2369. tests.add_content_git_repo(
  2370. os.path.join(self.path, "repos", "forks", "foo", "test.git"),
  2371. append="testing from foo's fork",
  2372. branch="feature",
  2373. )
  2374. # Create foo's fork of the test project
  2375. item = pagure.lib.model.Project(
  2376. user_id=2, # foo
  2377. name="test",
  2378. is_fork=True,
  2379. parent_id=1, # test
  2380. description="test project #1",
  2381. hook_token="aaabbbcccddd",
  2382. )
  2383. item.close_status = [
  2384. "Invalid",
  2385. "Insufficient data",
  2386. "Fixed",
  2387. "Duplicate",
  2388. ]
  2389. self.session.add(item)
  2390. self.session.commit()
  2391. # Get on with testing
  2392. user = tests.FakeUser()
  2393. user.username = "pingou"
  2394. with tests.user_set(self.app.application, user):
  2395. csrf_token = self.get_csrf()
  2396. # Query branches on the Ralph's fork
  2397. data = {"csrf_token": csrf_token, "repo": "test", "repouser": "foo"}
  2398. output = self.app.post("/pv/pull-request/ready", data=data)
  2399. self.assertEqual(output.status_code, 200)
  2400. js_data = json.loads(output.get_data(as_text=True))
  2401. self.assertEqual(sorted(js_data.keys()), ["code", "task"])
  2402. self.assertEqual(js_data["code"], "OK")
  2403. output = self.app.get("/pv/task/" + js_data["task"])
  2404. self.assertEqual(output.status_code, 200)
  2405. js_data = json.loads(output.get_data(as_text=True))
  2406. self.assertEqual(
  2407. js_data,
  2408. {
  2409. "results": {
  2410. "branch_w_pr": {},
  2411. "new_branch": {
  2412. "feature": {"commits": 1, "target_branch": "feature"}
  2413. },
  2414. }
  2415. },
  2416. )
  2417. def test_task_info_task_running(self):
  2418. """ Test the task_info internal API endpoint when the task isn't
  2419. ready.
  2420. """
  2421. task = MagicMock()
  2422. task.get = MagicMock(return_value="FAILED")
  2423. task.ready = MagicMock(return_value=False)
  2424. with patch(
  2425. "pagure.lib.tasks.get_result", MagicMock(return_value=task)
  2426. ):
  2427. output = self.app.get("/pv/task/2")
  2428. self.assertEqual(output.status_code, 418)
  2429. def test_task_info_task_passed(self):
  2430. """ Test the task_info internal API endpoint when the task failed.
  2431. """
  2432. task = MagicMock()
  2433. task.get = MagicMock(return_value="PASSED")
  2434. with patch(
  2435. "pagure.lib.tasks.get_result", MagicMock(return_value=task)
  2436. ):
  2437. output = self.app.get("/pv/task/2")
  2438. self.assertEqual(output.status_code, 200)
  2439. js_data = json.loads(output.get_data(as_text=True))
  2440. self.assertEqual(js_data, {"results": "PASSED"})
  2441. def test_task_info_task_failed(self):
  2442. """ Test the task_info internal API endpoint when the task failed.
  2443. """
  2444. task = MagicMock()
  2445. task.get = MagicMock(return_value=Exception("Random error"))
  2446. with patch(
  2447. "pagure.lib.tasks.get_result", MagicMock(return_value=task)
  2448. ):
  2449. output = self.app.get("/pv/task/2")
  2450. self.assertEqual(output.status_code, 200)
  2451. js_data = json.loads(output.get_data(as_text=True))
  2452. self.assertEqual(js_data, {"results": "Random error"})
  2453. def test_lookup_ssh_key(self):
  2454. """ Test the mergeable_request_pull endpoint when the backend
  2455. raises an GitError exception.
  2456. """
  2457. tests.create_projects(self.session)
  2458. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2459. project_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC4zmifEL8TLLZUZnjAuVL8495DAkpAAM2eBhwHwawBm"
  2460. project_key_fp = "SHA256:ZSUQAqpPDWi90Fs6Ow8Epc8F3qiKVfU+H5ssvo7jiI0"
  2461. pingou = pagure.lib.query.get_user(self.session, "pingou")
  2462. user_key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDTsfdTcXw4rlU1aQwOTbLOXqossLwpPIk27S/G17kUz"
  2463. user_key_fp = "SHA256:jUJHzrq2Ct6Ubf7Y9rnB6tGnbHM9dMVsveyfPojm+i0"
  2464. pagure.lib.query.add_sshkey_to_project_or_user(
  2465. self.session,
  2466. user_key,
  2467. pushaccess=True,
  2468. creator=pingou,
  2469. user=pingou,
  2470. )
  2471. pagure.lib.query.add_sshkey_to_project_or_user(
  2472. self.session,
  2473. project_key,
  2474. pushaccess=True,
  2475. creator=pingou,
  2476. project=repo,
  2477. )
  2478. self.session.commit()
  2479. url = "/pv/ssh/lookupkey/"
  2480. output = self.app.post(url, data={"search_key": "asdf"})
  2481. self.assertEqual(output.status_code, 200)
  2482. result = json.loads(output.get_data(as_text=True))
  2483. self.assertEqual(result["found"], False)
  2484. output = self.app.post(url, data={"search_key": user_key_fp})
  2485. self.assertEqual(output.status_code, 200)
  2486. result = json.loads(output.get_data(as_text=True))
  2487. self.assertEqual(result["found"], True)
  2488. self.assertEqual(result["username"], "pingou")
  2489. self.assertEqual(result["public_key"], user_key)
  2490. output = self.app.post(
  2491. url, data={"search_key": user_key_fp, "username": "pingou"}
  2492. )
  2493. self.assertEqual(output.status_code, 200)
  2494. result = json.loads(output.get_data(as_text=True))
  2495. self.assertEqual(result["found"], True)
  2496. self.assertEqual(result["username"], "pingou")
  2497. self.assertEqual(result["public_key"], user_key)
  2498. output = self.app.post(
  2499. url, data={"search_key": user_key_fp, "username": "foo"}
  2500. )
  2501. self.assertEqual(output.status_code, 200)
  2502. result = json.loads(output.get_data(as_text=True))
  2503. self.assertEqual(result["found"], False)
  2504. output = self.app.post(url, data={"search_key": project_key_fp})
  2505. self.assertEqual(output.status_code, 200)
  2506. result = json.loads(output.get_data(as_text=True))
  2507. self.assertEqual(result["found"], True)
  2508. self.assertEqual(result["username"], "deploykey_test_2")
  2509. self.assertEqual(result["public_key"], project_key)
  2510. @patch.dict(
  2511. "pagure.config.config",
  2512. {"REPOSPANNER_REGIONS": {"region": {"repo_prefix": "prefix"}}},
  2513. )
  2514. def test_check_ssh_access(self):
  2515. """ Test the SSH access check endpoint. """
  2516. tests.create_projects(self.session)
  2517. self.session.query(pagure.lib.model.Project).filter(
  2518. pagure.lib.model.Project.name == "test2"
  2519. ).update({pagure.lib.model.Project.repospanner_region: "region"})
  2520. self.session.commit()
  2521. url = "/pv/ssh/checkaccess/"
  2522. def runtest(project, username, access):
  2523. output = self.app.post(
  2524. url, data={"gitdir": project, "username": username}
  2525. )
  2526. self.assertEqual(output.status_code, 200)
  2527. result = json.loads(output.get_data(as_text=True))
  2528. self.assertEqual(result["access"], access)
  2529. return result
  2530. runtest("project.git", "pingou", False)
  2531. i1 = runtest("test.git", "pingou", True)
  2532. i2 = runtest("test.git", "foo", True)
  2533. i3 = runtest("tickets/test.git", "pingou", True)
  2534. i4 = runtest("test2.git", "pingou", True)
  2535. runtest("tickets/test.git", "foo", False)
  2536. self.assertEqual(i1["reponame"], "test.git")
  2537. self.assertEqual(i1["repospanner_reponame"], None)
  2538. self.assertEqual(i1["repotype"], "main")
  2539. self.assertEqual(i1["region"], None)
  2540. self.assertEqual(i1["project_name"], "test")
  2541. self.assertEqual(i1["project_user"], None)
  2542. self.assertEqual(i1["project_namespace"], None)
  2543. self.assertEqual(i1, i2)
  2544. self.assertEqual(i3["reponame"], "tickets/test.git")
  2545. self.assertEqual(i3["repospanner_reponame"], None)
  2546. self.assertEqual(i3["repotype"], "tickets")
  2547. self.assertEqual(i3["region"], None)
  2548. self.assertEqual(i3["project_name"], "test")
  2549. self.assertEqual(i3["project_user"], None)
  2550. self.assertEqual(i3["project_namespace"], None)
  2551. self.assertEqual(i4["repospanner_reponame"], "prefix/main/test2")
  2552. self.assertEqual(i4["region"], "region")
  2553. if __name__ == "__main__":
  2554. unittest.main(verbosity=2)