test_pagure_flask_ui_fork.py 133 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562
  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
  8. __requires__ = ['SQLAlchemy >= 0.8']
  9. import pkg_resources
  10. import json
  11. import unittest
  12. import shutil
  13. import sys
  14. import tempfile
  15. import time
  16. import os
  17. import re
  18. import pygit2
  19. import six
  20. from mock import patch, MagicMock
  21. from bs4 import BeautifulSoup
  22. from datetime import datetime, timedelta
  23. sys.path.insert(0, os.path.join(os.path.dirname(
  24. os.path.abspath(__file__)), '..'))
  25. import pagure
  26. import pagure.lib
  27. import tests
  28. from pagure.lib.repo import PagureRepo
  29. def _get_commits(output):
  30. ''' Returns the commits message in the output. All commits must have
  31. been made by `Alice Author` or `PY C` to be found.
  32. '''
  33. commits = []
  34. save = False
  35. cnt = 0
  36. for row in output.split('\n'):
  37. if row.strip() in ['Alice Author', 'Alice Äuthòr', 'PY C']:
  38. save = True
  39. if save:
  40. cnt += 1
  41. if cnt == 7:
  42. commits.append(row.strip())
  43. save = False
  44. cnt = 0
  45. return commits
  46. class PagureFlaskForktests(tests.Modeltests):
  47. """ Tests for flask fork controller of pagure """
  48. def set_up_git_repo(
  49. self, new_project=None, branch_from='feature', mtype='FF',
  50. prid=1, name_from='test'):
  51. """ Set up the git repo and create the corresponding PullRequest
  52. object.
  53. """
  54. # Create a git repo to play with
  55. gitrepo = os.path.join(self.path, 'repos', '%s.git' % name_from)
  56. repo = pygit2.init_repository(gitrepo, bare=True)
  57. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  58. repopath = os.path.join(newpath, 'test')
  59. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  60. # Create a file in that git repo
  61. with open(os.path.join(repopath, 'sources'), 'w') as stream:
  62. stream.write('foo\n bar')
  63. clone_repo.index.add('sources')
  64. clone_repo.index.write()
  65. try:
  66. com = repo.revparse_single('HEAD')
  67. prev_commit = [com.oid.hex]
  68. except:
  69. prev_commit = []
  70. # Commits the files added
  71. tree = clone_repo.index.write_tree()
  72. author = pygit2.Signature(
  73. 'Alice Author', 'alice@authors.tld')
  74. committer = pygit2.Signature(
  75. 'Cecil Committer', 'cecil@committers.tld')
  76. clone_repo.create_commit(
  77. 'refs/heads/master', # the name of the reference to update
  78. author,
  79. committer,
  80. 'Add sources file for testing',
  81. # binary string representing the tree object ID
  82. tree,
  83. # list of binary strings representing parents of the new commit
  84. prev_commit
  85. )
  86. time.sleep(1)
  87. refname = 'refs/heads/master:refs/heads/master'
  88. ori_remote = clone_repo.remotes[0]
  89. PagureRepo.push(ori_remote, refname)
  90. first_commit = repo.revparse_single('HEAD')
  91. def compatible_signature(name, email):
  92. if six.PY2:
  93. name = name.encode("utf-8")
  94. email = email.encode("utf-8")
  95. return pygit2.Signature(name, email)
  96. if mtype == 'merge':
  97. with open(os.path.join(repopath, '.gitignore'), 'w') as stream:
  98. stream.write('*~')
  99. clone_repo.index.add('.gitignore')
  100. clone_repo.index.write()
  101. # Commits the files added
  102. tree = clone_repo.index.write_tree()
  103. author = compatible_signature(
  104. 'Alice Äuthòr', 'alice@äuthòrs.tld')
  105. comitter = compatible_signature(
  106. 'Cecil Cõmmîttër', 'cecil@cõmmîttërs.tld')
  107. clone_repo.create_commit(
  108. 'refs/heads/master',
  109. author,
  110. committer,
  111. 'Add .gitignore file for testing',
  112. # binary string representing the tree object ID
  113. tree,
  114. # list of binary strings representing parents of the new commit
  115. [first_commit.oid.hex]
  116. )
  117. refname = 'refs/heads/master:refs/heads/master'
  118. ori_remote = clone_repo.remotes[0]
  119. PagureRepo.push(ori_remote, refname)
  120. if mtype == 'conflicts':
  121. with open(os.path.join(repopath, 'sources'), 'w') as stream:
  122. stream.write('foo\n bar\nbaz')
  123. clone_repo.index.add('sources')
  124. clone_repo.index.write()
  125. # Commits the files added
  126. tree = clone_repo.index.write_tree()
  127. author = pygit2.Signature(
  128. 'Alice Author', 'alice@authors.tld')
  129. committer = pygit2.Signature(
  130. 'Cecil Committer', 'cecil@committers.tld')
  131. clone_repo.create_commit(
  132. 'refs/heads/master',
  133. author,
  134. committer,
  135. 'Add sources conflicting',
  136. # binary string representing the tree object ID
  137. tree,
  138. # list of binary strings representing parents of the new commit
  139. [first_commit.oid.hex]
  140. )
  141. refname = 'refs/heads/master:refs/heads/master'
  142. ori_remote = clone_repo.remotes[0]
  143. PagureRepo.push(ori_remote, refname)
  144. # Set the second repo
  145. new_gitrepo = repopath
  146. if new_project:
  147. # Create a new git repo to play with
  148. new_gitrepo = os.path.join(newpath, new_project.fullname)
  149. if not os.path.exists(new_gitrepo):
  150. os.makedirs(new_gitrepo)
  151. new_repo = pygit2.clone_repository(gitrepo, new_gitrepo)
  152. repo = pygit2.Repository(new_gitrepo)
  153. if mtype != 'nochanges':
  154. # Edit the sources file again
  155. with open(os.path.join(new_gitrepo, 'sources'), 'w') as stream:
  156. stream.write('foo\n bar\nbaz\n boose')
  157. repo.index.add('sources')
  158. repo.index.write()
  159. # Commits the files added
  160. tree = repo.index.write_tree()
  161. author = pygit2.Signature(
  162. 'Alice Author', 'alice@authors.tld')
  163. committer = pygit2.Signature(
  164. 'Cecil Committer', 'cecil@committers.tld')
  165. repo.create_commit(
  166. 'refs/heads/%s' % branch_from,
  167. author,
  168. committer,
  169. 'A commit on branch %s' % branch_from,
  170. tree,
  171. [first_commit.oid.hex]
  172. )
  173. refname = 'refs/heads/%s' % (branch_from)
  174. ori_remote = repo.remotes[0]
  175. PagureRepo.push(ori_remote, refname)
  176. # Create a PR for these changes
  177. project = pagure.lib.get_authorized_project(self.session, 'test')
  178. req = pagure.lib.new_pull_request(
  179. session=self.session,
  180. repo_from=project,
  181. branch_from=branch_from,
  182. repo_to=project,
  183. branch_to='master',
  184. title='PR from the %s branch' % branch_from,
  185. user='pingou',
  186. )
  187. self.session.commit()
  188. self.assertEqual(req.id, prid)
  189. self.assertEqual(req.title, 'PR from the %s branch' % branch_from)
  190. shutil.rmtree(newpath)
  191. def test_request_pull_reference(self):
  192. """ Test if there is a reference created for a new PR. """
  193. tests.create_projects(self.session)
  194. tests.create_projects_git(
  195. os.path.join(self.path, 'requests'), bare=True)
  196. self.set_up_git_repo(new_project=None, branch_from='feature')
  197. project = pagure.lib.get_authorized_project(self.session, 'test')
  198. self.assertEqual(len(project.requests), 1)
  199. # View the pull-request
  200. output = self.app.get('/test/pull-request/1')
  201. self.assertEqual(output.status_code, 200)
  202. # Give time to the worker to process the task
  203. time.sleep(1)
  204. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  205. repo = pygit2.Repository(gitrepo)
  206. self.assertEqual(
  207. list(repo.listall_references()),
  208. ['refs/heads/feature', 'refs/heads/master', 'refs/pull/1/head']
  209. )
  210. @patch('pagure.lib.notify.send_email')
  211. def test_request_pull(self, send_email):
  212. """ Test the request_pull endpoint. """
  213. send_email.return_value = True
  214. tests.create_projects(self.session)
  215. tests.create_projects_git(
  216. os.path.join(self.path, 'requests'), bare=True)
  217. # Non-existant project
  218. output = self.app.get('/foobar/pull-request/1')
  219. self.assertEqual(output.status_code, 404)
  220. # Project has no PR
  221. output = self.app.get('/test/pull-request/1')
  222. self.assertEqual(output.status_code, 404)
  223. self.set_up_git_repo(new_project=None, branch_from='feature')
  224. project = pagure.lib.get_authorized_project(self.session, 'test')
  225. self.assertEqual(len(project.requests), 1)
  226. # View the pull-request
  227. output = self.app.get('/test/pull-request/1')
  228. self.assertEqual(output.status_code, 200)
  229. output_text = output.get_data(as_text=True)
  230. #self.assertIn(
  231. #'<h3><span class="label label-default">PR#1</span>\n'
  232. #' PR from the feature branch\n</h3>',
  233. #output_text)
  234. self.assertIn(
  235. 'title="View file as of 2a552b">sources</a>', output_text)
  236. # Test if the `open changed file icon` is displayed.
  237. self.assertIn(
  238. 'class="open_changed_file_icon_wrap"><span '
  239. 'class="fa fa-file-code-o fa-fw" '
  240. 'alt="Open changed file" title="Open changed file"></span>'
  241. '</a>', output_text)
  242. self.assertIn(
  243. '<span class="btn btn-success btn-sm font-weight-bold disabled opacity-100">+3</span>', output_text)
  244. self.assertIn(
  245. '<span class="btn btn-danger btn-sm font-weight-bold disabled opacity-100">-1</span>',
  246. output_text)
  247. @patch('pagure.lib.notify.send_email')
  248. def test_merge_request_pull_FF(self, send_email):
  249. """ Test the merge_request_pull endpoint with a FF PR. """
  250. send_email.return_value = True
  251. self.test_request_pull()
  252. user = tests.FakeUser()
  253. with tests.user_set(self.app.application, user):
  254. output = self.app.get('/test/pull-request/1')
  255. self.assertEqual(output.status_code, 200)
  256. csrf_token = self.get_csrf(output=output)
  257. # No CSRF
  258. output = self.app.post(
  259. '/test/pull-request/1/merge', data={}, follow_redirects=True)
  260. self.assertEqual(output.status_code, 200)
  261. output_text = output.get_data(as_text=True)
  262. self.assertIn(
  263. '<title>PR#1: PR from the feature branch - test\n - '
  264. 'Pagure</title>', output_text)
  265. #self.assertIn(
  266. #'<h3><span class="label label-default">PR#1</span>\n'
  267. #' PR from the feature branch\n</h3>',
  268. #output_text)
  269. self.assertIn(
  270. 'title="View file as of 2a552b">sources</a>', output_text)
  271. # Wrong project
  272. data = {
  273. 'csrf_token': csrf_token,
  274. }
  275. output = self.app.post(
  276. '/foobar/pull-request/100/merge', data=data, follow_redirects=True)
  277. self.assertEqual(output.status_code, 404)
  278. # Wrong project
  279. data = {
  280. 'csrf_token': csrf_token,
  281. }
  282. output = self.app.post(
  283. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  284. self.assertEqual(output.status_code, 403)
  285. user.username = 'pingou'
  286. with tests.user_set(self.app.application, user):
  287. # Wrong request id
  288. data = {
  289. 'csrf_token': csrf_token,
  290. }
  291. output = self.app.post(
  292. '/test/pull-request/100/merge', data=data, follow_redirects=True)
  293. self.assertEqual(output.status_code, 404)
  294. # Project w/o pull-request
  295. self.session.commit()
  296. repo = pagure.lib.get_authorized_project(self.session, 'test')
  297. settings = repo.settings
  298. settings['pull_requests'] = False
  299. repo.settings = settings
  300. self.session.add(repo)
  301. self.session.commit()
  302. # Pull-request disabled
  303. output = self.app.post(
  304. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  305. self.assertEqual(output.status_code, 404)
  306. # Project w pull-request but only assignee can merge
  307. self.session.commit()
  308. repo = pagure.lib.get_authorized_project(self.session, 'test')
  309. settings['pull_requests'] = True
  310. settings['Only_assignee_can_merge_pull-request'] = True
  311. repo.settings = settings
  312. self.session.add(repo)
  313. self.session.commit()
  314. output = self.app.post(
  315. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  316. self.assertEqual(output.status_code, 200)
  317. output_text = output.get_data(as_text=True)
  318. self.assertIn(
  319. '<title>PR#1: PR from the feature branch - test\n - '
  320. 'Pagure</title>', output_text)
  321. self.assertIn(
  322. '<h4 class="ml-1">\n <div>\n '
  323. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  324. '<span class="text-success '
  325. 'font-weight-bold">#1</span>\n '
  326. '<span class="font-weight-bold">\n '
  327. 'PR from the feature branch\n',
  328. output_text)
  329. self.assertIn(
  330. 'This request must be '
  331. 'assigned to be merged', output_text)
  332. # PR assigned but not to this user
  333. self.session.commit()
  334. repo = pagure.lib.get_authorized_project(self.session, 'test')
  335. req = repo.requests[0]
  336. req.assignee_id = 2
  337. self.session.add(req)
  338. self.session.commit()
  339. output = self.app.post(
  340. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  341. self.assertEqual(output.status_code, 200)
  342. output_text = output.get_data(as_text=True)
  343. self.assertIn(
  344. '<h4 class="ml-1">\n <div>\n '
  345. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  346. '<span class="text-success '
  347. 'font-weight-bold">#1</span>\n '
  348. '<span class="font-weight-bold">\n '
  349. 'PR from the feature branch\n',
  350. output_text)
  351. self.assertIn(
  352. 'Only the assignee can '
  353. 'merge this review', output_text)
  354. # Project w/ minimal PR score
  355. self.session.commit()
  356. repo = pagure.lib.get_authorized_project(self.session, 'test')
  357. settings['Only_assignee_can_merge_pull-request'] = False
  358. settings['Minimum_score_to_merge_pull-request'] = 2
  359. repo.settings = settings
  360. self.session.add(repo)
  361. self.session.commit()
  362. output = self.app.post(
  363. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  364. self.assertEqual(output.status_code, 200)
  365. output_text = output.get_data(as_text=True)
  366. self.assertIn(
  367. '<h4 class="ml-1">\n <div>\n '
  368. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  369. '<span class="text-success '
  370. 'font-weight-bold">#1</span>\n '
  371. '<span class="font-weight-bold">\n '
  372. 'PR from the feature branch\n',
  373. output_text)
  374. self.assertIn(
  375. 'This request does not '
  376. 'have the minimum review score necessary to be merged',
  377. output_text)
  378. # Merge
  379. self.session.commit()
  380. repo = pagure.lib.get_authorized_project(self.session, 'test')
  381. settings['Minimum_score_to_merge_pull-request'] = -1
  382. repo.settings = settings
  383. self.session.add(repo)
  384. self.session.commit()
  385. output = self.app.post(
  386. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  387. self.assertEqual(output.status_code, 200)
  388. output = self.app.get('/test/commits')
  389. output_text = output.get_data(as_text=True)
  390. self.assertIn(
  391. '<title>Commits - test - Pagure</title>', output_text)
  392. self.assertIn(
  393. 'A commit on branch feature', output_text)
  394. self.assertNotIn(
  395. 'Merge #1 `PR from the feature branch`', output_text)
  396. # Check if the closing notification was added
  397. output = self.app.get('/test/pull-request/1')
  398. self.assertIn(
  399. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  400. ' </span>\n by\n'
  401. ' <span title="PY C (pingou)">pingou.</span>\n',
  402. output.get_data(as_text=True))
  403. @patch('pagure.lib.notify.send_email')
  404. def test_merge_request_pull_merge(self, send_email):
  405. """ Test the merge_request_pull endpoint with a merge PR. """
  406. send_email.return_value = True
  407. tests.create_projects(self.session)
  408. tests.create_projects_git(
  409. os.path.join(self.path, 'requests'), bare=True)
  410. self.set_up_git_repo(
  411. new_project=None, branch_from='feature', mtype='merge')
  412. user = tests.FakeUser()
  413. user.username = 'pingou'
  414. with tests.user_set(self.app.application, user):
  415. output = self.app.get('/test/pull-request/1')
  416. self.assertEqual(output.status_code, 200)
  417. csrf_token = self.get_csrf(output=output)
  418. data = {
  419. 'csrf_token': csrf_token,
  420. }
  421. # Merge
  422. output = self.app.post(
  423. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  424. self.assertEqual(output.status_code, 200)
  425. self.assertIn(
  426. '<title>Overview - test - Pagure</title>', output.get_data(as_text=True))
  427. # Check if the closing notification was added
  428. output = self.app.get('/test/pull-request/1')
  429. self.assertIn(
  430. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  431. ' </span>\n by\n'
  432. ' <span title="PY C (pingou)">pingou.</span>\n',
  433. output.get_data(as_text=True))
  434. @patch('pagure.lib.notify.send_email')
  435. def test_merge_request_pull_merge_with_delete_branch(self, send_email):
  436. """ Test the merge_request_pull endpoint with a merge PR and delete source branch. """
  437. send_email.return_value = True
  438. tests.create_projects(self.session)
  439. tests.create_projects_git(
  440. os.path.join(self.path, 'requests'), bare=True)
  441. self.set_up_git_repo(
  442. new_project=None, branch_from='feature-branch', mtype='merge')
  443. user = tests.FakeUser()
  444. user.username = 'pingou'
  445. with tests.user_set(self.app.application, user):
  446. output = self.app.get('/test/pull-request/1')
  447. self.assertEqual(output.status_code, 200)
  448. data = {
  449. 'csrf_token': self.get_csrf(output=output),
  450. 'delete_branch': True,
  451. }
  452. # Merge
  453. output = self.app.post(
  454. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  455. self.assertEqual(output.status_code, 200)
  456. output_text = output.get_data(as_text=True)
  457. self.assertIn(
  458. '<title>Overview - test - Pagure</title>', output_text)
  459. # Check the branch is not mentioned
  460. self.assertNotIn(
  461. '<a class="" href="/test/branch/feature-branch"', output_text)
  462. @patch('pagure.lib.notify.send_email')
  463. def test_merge_request_pull_conflicts(self, send_email):
  464. """ Test the merge_request_pull endpoint with a conflicting PR. """
  465. send_email.return_value = True
  466. tests.create_projects(self.session)
  467. tests.create_projects_git(
  468. os.path.join(self.path, 'requests'), bare=True)
  469. self.set_up_git_repo(
  470. new_project=None, branch_from='feature', mtype='conflicts')
  471. user = tests.FakeUser()
  472. user.username = 'pingou'
  473. with tests.user_set(self.app.application, user):
  474. output = self.app.get('/test/pull-request/1')
  475. self.assertEqual(output.status_code, 200)
  476. csrf_token = self.get_csrf(output=output)
  477. data = {
  478. 'csrf_token': csrf_token,
  479. }
  480. # Merge conflicts
  481. output = self.app.post(
  482. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  483. self.assertEqual(output.status_code, 200)
  484. output_text = output.get_data(as_text=True)
  485. self.assertIn(
  486. '<h4 class="ml-1">\n <div>\n '
  487. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  488. '<span class="text-success '
  489. 'font-weight-bold">#1</span>\n '
  490. '<span class="font-weight-bold">\n '
  491. 'PR from the feature branch\n',
  492. output_text)
  493. self.assertIn('Merge conflicts!', output_text)
  494. @patch('pagure.lib.notify.send_email')
  495. def test_merge_request_pull_conflicts_with_delete_branch(self, send_email):
  496. """ Test the merge_request_pull endpoint with a conflicting PR and request deletion of branch. """
  497. send_email.return_value = True
  498. tests.create_projects(self.session)
  499. tests.create_projects_git(
  500. os.path.join(self.path, 'requests'), bare=True)
  501. self.set_up_git_repo(
  502. new_project=None, branch_from='feature-branch', mtype='conflicts')
  503. user = tests.FakeUser()
  504. user.username = 'pingou'
  505. with tests.user_set(self.app.application, user):
  506. output = self.app.get('/test/pull-request/1')
  507. self.assertEqual(output.status_code, 200)
  508. data = {
  509. 'csrf_token': self.get_csrf(output=output),
  510. 'delete_branch': True,
  511. }
  512. # Merge conflicts
  513. output = self.app.post(
  514. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  515. self.assertEqual(output.status_code, 200)
  516. output_text = output.get_data(as_text=True)
  517. self.assertIn(
  518. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n'
  519. ' <span class="text-success font-weight-bold">#1</span>\n'
  520. ' <span class="font-weight-bold">\n'
  521. ' PR from the feature-branch branch\n',
  522. output_text)
  523. self.assertIn('Merge conflicts!', output_text)
  524. # Check the branch still exists
  525. output = self.app.get('/test/branches')
  526. self.assertIn('feature-branch', output.get_data(as_text=True))
  527. @patch('pagure.lib.notify.send_email')
  528. def test_merge_request_pull_nochange(self, send_email):
  529. """ Test the merge_request_pull endpoint. """
  530. send_email.return_value = True
  531. tests.create_projects(self.session)
  532. tests.create_projects_git(
  533. os.path.join(self.path, 'requests'), bare=True)
  534. self.set_up_git_repo(
  535. new_project=None, branch_from='master', mtype='nochanges')
  536. user = tests.FakeUser()
  537. user.username = 'pingou'
  538. with tests.user_set(self.app.application, user):
  539. output = self.app.get('/test/pull-request/1')
  540. self.assertEqual(output.status_code, 200)
  541. csrf_token = self.get_csrf(output=output)
  542. data = {
  543. 'csrf_token': csrf_token,
  544. }
  545. # Nothing to merge
  546. output = self.app.post(
  547. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  548. self.assertEqual(output.status_code, 200)
  549. output_text = output.get_data(as_text=True)
  550. self.assertIn('Nothing to do, changes were already merged',
  551. output_text)
  552. # Check if the closing notification was added
  553. output = self.app.get('/test/pull-request/1')
  554. self.assertIn(
  555. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  556. ' </span>\n by\n'
  557. ' <span title="PY C (pingou)">pingou.</span>\n',
  558. output.get_data(as_text=True))
  559. @patch('pagure.lib.notify.send_email')
  560. def test_request_pull_close(self, send_email):
  561. """ Test the request_pull endpoint with a closed PR. """
  562. send_email.return_value = True
  563. self.test_merge_request_pull_FF()
  564. output = self.app.get('/test/pull-request/1')
  565. self.assertEqual(output.status_code, 200)
  566. output_text = output.get_data(as_text=True)
  567. self.assertIn('<span class="text-info font-weight-bold">Merged</span> '
  568. 'just now\n </span>\n by\n', output_text)
  569. self.assertIn(
  570. 'title="View file as of 2a552b">sources</a>', output_text)
  571. @patch('pagure.lib.notify.send_email')
  572. def test_request_pull_disabled(self, send_email):
  573. """ Test the request_pull endpoint with PR disabled. """
  574. send_email.return_value = True
  575. tests.create_projects(self.session)
  576. tests.create_projects_git(
  577. os.path.join(self.path, 'requests'), bare=True)
  578. self.set_up_git_repo(new_project=None, branch_from='feature')
  579. # Project w/o pull-request
  580. repo = pagure.lib.get_authorized_project(self.session, 'test')
  581. settings = repo.settings
  582. settings['pull_requests'] = False
  583. repo.settings = settings
  584. self.session.add(repo)
  585. self.session.commit()
  586. output = self.app.get('/test/pull-request/1')
  587. self.assertEqual(output.status_code, 404)
  588. @patch('pagure.lib.notify.send_email')
  589. @patch('pagure.lib.git.update_pull_ref')
  590. def test_request_pull_empty_repo(self, send_email, update_pull_ref):
  591. """ Test the request_pull endpoint against an empty repo. """
  592. # Mock update_pull_ref or the repo won't be empty anymore
  593. # (the PR will have been pushed to refs/pull)
  594. send_email.return_value = True
  595. tests.create_projects(self.session)
  596. item = pagure.lib.model.Project(
  597. user_id=2, # foo
  598. name='test',
  599. description='test project #1',
  600. hook_token='aaabbb',
  601. is_fork=True,
  602. parent_id=1,
  603. )
  604. self.session.add(item)
  605. self.session.commit()
  606. tests.create_projects_git(
  607. os.path.join(self.path, 'requests'), bare=True)
  608. tests.create_projects_git(
  609. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  610. # Create a git repo to play with
  611. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  612. self.assertFalse(os.path.exists(gitrepo))
  613. os.makedirs(gitrepo)
  614. repo = pygit2.init_repository(gitrepo, bare=True)
  615. # Create a fork of this repo
  616. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  617. gitrepo = os.path.join(self.path, 'repos', 'forks', 'foo', 'test.git')
  618. new_repo = pygit2.clone_repository(gitrepo, newpath)
  619. # Edit the sources file again
  620. with open(os.path.join(newpath, 'sources'), 'w') as stream:
  621. stream.write('foo\n bar\nbaz\n boose')
  622. new_repo.index.add('sources')
  623. new_repo.index.write()
  624. # Commits the files added
  625. tree = new_repo.index.write_tree()
  626. author = pygit2.Signature(
  627. 'Alice Author', 'alice@authors.tld')
  628. committer = pygit2.Signature(
  629. 'Cecil Committer', 'cecil@committers.tld')
  630. new_repo.create_commit(
  631. 'refs/heads/feature',
  632. author,
  633. committer,
  634. 'A commit on branch feature',
  635. tree,
  636. []
  637. )
  638. refname = 'refs/heads/feature:refs/heads/feature'
  639. ori_remote = new_repo.remotes[0]
  640. PagureRepo.push(ori_remote, refname)
  641. # Create a PR for these changes
  642. project = pagure.lib.get_authorized_project(self.session, 'test')
  643. req = pagure.lib.new_pull_request(
  644. session=self.session,
  645. repo_from=item,
  646. branch_from='feature',
  647. repo_to=project,
  648. branch_to='master',
  649. title='PR from the feature branch',
  650. user='pingou',
  651. )
  652. self.session.commit()
  653. self.assertEqual(req.id, 1)
  654. self.assertEqual(req.title, 'PR from the feature branch')
  655. output = self.app.get('/test/pull-request/1')
  656. self.assertEqual(output.status_code, 200)
  657. output_text = output.get_data(as_text=True)
  658. self.assertIn(
  659. '<h4 class="ml-1">\n <div>\n '
  660. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  661. '<span class="text-success '
  662. 'font-weight-bold">#1</span>\n '
  663. '<span class="font-weight-bold">\n '
  664. 'PR from the feature branch\n', output_text)
  665. self.assertTrue(
  666. output_text.count(
  667. '<span class="commitdate"'), 1)
  668. self.assertTrue(update_pull_ref.called)
  669. shutil.rmtree(newpath)
  670. @patch('pagure.lib.notify.send_email')
  671. def test_request_pull_empty_fork(self, send_email):
  672. """ Test the request_pull endpoint from an empty fork. """
  673. send_email.return_value = True
  674. tests.create_projects(self.session)
  675. item = pagure.lib.model.Project(
  676. user_id=2, # foo
  677. name='test',
  678. description='test project #1',
  679. hook_token='aaabbb',
  680. is_fork=True,
  681. parent_id=1,
  682. )
  683. self.session.add(item)
  684. self.session.commit()
  685. tests.create_projects_git(
  686. os.path.join(self.path, 'requests'), bare=True)
  687. tests.create_projects_git(
  688. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  689. # Create a git repo to play with
  690. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  691. self.assertFalse(os.path.exists(gitrepo))
  692. os.makedirs(gitrepo)
  693. repo = pygit2.init_repository(gitrepo, bare=True)
  694. # Create a fork of this repo
  695. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  696. gitrepo = os.path.join(
  697. self.path, 'repos', 'forks', 'foo', 'test.git')
  698. new_repo = pygit2.clone_repository(gitrepo, newpath)
  699. # Create a PR for these "changes" (there are none, both repos are
  700. # empty)
  701. project = pagure.lib.get_authorized_project(self.session, 'test')
  702. req = pagure.lib.new_pull_request(
  703. session=self.session,
  704. repo_from=item,
  705. branch_from='feature',
  706. repo_to=project,
  707. branch_to='master',
  708. title='PR from the feature branch',
  709. user='pingou',
  710. )
  711. self.session.commit()
  712. self.assertEqual(req.id, 1)
  713. self.assertEqual(req.title, 'PR from the feature branch')
  714. output = self.app.get('/test/pull-request/1', follow_redirects=True)
  715. self.assertEqual(output.status_code, 200)
  716. output_text = output.get_data(as_text=True)
  717. self.assertIn(
  718. '<title>PR#1: PR from the feature branch - test\n - Pagure</title>',
  719. output_text)
  720. self.assertIn(
  721. 'Fork is empty, there are no '
  722. 'commits to create a pull request with',
  723. output_text)
  724. shutil.rmtree(newpath)
  725. @patch('pagure.lib.notify.send_email')
  726. def test_request_pulls_order(self, send_email):
  727. """Test the request_pulls
  728. i.e Make sure that the results are displayed
  729. in the order required by the user"""
  730. send_email.return_value = True
  731. #Initially no project
  732. output = self.app.get('/test/pull-requests')
  733. self.assertEqual(output.status_code, 404)
  734. tests.create_projects(self.session)
  735. tests.create_projects_git(
  736. os.path.join(self.path, 'repos'), bare=True)
  737. repo = pagure.lib.get_authorized_project(self.session, 'test')
  738. item = pagure.lib.model.Project(
  739. user_id=2,
  740. name='test',
  741. description='test project #1',
  742. hook_token='aaabbb',
  743. is_fork=True,
  744. parent_id=1,
  745. )
  746. self.session.add(item)
  747. self.session.commit()
  748. # create PR's to play with
  749. # PR-1
  750. req = pagure.lib.new_pull_request(
  751. session=self.session,
  752. repo_to=repo,
  753. repo_from=item,
  754. branch_from='feature',
  755. branch_to='master',
  756. title='PR from the feature branch',
  757. user='pingou',
  758. status='Open',
  759. )
  760. self.session.commit()
  761. self.assertEqual(req.id, 1)
  762. self.assertEqual(req.title, 'PR from the feature branch')
  763. # PR-2
  764. req = pagure.lib.new_pull_request(
  765. session=self.session,
  766. repo_to=repo,
  767. branch_to='master',
  768. branch_from='feature',
  769. repo_from=item,
  770. title='test PR',
  771. user='pingou',
  772. status='Open',
  773. )
  774. self.session.commit()
  775. self.assertEqual(req.title, 'test PR')
  776. # PR-3
  777. req = pagure.lib.new_pull_request(
  778. session=self.session,
  779. repo_to=repo,
  780. branch_from='feature',
  781. branch_to='master',
  782. repo_from=item,
  783. title='test Invalid PR',
  784. user='pingou',
  785. status='Closed',
  786. )
  787. self.session.commit()
  788. self.assertEqual(req.title, 'test Invalid PR')
  789. # PR-4
  790. req = pagure.lib.new_pull_request(
  791. session=self.session,
  792. repo_to=repo,
  793. branch_from='feature',
  794. title='test PR for sort',
  795. repo_from=item,
  796. user='pingou',
  797. branch_to='master',
  798. status='Open',
  799. )
  800. self.session.commit()
  801. self.assertEqual(req.title, 'test PR for sort')
  802. # sort by last_updated
  803. output = self.app.get('/test/pull-requests?order_key=last_updated')
  804. output_text = output.get_data(as_text=True)
  805. tr_elements = re.findall('<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->', output_text, re.M | re.S)
  806. self.assertEqual(output.status_code, 200)
  807. # Make sure that issue four is first since it was modified last
  808. self.assertIn('href="/test/pull-request/4"', tr_elements[0])
  809. self.assertIn('href="/test/pull-request/2"', tr_elements[1])
  810. self.assertIn('href="/test/pull-request/1"', tr_elements[2])
  811. pr_one = pagure.lib.search_pull_requests(
  812. self.session, project_id=1, requestid=1)
  813. pr_one.last_updated = datetime.utcnow() + timedelta(seconds=2)
  814. self.session.add(pr_one)
  815. self.session.commit()
  816. # sort by last_updated
  817. output = self.app.get('/test/pull-requests?order_key=last_updated')
  818. output_text = output.get_data(as_text=True)
  819. tr_elements = re.findall('<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->', output_text, re.M | re.S)
  820. self.assertEqual(output.status_code, 200)
  821. # Make sure that PR four is first since it was modified last
  822. self.assertIn('href="/test/pull-request/1"', tr_elements[0])
  823. # Make sure that PR two is second since it was modified second
  824. self.assertIn('href="/test/pull-request/4"', tr_elements[1])
  825. # Make sure that PR one is last since it was modified first
  826. self.assertIn('href="/test/pull-request/2"', tr_elements[2])
  827. # Now query so that the results are ascending
  828. output = self.app.get('/test/pull-requests?'
  829. 'order_key=last_updated&order=asc')
  830. output_text = output.get_data(as_text=True)
  831. tr_elements = re.findall('<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->', output_text, re.M | re.S)
  832. self.assertIn('href="/test/pull-request/2"', tr_elements[0])
  833. self.assertIn('href="/test/pull-request/4"', tr_elements[1])
  834. self.assertIn('href="/test/pull-request/1"', tr_elements[2])
  835. #check that search_pattern argument works
  836. output = self.app.get('/test/pull-requests?search_pattern=feature')
  837. output_text = output.get_data(as_text=True)
  838. tr_elements = re.findall('<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->', output_text, re.M | re.S)
  839. self.assertIn('href="/test/pull-request/1"', tr_elements[0])
  840. self.assertEqual(len(tr_elements), 1)
  841. output = self.app.get('/test/pull-requests?search_pattern=PR')
  842. output_text = output.get_data(as_text=True)
  843. tr_elements = re.findall('<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->', output_text, re.M | re.S)
  844. self.assertIn('href="/test/pull-request/4"', tr_elements[0])
  845. self.assertIn('href="/test/pull-request/2"', tr_elements[1])
  846. self.assertIn('href="/test/pull-request/1"', tr_elements[2])
  847. self.assertEqual(len(tr_elements), 3)
  848. output = self.app.get('/test/pull-requests?search_pattern=*PR')
  849. output_text = output.get_data(as_text=True)
  850. tr_elements = re.findall('<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->', output_text, re.M | re.S)
  851. self.assertEqual(len(tr_elements), 1)
  852. self.assertIn('href="/test/pull-request/2"', tr_elements[0])
  853. @patch('pagure.lib.notify.send_email')
  854. def test_request_pulls(self, send_email):
  855. """ Test the request_pulls endpoint. """
  856. send_email.return_value = True
  857. # No such project
  858. output = self.app.get('/test/pull-requests')
  859. self.assertEqual(output.status_code, 404)
  860. tests.create_projects(self.session)
  861. tests.create_projects_git(
  862. os.path.join(self.path, 'repos'), bare=True)
  863. output = self.app.get('/test/pull-requests')
  864. self.assertEqual(output.status_code, 200)
  865. output_text = output.get_data(as_text=True)
  866. self.assertIn(
  867. '<span class="fa fa-fw fa-arrow-circle-down"></span> 0 Open PRs\n',
  868. output_text)
  869. self.set_up_git_repo(new_project=None, branch_from='feature')
  870. output = self.app.get('/test/pull-requests')
  871. self.assertEqual(output.status_code, 200)
  872. output_text = output.get_data(as_text=True)
  873. self.assertIn(
  874. '<span class="fa fa-fw fa-arrow-circle-down"></span> 1 Open PRs\n',
  875. output_text)
  876. output = self.app.get('/test/pull-requests?status=1')
  877. self.assertEqual(output.status_code, 200)
  878. output_text = output.get_data(as_text=True)
  879. self.assertIn(
  880. '<span class="fa fa-fw fa-arrow-circle-down"></span> 1 Open PRs\n',
  881. output_text)
  882. output = self.app.get('/test/pull-requests?status=true')
  883. self.assertEqual(output.status_code, 200)
  884. output_text = output.get_data(as_text=True)
  885. self.assertIn(
  886. '<span class="fa fa-fw fa-arrow-circle-down"></span> 1 Open PRs\n',
  887. output_text)
  888. output = self.app.get('/test/pull-requests?status=Merged')
  889. self.assertEqual(output.status_code, 200)
  890. output_text = output.get_data(as_text=True)
  891. self.assertIn(
  892. '<span class="fa fa-fw fa-arrow-circle-down"></span> 0 Merged PRs\n',
  893. output_text)
  894. output = self.app.get('/test/pull-requests?status=0')
  895. self.assertEqual(output.status_code, 200)
  896. output_text = output.get_data(as_text=True)
  897. self.assertIn(
  898. '<span class="fa fa-fw fa-arrow-circle-down"></span> 0 Merged PRs\n',
  899. output_text)
  900. output = self.app.get('/test/pull-requests?status=Closed')
  901. self.assertEqual(output.status_code, 200)
  902. output_text = output.get_data(as_text=True)
  903. self.assertIn(
  904. '<span class="fa fa-fw fa-arrow-circle-down"></span> 0 Cancelled PRs\n',
  905. output_text)
  906. # Project w/o pull-request
  907. repo = pagure.lib.get_authorized_project(self.session, 'test')
  908. settings = repo.settings
  909. settings['pull_requests'] = False
  910. repo.settings = settings
  911. self.session.add(repo)
  912. self.session.commit()
  913. output = self.app.get('/test/pull-requests')
  914. self.assertEqual(output.status_code, 404)
  915. @patch('pagure.lib.notify.send_email')
  916. def test_request_pull_patch(self, send_email):
  917. """ Test the request_pull_patch endpoint. """
  918. send_email.return_value = True
  919. output = self.app.get('/test/pull-request/1.patch')
  920. self.assertEqual(output.status_code, 404)
  921. tests.create_projects(self.session)
  922. tests.create_projects_git(
  923. os.path.join(self.path, 'requests'), bare=True)
  924. self.set_up_git_repo(
  925. new_project=None, branch_from='feature', mtype='merge')
  926. output = self.app.get('/test/pull-request/100.patch')
  927. self.assertEqual(output.status_code, 404)
  928. output = self.app.get('/test/pull-request/1.patch')
  929. self.assertEqual(output.status_code, 200)
  930. npatch = []
  931. for row in output.get_data(as_text=True).split('\n'):
  932. if row.startswith('Date:'):
  933. continue
  934. if row.startswith('From '):
  935. row = row.split(' ', 2)[2]
  936. npatch.append(row)
  937. exp = """Mon Sep 17 00:00:00 2001
  938. From: Alice Author <alice@authors.tld>
  939. Subject: A commit on branch feature
  940. ---
  941. diff --git a/.gitignore b/.gitignore
  942. new file mode 100644
  943. index 0000000..e4e5f6c
  944. --- /dev/null
  945. +++ b/.gitignore
  946. @@ -0,0 +1 @@
  947. +*~
  948. \ No newline at end of file
  949. diff --git a/sources b/sources
  950. index 9f44358..2a552bb 100644
  951. --- a/sources
  952. +++ b/sources
  953. @@ -1,2 +1,4 @@
  954. foo
  955. - bar
  956. \ No newline at end of file
  957. + bar
  958. +baz
  959. + boose
  960. \ No newline at end of file
  961. """
  962. patch = '\n'.join(npatch)
  963. #print patch
  964. self.assertEqual(patch, exp)
  965. # Project w/o pull-request
  966. repo = pagure.lib.get_authorized_project(self.session, 'test')
  967. settings = repo.settings
  968. settings['pull_requests'] = False
  969. repo.settings = settings
  970. self.session.add(repo)
  971. self.session.commit()
  972. output = self.app.get('/test/pull-request/1.patch')
  973. self.assertEqual(output.status_code, 404)
  974. @patch('pagure.lib.notify.send_email')
  975. def test_request_pull_diff(self, send_email):
  976. """ Test the request_pull_patch endpoint. """
  977. send_email.return_value = True
  978. output = self.app.get('/test/pull-request/1.diff')
  979. self.assertEqual(output.status_code, 404)
  980. tests.create_projects(self.session)
  981. tests.create_projects_git(
  982. os.path.join(self.path, 'requests'), bare=True)
  983. self.set_up_git_repo(
  984. new_project=None, branch_from='feature', mtype='merge')
  985. output = self.app.get('/test/pull-request/100.diff')
  986. self.assertEqual(output.status_code, 404)
  987. output = self.app.get('/test/pull-request/1.diff')
  988. self.assertEqual(output.status_code, 200)
  989. exp = """diff --git a/.gitignore b/.gitignore
  990. new file mode 100644
  991. index 0000000..e4e5f6c
  992. --- /dev/null
  993. +++ b/.gitignore
  994. @@ -0,0 +1 @@
  995. +*~
  996. \ No newline at end of file
  997. diff --git a/sources b/sources
  998. index 9f44358..2a552bb 100644
  999. --- a/sources
  1000. +++ b/sources
  1001. @@ -1,2 +1,4 @@
  1002. foo
  1003. - bar
  1004. \ No newline at end of file
  1005. + bar
  1006. +baz
  1007. + boose
  1008. \ No newline at end of file
  1009. """
  1010. self.assertEqual(output.get_data(as_text=True), exp)
  1011. # Project w/o pull-request
  1012. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1013. settings = repo.settings
  1014. settings['pull_requests'] = False
  1015. repo.settings = settings
  1016. self.session.add(repo)
  1017. self.session.commit()
  1018. output = self.app.get('/test/pull-request/1.diff')
  1019. self.assertEqual(output.status_code, 404)
  1020. @patch('pagure.lib.notify.send_email')
  1021. def test_request_pull_patch_close(self, send_email):
  1022. """ Test the request_pull_patch endpoint with a closed PR. """
  1023. send_email.return_value = True
  1024. self.test_merge_request_pull_FF()
  1025. output = self.app.get('/test/pull-request/1.patch')
  1026. self.assertEqual(output.status_code, 200)
  1027. npatch = []
  1028. for row in output.get_data(as_text=True).split('\n'):
  1029. if row.startswith('Date:'):
  1030. continue
  1031. if row.startswith('From '):
  1032. row = row.split(' ', 2)[2]
  1033. npatch.append(row)
  1034. exp = """Mon Sep 17 00:00:00 2001
  1035. From: Alice Author <alice@authors.tld>
  1036. Subject: A commit on branch feature
  1037. ---
  1038. diff --git a/sources b/sources
  1039. index 9f44358..2a552bb 100644
  1040. --- a/sources
  1041. +++ b/sources
  1042. @@ -1,2 +1,4 @@
  1043. foo
  1044. - bar
  1045. \ No newline at end of file
  1046. + bar
  1047. +baz
  1048. + boose
  1049. \ No newline at end of file
  1050. """
  1051. patch = '\n'.join(npatch)
  1052. #print patch
  1053. self.assertEqual(patch, exp)
  1054. @patch('pagure.lib.notify.send_email')
  1055. @patch('pagure.lib.git.update_pull_ref')
  1056. def test_request_pull_patch_empty_repo(self, send_email, update_pull_ref):
  1057. """ Test the request_pull_patch endpoint against an empty repo. """
  1058. # Mock update_pull_ref or the repo won't be empty anymore
  1059. # (the PR will have been pushed to refs/pull)
  1060. send_email.return_value = True
  1061. tests.create_projects(self.session)
  1062. item = pagure.lib.model.Project(
  1063. user_id=2, # foo
  1064. name='test',
  1065. description='test project #1',
  1066. hook_token='aaabbb',
  1067. is_fork=True,
  1068. parent_id=1,
  1069. )
  1070. self.session.add(item)
  1071. self.session.commit()
  1072. tests.create_projects_git(
  1073. os.path.join(self.path, 'requests'), bare=True)
  1074. tests.create_projects_git(
  1075. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  1076. # Create a git repo to play with
  1077. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  1078. self.assertFalse(os.path.exists(gitrepo))
  1079. os.makedirs(gitrepo)
  1080. repo = pygit2.init_repository(gitrepo, bare=True)
  1081. # Create a fork of this repo
  1082. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  1083. gitrepo = os.path.join(
  1084. self.path, 'repos', 'forks', 'foo', 'test.git')
  1085. new_repo = pygit2.clone_repository(gitrepo, newpath)
  1086. # Edit the sources file again
  1087. with open(os.path.join(newpath, 'sources'), 'w') as stream:
  1088. stream.write('foo\n bar\nbaz\n boose')
  1089. new_repo.index.add('sources')
  1090. new_repo.index.write()
  1091. # Commits the files added
  1092. tree = new_repo.index.write_tree()
  1093. author = pygit2.Signature(
  1094. 'Alice Author', 'alice@authors.tld')
  1095. committer = pygit2.Signature(
  1096. 'Cecil Committer', 'cecil@committers.tld')
  1097. new_repo.create_commit(
  1098. 'refs/heads/feature',
  1099. author,
  1100. committer,
  1101. 'A commit on branch feature',
  1102. tree,
  1103. []
  1104. )
  1105. refname = 'refs/heads/feature:refs/heads/feature'
  1106. ori_remote = new_repo.remotes[0]
  1107. PagureRepo.push(ori_remote, refname)
  1108. # Create a PR for these "changes" (there are none, both repos are
  1109. # empty)
  1110. project = pagure.lib.get_authorized_project(self.session, 'test')
  1111. req = pagure.lib.new_pull_request(
  1112. session=self.session,
  1113. repo_from=item,
  1114. branch_from='feature',
  1115. repo_to=project,
  1116. branch_to='master',
  1117. title='PR from the feature branch',
  1118. user='pingou',
  1119. )
  1120. self.session.commit()
  1121. self.assertEqual(req.id, 1)
  1122. self.assertEqual(req.title, 'PR from the feature branch')
  1123. output = self.app.get(
  1124. '/test/pull-request/1.patch', follow_redirects=True)
  1125. self.assertEqual(output.status_code, 200)
  1126. npatch = []
  1127. for row in output.get_data(as_text=True).split('\n'):
  1128. if row.startswith('Date:'):
  1129. continue
  1130. if row.startswith('From '):
  1131. row = row.split(' ', 2)[2]
  1132. npatch.append(row)
  1133. exp = """Mon Sep 17 00:00:00 2001
  1134. From: Alice Author <alice@authors.tld>
  1135. Subject: A commit on branch feature
  1136. ---
  1137. diff --git a/sources b/sources
  1138. new file mode 100644
  1139. index 0000000..2a552bb
  1140. --- /dev/null
  1141. +++ b/sources
  1142. @@ -0,0 +1,4 @@
  1143. +foo
  1144. + bar
  1145. +baz
  1146. + boose
  1147. \ No newline at end of file
  1148. """
  1149. patch = '\n'.join(npatch)
  1150. #print patch
  1151. self.assertEqual(patch, exp)
  1152. shutil.rmtree(newpath)
  1153. @patch('pagure.lib.notify.send_email')
  1154. def test_request_pull_patch_empty_fork(self, send_email):
  1155. """ Test the request_pull_patch endpoint from an empty fork. """
  1156. send_email.return_value = True
  1157. tests.create_projects(self.session)
  1158. item = pagure.lib.model.Project(
  1159. user_id=2, # foo
  1160. name='test',
  1161. description='test project #1',
  1162. hook_token='aaabbb',
  1163. is_fork=True,
  1164. parent_id=1,
  1165. )
  1166. self.session.add(item)
  1167. self.session.commit()
  1168. tests.create_projects_git(
  1169. os.path.join(self.path, 'requests'), bare=True)
  1170. tests.create_projects_git(
  1171. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  1172. # Create a git repo to play with
  1173. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  1174. self.assertFalse(os.path.exists(gitrepo))
  1175. os.makedirs(gitrepo)
  1176. repo = pygit2.init_repository(gitrepo, bare=True)
  1177. # Create a fork of this repo
  1178. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  1179. gitrepo = os.path.join(
  1180. self.path, 'repos', 'forks', 'foo', 'test.git')
  1181. new_repo = pygit2.clone_repository(gitrepo, newpath)
  1182. # Create a PR for these "changes" (there are none, both repos are
  1183. # empty)
  1184. project = pagure.lib.get_authorized_project(self.session, 'test')
  1185. req = pagure.lib.new_pull_request(
  1186. session=self.session,
  1187. repo_from=item,
  1188. branch_from='feature',
  1189. repo_to=project,
  1190. branch_to='master',
  1191. title='PR from the feature branch',
  1192. user='pingou',
  1193. )
  1194. self.session.commit()
  1195. self.assertEqual(req.id, 1)
  1196. self.assertEqual(req.title, 'PR from the feature branch')
  1197. output = self.app.get('/test/pull-request/1.patch',
  1198. follow_redirects=True)
  1199. self.assertEqual(output.status_code, 200)
  1200. output_text = output.get_data(as_text=True)
  1201. self.assertIn(
  1202. '<title>Overview - test - Pagure</title>',
  1203. output_text)
  1204. self.assertIn(
  1205. 'Fork is empty, there are no '
  1206. 'commits to create a pull request with',
  1207. output_text)
  1208. shutil.rmtree(newpath)
  1209. @patch('pagure.lib.notify.send_email')
  1210. def test_cancel_request_pull(self, send_email):
  1211. """ Test the cancel_request_pull endpoint. """
  1212. send_email.return_value = True
  1213. tests.create_projects(self.session)
  1214. tests.create_projects_git(
  1215. os.path.join(self.path, 'requests'), bare=True)
  1216. self.set_up_git_repo(
  1217. new_project=None, branch_from='feature', mtype='merge')
  1218. user = tests.FakeUser()
  1219. with tests.user_set(self.app.application, user):
  1220. output = self.app.post('/test/pull-request/cancel/1')
  1221. self.assertEqual(output.status_code, 302)
  1222. output = self.app.post(
  1223. '/test/pull-request/cancel/1', follow_redirects=True)
  1224. self.assertEqual(output.status_code, 200)
  1225. output_text = output.get_data(as_text=True)
  1226. self.assertIn(
  1227. '<title>Overview - test - Pagure</title>', output_text)
  1228. self.assertIn(
  1229. 'Invalid input submitted',
  1230. output_text)
  1231. output = self.app.get('/test/pull-request/1')
  1232. self.assertEqual(output.status_code, 200)
  1233. csrf_token = self.get_csrf(output=output)
  1234. data = {
  1235. 'csrf_token': csrf_token,
  1236. }
  1237. # Invalid project
  1238. output = self.app.post(
  1239. '/foo/pull-request/cancel/1', data=data,
  1240. follow_redirects=True)
  1241. self.assertEqual(output.status_code, 404)
  1242. # Invalid PR id
  1243. output = self.app.post(
  1244. '/test/pull-request/cancel/100', data=data,
  1245. follow_redirects=True)
  1246. self.assertEqual(output.status_code, 404)
  1247. # Invalid user for this project
  1248. output = self.app.post(
  1249. '/test/pull-request/cancel/1', data=data,
  1250. follow_redirects=True)
  1251. self.assertEqual(output.status_code, 403)
  1252. user.username = 'pingou'
  1253. with tests.user_set(self.app.application, user):
  1254. # Project w/o pull-request
  1255. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1256. settings = repo.settings
  1257. settings['pull_requests'] = False
  1258. repo.settings = settings
  1259. self.session.add(repo)
  1260. self.session.commit()
  1261. output = self.app.post(
  1262. '/test/pull-request/cancel/1', data=data,
  1263. follow_redirects=True)
  1264. self.assertEqual(output.status_code, 404)
  1265. # Project w/ pull-request
  1266. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1267. settings = repo.settings
  1268. settings['pull_requests'] = True
  1269. repo.settings = settings
  1270. self.session.add(repo)
  1271. self.session.commit()
  1272. output = self.app.post(
  1273. '/test/pull-request/cancel/1', data=data,
  1274. follow_redirects=True)
  1275. self.assertEqual(output.status_code, 200)
  1276. output_text = output.get_data(as_text=True)
  1277. self.assertIn(
  1278. '<title>Overview - test - Pagure</title>', output_text)
  1279. self.assertIn(
  1280. 'Pull request canceled!',
  1281. output_text)
  1282. @patch('pagure.lib.notify.send_email')
  1283. def test_reopen_request_pull(self, send_email):
  1284. """ Test the reopen_request_pull endpoint. """
  1285. send_email.return_value = True
  1286. tests.create_projects(self.session)
  1287. tests.create_projects_git(
  1288. os.path.join(self.path, 'requests'), bare=True)
  1289. self.set_up_git_repo(
  1290. new_project=None, branch_from='feature', mtype='merge')
  1291. user = tests.FakeUser()
  1292. with tests.user_set(self.app.application, user):
  1293. output = self.app.post('/test/pull-request/1/reopen')
  1294. self.assertEqual(output.status_code, 302)
  1295. output = self.app.post(
  1296. '/test/pull-request/1/reopen', follow_redirects=True)
  1297. self.assertEqual(output.status_code, 200)
  1298. output_text = output.get_data(as_text=True)
  1299. self.assertIn(
  1300. '<title>PR#1: PR from the feature branch - test\n - Pagure</title>', output_text)
  1301. self.assertIn(
  1302. #'Pull request reopened!',
  1303. 'return window.confirm("Are you sure you want to reopen this requested pull?")',
  1304. output_text)
  1305. output = self.app.get('/test/pull-request/1')
  1306. self.assertEqual(output.status_code, 200)
  1307. csrf_token = self.get_csrf(output=output)
  1308. data = {
  1309. 'csrf_token': csrf_token,
  1310. }
  1311. # Invalid project
  1312. output = self.app.post(
  1313. '/foo/pull-request/1/reopen', data=data,
  1314. follow_redirects=True)
  1315. self.assertEqual(output.status_code, 404)
  1316. # Invalid PR id
  1317. output = self.app.post(
  1318. '/test/pull-request/100/reopen', data=data,
  1319. follow_redirects=True)
  1320. self.assertEqual(output.status_code, 404)
  1321. # Invalid user for this project
  1322. output = self.app.post(
  1323. '/test/pull-request/1/reopen', data=data,
  1324. follow_redirects=True)
  1325. self.assertEqual(output.status_code, 403)
  1326. user.username = 'pingou'
  1327. with tests.user_set(self.app.application, user):
  1328. # Project w/o pull-request
  1329. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1330. settings = repo.settings
  1331. settings['pull_requests'] = False
  1332. repo.settings = settings
  1333. self.session.add(repo)
  1334. self.session.commit()
  1335. output = self.app.post(
  1336. '/test/pull-request/1/reopen', data=data,
  1337. follow_redirects=True)
  1338. self.assertEqual(output.status_code, 404)
  1339. # Project w/ pull-request
  1340. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1341. settings = repo.settings
  1342. settings['pull_requests'] = True
  1343. repo.settings = settings
  1344. self.session.add(repo)
  1345. self.session.commit()
  1346. output = self.app.post(
  1347. '/test/pull-request/cancel/1', data=data,
  1348. follow_redirects=True)
  1349. output = self.app.post(
  1350. '/test/pull-request/1/reopen', data=data,
  1351. follow_redirects=True)
  1352. self.assertEqual(output.status_code, 200)
  1353. output_text = output.get_data(as_text=True)
  1354. self.assertIn(
  1355. '<title>PR#1: PR from the feature branch - test\n - '
  1356. 'Pagure</title>', output_text)
  1357. self.assertIn(
  1358. 'return window.confirm("Are you sure you want to reopen this requested pull?")',
  1359. output_text)
  1360. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1361. def test_update_pull_requests_assign(self):
  1362. """ Test the update_pull_requests endpoint when assigning a PR.
  1363. """
  1364. tests.create_projects(self.session)
  1365. tests.create_projects_git(
  1366. os.path.join(self.path, 'requests'), bare=True)
  1367. self.set_up_git_repo(new_project=None, branch_from='feature')
  1368. user = tests.FakeUser()
  1369. user.username = 'pingou'
  1370. with tests.user_set(self.app.application, user):
  1371. # No such project
  1372. output = self.app.post('/foo/pull-request/1/update')
  1373. self.assertEqual(output.status_code, 404)
  1374. output = self.app.post('/test/pull-request/100/update')
  1375. self.assertEqual(output.status_code, 404)
  1376. # Invalid input
  1377. output = self.app.post(
  1378. '/test/pull-request/1/update', follow_redirects=True)
  1379. self.assertEqual(output.status_code, 200)
  1380. output_text = output.get_data(as_text=True)
  1381. self.assertIn(
  1382. '<title>PR#1: PR from the feature branch - test\n - '
  1383. 'Pagure</title>', output_text)
  1384. self.assertIn(
  1385. '<h4 class="ml-1">\n <div>\n '
  1386. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1387. '<span class="text-success '
  1388. 'font-weight-bold">#1</span>\n '
  1389. '<span class="font-weight-bold">\n '
  1390. 'PR from the feature branch\n', output_text)
  1391. self.assertNotIn(
  1392. 'Request assigned',
  1393. output_text)
  1394. output = self.app.get('/test/pull-request/1')
  1395. self.assertEqual(output.status_code, 200)
  1396. csrf_token = self.get_csrf(output=output)
  1397. data = {
  1398. 'user': 'pingou',
  1399. }
  1400. # No CSRF
  1401. output = self.app.post(
  1402. '/test/pull-request/1/update', data=data,
  1403. follow_redirects=True)
  1404. self.assertEqual(output.status_code, 200)
  1405. output_text = output.get_data(as_text=True)
  1406. self.assertIn(
  1407. '<title>PR#1: PR from the feature branch - test\n - '
  1408. 'Pagure</title>', output_text)
  1409. self.assertIn(
  1410. '<h4 class="ml-1">\n <div>\n '
  1411. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1412. '<span class="text-success '
  1413. 'font-weight-bold">#1</span>\n '
  1414. '<span class="font-weight-bold">\n '
  1415. 'PR from the feature branch\n', output_text)
  1416. self.assertNotIn(
  1417. 'Request assigned',
  1418. output_text)
  1419. # Invalid assignee
  1420. data = {
  1421. 'csrf_token': csrf_token,
  1422. 'user': 'bar',
  1423. }
  1424. output = self.app.post(
  1425. '/test/pull-request/1/update', data=data,
  1426. follow_redirects=True)
  1427. self.assertEqual(output.status_code, 200)
  1428. output_text = output.get_data(as_text=True)
  1429. self.assertIn(
  1430. '<title>PR#1: PR from the feature branch - test\n - '
  1431. 'Pagure</title>', output_text)
  1432. self.assertIn(
  1433. '<h4 class="ml-1">\n <div>\n '
  1434. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1435. '<span class="text-success '
  1436. 'font-weight-bold">#1</span>\n '
  1437. '<span class="font-weight-bold">\n '
  1438. 'PR from the feature branch\n', output_text)
  1439. self.assertIn(
  1440. 'No user &#34;bar&#34; found',
  1441. output_text)
  1442. # Assign the PR
  1443. data = {
  1444. 'csrf_token': csrf_token,
  1445. 'user': 'pingou',
  1446. }
  1447. user.username = 'foo'
  1448. with tests.user_set(self.app.application, user):
  1449. output = self.app.post(
  1450. '/test/pull-request/1/update', data=data,
  1451. follow_redirects=True)
  1452. self.assertEqual(output.status_code, 403)
  1453. user.username = 'pingou'
  1454. with tests.user_set(self.app.application, user):
  1455. output = self.app.post(
  1456. '/test/pull-request/1/update', data=data,
  1457. follow_redirects=True)
  1458. self.assertEqual(output.status_code, 200)
  1459. output_text = output.get_data(as_text=True)
  1460. self.assertIn(
  1461. '<title>PR#1: PR from the feature branch - test\n - '
  1462. 'Pagure</title>', output_text)
  1463. self.assertIn(
  1464. '<h4 class="ml-1">\n <div>\n '
  1465. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1466. '<span class="text-success '
  1467. 'font-weight-bold">#1</span>\n '
  1468. '<span class="font-weight-bold">\n '
  1469. 'PR from the feature branch\n', output_text)
  1470. self.assertIn(
  1471. 'Request assigned',
  1472. output_text)
  1473. # Pull-Request closed
  1474. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1475. req = repo.requests[0]
  1476. req.status = 'Closed'
  1477. req.closed_by_in = 1
  1478. self.session.add(req)
  1479. self.session.commit()
  1480. output = self.app.post(
  1481. '/test/pull-request/1/update', data=data,
  1482. follow_redirects=True)
  1483. self.assertEqual(output.status_code, 403)
  1484. # Project w/o pull-request
  1485. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1486. settings = repo.settings
  1487. settings['pull_requests'] = False
  1488. repo.settings = settings
  1489. self.session.add(repo)
  1490. self.session.commit()
  1491. output = self.app.post(
  1492. '/test/pull-request/1/update', data=data,
  1493. follow_redirects=True)
  1494. self.assertEqual(output.status_code, 404)
  1495. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  1496. def test_update_pull_requests_tag(self):
  1497. """ Test the update_pull_requests endpoint when tagging a PR.
  1498. """
  1499. tests.create_projects(self.session)
  1500. tests.create_projects_git(
  1501. os.path.join(self.path, 'requests'), bare=True)
  1502. self.set_up_git_repo(new_project=None, branch_from='feature')
  1503. user = tests.FakeUser()
  1504. user.username = 'pingou'
  1505. with tests.user_set(self.app.application, user):
  1506. output = self.app.get('/test/pull-request/1')
  1507. self.assertEqual(output.status_code, 200)
  1508. csrf_token = self.get_csrf(output=output)
  1509. data = {
  1510. 'tag': 'black',
  1511. }
  1512. # No CSRF
  1513. output = self.app.post(
  1514. '/test/pull-request/1/update', data=data,
  1515. follow_redirects=True)
  1516. self.assertEqual(output.status_code, 200)
  1517. output_text = output.get_data(as_text=True)
  1518. self.assertIn(
  1519. '<title>PR#1: PR from the feature branch - test\n - '
  1520. 'Pagure</title>', output_text)
  1521. self.assertIn(
  1522. '<h4 class="ml-1">\n <div>\n '
  1523. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1524. '<span class="text-success '
  1525. 'font-weight-bold">#1</span>\n '
  1526. '<span class="font-weight-bold">\n '
  1527. 'PR from the feature branch\n', output_text)
  1528. self.assertNotIn(
  1529. 'Request assigned',
  1530. output_text)
  1531. # Tag the PR
  1532. data = {
  1533. 'csrf_token': csrf_token,
  1534. 'tag': 'black',
  1535. }
  1536. output = self.app.post(
  1537. '/test/pull-request/1/update', data=data,
  1538. follow_redirects=True)
  1539. self.assertEqual(output.status_code, 200)
  1540. output_text = output.get_data(as_text=True)
  1541. self.assertIn(
  1542. '<title>PR#1: PR from the feature branch - test\n - '
  1543. 'Pagure</title>', output_text)
  1544. self.assertIn(
  1545. '<h4 class="ml-1">\n <div>\n '
  1546. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1547. '<span class="text-success '
  1548. 'font-weight-bold">#1</span>\n '
  1549. '<span class="font-weight-bold">\n '
  1550. 'PR from the feature branch\n', output_text)
  1551. self.assertIn(
  1552. 'Pull-request tagged with: black',
  1553. output_text)
  1554. self.assertIn(
  1555. 'title="comma separated list of tags"\n '
  1556. 'value="black" />', output_text)
  1557. # Try as another user
  1558. user.username = 'foo'
  1559. with tests.user_set(self.app.application, user):
  1560. # Tag the PR
  1561. data = {
  1562. 'csrf_token': csrf_token,
  1563. 'tag': 'blue, yellow',
  1564. }
  1565. output = self.app.post(
  1566. '/test/pull-request/1/update', data=data,
  1567. follow_redirects=True)
  1568. self.assertEqual(output.status_code, 403)
  1569. # Make the PR be from foo
  1570. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1571. req = repo.requests[0]
  1572. req.user_id = 2
  1573. self.session.add(req)
  1574. self.session.commit()
  1575. # Re-try to tag the PR
  1576. data = {
  1577. 'csrf_token': csrf_token,
  1578. 'tag': 'blue, yellow',
  1579. }
  1580. output = self.app.post(
  1581. '/test/pull-request/1/update', data=data,
  1582. follow_redirects=True)
  1583. self.assertEqual(output.status_code, 200)
  1584. soup = BeautifulSoup(output.get_data(as_text=True), "html.parser")
  1585. self.assertEqual(
  1586. soup.find("title").string,
  1587. 'PR#1: PR from the feature branch - test\n - Pagure'
  1588. )
  1589. self.assertIn('Pull-request **un**tagged with: black', output.get_data(as_text=True))
  1590. self.assertIn('Pull-request tagged with: blue, yellow', output.get_data(as_text=True))
  1591. user.username = 'pingou'
  1592. with tests.user_set(self.app.application, user):
  1593. # Pull-Request closed
  1594. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1595. req = repo.requests[0]
  1596. req.status = 'Closed'
  1597. req.closed_by_in = 1
  1598. self.session.add(req)
  1599. self.session.commit()
  1600. output = self.app.post(
  1601. '/test/pull-request/1/update', data=data,
  1602. follow_redirects=True)
  1603. self.assertEqual(output.status_code, 403)
  1604. # Project w/o pull-request
  1605. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1606. settings = repo.settings
  1607. settings['pull_requests'] = False
  1608. repo.settings = settings
  1609. self.session.add(repo)
  1610. self.session.commit()
  1611. output = self.app.post(
  1612. '/test/pull-request/1/update', data=data,
  1613. follow_redirects=True)
  1614. self.assertEqual(output.status_code, 404)
  1615. @patch('pagure.lib.notify.send_email')
  1616. def test_fork_project(self, send_email):
  1617. """ Test the fork_project endpoint. """
  1618. send_email.return_value = True
  1619. tests.create_projects(self.session)
  1620. for folder in ['docs', 'tickets', 'requests', 'repos']:
  1621. tests.create_projects_git(
  1622. os.path.join(self.path, folder), bare=True)
  1623. user = tests.FakeUser()
  1624. user.username = 'pingou'
  1625. with tests.user_set(self.app.application, user):
  1626. output = self.app.post('/do_fork/test')
  1627. self.assertEqual(output.status_code, 400)
  1628. output = self.app.get('/new/')
  1629. self.assertEqual(output.status_code, 200)
  1630. self.assertIn('<strong>Create new Project</strong>', output.get_data(as_text=True))
  1631. csrf_token = self.get_csrf(output=output)
  1632. data = {
  1633. 'csrf_token': csrf_token,
  1634. }
  1635. output = self.app.post(
  1636. '/do_fork/foo', data=data, follow_redirects=True)
  1637. self.assertEqual(output.status_code, 404)
  1638. user.username = 'foo'
  1639. with tests.user_set(self.app.application, user):
  1640. output = self.app.post('/do_fork/test')
  1641. self.assertEqual(output.status_code, 400)
  1642. data = {
  1643. 'csrf_token': csrf_token,
  1644. }
  1645. output = self.app.post(
  1646. '/do_fork/test', data=data, follow_redirects=True)
  1647. self.assertEqual(output.status_code, 200)
  1648. @patch('pagure.lib.notify.send_email')
  1649. def test_new_request_pull_branch_space(self, send_email):
  1650. """ Test the new_request_pull endpoint. """
  1651. send_email.return_value = True
  1652. self.test_fork_project()
  1653. tests.create_projects_git(
  1654. os.path.join(self.path, 'requests'), bare=True)
  1655. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1656. fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
  1657. self.set_up_git_repo(
  1658. new_project=fork, branch_from='feature', mtype='FF')
  1659. user = tests.FakeUser(username = 'pingou')
  1660. with tests.user_set(self.app.application, user):
  1661. output = self.app.get('/test/diff/master..foo bar')
  1662. self.assertEqual(output.status_code, 400)
  1663. output_text = output.get_data(as_text=True)
  1664. self.assertIn(
  1665. '<p>Branch foo bar does not exist</p>', output_text)
  1666. @patch('pagure.lib.notify.send_email')
  1667. def test_new_request_pull(self, send_email):
  1668. """ Test the new_request_pull endpoint. """
  1669. send_email.return_value = True
  1670. self.test_fork_project()
  1671. tests.create_projects_git(
  1672. os.path.join(self.path, 'requests'), bare=True)
  1673. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1674. fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
  1675. self.set_up_git_repo(
  1676. new_project=fork, branch_from='feature', mtype='FF')
  1677. user = tests.FakeUser()
  1678. user.username = 'foo'
  1679. with tests.user_set(self.app.application, user):
  1680. output = self.app.get('/foo/diff/master..feature')
  1681. self.assertEqual(output.status_code, 404)
  1682. output = self.app.get('/test/diff/master..foo')
  1683. self.assertEqual(output.status_code, 400)
  1684. output = self.app.get('/test/diff/foo..master')
  1685. self.assertEqual(output.status_code, 400)
  1686. output = self.app.get('/test/diff/feature..master')
  1687. self.assertEqual(output.status_code, 200)
  1688. output_text = output.get_data(as_text=True)
  1689. self.assertIn(
  1690. '<title>Diff from master to feature - test\n - '
  1691. 'Pagure</title>', output_text)
  1692. self.assertIn(
  1693. '<p class="error"> No commits found </p>', output_text)
  1694. output = self.app.get('/test/diff/master..feature')
  1695. self.assertEqual(output.status_code, 200)
  1696. output_text = output.get_data(as_text=True)
  1697. self.assertIn(
  1698. '<title>Diff from feature to master - test\n - '
  1699. 'Pagure</title>', output_text)
  1700. self.assertNotIn(
  1701. '<input type="submit" class="submit positive button" '
  1702. 'value="Create">', output_text)
  1703. user.username = 'pingou'
  1704. with tests.user_set(self.app.application, user):
  1705. output = self.app.get('/test/diff/master..feature')
  1706. self.assertEqual(output.status_code, 200)
  1707. output_text = output.get_data(as_text=True)
  1708. self.assertIn(
  1709. '<title>Create new Pull Request for master - test\n - '
  1710. 'Pagure</title>', output_text)
  1711. self.assertIn(
  1712. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  1713. output_text)
  1714. csrf_token = self.get_csrf(output=output)
  1715. # Case 1 - Add an initial comment
  1716. data = {
  1717. 'csrf_token': csrf_token,
  1718. 'title': 'foo bar PR',
  1719. 'initial_comment': 'Test Initial Comment',
  1720. }
  1721. output = self.app.post(
  1722. '/test/diff/master..feature', data=data, follow_redirects=True)
  1723. self.assertEqual(output.status_code, 200)
  1724. output_text = output.get_data(as_text=True)
  1725. self.assertIn(
  1726. '<title>PR#2: foo bar PR - test\n - Pagure</title>',
  1727. output_text)
  1728. self.assertIn('<p>Test Initial Comment</p>',
  1729. output_text)
  1730. self.assertEqual(
  1731. output_text.count('title="PY C (pingou)"'),
  1732. 2)
  1733. # Test if the `open changed file icon` is displayed.
  1734. self.assertIn(
  1735. 'class="open_changed_file_icon_wrap"><span '
  1736. 'class="fa fa-file-code-o fa-fw" '
  1737. 'alt="Open changed file" title="Open changed file"></span>'
  1738. '</a>', output_text)
  1739. # Case 2 - Add an empty initial comment
  1740. data = {
  1741. 'csrf_token': csrf_token,
  1742. 'title': 'foo bar PR',
  1743. 'initial_comment': '',
  1744. }
  1745. output = self.app.post(
  1746. '/test/diff/master..feature', data=data, follow_redirects=True)
  1747. self.assertEqual(output.status_code, 200)
  1748. output_text = output.get_data(as_text=True)
  1749. self.assertIn(
  1750. '<title>PR#3: foo bar PR - test\n - Pagure</title>',
  1751. output_text)
  1752. self.assertNotIn('<div id="comment-', output_text)
  1753. @patch('pagure.lib.notify.send_email')
  1754. def test_new_request_pull_req_sign_off_view(self, send_email):
  1755. """ Test the new_request_pull endpoint. """
  1756. send_email.return_value = True
  1757. self.test_fork_project()
  1758. tests.create_projects_git(
  1759. os.path.join(self.path, 'requests'), bare=True)
  1760. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1761. fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
  1762. # Enforce Signed-of-by in the repo
  1763. settings = repo.settings
  1764. settings['Enforce_signed-off_commits_in_pull-request'] = True
  1765. repo.settings = settings
  1766. self.session.add(repo)
  1767. self.session.commit()
  1768. self.set_up_git_repo(
  1769. new_project=fork, branch_from='feature', mtype='FF')
  1770. user = tests.FakeUser()
  1771. user.username = 'foo'
  1772. with tests.user_set(self.app.application, user):
  1773. output = self.app.get('/test/diff/master..feature')
  1774. self.assertEqual(output.status_code, 200)
  1775. output_text = output.get_data(as_text=True)
  1776. self.assertIn(
  1777. '<title>Diff from feature to master - test\n - '
  1778. 'Pagure</title>', output_text)
  1779. self.assertIn(
  1780. 'This project enforces the '
  1781. 'Signed-off-by statement on all commits', output_text)
  1782. self.assertNotIn(
  1783. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  1784. output_text)
  1785. self.assertNotIn(
  1786. 'This repo enforces that '
  1787. 'all commits are signed off by their author.', output_text)
  1788. @patch('pagure.lib.notify.send_email')
  1789. def test_new_request_pull_req_sign_off_submit(self, send_email):
  1790. """ Test the new_request_pull endpoint. """
  1791. send_email.return_value = True
  1792. self.test_fork_project()
  1793. tests.create_projects_git(
  1794. os.path.join(self.path, 'requests'), bare=True)
  1795. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1796. fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
  1797. # Enforce Signed-of-by in the repo
  1798. settings = repo.settings
  1799. settings['Enforce_signed-off_commits_in_pull-request'] = True
  1800. repo.settings = settings
  1801. self.session.add(repo)
  1802. self.session.commit()
  1803. self.set_up_git_repo(
  1804. new_project=fork, branch_from='feature', mtype='FF')
  1805. user = tests.FakeUser()
  1806. user.username = 'pingou'
  1807. with tests.user_set(self.app.application, user):
  1808. output = self.app.get('/test/diff/master..feature')
  1809. self.assertEqual(output.status_code, 200)
  1810. output_text = output.get_data(as_text=True)
  1811. self.assertIn(
  1812. '<title>Create new Pull Request for master - test\n - '
  1813. 'Pagure</title>', output_text)
  1814. self.assertIn(
  1815. 'This project enforces the '
  1816. 'Signed-off-by statement on all commits', output_text)
  1817. self.assertIn(
  1818. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  1819. output_text)
  1820. csrf_token = self.get_csrf(output=output)
  1821. # Try to create the PR
  1822. data = {
  1823. 'csrf_token': csrf_token,
  1824. 'title': 'foo bar PR',
  1825. 'initial_comment': 'Test Initial Comment',
  1826. }
  1827. output = self.app.post(
  1828. '/test/diff/master..feature', data=data, follow_redirects=True)
  1829. self.assertEqual(output.status_code, 200)
  1830. output_text = output.get_data(as_text=True)
  1831. self.assertIn(
  1832. '<title>Create new Pull Request for master - test\n - '
  1833. 'Pagure</title>', output_text)
  1834. # Flashed information message
  1835. self.assertIn(
  1836. 'This project enforces the '
  1837. 'Signed-off-by statement on all commits', output_text)
  1838. # Flashed error message
  1839. self.assertIn(
  1840. 'This repo enforces that '
  1841. 'all commits are signed off by their author.', output_text)
  1842. self.assertIn(
  1843. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  1844. output_text)
  1845. @patch('pagure.lib.notify.send_email')
  1846. def test_request_pull_commit_start_stop(self, send_email):
  1847. """ Test the the commit start and stop of brand new PR. """
  1848. send_email.return_value = True
  1849. self.test_fork_project()
  1850. tests.create_projects_git(
  1851. os.path.join(self.path, 'requests'), bare=True)
  1852. repo = pagure.lib.get_authorized_project(self.session, 'test')
  1853. fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
  1854. self.set_up_git_repo(
  1855. new_project=fork, branch_from='feature', mtype='FF')
  1856. user = tests.FakeUser()
  1857. user.username = 'pingou'
  1858. with tests.user_set(self.app.application, user):
  1859. output = self.app.get('/test/diff/master..feature')
  1860. self.assertEqual(output.status_code, 200)
  1861. output_text = output.get_data(as_text=True)
  1862. self.assertIn(
  1863. '<title>Create new Pull Request for master - test\n - '
  1864. 'Pagure</title>', output_text)
  1865. self.assertIn(
  1866. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  1867. output_text)
  1868. csrf_token = self.get_csrf(output=output)
  1869. # Case 1 - Add an initial comment
  1870. data = {
  1871. 'csrf_token': csrf_token,
  1872. 'title': 'foo bar PR',
  1873. 'initial_comment': 'Test Initial Comment',
  1874. }
  1875. output = self.app.post(
  1876. '/test/diff/master..feature', data=data, follow_redirects=True)
  1877. self.assertEqual(output.status_code, 200)
  1878. output_text = output.get_data(as_text=True)
  1879. self.assertIn(
  1880. '<title>PR#2: foo bar PR - test\n - Pagure</title>',
  1881. output_text)
  1882. self.assertIn('<p>Test Initial Comment</p>', output_text)
  1883. # Check if commit start and stop have been set for PR#2
  1884. request = pagure.lib.search_pull_requests(
  1885. self.session, project_id=1, requestid=2)
  1886. self.assertIsNotNone(request.commit_start)
  1887. self.assertIsNotNone(request.commit_stop)
  1888. @patch('pagure.lib.notify.send_email')
  1889. def test_new_request_pull_fork_to_fork_pr_disabled(self, send_email):
  1890. """ Test creating a fork to fork PR. """
  1891. send_email.return_value = True
  1892. self.test_fork_project()
  1893. # Create a 3rd user
  1894. item = pagure.lib.model.User(
  1895. user='ralph',
  1896. fullname='Ralph bar',
  1897. password='ralph_foo',
  1898. default_email='ralph@bar.com',
  1899. )
  1900. self.session.add(item)
  1901. item = pagure.lib.model.UserEmail(
  1902. user_id=3,
  1903. email='ralph@bar.com')
  1904. self.session.add(item)
  1905. self.session.commit()
  1906. user = tests.FakeUser()
  1907. user.username = 'ralph'
  1908. with tests.user_set(self.app.application, user):
  1909. # Have Ralph fork, foo's fork of test
  1910. output = self.app.get('/fork/foo/test')
  1911. self.assertEqual(output.status_code, 200)
  1912. output = self.app.post('/do_fork/fork/foo/test')
  1913. self.assertEqual(output.status_code, 400)
  1914. csrf_token = self.get_csrf()
  1915. data = {
  1916. 'csrf_token': csrf_token,
  1917. }
  1918. output = self.app.post(
  1919. '/do_fork/fork/foo/test', data=data,
  1920. follow_redirects=True)
  1921. self.assertEqual(output.status_code, 200)
  1922. # Check that Ralph's fork do exist
  1923. output = self.app.get('/fork/ralph/test')
  1924. self.assertEqual(output.status_code, 200)
  1925. tests.create_projects_git(
  1926. os.path.join(self.path, 'requests'), bare=True)
  1927. fork = pagure.lib.get_authorized_project(
  1928. self.session, 'test', user='ralph')
  1929. self.set_up_git_repo(
  1930. new_project=fork, branch_from='feature', mtype='FF')
  1931. # Try opening a pull-request
  1932. output = self.app.get(
  1933. '/fork/ralph/test/diff/master..feature')
  1934. self.assertEqual(output.status_code, 404)
  1935. self.assertIn(
  1936. '<p>No pull-request allowed on this project</p>',
  1937. output.get_data(as_text=True))
  1938. @patch('pagure.lib.notify.send_email')
  1939. def test_new_request_pull_fork_to_fork(self, send_email):
  1940. """ Test creating a fork to fork PR. """
  1941. send_email.return_value = True
  1942. self.test_fork_project()
  1943. # Create a 3rd user
  1944. item = pagure.lib.model.User(
  1945. user='ralph',
  1946. fullname='Ralph bar',
  1947. password='ralph_foo',
  1948. default_email='ralph@bar.com',
  1949. )
  1950. self.session.add(item)
  1951. item = pagure.lib.model.UserEmail(
  1952. user_id=3,
  1953. email='ralph@bar.com')
  1954. self.session.add(item)
  1955. self.session.commit()
  1956. user = tests.FakeUser()
  1957. user.username = 'ralph'
  1958. with tests.user_set(self.app.application, user):
  1959. # Have Ralph fork, foo's fork of test
  1960. output = self.app.get('/fork/foo/test')
  1961. self.assertEqual(output.status_code, 200)
  1962. output = self.app.post('/do_fork/fork/foo/test')
  1963. self.assertEqual(output.status_code, 400)
  1964. csrf_token = self.get_csrf()
  1965. data = {
  1966. 'csrf_token': csrf_token,
  1967. }
  1968. output = self.app.post(
  1969. '/do_fork/fork/foo/test', data=data,
  1970. follow_redirects=True)
  1971. self.assertEqual(output.status_code, 200)
  1972. # Check that Ralph's fork do exist
  1973. output = self.app.get('/fork/ralph/test')
  1974. self.assertEqual(output.status_code, 200)
  1975. tests.create_projects_git(
  1976. os.path.join(self.path, 'requests'), bare=True)
  1977. # Turn on pull-request on the fork
  1978. repo = pagure.lib.get_authorized_project(
  1979. self.session, 'test', user='foo')
  1980. settings = repo.settings
  1981. settings['pull_requests'] = True
  1982. repo.settings = settings
  1983. self.session.add(repo)
  1984. self.session.commit()
  1985. # Add some content to the parent
  1986. self.set_up_git_repo(
  1987. new_project=repo, branch_from='master', mtype='FF',
  1988. name_from=repo.fullname)
  1989. fork = pagure.lib.get_authorized_project(
  1990. self.session, 'test', user='ralph')
  1991. self.set_up_git_repo(
  1992. new_project=fork, branch_from='feature', mtype='FF',
  1993. prid=2, name_from=fork.fullname)
  1994. # Try opening a pull-request
  1995. output = self.app.get(
  1996. '/fork/ralph/test/diff/master..feature')
  1997. self.assertEqual(output.status_code, 200)
  1998. output_text = output.get_data(as_text=True)
  1999. self.assertIn(
  2000. '<title>Create new Pull Request for master - fork/ralph/test\n - '
  2001. 'Pagure</title>', output_text)
  2002. self.assertIn(
  2003. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2004. output_text)
  2005. csrf_token = self.get_csrf(output=output)
  2006. # Case 1 - Add an initial comment
  2007. data = {
  2008. 'csrf_token': csrf_token,
  2009. 'title': 'foo bar PR',
  2010. 'initial_comment': 'Test Initial Comment',
  2011. }
  2012. output = self.app.post(
  2013. '/fork/ralph/test/diff/master..feature',
  2014. data=data, follow_redirects=True)
  2015. self.assertEqual(output.status_code, 200)
  2016. output_text = output.get_data(as_text=True)
  2017. self.assertIn(
  2018. '<title>PR#1: foo bar PR - fork/foo/test\n - Pagure</title>',
  2019. output_text)
  2020. self.assertIn('<p>Test Initial Comment</p>', output_text)
  2021. @patch('pagure.lib.notify.send_email')
  2022. def test_new_request_pull_fork_to_other_fork(self, send_email):
  2023. """ Test creating a PR from fork to a fork of the same family. """
  2024. send_email.return_value = True
  2025. self.test_fork_project()
  2026. # Create a 3rd user
  2027. item = pagure.lib.model.User(
  2028. user='ralph',
  2029. fullname='Ralph bar',
  2030. password='ralph_foo',
  2031. default_email='ralph@bar.com',
  2032. )
  2033. self.session.add(item)
  2034. item = pagure.lib.model.UserEmail(
  2035. user_id=3,
  2036. email='ralph@bar.com')
  2037. self.session.add(item)
  2038. self.session.commit()
  2039. user = tests.FakeUser()
  2040. user.username = 'ralph'
  2041. with tests.user_set(self.app.application, user):
  2042. csrf_token = self.get_csrf()
  2043. data = {
  2044. 'csrf_token': csrf_token,
  2045. }
  2046. output = self.app.post(
  2047. '/do_fork/test', data=data,
  2048. follow_redirects=True)
  2049. self.assertEqual(output.status_code, 200)
  2050. # Check that Ralph's fork do exist
  2051. output = self.app.get('/fork/ralph/test')
  2052. self.assertEqual(output.status_code, 200)
  2053. tests.create_projects_git(
  2054. os.path.join(self.path, 'requests'), bare=True)
  2055. # Turn on pull-request on the fork
  2056. repo = pagure.lib.get_authorized_project(
  2057. self.session, 'test', user='foo')
  2058. settings = repo.settings
  2059. settings['pull_requests'] = True
  2060. repo.settings = settings
  2061. self.session.add(repo)
  2062. self.session.commit()
  2063. # Add some content to the parents
  2064. self.set_up_git_repo(
  2065. new_project=repo, branch_from='master', mtype='FF')
  2066. self.set_up_git_repo(
  2067. new_project=repo, branch_from='master', mtype='FF',
  2068. name_from=repo.fullname, prid=2)
  2069. fork = pagure.lib.get_authorized_project(
  2070. self.session, 'test', user='ralph')
  2071. self.set_up_git_repo(
  2072. new_project=fork, branch_from='feature', mtype='FF',
  2073. prid=3, name_from=fork.fullname)
  2074. # Try opening a pull-request
  2075. output = self.app.get(
  2076. '/fork/ralph/test/diff/master..feature?project_to=fork/foo/test')
  2077. self.assertEqual(output.status_code, 200)
  2078. output_text = output.get_data(as_text=True)
  2079. self.assertIn(
  2080. '<title>Create new Pull Request for master - fork/ralph/test\n - '
  2081. 'Pagure</title>', output_text)
  2082. self.assertIn(
  2083. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2084. output_text)
  2085. csrf_token = self.get_csrf(output=output)
  2086. # Case 1 - Opening PR to fork/foo/test
  2087. data = {
  2088. 'csrf_token': csrf_token,
  2089. 'title': 'foo bar PR',
  2090. 'initial_comment': 'Test Initial Comment',
  2091. }
  2092. output = self.app.post(
  2093. '/fork/ralph/test/diff/master..feature?project_to=fork/foo/test',
  2094. data=data, follow_redirects=True)
  2095. self.assertEqual(output.status_code, 200)
  2096. output_text = output.get_data(as_text=True)
  2097. self.assertIn(
  2098. '<title>PR#1: foo bar PR - fork/foo/test\n - Pagure</title>',
  2099. output_text)
  2100. self.assertIn('<p>Test Initial Comment</p>', output_text)
  2101. # Case 1 - Opening PR to parent repo, shows project_to works
  2102. output = self.app.post(
  2103. '/fork/ralph/test/diff/master..feature',
  2104. data=data, follow_redirects=True)
  2105. self.assertEqual(output.status_code, 200)
  2106. output_text = output.get_data(as_text=True)
  2107. self.assertIn(
  2108. '<title>PR#4: foo bar PR - test\n - Pagure</title>',
  2109. output_text)
  2110. self.assertIn('<p>Test Initial Comment</p>', output_text)
  2111. @patch('pagure.lib.notify.send_email')
  2112. def test_new_request_pull_fork_to_other_unrelated_fork(self, send_email):
  2113. """ Test creating a PR from fork to fork that isn't from the same
  2114. family.
  2115. """
  2116. send_email.return_value = True
  2117. self.test_fork_project()
  2118. # Create a 3rd user
  2119. item = pagure.lib.model.User(
  2120. user='ralph',
  2121. fullname='Ralph bar',
  2122. password='ralph_foo',
  2123. default_email='ralph@bar.com',
  2124. )
  2125. self.session.add(item)
  2126. item = pagure.lib.model.UserEmail(
  2127. user_id=3,
  2128. email='ralph@bar.com')
  2129. self.session.add(item)
  2130. self.session.commit()
  2131. user = tests.FakeUser()
  2132. user.username = 'ralph'
  2133. with tests.user_set(self.app.application, user):
  2134. csrf_token = self.get_csrf()
  2135. data = {
  2136. 'csrf_token': csrf_token,
  2137. }
  2138. output = self.app.post(
  2139. '/do_fork/test2', data=data,
  2140. follow_redirects=True)
  2141. self.assertEqual(output.status_code, 200)
  2142. # Check that Ralph's fork do exist
  2143. output = self.app.get('/fork/ralph/test2')
  2144. self.assertEqual(output.status_code, 200)
  2145. tests.create_projects_git(
  2146. os.path.join(self.path, 'requests'), bare=True)
  2147. # Turn on pull-request on the fork
  2148. repo = pagure.lib.get_authorized_project(
  2149. self.session, 'test', user='foo')
  2150. settings = repo.settings
  2151. settings['pull_requests'] = True
  2152. repo.settings = settings
  2153. self.session.add(repo)
  2154. self.session.commit()
  2155. # Add some content to the parent
  2156. self.set_up_git_repo(
  2157. new_project=repo, branch_from='master', mtype='FF',
  2158. name_from=repo.fullname)
  2159. fork = pagure.lib.get_authorized_project(
  2160. self.session, 'test2', user='ralph')
  2161. self.set_up_git_repo(
  2162. new_project=fork, branch_from='feature', mtype='FF',
  2163. prid=2, name_from=fork.fullname)
  2164. # Case 1 - Opening PR to fork/foo/test
  2165. data = {
  2166. 'csrf_token': csrf_token,
  2167. 'title': 'foo bar PR',
  2168. 'initial_comment': 'Test Initial Comment',
  2169. }
  2170. output = self.app.post(
  2171. '/fork/ralph/test2/diff/master..feature?project_to=fork/foo/test',
  2172. data=data, follow_redirects=True)
  2173. self.assertEqual(output.status_code, 400)
  2174. self.assertIn(
  2175. "<p>fork/foo/test is not part of fork/ralph/test2's "
  2176. "family</p>", output.get_data(as_text=True))
  2177. @patch('pagure.lib.notify.send_email')
  2178. def test_new_request_pull_empty_repo(self, send_email):
  2179. """ Test the new_request_pull endpoint against an empty repo. """
  2180. send_email.return_value = True
  2181. self.test_fork_project()
  2182. tests.create_projects_git(
  2183. os.path.join(self.path, 'requests'), bare=True)
  2184. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2185. fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
  2186. # Create a git repo to play with
  2187. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  2188. repo = pygit2.init_repository(gitrepo, bare=True)
  2189. # Create a fork of this repo
  2190. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  2191. gitrepo = os.path.join(self.path, 'repos', 'forks', 'foo', 'test.git')
  2192. new_repo = pygit2.clone_repository(gitrepo, newpath)
  2193. user = tests.FakeUser()
  2194. user.username = 'foo'
  2195. with tests.user_set(self.app.application, user):
  2196. output = self.app.get(
  2197. '/fork/foo/test/diff/master..feature',
  2198. follow_redirects=True)
  2199. self.assertEqual(output.status_code, 400)
  2200. self.assertIn(
  2201. '<p>Fork is empty, there are no commits to create a pull '
  2202. 'request with</p>', output.get_data(as_text=True))
  2203. output = self.app.get('/test/new_issue')
  2204. csrf_token = self.get_csrf(output=output)
  2205. data = {
  2206. 'csrf_token': csrf_token,
  2207. 'title': 'foo bar PR',
  2208. }
  2209. output = self.app.post(
  2210. '/test/diff/master..feature', data=data, follow_redirects=True)
  2211. self.assertEqual(output.status_code, 400)
  2212. self.assertIn(
  2213. '<p>Fork is empty, there are no commits to create a pull '
  2214. 'request with</p>', output.get_data(as_text=True))
  2215. shutil.rmtree(newpath)
  2216. @patch('pagure.lib.notify.send_email')
  2217. def test_new_request_pull_empty_fork(self, send_email):
  2218. """ Test the new_request_pull endpoint against an empty repo. """
  2219. send_email.return_value = True
  2220. self.test_fork_project()
  2221. tests.create_projects_git(
  2222. os.path.join(self.path, 'requests'), bare=True)
  2223. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2224. fork = pagure.lib.get_authorized_project(self.session, 'test', user='foo')
  2225. # Create a git repo to play with
  2226. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  2227. repo = pygit2.init_repository(gitrepo, bare=True)
  2228. # Create a fork of this repo
  2229. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  2230. gitrepo = os.path.join(
  2231. self.path, 'repos', 'forks', 'foo', 'test.git')
  2232. new_repo = pygit2.clone_repository(gitrepo, newpath)
  2233. user = tests.FakeUser()
  2234. user.username = 'foo'
  2235. with tests.user_set(self.app.application, user):
  2236. output = self.app.get(
  2237. '/fork/foo/test/diff/master..master', follow_redirects=True)
  2238. self.assertEqual(output.status_code, 400)
  2239. self.assertIn(
  2240. '<p>Fork is empty, there are no commits to create a pull '
  2241. 'request with</p>', output.get_data(as_text=True))
  2242. shutil.rmtree(newpath)
  2243. @patch('pagure.lib.notify.send_email')
  2244. def test_pull_request_add_comment(self, send_email):
  2245. """ Test the pull_request_add_comment endpoint. """
  2246. send_email.return_value = True
  2247. self.test_request_pull()
  2248. user = tests.FakeUser()
  2249. user.username = 'pingou'
  2250. with tests.user_set(self.app.application, user):
  2251. output = self.app.post('/foo/pull-request/1/comment')
  2252. self.assertEqual(output.status_code, 404)
  2253. output = self.app.post('/test/pull-request/100/comment')
  2254. self.assertEqual(output.status_code, 404)
  2255. output = self.app.post('/test/pull-request/1/comment')
  2256. self.assertEqual(output.status_code, 200)
  2257. self.assertTrue(
  2258. output.get_data(as_text=True).startswith('\n<section class="add_comment">'))
  2259. csrf_token = self.get_csrf(output=output)
  2260. data = {
  2261. 'csrf_token': csrf_token,
  2262. 'comment': 'This look alright but we can do better',
  2263. }
  2264. output = self.app.post(
  2265. '/test/pull-request/1/comment', data=data,
  2266. follow_redirects=True)
  2267. self.assertEqual(output.status_code, 200)
  2268. output_text = output.get_data(as_text=True)
  2269. self.assertIn(
  2270. '<title>PR#1: PR from the feature branch - test\n - '
  2271. 'Pagure</title>', output_text)
  2272. self.assertIn(
  2273. 'Comment added',
  2274. output_text)
  2275. self.assertEqual(output_text.count('title="PY C (pingou)"'), 2)
  2276. # Project w/o pull-request
  2277. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2278. settings = repo.settings
  2279. settings['pull_requests'] = False
  2280. repo.settings = settings
  2281. self.session.add(repo)
  2282. self.session.commit()
  2283. output = self.app.post(
  2284. '/test/pull-request/1/comment', data=data,
  2285. follow_redirects=True)
  2286. self.assertEqual(output.status_code, 404)
  2287. @patch('pagure.lib.notify.send_email')
  2288. def test_pull_request_drop_comment(self, send_email):
  2289. """ Test the pull_request_drop_comment endpoint. """
  2290. send_email.return_value = True
  2291. self.test_pull_request_add_comment()
  2292. # Project w/ pull-request
  2293. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2294. settings = repo.settings
  2295. settings['pull_requests'] = True
  2296. repo.settings = settings
  2297. self.session.add(repo)
  2298. self.session.commit()
  2299. user = tests.FakeUser()
  2300. user.username = 'foo'
  2301. with tests.user_set(self.app.application, user):
  2302. output = self.app.post('/foo/pull-request/1/comment/drop')
  2303. self.assertEqual(output.status_code, 404)
  2304. output = self.app.post('/test/pull-request/100/comment/drop')
  2305. self.assertEqual(output.status_code, 404)
  2306. output = self.app.post(
  2307. '/test/pull-request/1/comment/drop', follow_redirects=True)
  2308. self.assertEqual(output.status_code, 200)
  2309. output_text = output.get_data(as_text=True)
  2310. self.assertIn(
  2311. '<h4 class="ml-1">\n <div>\n '
  2312. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  2313. '<span class="text-success '
  2314. 'font-weight-bold">#1</span>\n '
  2315. '<span class="font-weight-bold">\n '
  2316. 'PR from the feature branch\n', output_text)
  2317. #self.assertIn('href="#comment-1">¶</a>', output_text)
  2318. self.assertIn(
  2319. '<p>This look alright but we can do better</p>',
  2320. output_text)
  2321. csrf_token = self.get_csrf(output=output)
  2322. # Invalid comment id
  2323. data = {
  2324. 'csrf_token': csrf_token,
  2325. 'drop_comment': '10',
  2326. }
  2327. output = self.app.post(
  2328. '/test/pull-request/1/comment/drop', data=data,
  2329. follow_redirects=True)
  2330. self.assertEqual(output.status_code, 404)
  2331. data['drop_comment'] = '1'
  2332. output = self.app.post(
  2333. '/test/pull-request/1/comment/drop', data=data,
  2334. follow_redirects=True)
  2335. self.assertEqual(output.status_code, 403)
  2336. user.username = 'pingou'
  2337. with tests.user_set(self.app.application, user):
  2338. # Drop comment
  2339. output = self.app.post(
  2340. '/test/pull-request/1/comment/drop', data=data,
  2341. follow_redirects=True)
  2342. self.assertEqual(output.status_code, 200)
  2343. output_text = output.get_data(as_text=True)
  2344. self.assertIn(
  2345. '<h4 class="ml-1">\n <div>\n '
  2346. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  2347. '<span class="text-success '
  2348. 'font-weight-bold">#1</span>\n '
  2349. '<span class="font-weight-bold">\n '
  2350. 'PR from the feature branch\n',
  2351. output_text)
  2352. self.assertIn(
  2353. 'Comment removed',
  2354. output_text)
  2355. # Project w/o pull-request
  2356. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2357. settings = repo.settings
  2358. settings['pull_requests'] = False
  2359. repo.settings = settings
  2360. self.session.add(repo)
  2361. self.session.commit()
  2362. output = self.app.post(
  2363. '/test/pull-request/1/comment/drop', data=data,
  2364. follow_redirects=True)
  2365. self.assertEqual(output.status_code, 404)
  2366. @patch('pagure.lib.notify.send_email')
  2367. def test_pull_request_edit_comment(self, send_email):
  2368. """ Test the pull request edit comment endpoint """
  2369. send_email.return_value = True
  2370. self.test_request_pull()
  2371. user = tests.FakeUser()
  2372. user.username = 'pingou'
  2373. with tests.user_set(self.app.application, user):
  2374. # Repo 'foo' does not exist so it is verifying that condition
  2375. output = self.app.post('/foo/pull-request/1/comment/1/edit')
  2376. self.assertEqual(output.status_code, 404)
  2377. # Here no comment is present in the PR so its verifying that condition
  2378. output = self.app.post('/test/pull-request/100/comment/100/edit')
  2379. self.assertEqual(output.status_code, 404)
  2380. output = self.app.post('/test/pull-request/1/comment')
  2381. self.assertEqual(output.status_code, 200)
  2382. # Creating comment to play with
  2383. self.assertTrue(
  2384. output.get_data(as_text=True).startswith('\n<section class="add_comment">'))
  2385. csrf_token = self.get_csrf(output=output)
  2386. data = {
  2387. 'csrf_token': csrf_token,
  2388. 'comment': 'This look alright but we can do better',
  2389. }
  2390. output = self.app.post(
  2391. '/test/pull-request/1/comment', data=data,
  2392. follow_redirects=True)
  2393. self.assertEqual(output.status_code, 200)
  2394. output_text = output.get_data(as_text=True)
  2395. self.assertIn(
  2396. '<h4 class="ml-1">\n <div>\n '
  2397. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  2398. '<span class="text-success '
  2399. 'font-weight-bold">#1</span>\n '
  2400. '<span class="font-weight-bold">\n '
  2401. 'PR from the feature branch\n',
  2402. output_text)
  2403. self.assertIn(
  2404. 'Comment added',
  2405. output_text)
  2406. # Check if the comment is there
  2407. self.assertIn(
  2408. '<p>This look alright but we can do better</p>', output_text)
  2409. output = self.app.get('/test/pull-request/1/comment/1/edit')
  2410. self.assertEqual(output.status_code, 200)
  2411. output_text = output.get_data(as_text=True)
  2412. self.assertIn('<section class="edit_comment">', output_text)
  2413. # Checking if the comment is there in the update page
  2414. self.assertIn(
  2415. 'This look alright but we can do better</textarea>', output_text)
  2416. csrf_token = self.get_csrf(output=output)
  2417. data = {
  2418. 'csrf_token': csrf_token,
  2419. 'update_comment': 'This look alright but we can do better than this.',
  2420. }
  2421. output = self.app.post(
  2422. '/test/pull-request/1/comment/1/edit', data=data,
  2423. follow_redirects=True)
  2424. output_text = output.get_data(as_text=True)
  2425. # Checking if the comment is updated in the main page
  2426. self.assertIn(
  2427. '<p>This look alright but we can do better than this.</p>', output_text)
  2428. self.assertIn(
  2429. '<h4 class="ml-1">\n <div>\n '
  2430. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  2431. '<span class="text-success '
  2432. 'font-weight-bold">#1</span>\n '
  2433. '<span class="font-weight-bold">\n '
  2434. 'PR from the feature branch\n',
  2435. output_text)
  2436. # Checking if Edited by User is there or not
  2437. self.assertTrue(
  2438. '<small>Edited just now by pingou </small>'
  2439. in output_text
  2440. or
  2441. '<small>Edited seconds ago by pingou </small>'
  2442. in output_text)
  2443. self.assertIn(
  2444. 'Comment updated', output_text)
  2445. # Project w/o pull-request
  2446. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2447. settings = repo.settings
  2448. settings['pull_requests'] = False
  2449. repo.settings = settings
  2450. self.session.add(repo)
  2451. self.session.commit()
  2452. output = self.app.post(
  2453. '/test/pull-request/1/comment/edit/1', data=data,
  2454. follow_redirects=True)
  2455. self.assertEqual(output.status_code, 404)
  2456. @patch('pagure.lib.notify.send_email')
  2457. def test_merge_request_pull_FF_w_merge_commit(self, send_email):
  2458. """ Test the merge_request_pull endpoint with a FF PR but with a
  2459. merge commit.
  2460. """
  2461. send_email.return_value = True
  2462. self.test_request_pull()
  2463. user = tests.FakeUser()
  2464. with tests.user_set(self.app.application, user):
  2465. output = self.app.get('/test/pull-request/1')
  2466. self.assertEqual(output.status_code, 200)
  2467. csrf_token = self.get_csrf(output=output)
  2468. # No CSRF
  2469. output = self.app.post(
  2470. '/test/pull-request/1/merge', data={}, follow_redirects=True)
  2471. self.assertEqual(output.status_code, 200)
  2472. output_text = output.get_data(as_text=True)
  2473. self.assertIn(
  2474. '<title>PR#1: PR from the feature branch - test\n - '
  2475. 'Pagure</title>', output_text)
  2476. self.assertIn(
  2477. '<h4 class="ml-1">\n <div>\n '
  2478. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  2479. '<span class="text-success '
  2480. 'font-weight-bold">#1</span>\n '
  2481. '<span class="font-weight-bold">\n '
  2482. 'PR from the feature branch\n', output_text)
  2483. self.assertIn(
  2484. 'title="View file as of 2a552b">sources</a>', output_text)
  2485. # Wrong project
  2486. data = {
  2487. 'csrf_token': csrf_token,
  2488. }
  2489. output = self.app.post(
  2490. '/foobar/pull-request/100/merge', data=data, follow_redirects=True)
  2491. self.assertEqual(output.status_code, 404)
  2492. # Wrong project
  2493. data = {
  2494. 'csrf_token': csrf_token,
  2495. }
  2496. output = self.app.post(
  2497. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  2498. self.assertEqual(output.status_code, 403)
  2499. user.username = 'pingou'
  2500. with tests.user_set(self.app.application, user):
  2501. # Wrong request id
  2502. data = {
  2503. 'csrf_token': csrf_token,
  2504. }
  2505. output = self.app.post(
  2506. '/test/pull-request/100/merge', data=data, follow_redirects=True)
  2507. self.assertEqual(output.status_code, 404)
  2508. # Project requiring a merge commit
  2509. repo = pagure.lib.get_authorized_project(self.session, 'test')
  2510. settings = repo.settings
  2511. settings['always_merge'] = True
  2512. repo.settings = settings
  2513. self.session.add(repo)
  2514. self.session.commit()
  2515. # Merge
  2516. output = self.app.post(
  2517. '/test/pull-request/1/merge', data=data, follow_redirects=True)
  2518. self.assertEqual(output.status_code, 200)
  2519. output = self.app.get('/test/commits')
  2520. output_text = output.get_data(as_text=True)
  2521. self.assertIn(
  2522. '<title>Commits - test - Pagure</title>', output_text)
  2523. self.assertIn(
  2524. 'Merge #1 `PR from the feature branch`', output_text)
  2525. self.assertIn(
  2526. 'A commit on branch feature', output_text)
  2527. # Check if the closing notification was added
  2528. output = self.app.get('/test/pull-request/1')
  2529. self.assertIn(
  2530. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  2531. ' </span>\n by\n'
  2532. ' <span title="PY C (pingou)">pingou.</span>\n',
  2533. output.get_data(as_text=True))
  2534. @patch('pagure.lib.notify.send_email')
  2535. def test_internal_endpoint_main_ahead(self, send_email):
  2536. """ Test the new_request_pull endpoint when the main repo is ahead
  2537. of the fork.
  2538. """
  2539. send_email.return_value = True
  2540. tests.create_projects(self.session)
  2541. tests.create_projects_git(
  2542. os.path.join(self.path, 'requests'), bare=True)
  2543. self.set_up_git_repo(
  2544. new_project=None,
  2545. branch_from='feature')
  2546. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  2547. repo = pygit2.init_repository(gitrepo, bare=True)
  2548. # Make the main repo be ahead of the fork
  2549. # First commit
  2550. newpath = tempfile.mkdtemp(prefix='pagure-test')
  2551. repopath = os.path.join(newpath, 'test')
  2552. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  2553. # Create a file in that git repo
  2554. with open(os.path.join(repopath, 'testfile'), 'w') as stream:
  2555. stream.write('foo\n bar')
  2556. clone_repo.index.add('testfile')
  2557. clone_repo.index.write()
  2558. # Commits the files added
  2559. last_commit = clone_repo.revparse_single('HEAD')
  2560. tree = clone_repo.index.write_tree()
  2561. author = pygit2.Signature(
  2562. 'Alice Author', 'alice@authors.tld')
  2563. committer = pygit2.Signature(
  2564. 'Cecil Committer', 'cecil@committers.tld')
  2565. clone_repo.create_commit(
  2566. 'refs/heads/master', # the name of the reference to update
  2567. author,
  2568. committer,
  2569. 'Add testfile file for testing',
  2570. # binary string representing the tree object ID
  2571. tree,
  2572. # list of binary strings representing parents of the new commit
  2573. [last_commit.oid.hex]
  2574. )
  2575. # Second commit
  2576. with open(os.path.join(repopath, 'testfile'), 'a') as stream:
  2577. stream.write('\nfoo2\n bar2')
  2578. clone_repo.index.add('testfile')
  2579. clone_repo.index.write()
  2580. # Commits the files added
  2581. last_commit = clone_repo.revparse_single('HEAD')
  2582. tree = clone_repo.index.write_tree()
  2583. author = pygit2.Signature(
  2584. 'Alice Author', 'alice@authors.tld')
  2585. committer = pygit2.Signature(
  2586. 'Cecil Committer', 'cecil@committers.tld')
  2587. clone_repo.create_commit(
  2588. 'refs/heads/master', # the name of the reference to update
  2589. author,
  2590. committer,
  2591. 'Add a second commit to testfile for testing',
  2592. # binary string representing the tree object ID
  2593. tree,
  2594. # list of binary strings representing parents of the new commit
  2595. [last_commit.oid.hex]
  2596. )
  2597. # Third commit
  2598. with open(os.path.join(repopath, 'testfile'), 'a') as stream:
  2599. stream.write('\nfoo3\n bar3')
  2600. clone_repo.index.add('testfile')
  2601. clone_repo.index.write()
  2602. # Commits the files added
  2603. last_commit = clone_repo.revparse_single('HEAD')
  2604. tree = clone_repo.index.write_tree()
  2605. author = pygit2.Signature(
  2606. 'Alice Author', 'alice@authors.tld')
  2607. committer = pygit2.Signature(
  2608. 'Cecil Committer', 'cecil@committers.tld')
  2609. clone_repo.create_commit(
  2610. 'refs/heads/master', # the name of the reference to update
  2611. author,
  2612. committer,
  2613. 'Add a third commit to testfile for testing',
  2614. # binary string representing the tree object ID
  2615. tree,
  2616. # list of binary strings representing parents of the new commit
  2617. [last_commit.oid.hex]
  2618. )
  2619. refname = 'refs/heads/master:refs/heads/master'
  2620. ori_remote = clone_repo.remotes[0]
  2621. PagureRepo.push(ori_remote, refname)
  2622. shutil.rmtree(newpath)
  2623. user = tests.FakeUser()
  2624. user.username = 'foo'
  2625. with tests.user_set(self.app.application, user):
  2626. csrf_token = self.get_csrf()
  2627. output = self.app.post(
  2628. '/pv/pull-request/ready',
  2629. data={'repo': 'test', 'csrf_token': csrf_token}
  2630. )
  2631. self.assertEqual(output.status_code, 200)
  2632. data = json.loads(output.get_data(as_text=True))
  2633. self.assertEqual(
  2634. data,
  2635. {
  2636. "code": "OK",
  2637. "message": {
  2638. "branch_w_pr": {
  2639. "feature": "test/pull-request/1"
  2640. },
  2641. "new_branch": {}
  2642. }
  2643. }
  2644. )
  2645. @patch('pagure.lib.notify.send_email')
  2646. def test_fork_edit_file(self, send_email):
  2647. """ Test the fork_edit file endpoint. """
  2648. send_email.return_value = True
  2649. # Git repo not found
  2650. output = self.app.post('fork_edit/test/edit/master/f/sources')
  2651. self.assertEqual(output.status_code, 404)
  2652. tests.create_projects(self.session)
  2653. for folder in ['docs', 'tickets', 'requests', 'repos']:
  2654. tests.create_projects_git(
  2655. os.path.join(self.path, folder), bare=True)
  2656. # User not logged in
  2657. output = self.app.post('fork_edit/test/edit/master/f/sources')
  2658. self.assertEqual(output.status_code, 302)
  2659. user = tests.FakeUser()
  2660. user.username = 'pingou'
  2661. with tests.user_set(self.app.application, user):
  2662. # Invalid request
  2663. output = self.app.post('fork_edit/test/edit/master/f/source')
  2664. self.assertEqual(output.status_code, 400)
  2665. output = self.app.get('/new/')
  2666. self.assertEqual(output.status_code, 200)
  2667. self.assertIn('<strong>Create new Project</strong>', output.get_data(as_text=True))
  2668. csrf_token = self.get_csrf(output=output)
  2669. data = {
  2670. 'csrf_token': csrf_token,
  2671. }
  2672. # No files can be found since they are not added
  2673. output = self.app.post('fork_edit/test/edit/master/f/sources',
  2674. data=data, follow_redirects=True)
  2675. self.assertEqual(output.status_code, 404)
  2676. user = tests.FakeUser()
  2677. user.username = 'foo'
  2678. with tests.user_set(self.app.application, user):
  2679. data = {
  2680. 'csrf_token': csrf_token,
  2681. }
  2682. # Invalid request
  2683. output = self.app.post('fork_edit/test/edit/master/f/sources',
  2684. follow_redirects=True)
  2685. self.assertEqual(output.status_code, 400)
  2686. # Add content to the repo
  2687. tests.add_content_git_repo(os.path.join(
  2688. pagure.config.config['GIT_FOLDER'], 'test.git'))
  2689. tests.add_readme_git_repo(os.path.join(
  2690. pagure.config.config['GIT_FOLDER'], 'test.git'))
  2691. tests.add_binary_git_repo(
  2692. os.path.join(
  2693. pagure.config.config['GIT_FOLDER'], 'test.git'), 'test.jpg')
  2694. # Check if button exists
  2695. output = self.app.get('/test/blob/master/f/sources')
  2696. self.assertEqual(output.status_code, 200)
  2697. self.assertIn(
  2698. 'Fork and Edit\n </button>\n',
  2699. output.get_data(as_text=True))
  2700. # Check fork-edit doesn't show for binary files
  2701. output = self.app.get('/test/blob/master/f/test.jpg')
  2702. self.assertEqual(output.status_code, 200)
  2703. self.assertNotIn(
  2704. 'Fork and Edit\n </button>\n',
  2705. output.get_data(as_text=True))
  2706. # Check for edit panel
  2707. output = self.app.post('fork_edit/test/edit/master/f/sources',
  2708. data=data, follow_redirects=True)
  2709. self.assertEqual(output.status_code, 200)
  2710. output_text = output.get_data(as_text=True)
  2711. self.assertIn(
  2712. '<li><a href="/fork/foo/test/tree/master">'
  2713. '<span class="fa fa-random"></span>&nbsp; master</a>'
  2714. '</li><li class="active"><span class="fa fa-file">'
  2715. '</span>&nbsp; sources</li>',
  2716. output_text)
  2717. self.assertIn(
  2718. '<textarea id="textareaCode" name="content">foo\n bar</textarea>',
  2719. output_text)
  2720. # Check for edit panel- Fork already done
  2721. output = self.app.post('fork_edit/test/edit/master/f/sources',
  2722. data=data, follow_redirects=True)
  2723. self.assertEqual(output.status_code, 200)
  2724. output_text = output.get_data(as_text=True)
  2725. self.assertIn(
  2726. '<title>Edit - test - Pagure</title>',
  2727. output_text)
  2728. self.assertIn(
  2729. 'You had already forked '
  2730. 'this project', output_text)
  2731. self.assertIn(
  2732. '<i class="fa fa-code-fork fa-fw"></i> View Upstream',
  2733. output_text)
  2734. self.assertIn(
  2735. '<li><a href="/fork/foo/test/tree/master">'
  2736. '<span class="fa fa-random"></span>&nbsp; master</a>'
  2737. '</li><li class="active"><span class="fa fa-file">'
  2738. '</span>&nbsp; sources</li>',
  2739. output_text)
  2740. self.assertIn(
  2741. '<textarea id="textareaCode" name="content">foo\n bar</textarea>',
  2742. output_text)
  2743. # View what's supposed to be an image
  2744. output = self.app.post('fork_edit/test/edit/master/f/test.jpg',
  2745. data=data, follow_redirects=True)
  2746. self.assertEqual(output.status_code, 400)
  2747. self.assertIn('<p>Cannot edit binary files</p>', output.get_data(as_text=True))
  2748. # Check fork-edit shows when user is not logged in
  2749. output = self.app.get('/test/blob/master/f/sources')
  2750. self.assertEqual(output.status_code, 200)
  2751. self.assertIn(
  2752. 'Fork and Edit\n </button>\n',
  2753. output.get_data(as_text=True))
  2754. # Check if fork-edit shows for different user
  2755. user.username = 'pingou'
  2756. with tests.user_set(self.app.application, user):
  2757. # Check if button exists
  2758. output = self.app.get('/test/blob/master/f/sources')
  2759. self.assertEqual(output.status_code, 200)
  2760. self.assertIn(
  2761. 'Edit in your fork\n </button>\n',
  2762. output.get_data(as_text=True))
  2763. # Check fork-edit doesn't show for binary
  2764. output = self.app.get('/test/blob/master/f/test.jpg')
  2765. self.assertEqual(output.status_code, 200)
  2766. self.assertNotIn(
  2767. 'Edit in your fork\n </button>\n',
  2768. output.get_data(as_text=True))
  2769. @patch('pagure.lib.notify.send_email', MagicMock(return_value=True))
  2770. def test_fork_edit_file_namespace(self):
  2771. """ Test the fork_edit file endpoint on a namespaced project. """
  2772. tests.create_projects(self.session)
  2773. for folder in ['docs', 'tickets', 'requests', 'repos']:
  2774. tests.create_projects_git(
  2775. os.path.join(self.path, folder), bare=True)
  2776. # User not logged in
  2777. output = self.app.post(
  2778. 'fork_edit/somenamespace/test3/edit/master/f/sources')
  2779. self.assertEqual(output.status_code, 302)
  2780. user = tests.FakeUser()
  2781. user.username = 'pingou'
  2782. with tests.user_set(self.app.application, user):
  2783. # Invalid request
  2784. output = self.app.post(
  2785. 'fork_edit/somenamespace/test3/edit/master/f/sources')
  2786. self.assertEqual(output.status_code, 400)
  2787. output = self.app.get('/new/')
  2788. self.assertEqual(output.status_code, 200)
  2789. self.assertIn('<strong>Create new Project</strong>', output.get_data(as_text=True))
  2790. csrf_token = self.get_csrf(output=output)
  2791. data = {
  2792. 'csrf_token': csrf_token,
  2793. }
  2794. # No files can be found since they are not added
  2795. output = self.app.post(
  2796. 'fork_edit/somenamespace/test3/edit/master/f/sources',
  2797. data=data, follow_redirects=True)
  2798. self.assertEqual(output.status_code, 404)
  2799. user = tests.FakeUser()
  2800. user.username = 'foo'
  2801. with tests.user_set(self.app.application, user):
  2802. data = {
  2803. 'csrf_token': csrf_token,
  2804. }
  2805. # Invalid request
  2806. output = self.app.post(
  2807. 'fork_edit/somenamespace/test3/edit/master/f/sources',
  2808. follow_redirects=True)
  2809. self.assertEqual(output.status_code, 400)
  2810. # Add content to the repo
  2811. tests.add_content_git_repo(os.path.join(
  2812. pagure.config.config['GIT_FOLDER'],
  2813. 'somenamespace', 'test3.git'))
  2814. tests.add_readme_git_repo(os.path.join(
  2815. pagure.config.config['GIT_FOLDER'],
  2816. 'somenamespace', 'test3.git'))
  2817. tests.add_binary_git_repo(
  2818. os.path.join(
  2819. pagure.config.config['GIT_FOLDER'],
  2820. 'somenamespace', 'test3.git'), 'test.jpg')
  2821. # Check if button exists
  2822. output = self.app.get('/somenamespace/test3/blob/master/f/sources')
  2823. self.assertEqual(output.status_code, 200)
  2824. self.assertIn(
  2825. 'Fork and Edit\n </button>\n',
  2826. output.get_data(as_text=True))
  2827. # Check fork-edit doesn't show for binary files
  2828. output = self.app.get('/somenamespace/test3/blob/master/f/test.jpg')
  2829. self.assertEqual(output.status_code, 200)
  2830. self.assertNotIn(
  2831. 'Fork and Edit\n </button>\n',
  2832. output.get_data(as_text=True))
  2833. # Check for edit panel
  2834. output = self.app.post(
  2835. 'fork_edit/somenamespace/test3/edit/master/f/sources',
  2836. data=data, follow_redirects=True)
  2837. self.assertEqual(output.status_code, 200)
  2838. output_text = output.get_data(as_text=True)
  2839. self.assertIn(
  2840. '<title>Edit - somenamespace/test3 - Pagure</title>',
  2841. output_text)
  2842. self.assertIn(
  2843. '<i class="fa fa-code-fork fa-fw"></i> View Upstream',
  2844. output_text)
  2845. self.assertIn(
  2846. '<li><a href="/fork/foo/somenamespace/test3/tree/master">'
  2847. '<span class="fa fa-random"></span>&nbsp; master</a>'
  2848. '</li><li class="active"><span class="fa fa-file">'
  2849. '</span>&nbsp; sources</li>',
  2850. output_text)
  2851. self.assertIn(
  2852. '<textarea id="textareaCode" name="content">foo\n bar</textarea>',
  2853. output_text)
  2854. # Check for edit panel - while the project was already forked
  2855. output = self.app.post(
  2856. 'fork_edit/somenamespace/test3/edit/master/f/sources',
  2857. data=data, follow_redirects=True)
  2858. self.assertEqual(output.status_code, 200)
  2859. output_text = output.get_data(as_text=True)
  2860. self.assertIn(
  2861. '<title>Edit - somenamespace/test3 - Pagure</title>',
  2862. output_text)
  2863. self.assertIn(
  2864. 'You had already forked '
  2865. 'this project', output_text)
  2866. self.assertIn(
  2867. '<i class="fa fa-code-fork fa-fw"></i> View Upstream',
  2868. output_text)
  2869. self.assertIn(
  2870. '<li><a href="/fork/foo/somenamespace/test3/tree/master">'
  2871. '<span class="fa fa-random"></span>&nbsp; master</a>'
  2872. '</li><li class="active"><span class="fa fa-file">'
  2873. '</span>&nbsp; sources</li>',
  2874. output_text)
  2875. self.assertIn(
  2876. '<textarea id="textareaCode" name="content">foo\n bar</textarea>',
  2877. output_text)
  2878. @patch('pagure.lib.notify.send_email')
  2879. def test_fork_without_main_repo(self, send_email):
  2880. """ Test the fork without the main repo. """
  2881. send_email.return_value = True
  2882. tests.create_projects(self.session)
  2883. # Create a fork with no parent i.e parent_id = None
  2884. item = pagure.lib.model.Project(
  2885. user_id=2, # foo
  2886. name='test',
  2887. description='test project #1',
  2888. hook_token='aaabbb',
  2889. is_fork=True,
  2890. parent_id=None,
  2891. )
  2892. self.session.add(item)
  2893. self.session.commit()
  2894. # Get fork project
  2895. project = pagure.lib._get_project(self.session, 'test', 'foo')
  2896. # Pull-requests and issue-trackers are off for forks
  2897. # lib function is not used here so mannually turning them off
  2898. project_settings = project.settings
  2899. project_settings['pull_requests'] = False
  2900. project_settings['issue_tracker'] = False
  2901. project.settings = project_settings
  2902. self.session.add(project)
  2903. self.session.commit()
  2904. tests.create_projects_git(
  2905. os.path.join(self.path, 'repos', 'forks', 'foo'), bare=True)
  2906. # Create a git repo to play with
  2907. gitrepo = os.path.join(self.path, 'repos', 'test.git')
  2908. self.assertFalse(os.path.exists(gitrepo))
  2909. os.makedirs(gitrepo)
  2910. repo = pygit2.init_repository(gitrepo, bare=True)
  2911. # Create a fork of this repo
  2912. newpath = tempfile.mkdtemp(prefix='pagure-fork-test')
  2913. gitrepo = os.path.join(self.path, 'repos', 'forks', 'foo', 'test.git')
  2914. new_repo = pygit2.clone_repository(gitrepo, newpath)
  2915. tests.add_content_git_repo(gitrepo)
  2916. # UI test for deleted main
  2917. output = self.app.get('/fork/foo/test')
  2918. self.assertEqual(output.status_code, 200)
  2919. self.assertIn('Forked from a deleted repository', output.get_data(as_text=True))
  2920. # Testing commit endpoint
  2921. output = self.app.get('/fork/foo/test/commits/master')
  2922. self.assertEqual(output.status_code, 200)
  2923. self.assertIn(
  2924. 'Commits <span class="badge badge-secondary"> 2</span>\n',
  2925. output.get_data(as_text=True))
  2926. # Test pull-request endpoint
  2927. output = self.app.get('/fork/foo/test/pull-requests')
  2928. self.assertEqual(output.status_code, 404)
  2929. # Test issue-tracker endpoint
  2930. output = self.app.get('/fork/foo/test/issues')
  2931. self.assertEqual(output.status_code, 404)
  2932. shutil.rmtree(newpath)
  2933. def _set_up_for_reaction_test(self):
  2934. self.session.add(pagure.lib.model.User(
  2935. user='jdoe',
  2936. fullname='John Doe',
  2937. password=b'password',
  2938. default_email='jdoe@example.com',
  2939. ))
  2940. self.session.commit()
  2941. tests.create_projects(self.session)
  2942. tests.create_projects_git(
  2943. os.path.join(self.path, 'requests'), bare=True)
  2944. self.set_up_git_repo(new_project=None, branch_from='feature')
  2945. pagure.lib.get_authorized_project(self.session, 'test')
  2946. request = pagure.lib.search_pull_requests(
  2947. self.session, requestid=1, project_id=1,
  2948. )
  2949. pagure.lib.add_pull_request_comment(
  2950. self.session,
  2951. request=request,
  2952. commit=None,
  2953. tree_id=None,
  2954. filename=None,
  2955. row=None,
  2956. comment='Hello',
  2957. user='jdoe',
  2958. )
  2959. self.session.commit()
  2960. @patch('pagure.lib.notify.send_email')
  2961. def test_add_reaction(self, send_email):
  2962. """ Test the request_pull endpoint. """
  2963. send_email.return_value = True
  2964. self._set_up_for_reaction_test()
  2965. user = tests.FakeUser()
  2966. user.username = 'pingou'
  2967. with tests.user_set(self.app.application, user):
  2968. output = self.app.get('/test/pull-request/1')
  2969. self.assertEqual(output.status_code, 200)
  2970. data = {
  2971. 'csrf_token': self.get_csrf(output=output),
  2972. 'reaction': 'Thumbs up',
  2973. }
  2974. output = self.app.post(
  2975. '/test/pull-request/1/comment/1/react',
  2976. data=data,
  2977. follow_redirects=True,
  2978. )
  2979. self.assertEqual(output.status_code, 200)
  2980. # Load the page and check reaction is added.
  2981. output = self.app.get('/test/pull-request/1')
  2982. self.assertEqual(output.status_code, 200)
  2983. self.assertIn(
  2984. 'Thumbs up sent by pingou',
  2985. output.get_data(as_text=True)
  2986. )
  2987. @patch('pagure.lib.notify.send_email')
  2988. def test_add_reaction_unauthenticated(self, send_email):
  2989. """ Test the request_pull endpoint. """
  2990. send_email.return_value = True
  2991. self._set_up_for_reaction_test()
  2992. output = self.app.get('/test/pull-request/1')
  2993. self.assertEqual(output.status_code, 200)
  2994. data = {
  2995. 'csrf_token': self.get_csrf(output=output),
  2996. 'reaction': 'Thumbs down',
  2997. }
  2998. output = self.app.post(
  2999. '/test/pull-request/1/comment/1/react',
  3000. data=data,
  3001. follow_redirects=False,
  3002. )
  3003. # Redirect to login page
  3004. self.assertEqual(output.status_code, 302)
  3005. self.assertIn('/login/', output.headers['Location'])
  3006. if __name__ == '__main__':
  3007. unittest.main(verbosity=2)