1
0

test_pagure_flask_internal.py 108 KB

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