test_pagure_flask_ui_fork.py 174 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2015-2017 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. from __future__ import unicode_literals, absolute_import
  8. import json
  9. import unittest
  10. import shutil
  11. import sys
  12. import tempfile
  13. import time
  14. import os
  15. import re
  16. import pygit2
  17. import six
  18. from mock import patch, MagicMock
  19. from bs4 import BeautifulSoup
  20. from datetime import datetime, timedelta
  21. sys.path.insert(
  22. 0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
  23. )
  24. import pagure.lib.query
  25. import pagure.lib.tasks
  26. import tests
  27. from pagure.lib.repo import PagureRepo
  28. def _get_commits(output):
  29. """ Returns the commits message in the output. All commits must have
  30. been made by `Alice Author` or `PY C` to be found.
  31. """
  32. commits = []
  33. save = False
  34. cnt = 0
  35. for row in output.split("\n"):
  36. if row.strip() in ["Alice Author", "Alice Äuthòr", "PY C"]:
  37. save = True
  38. if save:
  39. cnt += 1
  40. if cnt == 7:
  41. commits.append(row.strip())
  42. save = False
  43. cnt = 0
  44. return commits
  45. def set_up_git_repo(
  46. session,
  47. path,
  48. new_project=None,
  49. branch_from="feature",
  50. mtype="FF",
  51. prid=1,
  52. name_from="test",
  53. ):
  54. """ Set up the git repo and create the corresponding PullRequest
  55. object.
  56. """
  57. # Create a git repo to play with
  58. gitrepo = os.path.join(path, "repos", "%s.git" % name_from)
  59. repo = pygit2.init_repository(gitrepo, bare=True)
  60. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  61. repopath = os.path.join(newpath, "test")
  62. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  63. # Create a file in that git repo
  64. with open(os.path.join(repopath, "sources"), "w") as stream:
  65. stream.write("foo\n bar")
  66. clone_repo.index.add("sources")
  67. clone_repo.index.write()
  68. try:
  69. com = repo.revparse_single("HEAD")
  70. prev_commit = [com.oid.hex]
  71. except:
  72. prev_commit = []
  73. # Commits the files added
  74. tree = clone_repo.index.write_tree()
  75. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  76. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  77. clone_repo.create_commit(
  78. "refs/heads/master", # the name of the reference to update
  79. author,
  80. committer,
  81. "Add sources file for testing",
  82. # binary string representing the tree object ID
  83. tree,
  84. # list of binary strings representing parents of the new commit
  85. prev_commit,
  86. )
  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("Alice Äuthòr", "alice@äuthòrs.tld")
  104. comitter = compatible_signature(
  105. "Cecil Cõmmîttër", "cecil@cõmmîttërs.tld"
  106. )
  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("Alice Author", "alice@authors.tld")
  128. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  129. clone_repo.create_commit(
  130. "refs/heads/master",
  131. author,
  132. committer,
  133. "Add sources conflicting",
  134. # binary string representing the tree object ID
  135. tree,
  136. # list of binary strings representing parents of the new commit
  137. [first_commit.oid.hex],
  138. )
  139. refname = "refs/heads/master:refs/heads/master"
  140. ori_remote = clone_repo.remotes[0]
  141. PagureRepo.push(ori_remote, refname)
  142. # Set the second repo
  143. new_gitrepo = repopath
  144. if new_project:
  145. # Create a new git repo to play with
  146. new_gitrepo = os.path.join(newpath, new_project.fullname)
  147. if not os.path.exists(new_gitrepo):
  148. os.makedirs(new_gitrepo)
  149. new_repo = pygit2.clone_repository(gitrepo, new_gitrepo)
  150. repo = pygit2.Repository(new_gitrepo)
  151. if mtype != "nochanges":
  152. # Edit the sources file again
  153. with open(os.path.join(new_gitrepo, "sources"), "w") as stream:
  154. stream.write("foo\n bar\nbaz\n boose")
  155. repo.index.add("sources")
  156. repo.index.write()
  157. # Commits the files added
  158. tree = repo.index.write_tree()
  159. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  160. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  161. repo.create_commit(
  162. "refs/heads/%s" % branch_from,
  163. author,
  164. committer,
  165. "A commit on branch %s\n\nMore information" % branch_from,
  166. tree,
  167. [first_commit.oid.hex],
  168. )
  169. refname = "refs/heads/%s" % (branch_from)
  170. ori_remote = repo.remotes[0]
  171. PagureRepo.push(ori_remote, refname)
  172. # Create a PR for these changes
  173. project = pagure.lib.query.get_authorized_project(session, "test")
  174. req = pagure.lib.query.new_pull_request(
  175. session=session,
  176. repo_from=project,
  177. branch_from=branch_from,
  178. repo_to=project,
  179. branch_to="master",
  180. title="PR from the %s branch" % branch_from,
  181. user="pingou",
  182. )
  183. session.commit()
  184. assert req.id == prid
  185. assert req.title == "PR from the %s branch" % branch_from
  186. shutil.rmtree(newpath)
  187. class PagureFlaskForktests(tests.Modeltests):
  188. """ Tests for flask fork controller of pagure """
  189. def test_request_pull_reference(self):
  190. """ Test if there is a reference created for a new PR. """
  191. tests.create_projects(self.session)
  192. tests.create_projects_git(
  193. os.path.join(self.path, "requests"), bare=True
  194. )
  195. set_up_git_repo(
  196. self.session, self.path, new_project=None, branch_from="feature"
  197. )
  198. project = pagure.lib.query.get_authorized_project(self.session, "test")
  199. self.assertEqual(len(project.requests), 1)
  200. # View the pull-request
  201. output = self.app.get("/test/pull-request/1")
  202. self.assertEqual(output.status_code, 200)
  203. gitrepo = os.path.join(self.path, "repos", "test.git")
  204. repo = pygit2.Repository(gitrepo)
  205. self.assertEqual(
  206. list(repo.listall_references()),
  207. ["refs/heads/feature", "refs/heads/master", "refs/pull/1/head"],
  208. )
  209. @patch("pagure.lib.notify.send_email")
  210. def test_request_pull(self, send_email):
  211. """ Test the request_pull endpoint. """
  212. send_email.return_value = True
  213. tests.create_projects(self.session)
  214. tests.create_projects_git(
  215. os.path.join(self.path, "requests"), bare=True
  216. )
  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. set_up_git_repo(
  224. self.session, self.path, new_project=None, branch_from="feature"
  225. )
  226. project = pagure.lib.query.get_authorized_project(self.session, "test")
  227. self.assertEqual(len(project.requests), 1)
  228. # View the pull-request
  229. output = self.app.get("/test/pull-request/1")
  230. self.assertEqual(output.status_code, 200)
  231. output_text = output.get_data(as_text=True)
  232. # self.assertIn(
  233. #'<h3><span class="label label-default">PR#1</span>\n'
  234. #' PR from the feature branch\n</h3>',
  235. # output_text)
  236. self.assertIn(
  237. 'title="View file as of 2a552b">sources</a>', output_text
  238. )
  239. # Test if the `open changed file icon` is displayed.
  240. self.assertIn(
  241. 'class="open_changed_file_icon_wrap"><span '
  242. 'class="fa fa-file-code-o fa-fw" '
  243. 'alt="Open changed file" title="Open changed file"></span>'
  244. "</a>",
  245. output_text,
  246. )
  247. self.assertIn(
  248. '<span class="btn btn-success btn-sm font-weight-bold disabled opacity-100">+3</span>',
  249. output_text,
  250. )
  251. self.assertIn(
  252. '<span class="btn btn-danger btn-sm font-weight-bold disabled opacity-100">-1</span>',
  253. output_text,
  254. )
  255. @patch("pagure.lib.notify.send_email")
  256. def test_task_update_request_pull(self, send_email):
  257. """ Test the task update_pull_request endpoint. """
  258. send_email.return_value = True
  259. tests.create_projects(self.session)
  260. tests.create_projects_git(
  261. os.path.join(self.path, "requests"), bare=True
  262. )
  263. set_up_git_repo(
  264. self.session, self.path, new_project=None, branch_from="feature"
  265. )
  266. self.session = pagure.lib.query.create_session(self.dbpath)
  267. project = pagure.lib.query.get_authorized_project(self.session, "test")
  268. self.assertEqual(len(project.requests), 1)
  269. request = project.requests[0]
  270. self.assertEqual(len(request.comments), 0)
  271. start_commit = request.commit_start
  272. stop_commit = request.commit_stop
  273. # View the pull-request
  274. output = self.app.get("/test/pull-request/1")
  275. self.assertEqual(output.status_code, 200)
  276. output_text = output.get_data(as_text=True)
  277. self.assertIn(
  278. "<title>PR#1: PR from the feature branch - test\n - Pagure</title>",
  279. output_text,
  280. )
  281. self.assertIn(
  282. 'title="View file as of 2a552b">sources</a>', output_text
  283. )
  284. # Add a new commit on the repo from
  285. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  286. gitrepo = os.path.join(self.path, "repos", "test.git")
  287. repopath = os.path.join(newpath, "test")
  288. clone_repo = pygit2.clone_repository(
  289. gitrepo, repopath, checkout_branch="feature"
  290. )
  291. def compatible_signature(name, email):
  292. if six.PY2:
  293. name = name.encode("utf-8")
  294. email = email.encode("utf-8")
  295. return pygit2.Signature(name, email)
  296. with open(os.path.join(repopath, ".gitignore"), "w") as stream:
  297. stream.write("*~")
  298. clone_repo.index.add(".gitignore")
  299. clone_repo.index.write()
  300. com = clone_repo.revparse_single("HEAD")
  301. prev_commit = [com.oid.hex]
  302. # Commits the files added
  303. tree = clone_repo.index.write_tree()
  304. author = compatible_signature("Alice Äuthòr", "alice@äuthòrs.tld")
  305. comitter = compatible_signature(
  306. "Cecil Cõmmîttër", "cecil@cõmmîttërs.tld"
  307. )
  308. clone_repo.create_commit(
  309. "refs/heads/feature",
  310. author,
  311. comitter,
  312. "Add .gitignore file for testing",
  313. # binary string representing the tree object ID
  314. tree,
  315. # list of binary strings representing parents of the new commit
  316. prev_commit,
  317. )
  318. refname = "refs/heads/feature:refs/heads/feature"
  319. ori_remote = clone_repo.remotes[0]
  320. PagureRepo.push(ori_remote, refname)
  321. shutil.rmtree(newpath)
  322. pagure.lib.tasks.update_pull_request(request.uid)
  323. self.session = pagure.lib.query.create_session(self.dbpath)
  324. project = pagure.lib.query.get_authorized_project(self.session, "test")
  325. self.assertEqual(len(project.requests), 1)
  326. request = project.requests[0]
  327. self.assertEqual(len(request.comments), 1)
  328. self.assertIsNotNone(request.commit_start)
  329. self.assertIsNotNone(request.commit_stop)
  330. self.assertNotEqual(start_commit, request.commit_start)
  331. self.assertNotEqual(stop_commit, request.commit_stop)
  332. @patch("pagure.lib.notify.send_email")
  333. def test_request_pull_ci_dropdown(self, send_email):
  334. """ Test presence of the "Rerun CI" dropdown with various settings. """
  335. send_email.return_value = True
  336. tests.create_projects(self.session)
  337. tests.create_projects_git(
  338. os.path.join(self.path, "requests"), bare=True
  339. )
  340. set_up_git_repo(
  341. self.session, self.path, new_project=None, branch_from="feature"
  342. )
  343. user = tests.FakeUser()
  344. user.username = "pingou"
  345. with tests.user_set(self.app.application, user):
  346. # old-style TRIGGER_CI list - test backwards compatibility
  347. with patch.dict(
  348. "pagure.config.config",
  349. {"TRIGGER_CI": ["old-style-trigger-ci"]},
  350. ):
  351. output = self.app.get("/test/pull-request/1")
  352. self.assertEqual(output.status_code, 200)
  353. output_text = output.get_data(as_text=True)
  354. self.assertNotIn("Rerun CI", output_text)
  355. # new-style TRIGGER_CI, but no button to show
  356. with patch.dict(
  357. "pagure.config.config", {"TRIGGER_CI": {"no-button": None}}
  358. ):
  359. output = self.app.get("/test/pull-request/1")
  360. self.assertEqual(output.status_code, 200)
  361. output_text = output.get_data(as_text=True)
  362. self.assertNotIn("Rerun CI", output_text)
  363. trigger_ci = {
  364. "foobar-ci": {
  365. "name": "foobar-ci-name",
  366. "description": "barfoo",
  367. },
  368. "spam-ci": {
  369. "name": "spam-ci-name",
  370. "description": "with beans and eggs",
  371. },
  372. "no-button-for-me-ci": None,
  373. }
  374. # new-style TRIGGER_CI, several buttons to show
  375. with patch.dict(
  376. "pagure.config.config", {"TRIGGER_CI": trigger_ci}
  377. ):
  378. output = self.app.get("/test/pull-request/1")
  379. self.assertEqual(output.status_code, 200)
  380. output_text = output.get_data(as_text=True)
  381. self.assertIn("Rerun CI", output_text)
  382. self.assertIn("foobar-ci-name", output_text)
  383. self.assertIn("spam-ci-name", output_text)
  384. self.assertNotIn("no-button-for-me-ci", output_text)
  385. trigger_ci = {
  386. "foobar-ci": {
  387. "name": "foobar-ci-name",
  388. "description": "barfoo",
  389. "requires_project_hook_attr": (
  390. "ci_hook",
  391. "active_pr",
  392. True,
  393. ),
  394. }
  395. }
  396. # new-style TRIGGER_CI with requires_project_hook_attr that is
  397. # not fulfilled by the project
  398. with patch.dict(
  399. "pagure.config.config", {"TRIGGER_CI": trigger_ci}
  400. ):
  401. output = self.app.get("/test/pull-request/1")
  402. self.assertEqual(output.status_code, 200)
  403. output_text = output.get_data(as_text=True)
  404. self.assertNotIn("Rerun CI", output_text)
  405. # now activate the hook and try again
  406. data = {
  407. "active_pr": "y",
  408. "ci_url": "https://jenkins.fedoraproject.org",
  409. "ci_job": "ci_job",
  410. "ci_type": "jenkins",
  411. "csrf_token": self.get_csrf(),
  412. }
  413. output = self.app.post(
  414. "/test/settings/Pagure CI", data=data, follow_redirects=True
  415. )
  416. self.assertEqual(output.status_code, 200)
  417. with patch.dict(
  418. "pagure.config.config", {"TRIGGER_CI": trigger_ci}
  419. ):
  420. output = self.app.get("/test/pull-request/1")
  421. self.assertEqual(output.status_code, 200)
  422. output_text = output.get_data(as_text=True)
  423. self.assertIn("Rerun CI", output_text)
  424. self.assertIn("foobar-ci-name", output_text)
  425. # shouldn't show up if user is not logged in
  426. with patch.dict("pagure.config.config", {"TRIGGER_CI": trigger_ci}):
  427. output = self.app.get("/test/pull-request/1")
  428. self.assertEqual(output.status_code, 200)
  429. output_text = output.get_data(as_text=True)
  430. self.assertNotIn("Rerun CI", output_text)
  431. @patch("pagure.lib.notify.send_email")
  432. @patch.dict(
  433. "pagure.config.config",
  434. {"TRIGGER_CI": {"CI1": {"name": "CI1", "description": "CI1!"}}},
  435. )
  436. def test_request_pull_ci_rerun(self, send_email):
  437. """ Test rerunning CI using button from the "Rerun CI" dropdown. """
  438. send_email.return_value = True
  439. tests.create_projects(self.session)
  440. tests.create_projects_git(
  441. os.path.join(self.path, "requests"), bare=True
  442. )
  443. set_up_git_repo(
  444. self.session, self.path, new_project=None, branch_from="feature"
  445. )
  446. user = tests.FakeUser()
  447. user.username = "pingou"
  448. project = pagure.lib.query.get_authorized_project(self.session, "test")
  449. request = project.requests[0]
  450. with tests.user_set(self.app.application, user):
  451. # no csrf token
  452. output = self.app.get("/test/pull-request/1")
  453. self.assertEqual(output.status_code, 200)
  454. output = self.app.post(
  455. "/test/pull-request/1/trigger-ci", follow_redirects=True
  456. )
  457. self.assertEqual(output.status_code, 200)
  458. self.assertIn("Invalid input", output.get_data(as_text=True))
  459. # no such PR
  460. output = self.app.get("/test/pull-request/1")
  461. self.assertEqual(output.status_code, 200)
  462. output = self.app.post(
  463. "/test/pull-request/2/trigger-ci", follow_redirects=True
  464. )
  465. self.assertEqual(output.status_code, 404)
  466. # wrong comment
  467. output = self.app.get("/test/pull-request/1")
  468. self.assertEqual(output.status_code, 200)
  469. csrf_token = self.get_csrf(output=output)
  470. data = {"csrf_token": csrf_token, "comment": "this doesnt exist"}
  471. output = self.app.post(
  472. "/test/pull-request/1/trigger-ci",
  473. data=data,
  474. follow_redirects=True,
  475. )
  476. self.assertEqual(output.status_code, 200)
  477. self.assertIn("Invalid input", output.get_data(as_text=True))
  478. # everything ok
  479. output = self.app.get("/test/pull-request/1")
  480. self.assertEqual(output.status_code, 200)
  481. csrf_token = self.get_csrf(output=output)
  482. data = {"csrf_token": csrf_token, "comment": "CI1"}
  483. output = self.app.post(
  484. "/test/pull-request/1/trigger-ci",
  485. data=data,
  486. follow_redirects=True,
  487. )
  488. output_text = output.get_data(as_text=True)
  489. self.assertEqual(output.status_code, 200)
  490. self.assertIn("<p>CI1</p>", output_text)
  491. comment = request.comments[0]
  492. self.assertTrue(comment.notification)
  493. self.assertEqual(comment.comment, "CI1")
  494. @patch("pagure.lib.notify.send_email")
  495. def test_merge_request_pull_FF(self, send_email):
  496. """ Test the merge_request_pull endpoint with a FF PR. """
  497. send_email.return_value = True
  498. self.test_request_pull()
  499. user = tests.FakeUser()
  500. with tests.user_set(self.app.application, user):
  501. output = self.app.get("/test/pull-request/1")
  502. self.assertEqual(output.status_code, 200)
  503. csrf_token = self.get_csrf(output=output)
  504. # No CSRF
  505. output = self.app.post(
  506. "/test/pull-request/1/merge", data={}, follow_redirects=True
  507. )
  508. self.assertEqual(output.status_code, 200)
  509. output_text = output.get_data(as_text=True)
  510. self.assertIn(
  511. "<title>PR#1: PR from the feature branch - test\n - "
  512. "Pagure</title>",
  513. output_text,
  514. )
  515. # self.assertIn(
  516. #'<h3><span class="label label-default">PR#1</span>\n'
  517. #' PR from the feature branch\n</h3>',
  518. # output_text)
  519. self.assertIn(
  520. 'title="View file as of 2a552b">sources</a>', output_text
  521. )
  522. # Wrong project
  523. data = {"csrf_token": csrf_token}
  524. output = self.app.post(
  525. "/foobar/pull-request/100/merge",
  526. data=data,
  527. follow_redirects=True,
  528. )
  529. self.assertEqual(output.status_code, 404)
  530. # Wrong project
  531. data = {"csrf_token": csrf_token}
  532. output = self.app.post(
  533. "/test/pull-request/1/merge", data=data, follow_redirects=True
  534. )
  535. self.assertEqual(output.status_code, 403)
  536. user.username = "pingou"
  537. with tests.user_set(self.app.application, user):
  538. # Wrong request id
  539. data = {"csrf_token": csrf_token}
  540. output = self.app.post(
  541. "/test/pull-request/100/merge",
  542. data=data,
  543. follow_redirects=True,
  544. )
  545. self.assertEqual(output.status_code, 404)
  546. # Project w/o pull-request
  547. self.session.commit()
  548. repo = pagure.lib.query.get_authorized_project(
  549. self.session, "test"
  550. )
  551. settings = repo.settings
  552. settings["pull_requests"] = False
  553. repo.settings = settings
  554. self.session.add(repo)
  555. self.session.commit()
  556. # Pull-request disabled
  557. output = self.app.post(
  558. "/test/pull-request/1/merge", data=data, follow_redirects=True
  559. )
  560. self.assertEqual(output.status_code, 404)
  561. # Project w pull-request but only assignee can merge
  562. self.session.commit()
  563. repo = pagure.lib.query.get_authorized_project(
  564. self.session, "test"
  565. )
  566. settings["pull_requests"] = True
  567. settings["Only_assignee_can_merge_pull-request"] = True
  568. repo.settings = settings
  569. self.session.add(repo)
  570. self.session.commit()
  571. output = self.app.post(
  572. "/test/pull-request/1/merge", data=data, follow_redirects=True
  573. )
  574. self.assertEqual(output.status_code, 200)
  575. output_text = output.get_data(as_text=True)
  576. self.assertIn(
  577. "<title>PR#1: PR from the feature branch - test\n - "
  578. "Pagure</title>",
  579. output_text,
  580. )
  581. self.assertIn(
  582. '<h4 class="ml-1">\n <div>\n '
  583. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  584. '<span class="text-success '
  585. 'font-weight-bold">#1</span>\n '
  586. '<span class="font-weight-bold">\n '
  587. "PR from the feature branch\n",
  588. output_text,
  589. )
  590. self.assertIn(
  591. "This request must be " "assigned to be merged", output_text
  592. )
  593. # PR assigned but not to this user
  594. self.session.commit()
  595. repo = pagure.lib.query.get_authorized_project(
  596. self.session, "test"
  597. )
  598. req = repo.requests[0]
  599. req.assignee_id = 2
  600. self.session.add(req)
  601. self.session.commit()
  602. output = self.app.post(
  603. "/test/pull-request/1/merge", data=data, follow_redirects=True
  604. )
  605. self.assertEqual(output.status_code, 200)
  606. output_text = output.get_data(as_text=True)
  607. self.assertIn(
  608. '<h4 class="ml-1">\n <div>\n '
  609. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  610. '<span class="text-success '
  611. 'font-weight-bold">#1</span>\n '
  612. '<span class="font-weight-bold">\n '
  613. "PR from the feature branch\n",
  614. output_text,
  615. )
  616. self.assertIn(
  617. "Only the assignee can merge this request", output_text
  618. )
  619. # Project w/ minimal PR score
  620. self.session.commit()
  621. repo = pagure.lib.query.get_authorized_project(
  622. self.session, "test"
  623. )
  624. settings["Only_assignee_can_merge_pull-request"] = False
  625. settings["Minimum_score_to_merge_pull-request"] = 2
  626. repo.settings = settings
  627. self.session.add(repo)
  628. self.session.commit()
  629. output = self.app.post(
  630. "/test/pull-request/1/merge", data=data, follow_redirects=True
  631. )
  632. self.assertEqual(output.status_code, 200)
  633. output_text = output.get_data(as_text=True)
  634. self.assertIn(
  635. '<h4 class="ml-1">\n <div>\n '
  636. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  637. '<span class="text-success '
  638. 'font-weight-bold">#1</span>\n '
  639. '<span class="font-weight-bold">\n '
  640. "PR from the feature branch\n",
  641. output_text,
  642. )
  643. self.assertIn(
  644. "This request does not "
  645. "have the minimum review score necessary to be merged",
  646. output_text,
  647. )
  648. # Merge
  649. self.session.commit()
  650. repo = pagure.lib.query.get_authorized_project(
  651. self.session, "test"
  652. )
  653. settings["Minimum_score_to_merge_pull-request"] = -1
  654. repo.settings = settings
  655. self.session.add(repo)
  656. self.session.commit()
  657. output = self.app.post(
  658. "/test/pull-request/1/merge", data=data, follow_redirects=True
  659. )
  660. self.assertEqual(output.status_code, 200)
  661. output = self.app.get("/test/commits")
  662. output_text = output.get_data(as_text=True)
  663. self.assertIn(
  664. "<title>Commits - test - Pagure</title>", output_text
  665. )
  666. self.assertIn("A commit on branch feature", output_text)
  667. self.assertNotIn(
  668. "Merge #1 `PR from the feature branch`", output_text
  669. )
  670. # Check if the closing notification was added
  671. output = self.app.get("/test/pull-request/1")
  672. self.assertIn(
  673. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  674. " </span>\n by\n"
  675. ' <span title="PY C (pingou)">pingou.</span>\n',
  676. output.get_data(as_text=True),
  677. )
  678. @patch("pagure.lib.notify.send_email")
  679. def test_merge_request_pull_merge(self, send_email):
  680. """ Test the merge_request_pull endpoint with a merge PR. """
  681. send_email.return_value = True
  682. tests.create_projects(self.session)
  683. tests.create_projects_git(
  684. os.path.join(self.path, "requests"), bare=True
  685. )
  686. set_up_git_repo(
  687. self.session,
  688. self.path,
  689. new_project=None,
  690. branch_from="feature",
  691. mtype="merge",
  692. )
  693. user = tests.FakeUser()
  694. user.username = "pingou"
  695. with tests.user_set(self.app.application, user):
  696. output = self.app.get("/test/pull-request/1")
  697. self.assertEqual(output.status_code, 200)
  698. csrf_token = self.get_csrf(output=output)
  699. data = {"csrf_token": csrf_token}
  700. # Merge
  701. output = self.app.post(
  702. "/test/pull-request/1/merge", data=data, follow_redirects=True
  703. )
  704. self.assertEqual(output.status_code, 200)
  705. self.assertIn(
  706. "<title>Overview - test - Pagure</title>",
  707. output.get_data(as_text=True),
  708. )
  709. # Check if the closing notification was added
  710. output = self.app.get("/test/pull-request/1")
  711. self.assertIn(
  712. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  713. " </span>\n by\n"
  714. ' <span title="PY C (pingou)">pingou.</span>\n',
  715. output.get_data(as_text=True),
  716. )
  717. @patch("pagure.lib.notify.send_email")
  718. def test_merge_request_pull_merge_with_comment(self, send_email):
  719. """ Test the merge_request_pull endpoint with a merge PR. """
  720. send_email.return_value = True
  721. tests.create_projects(self.session)
  722. tests.create_projects_git(
  723. os.path.join(self.path, "requests"), bare=True
  724. )
  725. set_up_git_repo(
  726. self.session,
  727. self.path,
  728. new_project=None,
  729. branch_from="feature",
  730. mtype="merge",
  731. )
  732. self.session = pagure.lib.query.create_session(self.dbpath)
  733. request = pagure.lib.query.search_pull_requests(
  734. self.session, project_id=1, requestid=1
  735. )
  736. self.assertEqual(len(request.comments), 0)
  737. user = tests.FakeUser()
  738. user.username = "pingou"
  739. with tests.user_set(self.app.application, user):
  740. output = self.app.get("/test/pull-request/1")
  741. self.assertEqual(output.status_code, 200)
  742. csrf_token = self.get_csrf(output=output)
  743. data = {
  744. "csrf_token": csrf_token,
  745. "comment": "Thanks for the review and the suggestions!",
  746. }
  747. # Merge
  748. output = self.app.post(
  749. "/test/pull-request/1/merge", data=data, follow_redirects=True
  750. )
  751. self.assertEqual(output.status_code, 200)
  752. self.assertIn(
  753. "<title>Overview - test - Pagure</title>",
  754. output.get_data(as_text=True),
  755. )
  756. # Check if the closing notification was added
  757. output = self.app.get("/test/pull-request/1")
  758. output_text = output.get_data(as_text=True)
  759. self.assertIn(
  760. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  761. " </span>\n by\n"
  762. ' <span title="PY C (pingou)">pingou.</span>\n',
  763. output_text,
  764. )
  765. self.assertIn(
  766. "Thanks for the review and the suggestions!", output_text
  767. )
  768. self.session = pagure.lib.query.create_session(self.dbpath)
  769. request = pagure.lib.query.search_pull_requests(
  770. self.session, project_id=1, requestid=1
  771. )
  772. self.assertEqual(len(request.comments), 2)
  773. @patch("pagure.lib.notify.send_email")
  774. def test_merge_request_pull_merge_with_delete_branch(self, send_email):
  775. """ Test the merge_request_pull endpoint with a merge PR and delete source branch. """
  776. send_email.return_value = True
  777. tests.create_projects(self.session)
  778. tests.create_projects_git(
  779. os.path.join(self.path, "requests"), bare=True
  780. )
  781. set_up_git_repo(
  782. self.session,
  783. self.path,
  784. new_project=None,
  785. branch_from="feature-branch",
  786. mtype="merge",
  787. )
  788. user = tests.FakeUser()
  789. user.username = "pingou"
  790. with tests.user_set(self.app.application, user):
  791. output = self.app.get("/test/pull-request/1")
  792. self.assertEqual(output.status_code, 200)
  793. data = {
  794. "csrf_token": self.get_csrf(output=output),
  795. "delete_branch": True,
  796. }
  797. # Merge
  798. output = self.app.post(
  799. "/test/pull-request/1/merge", data=data, follow_redirects=True
  800. )
  801. self.assertEqual(output.status_code, 200)
  802. output_text = output.get_data(as_text=True)
  803. self.assertIn(
  804. "<title>Overview - test - Pagure</title>", output_text
  805. )
  806. # Check the branch is not mentioned
  807. self.assertNotIn(
  808. '<a class="" href="/test/branch/feature-branch"', output_text
  809. )
  810. @patch("pagure.lib.notify.send_email")
  811. def test_merge_request_pull_conflicts(self, send_email):
  812. """ Test the merge_request_pull endpoint with a conflicting PR. """
  813. send_email.return_value = True
  814. tests.create_projects(self.session)
  815. tests.create_projects_git(
  816. os.path.join(self.path, "requests"), bare=True
  817. )
  818. set_up_git_repo(
  819. self.session,
  820. self.path,
  821. new_project=None,
  822. branch_from="feature",
  823. mtype="conflicts",
  824. )
  825. user = tests.FakeUser()
  826. user.username = "pingou"
  827. with tests.user_set(self.app.application, user):
  828. output = self.app.get("/test/pull-request/1")
  829. self.assertEqual(output.status_code, 200)
  830. csrf_token = self.get_csrf(output=output)
  831. data = {"csrf_token": csrf_token}
  832. # Merge conflicts
  833. output = self.app.post(
  834. "/test/pull-request/1/merge", data=data, follow_redirects=True
  835. )
  836. self.assertEqual(output.status_code, 200)
  837. output_text = output.get_data(as_text=True)
  838. self.assertIn(
  839. '<h4 class="ml-1">\n <div>\n '
  840. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  841. '<span class="text-success '
  842. 'font-weight-bold">#1</span>\n '
  843. '<span class="font-weight-bold">\n '
  844. "PR from the feature branch\n",
  845. output_text,
  846. )
  847. self.assertIn("Merge conflicts!", output_text)
  848. @patch("pagure.lib.notify.send_email")
  849. def test_merge_request_pull_conflicts_with_delete_branch(self, send_email):
  850. """ Test the merge_request_pull endpoint with a conflicting PR and request deletion of branch. """
  851. send_email.return_value = True
  852. tests.create_projects(self.session)
  853. tests.create_projects_git(
  854. os.path.join(self.path, "requests"), bare=True
  855. )
  856. set_up_git_repo(
  857. self.session,
  858. self.path,
  859. new_project=None,
  860. branch_from="feature-branch",
  861. mtype="conflicts",
  862. )
  863. user = tests.FakeUser()
  864. user.username = "pingou"
  865. with tests.user_set(self.app.application, user):
  866. output = self.app.get("/test/pull-request/1")
  867. self.assertEqual(output.status_code, 200)
  868. data = {
  869. "csrf_token": self.get_csrf(output=output),
  870. "delete_branch": True,
  871. }
  872. # Merge conflicts
  873. output = self.app.post(
  874. "/test/pull-request/1/merge", data=data, follow_redirects=True
  875. )
  876. self.assertEqual(output.status_code, 200)
  877. output_text = output.get_data(as_text=True)
  878. self.assertIn(
  879. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n'
  880. ' <span class="text-success font-weight-bold">#1</span>\n'
  881. ' <span class="font-weight-bold">\n'
  882. " PR from the feature-branch branch\n",
  883. output_text,
  884. )
  885. self.assertIn("Merge conflicts!", output_text)
  886. # Check the branch still exists
  887. output = self.app.get("/test/branches")
  888. self.assertIn("feature-branch", output.get_data(as_text=True))
  889. @patch("pagure.lib.notify.send_email")
  890. def test_merge_request_pull_nochange(self, send_email):
  891. """ Test the merge_request_pull endpoint. """
  892. send_email.return_value = True
  893. tests.create_projects(self.session)
  894. tests.create_projects_git(
  895. os.path.join(self.path, "requests"), bare=True
  896. )
  897. set_up_git_repo(
  898. self.session,
  899. self.path,
  900. new_project=None,
  901. branch_from="master",
  902. mtype="nochanges",
  903. )
  904. user = tests.FakeUser()
  905. user.username = "pingou"
  906. with tests.user_set(self.app.application, user):
  907. output = self.app.get("/test/pull-request/1")
  908. self.assertEqual(output.status_code, 200)
  909. csrf_token = self.get_csrf(output=output)
  910. data = {"csrf_token": csrf_token}
  911. # Nothing to merge
  912. output = self.app.post(
  913. "/test/pull-request/1/merge", data=data, follow_redirects=True
  914. )
  915. self.assertEqual(output.status_code, 200)
  916. output_text = output.get_data(as_text=True)
  917. self.assertIn(
  918. "Nothing to do, changes were already merged", output_text
  919. )
  920. # Check if the closing notification was added
  921. output = self.app.get("/test/pull-request/1")
  922. self.assertIn(
  923. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  924. " </span>\n by\n"
  925. ' <span title="PY C (pingou)">pingou.</span>\n',
  926. output.get_data(as_text=True),
  927. )
  928. @patch("pagure.lib.notify.send_email")
  929. def test_request_pull_close(self, send_email):
  930. """ Test the request_pull endpoint with a closed PR. """
  931. send_email.return_value = True
  932. self.test_merge_request_pull_FF()
  933. output = self.app.get("/test/pull-request/1")
  934. self.assertEqual(output.status_code, 200)
  935. output_text = output.get_data(as_text=True)
  936. self.assertIn(
  937. '<span class="text-info font-weight-bold">Merged</span> '
  938. "just now\n </span>\n by\n",
  939. output_text,
  940. )
  941. self.assertIn(
  942. 'title="View file as of 2a552b">sources</a>', output_text
  943. )
  944. @patch("pagure.lib.notify.send_email")
  945. def test_request_pull_disabled(self, send_email):
  946. """ Test the request_pull endpoint with PR disabled. """
  947. send_email.return_value = True
  948. tests.create_projects(self.session)
  949. tests.create_projects_git(
  950. os.path.join(self.path, "requests"), bare=True
  951. )
  952. set_up_git_repo(
  953. self.session, self.path, new_project=None, branch_from="feature"
  954. )
  955. # Project w/o pull-request
  956. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  957. settings = repo.settings
  958. settings["pull_requests"] = False
  959. repo.settings = settings
  960. self.session.add(repo)
  961. self.session.commit()
  962. output = self.app.get("/test/pull-request/1")
  963. self.assertEqual(output.status_code, 404)
  964. @patch("pagure.lib.notify.send_email")
  965. @patch("pagure.lib.git.update_pull_ref")
  966. def test_request_pull_empty_repo(self, send_email, update_pull_ref):
  967. """ Test the request_pull endpoint against an empty repo. """
  968. # Mock update_pull_ref or the repo won't be empty anymore
  969. # (the PR will have been pushed to refs/pull)
  970. send_email.return_value = True
  971. tests.create_projects(self.session)
  972. item = pagure.lib.model.Project(
  973. user_id=2, # foo
  974. name="test",
  975. description="test project #1",
  976. hook_token="aaabbb",
  977. is_fork=True,
  978. parent_id=1,
  979. )
  980. self.session.add(item)
  981. self.session.commit()
  982. tests.create_projects_git(
  983. os.path.join(self.path, "requests"), bare=True
  984. )
  985. tests.create_projects_git(
  986. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  987. )
  988. # Create a git repo to play with
  989. gitrepo = os.path.join(self.path, "repos", "test.git")
  990. self.assertFalse(os.path.exists(gitrepo))
  991. os.makedirs(gitrepo)
  992. repo = pygit2.init_repository(gitrepo, bare=True)
  993. # Create a fork of this repo
  994. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  995. gitrepo = os.path.join(self.path, "repos", "forks", "foo", "test.git")
  996. new_repo = pygit2.clone_repository(gitrepo, newpath)
  997. # Edit the sources file again
  998. with open(os.path.join(newpath, "sources"), "w") as stream:
  999. stream.write("foo\n bar\nbaz\n boose")
  1000. new_repo.index.add("sources")
  1001. new_repo.index.write()
  1002. # Commits the files added
  1003. tree = new_repo.index.write_tree()
  1004. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1005. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1006. new_repo.create_commit(
  1007. "refs/heads/feature",
  1008. author,
  1009. committer,
  1010. "A commit on branch feature",
  1011. tree,
  1012. [],
  1013. )
  1014. refname = "refs/heads/feature:refs/heads/feature"
  1015. ori_remote = new_repo.remotes[0]
  1016. PagureRepo.push(ori_remote, refname)
  1017. # Create a PR for these changes
  1018. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1019. req = pagure.lib.query.new_pull_request(
  1020. session=self.session,
  1021. repo_from=item,
  1022. branch_from="feature",
  1023. repo_to=project,
  1024. branch_to="master",
  1025. title="PR from the feature branch",
  1026. user="pingou",
  1027. )
  1028. self.session.commit()
  1029. self.assertEqual(req.id, 1)
  1030. self.assertEqual(req.title, "PR from the feature branch")
  1031. output = self.app.get("/test/pull-request/1")
  1032. self.assertEqual(output.status_code, 200)
  1033. output_text = output.get_data(as_text=True)
  1034. self.assertIn(
  1035. '<h4 class="ml-1">\n <div>\n '
  1036. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1037. '<span class="text-success '
  1038. 'font-weight-bold">#1</span>\n '
  1039. '<span class="font-weight-bold">\n '
  1040. "PR from the feature branch\n",
  1041. output_text,
  1042. )
  1043. self.assertTrue(output_text.count('<span class="commitdate"'), 1)
  1044. self.assertTrue(update_pull_ref.called)
  1045. shutil.rmtree(newpath)
  1046. @patch("pagure.lib.notify.send_email")
  1047. def test_request_pull_empty_fork(self, send_email):
  1048. """ Test the request_pull endpoint from an empty fork. """
  1049. send_email.return_value = True
  1050. tests.create_projects(self.session)
  1051. item = pagure.lib.model.Project(
  1052. user_id=2, # foo
  1053. name="test",
  1054. description="test project #1",
  1055. hook_token="aaabbb",
  1056. is_fork=True,
  1057. parent_id=1,
  1058. )
  1059. self.session.add(item)
  1060. self.session.commit()
  1061. tests.create_projects_git(
  1062. os.path.join(self.path, "requests"), bare=True
  1063. )
  1064. tests.create_projects_git(
  1065. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  1066. )
  1067. # Create a git repo to play with
  1068. gitrepo = os.path.join(self.path, "repos", "test.git")
  1069. self.assertFalse(os.path.exists(gitrepo))
  1070. os.makedirs(gitrepo)
  1071. repo = pygit2.init_repository(gitrepo, bare=True)
  1072. # Create a fork of this repo
  1073. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  1074. gitrepo = os.path.join(self.path, "repos", "forks", "foo", "test.git")
  1075. new_repo = pygit2.clone_repository(gitrepo, newpath)
  1076. # Create a PR for these "changes" (there are none, both repos are
  1077. # empty)
  1078. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1079. req = pagure.lib.query.new_pull_request(
  1080. session=self.session,
  1081. repo_from=item,
  1082. branch_from="feature",
  1083. repo_to=project,
  1084. branch_to="master",
  1085. title="PR from the feature branch",
  1086. user="pingou",
  1087. )
  1088. self.session.commit()
  1089. self.assertEqual(req.id, 1)
  1090. self.assertEqual(req.title, "PR from the feature branch")
  1091. output = self.app.get("/test/pull-request/1", follow_redirects=True)
  1092. self.assertEqual(output.status_code, 200)
  1093. output_text = output.get_data(as_text=True)
  1094. self.assertIn(
  1095. "<title>PR#1: PR from the feature branch - test\n - Pagure</title>",
  1096. output_text,
  1097. )
  1098. self.assertIn(
  1099. "Fork is empty, there are no "
  1100. "commits to create a pull request with",
  1101. output_text,
  1102. )
  1103. shutil.rmtree(newpath)
  1104. @patch("pagure.lib.notify.send_email")
  1105. def test_request_pulls_order(self, send_email):
  1106. """Test the request_pulls
  1107. i.e Make sure that the results are displayed
  1108. in the order required by the user"""
  1109. send_email.return_value = True
  1110. # Initially no project
  1111. output = self.app.get("/test/pull-requests")
  1112. self.assertEqual(output.status_code, 404)
  1113. tests.create_projects(self.session)
  1114. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1115. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  1116. item = pagure.lib.model.Project(
  1117. user_id=2,
  1118. name="test",
  1119. description="test project #1",
  1120. hook_token="aaabbb",
  1121. is_fork=True,
  1122. parent_id=1,
  1123. )
  1124. self.session.add(item)
  1125. self.session.commit()
  1126. # create PR's to play with
  1127. # PR-1
  1128. req = pagure.lib.query.new_pull_request(
  1129. session=self.session,
  1130. repo_to=repo,
  1131. repo_from=item,
  1132. branch_from="feature",
  1133. branch_to="master",
  1134. title="PR from the feature branch",
  1135. user="pingou",
  1136. status="Open",
  1137. )
  1138. self.session.commit()
  1139. self.assertEqual(req.id, 1)
  1140. self.assertEqual(req.title, "PR from the feature branch")
  1141. # PR-2
  1142. req = pagure.lib.query.new_pull_request(
  1143. session=self.session,
  1144. repo_to=repo,
  1145. branch_to="master",
  1146. branch_from="feature",
  1147. repo_from=item,
  1148. title="test PR",
  1149. user="pingou",
  1150. status="Open",
  1151. )
  1152. self.session.commit()
  1153. self.assertEqual(req.title, "test PR")
  1154. # PR-3
  1155. req = pagure.lib.query.new_pull_request(
  1156. session=self.session,
  1157. repo_to=repo,
  1158. branch_from="feature",
  1159. branch_to="master",
  1160. repo_from=item,
  1161. title="test Invalid PR",
  1162. user="pingou",
  1163. status="Closed",
  1164. )
  1165. self.session.commit()
  1166. self.assertEqual(req.title, "test Invalid PR")
  1167. # PR-4
  1168. req = pagure.lib.query.new_pull_request(
  1169. session=self.session,
  1170. repo_to=repo,
  1171. branch_from="feature",
  1172. title="test PR for sort",
  1173. repo_from=item,
  1174. user="pingou",
  1175. branch_to="master",
  1176. status="Open",
  1177. )
  1178. self.session.commit()
  1179. self.assertEqual(req.title, "test PR for sort")
  1180. # sort by last_updated
  1181. output = self.app.get("/test/pull-requests?order_key=last_updated")
  1182. output_text = output.get_data(as_text=True)
  1183. tr_elements = re.findall(
  1184. '<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->',
  1185. output_text,
  1186. re.M | re.S,
  1187. )
  1188. self.assertEqual(output.status_code, 200)
  1189. # Make sure that issue four is first since it was modified last
  1190. self.assertIn('href="/test/pull-request/4"', tr_elements[0])
  1191. self.assertIn('href="/test/pull-request/2"', tr_elements[1])
  1192. self.assertIn('href="/test/pull-request/1"', tr_elements[2])
  1193. pr_one = pagure.lib.query.search_pull_requests(
  1194. self.session, project_id=1, requestid=1
  1195. )
  1196. pr_one.last_updated = datetime.utcnow() + timedelta(seconds=2)
  1197. self.session.add(pr_one)
  1198. self.session.commit()
  1199. # sort by last_updated
  1200. output = self.app.get("/test/pull-requests?order_key=last_updated")
  1201. output_text = output.get_data(as_text=True)
  1202. tr_elements = re.findall(
  1203. '<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->',
  1204. output_text,
  1205. re.M | re.S,
  1206. )
  1207. self.assertEqual(output.status_code, 200)
  1208. # Make sure that PR four is first since it was modified last
  1209. self.assertIn('href="/test/pull-request/1"', tr_elements[0])
  1210. # Make sure that PR two is second since it was modified second
  1211. self.assertIn('href="/test/pull-request/4"', tr_elements[1])
  1212. # Make sure that PR one is last since it was modified first
  1213. self.assertIn('href="/test/pull-request/2"', tr_elements[2])
  1214. # Now query so that the results are ascending
  1215. output = self.app.get(
  1216. "/test/pull-requests?" "order_key=last_updated&order=asc"
  1217. )
  1218. output_text = output.get_data(as_text=True)
  1219. tr_elements = re.findall(
  1220. '<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->',
  1221. output_text,
  1222. re.M | re.S,
  1223. )
  1224. self.assertIn('href="/test/pull-request/2"', tr_elements[0])
  1225. self.assertIn('href="/test/pull-request/4"', tr_elements[1])
  1226. self.assertIn('href="/test/pull-request/1"', tr_elements[2])
  1227. # check that search_pattern argument works
  1228. output = self.app.get("/test/pull-requests?search_pattern=feature")
  1229. output_text = output.get_data(as_text=True)
  1230. tr_elements = re.findall(
  1231. '<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->',
  1232. output_text,
  1233. re.M | re.S,
  1234. )
  1235. self.assertIn('href="/test/pull-request/1"', tr_elements[0])
  1236. self.assertEqual(len(tr_elements), 1)
  1237. output = self.app.get("/test/pull-requests?search_pattern=PR")
  1238. output_text = output.get_data(as_text=True)
  1239. tr_elements = re.findall(
  1240. '<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->',
  1241. output_text,
  1242. re.M | re.S,
  1243. )
  1244. self.assertIn('href="/test/pull-request/4"', tr_elements[0])
  1245. self.assertIn('href="/test/pull-request/2"', tr_elements[1])
  1246. self.assertIn('href="/test/pull-request/1"', tr_elements[2])
  1247. self.assertEqual(len(tr_elements), 3)
  1248. output = self.app.get("/test/pull-requests?search_pattern=*PR")
  1249. output_text = output.get_data(as_text=True)
  1250. tr_elements = re.findall(
  1251. '<div class="request-row list-group-item list-group-item-action ">(.*?)</div><!--end request-row-->',
  1252. output_text,
  1253. re.M | re.S,
  1254. )
  1255. self.assertEqual(len(tr_elements), 1)
  1256. self.assertIn('href="/test/pull-request/2"', tr_elements[0])
  1257. @patch("pagure.lib.notify.send_email")
  1258. def test_request_pulls(self, send_email):
  1259. """ Test the request_pulls endpoint. """
  1260. send_email.return_value = True
  1261. # No such project
  1262. output = self.app.get("/test/pull-requests")
  1263. self.assertEqual(output.status_code, 404)
  1264. tests.create_projects(self.session)
  1265. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  1266. output = self.app.get("/test/pull-requests")
  1267. self.assertEqual(output.status_code, 200)
  1268. output_text = output.get_data(as_text=True)
  1269. self.assertIn(
  1270. '<span class="fa fa-fw fa-arrow-circle-down"></span> 0 Open PRs\n',
  1271. output_text,
  1272. )
  1273. set_up_git_repo(
  1274. self.session, self.path, new_project=None, branch_from="feature"
  1275. )
  1276. output = self.app.get("/test/pull-requests")
  1277. self.assertEqual(output.status_code, 200)
  1278. output_text = output.get_data(as_text=True)
  1279. self.assertIn(
  1280. '<span class="fa fa-fw fa-arrow-circle-down"></span> 1 Open PRs\n',
  1281. output_text,
  1282. )
  1283. output = self.app.get("/test/pull-requests?status=1")
  1284. self.assertEqual(output.status_code, 200)
  1285. output_text = output.get_data(as_text=True)
  1286. self.assertIn(
  1287. '<span class="fa fa-fw fa-arrow-circle-down"></span> 1 Open PRs\n',
  1288. output_text,
  1289. )
  1290. output = self.app.get("/test/pull-requests?status=true")
  1291. self.assertEqual(output.status_code, 200)
  1292. output_text = output.get_data(as_text=True)
  1293. self.assertIn(
  1294. '<span class="fa fa-fw fa-arrow-circle-down"></span> 1 Open PRs\n',
  1295. output_text,
  1296. )
  1297. output = self.app.get("/test/pull-requests?status=Merged")
  1298. self.assertEqual(output.status_code, 200)
  1299. output_text = output.get_data(as_text=True)
  1300. self.assertIn(
  1301. '<span class="fa fa-fw fa-arrow-circle-down"></span> 0 Merged PRs\n',
  1302. output_text,
  1303. )
  1304. output = self.app.get("/test/pull-requests?status=0")
  1305. self.assertEqual(output.status_code, 200)
  1306. output_text = output.get_data(as_text=True)
  1307. self.assertIn(
  1308. '<span class="fa fa-fw fa-arrow-circle-down"></span> 0 Merged PRs\n',
  1309. output_text,
  1310. )
  1311. output = self.app.get("/test/pull-requests?status=Closed")
  1312. self.assertEqual(output.status_code, 200)
  1313. output_text = output.get_data(as_text=True)
  1314. self.assertIn(
  1315. '<span class="fa fa-fw fa-arrow-circle-down"></span> 0 Cancelled PRs\n',
  1316. output_text,
  1317. )
  1318. # Project w/o pull-request
  1319. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  1320. settings = repo.settings
  1321. settings["pull_requests"] = False
  1322. repo.settings = settings
  1323. self.session.add(repo)
  1324. self.session.commit()
  1325. output = self.app.get("/test/pull-requests")
  1326. self.assertEqual(output.status_code, 404)
  1327. @patch("pagure.lib.notify.send_email")
  1328. def test_request_pull_patch(self, send_email):
  1329. """ Test the request_pull_patch endpoint. """
  1330. send_email.return_value = True
  1331. output = self.app.get("/test/pull-request/1.patch")
  1332. self.assertEqual(output.status_code, 404)
  1333. tests.create_projects(self.session)
  1334. tests.create_projects_git(
  1335. os.path.join(self.path, "requests"), bare=True
  1336. )
  1337. set_up_git_repo(
  1338. self.session,
  1339. self.path,
  1340. new_project=None,
  1341. branch_from="feature",
  1342. mtype="merge",
  1343. )
  1344. output = self.app.get("/test/pull-request/100.patch")
  1345. self.assertEqual(output.status_code, 404)
  1346. output = self.app.get("/test/pull-request/1.patch")
  1347. self.assertEqual(output.status_code, 200)
  1348. npatch = []
  1349. for row in output.get_data(as_text=True).split("\n"):
  1350. if row.startswith("Date:"):
  1351. continue
  1352. if row.startswith("From "):
  1353. row = row.split(" ", 2)[2]
  1354. npatch.append(row)
  1355. exp = r"""Mon Sep 17 00:00:00 2001
  1356. From: Alice Author <alice@authors.tld>
  1357. Subject: A commit on branch feature
  1358. More information
  1359. ---
  1360. diff --git a/.gitignore b/.gitignore
  1361. new file mode 100644
  1362. index 0000000..e4e5f6c
  1363. --- /dev/null
  1364. +++ b/.gitignore
  1365. @@ -0,0 +1 @@
  1366. +*~
  1367. \ No newline at end of file
  1368. diff --git a/sources b/sources
  1369. index 9f44358..2a552bb 100644
  1370. --- a/sources
  1371. +++ b/sources
  1372. @@ -1,2 +1,4 @@
  1373. foo
  1374. - bar
  1375. \ No newline at end of file
  1376. + bar
  1377. +baz
  1378. + boose
  1379. \ No newline at end of file
  1380. """
  1381. patch = "\n".join(npatch)
  1382. # print patch
  1383. self.assertEqual(patch, exp)
  1384. # Project w/o pull-request
  1385. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  1386. settings = repo.settings
  1387. settings["pull_requests"] = False
  1388. repo.settings = settings
  1389. self.session.add(repo)
  1390. self.session.commit()
  1391. output = self.app.get("/test/pull-request/1.patch")
  1392. self.assertEqual(output.status_code, 404)
  1393. @patch("pagure.lib.notify.send_email")
  1394. def test_request_pull_diff(self, send_email):
  1395. """ Test the request_pull_patch endpoint. """
  1396. send_email.return_value = True
  1397. output = self.app.get("/test/pull-request/1.diff")
  1398. self.assertEqual(output.status_code, 404)
  1399. tests.create_projects(self.session)
  1400. tests.create_projects_git(
  1401. os.path.join(self.path, "requests"), bare=True
  1402. )
  1403. set_up_git_repo(
  1404. self.session,
  1405. self.path,
  1406. new_project=None,
  1407. branch_from="feature",
  1408. mtype="merge",
  1409. )
  1410. output = self.app.get("/test/pull-request/100.diff")
  1411. self.assertEqual(output.status_code, 404)
  1412. output = self.app.get("/test/pull-request/1.diff")
  1413. self.assertEqual(output.status_code, 200)
  1414. exp = r"""diff --git a/.gitignore b/.gitignore
  1415. new file mode 100644
  1416. index 0000000..e4e5f6c
  1417. --- /dev/null
  1418. +++ b/.gitignore
  1419. @@ -0,0 +1 @@
  1420. +*~
  1421. \ No newline at end of file
  1422. diff --git a/sources b/sources
  1423. index 9f44358..2a552bb 100644
  1424. --- a/sources
  1425. +++ b/sources
  1426. @@ -1,2 +1,4 @@
  1427. foo
  1428. - bar
  1429. \ No newline at end of file
  1430. + bar
  1431. +baz
  1432. + boose
  1433. \ No newline at end of file
  1434. """
  1435. self.assertEqual(output.get_data(as_text=True), exp)
  1436. # Project w/o pull-request
  1437. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  1438. settings = repo.settings
  1439. settings["pull_requests"] = False
  1440. repo.settings = settings
  1441. self.session.add(repo)
  1442. self.session.commit()
  1443. output = self.app.get("/test/pull-request/1.diff")
  1444. self.assertEqual(output.status_code, 404)
  1445. @patch("pagure.lib.notify.send_email")
  1446. def test_request_pull_patch_close(self, send_email):
  1447. """ Test the request_pull_patch endpoint with a closed PR. """
  1448. send_email.return_value = True
  1449. self.test_merge_request_pull_FF()
  1450. output = self.app.get("/test/pull-request/1.patch")
  1451. self.assertEqual(output.status_code, 200)
  1452. npatch = []
  1453. for row in output.get_data(as_text=True).split("\n"):
  1454. if row.startswith("Date:"):
  1455. continue
  1456. if row.startswith("From "):
  1457. row = row.split(" ", 2)[2]
  1458. npatch.append(row)
  1459. exp = r"""Mon Sep 17 00:00:00 2001
  1460. From: Alice Author <alice@authors.tld>
  1461. Subject: A commit on branch feature
  1462. More information
  1463. ---
  1464. diff --git a/sources b/sources
  1465. index 9f44358..2a552bb 100644
  1466. --- a/sources
  1467. +++ b/sources
  1468. @@ -1,2 +1,4 @@
  1469. foo
  1470. - bar
  1471. \ No newline at end of file
  1472. + bar
  1473. +baz
  1474. + boose
  1475. \ No newline at end of file
  1476. """
  1477. patch = "\n".join(npatch)
  1478. # print patch
  1479. self.assertEqual(patch, exp)
  1480. @patch("pagure.lib.notify.send_email")
  1481. @patch("pagure.lib.git.update_pull_ref")
  1482. def test_request_pull_patch_empty_repo(self, send_email, update_pull_ref):
  1483. """ Test the request_pull_patch endpoint against an empty repo. """
  1484. # Mock update_pull_ref or the repo won't be empty anymore
  1485. # (the PR will have been pushed to refs/pull)
  1486. send_email.return_value = True
  1487. tests.create_projects(self.session)
  1488. item = pagure.lib.model.Project(
  1489. user_id=2, # foo
  1490. name="test",
  1491. description="test project #1",
  1492. hook_token="aaabbb",
  1493. is_fork=True,
  1494. parent_id=1,
  1495. )
  1496. self.session.add(item)
  1497. self.session.commit()
  1498. tests.create_projects_git(
  1499. os.path.join(self.path, "requests"), bare=True
  1500. )
  1501. tests.create_projects_git(
  1502. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  1503. )
  1504. # Create a git repo to play with
  1505. gitrepo = os.path.join(self.path, "repos", "test.git")
  1506. self.assertFalse(os.path.exists(gitrepo))
  1507. os.makedirs(gitrepo)
  1508. repo = pygit2.init_repository(gitrepo, bare=True)
  1509. # Create a fork of this repo
  1510. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  1511. gitrepo = os.path.join(self.path, "repos", "forks", "foo", "test.git")
  1512. new_repo = pygit2.clone_repository(gitrepo, newpath)
  1513. # Edit the sources file again
  1514. with open(os.path.join(newpath, "sources"), "w") as stream:
  1515. stream.write("foo\n bar\nbaz\n boose")
  1516. new_repo.index.add("sources")
  1517. new_repo.index.write()
  1518. # Commits the files added
  1519. tree = new_repo.index.write_tree()
  1520. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  1521. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  1522. new_repo.create_commit(
  1523. "refs/heads/feature",
  1524. author,
  1525. committer,
  1526. "A commit on branch feature",
  1527. tree,
  1528. [],
  1529. )
  1530. refname = "refs/heads/feature:refs/heads/feature"
  1531. ori_remote = new_repo.remotes[0]
  1532. PagureRepo.push(ori_remote, refname)
  1533. # Create a PR for these "changes" (there are none, both repos are
  1534. # empty)
  1535. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1536. req = pagure.lib.query.new_pull_request(
  1537. session=self.session,
  1538. repo_from=item,
  1539. branch_from="feature",
  1540. repo_to=project,
  1541. branch_to="master",
  1542. title="PR from the feature branch",
  1543. user="pingou",
  1544. )
  1545. self.session.commit()
  1546. self.assertEqual(req.id, 1)
  1547. self.assertEqual(req.title, "PR from the feature branch")
  1548. output = self.app.get(
  1549. "/test/pull-request/1.patch", follow_redirects=True
  1550. )
  1551. self.assertEqual(output.status_code, 200)
  1552. npatch = []
  1553. for row in output.get_data(as_text=True).split("\n"):
  1554. if row.startswith("Date:"):
  1555. continue
  1556. if row.startswith("From "):
  1557. row = row.split(" ", 2)[2]
  1558. npatch.append(row)
  1559. exp = r"""Mon Sep 17 00:00:00 2001
  1560. From: Alice Author <alice@authors.tld>
  1561. Subject: A commit on branch feature
  1562. ---
  1563. diff --git a/sources b/sources
  1564. new file mode 100644
  1565. index 0000000..2a552bb
  1566. --- /dev/null
  1567. +++ b/sources
  1568. @@ -0,0 +1,4 @@
  1569. +foo
  1570. + bar
  1571. +baz
  1572. + boose
  1573. \ No newline at end of file
  1574. """
  1575. patch = "\n".join(npatch)
  1576. # print patch
  1577. self.assertEqual(patch, exp)
  1578. shutil.rmtree(newpath)
  1579. @patch("pagure.lib.notify.send_email")
  1580. def test_request_pull_patch_empty_fork(self, send_email):
  1581. """ Test the request_pull_patch endpoint from an empty fork. """
  1582. send_email.return_value = True
  1583. tests.create_projects(self.session)
  1584. item = pagure.lib.model.Project(
  1585. user_id=2, # foo
  1586. name="test",
  1587. description="test project #1",
  1588. hook_token="aaabbb",
  1589. is_fork=True,
  1590. parent_id=1,
  1591. )
  1592. self.session.add(item)
  1593. self.session.commit()
  1594. tests.create_projects_git(
  1595. os.path.join(self.path, "requests"), bare=True
  1596. )
  1597. tests.create_projects_git(
  1598. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  1599. )
  1600. # Create a git repo to play with
  1601. gitrepo = os.path.join(self.path, "repos", "test.git")
  1602. self.assertFalse(os.path.exists(gitrepo))
  1603. os.makedirs(gitrepo)
  1604. repo = pygit2.init_repository(gitrepo, bare=True)
  1605. # Create a fork of this repo
  1606. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  1607. gitrepo = os.path.join(self.path, "repos", "forks", "foo", "test.git")
  1608. new_repo = pygit2.clone_repository(gitrepo, newpath)
  1609. # Create a PR for these "changes" (there are none, both repos are
  1610. # empty)
  1611. project = pagure.lib.query.get_authorized_project(self.session, "test")
  1612. req = pagure.lib.query.new_pull_request(
  1613. session=self.session,
  1614. repo_from=item,
  1615. branch_from="feature",
  1616. repo_to=project,
  1617. branch_to="master",
  1618. title="PR from the feature branch",
  1619. user="pingou",
  1620. )
  1621. self.session.commit()
  1622. self.assertEqual(req.id, 1)
  1623. self.assertEqual(req.title, "PR from the feature branch")
  1624. output = self.app.get(
  1625. "/test/pull-request/1.patch", follow_redirects=True
  1626. )
  1627. self.assertEqual(output.status_code, 200)
  1628. output_text = output.get_data(as_text=True)
  1629. self.assertIn("<title>Overview - test - Pagure</title>", output_text)
  1630. self.assertIn(
  1631. "Fork is empty, there are no "
  1632. "commits to create a pull request with",
  1633. output_text,
  1634. )
  1635. shutil.rmtree(newpath)
  1636. @patch("pagure.lib.notify.send_email")
  1637. def test_close_request_pull(self, send_email):
  1638. """ Test the close_request_pull endpoint. """
  1639. send_email.return_value = True
  1640. tests.create_projects(self.session)
  1641. tests.create_projects_git(
  1642. os.path.join(self.path, "requests"), bare=True
  1643. )
  1644. set_up_git_repo(
  1645. self.session,
  1646. self.path,
  1647. new_project=None,
  1648. branch_from="feature",
  1649. mtype="merge",
  1650. )
  1651. user = tests.FakeUser()
  1652. with tests.user_set(self.app.application, user):
  1653. output = self.app.post("/test/pull-request/close/1")
  1654. self.assertEqual(output.status_code, 302)
  1655. output = self.app.post(
  1656. "/test/pull-request/close/1", follow_redirects=True
  1657. )
  1658. self.assertEqual(output.status_code, 200)
  1659. output_text = output.get_data(as_text=True)
  1660. self.assertIn(
  1661. "<title>Overview - test - Pagure</title>", output_text
  1662. )
  1663. self.assertIn("Invalid input submitted", output_text)
  1664. output = self.app.get("/test/pull-request/1")
  1665. self.assertEqual(output.status_code, 200)
  1666. csrf_token = self.get_csrf(output=output)
  1667. data = {"csrf_token": csrf_token}
  1668. # Invalid project
  1669. output = self.app.post(
  1670. "/foo/pull-request/close/1", data=data, follow_redirects=True
  1671. )
  1672. self.assertEqual(output.status_code, 404)
  1673. # Invalid PR id
  1674. output = self.app.post(
  1675. "/test/pull-request/close/100",
  1676. data=data,
  1677. follow_redirects=True,
  1678. )
  1679. self.assertEqual(output.status_code, 404)
  1680. # Invalid user for this project
  1681. output = self.app.post(
  1682. "/test/pull-request/close/1", data=data, follow_redirects=True
  1683. )
  1684. self.assertEqual(output.status_code, 403)
  1685. user.username = "pingou"
  1686. with tests.user_set(self.app.application, user):
  1687. # Project w/o pull-request
  1688. repo = pagure.lib.query.get_authorized_project(
  1689. self.session, "test"
  1690. )
  1691. settings = repo.settings
  1692. settings["pull_requests"] = False
  1693. repo.settings = settings
  1694. self.session.add(repo)
  1695. self.session.commit()
  1696. output = self.app.post(
  1697. "/test/pull-request/close/1", data=data, follow_redirects=True
  1698. )
  1699. self.assertEqual(output.status_code, 404)
  1700. # Project w/ pull-request
  1701. repo = pagure.lib.query.get_authorized_project(
  1702. self.session, "test"
  1703. )
  1704. settings = repo.settings
  1705. settings["pull_requests"] = True
  1706. repo.settings = settings
  1707. self.session.add(repo)
  1708. self.session.commit()
  1709. output = self.app.post(
  1710. "/test/pull-request/close/1", data=data, follow_redirects=True
  1711. )
  1712. self.assertEqual(output.status_code, 200)
  1713. output_text = output.get_data(as_text=True)
  1714. self.assertIn(
  1715. "<title>Overview - test - Pagure</title>", output_text
  1716. )
  1717. self.assertIn("Pull request closed!", output_text)
  1718. @patch("pagure.lib.notify.send_email")
  1719. def test_reopen_request_pull(self, send_email):
  1720. """ Test the reopen_request_pull endpoint. """
  1721. send_email.return_value = True
  1722. tests.create_projects(self.session)
  1723. tests.create_projects_git(
  1724. os.path.join(self.path, "requests"), bare=True
  1725. )
  1726. set_up_git_repo(
  1727. self.session,
  1728. self.path,
  1729. new_project=None,
  1730. branch_from="feature",
  1731. mtype="merge",
  1732. )
  1733. user = tests.FakeUser()
  1734. with tests.user_set(self.app.application, user):
  1735. output = self.app.post("/test/pull-request/1/reopen")
  1736. self.assertEqual(output.status_code, 302)
  1737. output = self.app.post(
  1738. "/test/pull-request/1/reopen", follow_redirects=True
  1739. )
  1740. self.assertEqual(output.status_code, 200)
  1741. output_text = output.get_data(as_text=True)
  1742. self.assertIn(
  1743. "<title>PR#1: PR from the feature branch - test\n - Pagure</title>",
  1744. output_text,
  1745. )
  1746. self.assertIn(
  1747. #'Pull request reopened!',
  1748. 'return window.confirm("Are you sure you want to reopen this requested pull?")',
  1749. output_text,
  1750. )
  1751. output = self.app.get("/test/pull-request/1")
  1752. self.assertEqual(output.status_code, 200)
  1753. csrf_token = self.get_csrf(output=output)
  1754. data = {"csrf_token": csrf_token}
  1755. # Invalid project
  1756. output = self.app.post(
  1757. "/foo/pull-request/1/reopen", data=data, follow_redirects=True
  1758. )
  1759. self.assertEqual(output.status_code, 404)
  1760. # Invalid PR id
  1761. output = self.app.post(
  1762. "/test/pull-request/100/reopen",
  1763. data=data,
  1764. follow_redirects=True,
  1765. )
  1766. self.assertEqual(output.status_code, 404)
  1767. # Invalid user for this project
  1768. output = self.app.post(
  1769. "/test/pull-request/1/reopen", data=data, follow_redirects=True
  1770. )
  1771. self.assertEqual(output.status_code, 403)
  1772. user.username = "pingou"
  1773. with tests.user_set(self.app.application, user):
  1774. # Project w/o pull-request
  1775. repo = pagure.lib.query.get_authorized_project(
  1776. self.session, "test"
  1777. )
  1778. settings = repo.settings
  1779. settings["pull_requests"] = False
  1780. repo.settings = settings
  1781. self.session.add(repo)
  1782. self.session.commit()
  1783. output = self.app.post(
  1784. "/test/pull-request/1/reopen", data=data, follow_redirects=True
  1785. )
  1786. self.assertEqual(output.status_code, 404)
  1787. # Project w/ pull-request
  1788. repo = pagure.lib.query.get_authorized_project(
  1789. self.session, "test"
  1790. )
  1791. settings = repo.settings
  1792. settings["pull_requests"] = True
  1793. repo.settings = settings
  1794. self.session.add(repo)
  1795. self.session.commit()
  1796. output = self.app.post(
  1797. "/test/pull-request/cancel/1", data=data, follow_redirects=True
  1798. )
  1799. output = self.app.post(
  1800. "/test/pull-request/1/reopen", data=data, follow_redirects=True
  1801. )
  1802. self.assertEqual(output.status_code, 200)
  1803. output_text = output.get_data(as_text=True)
  1804. self.assertIn(
  1805. "<title>PR#1: PR from the feature branch - test\n - "
  1806. "Pagure</title>",
  1807. output_text,
  1808. )
  1809. self.assertIn(
  1810. 'return window.confirm("Are you sure you want to reopen this requested pull?")',
  1811. output_text,
  1812. )
  1813. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  1814. def test_update_pull_requests_assign(self):
  1815. """ Test the update_pull_requests endpoint when assigning a PR.
  1816. """
  1817. tests.create_projects(self.session)
  1818. tests.create_projects_git(
  1819. os.path.join(self.path, "requests"), bare=True
  1820. )
  1821. set_up_git_repo(
  1822. self.session, self.path, new_project=None, branch_from="feature"
  1823. )
  1824. user = tests.FakeUser()
  1825. user.username = "pingou"
  1826. with tests.user_set(self.app.application, user):
  1827. # No such project
  1828. output = self.app.post("/foo/pull-request/1/update")
  1829. self.assertEqual(output.status_code, 404)
  1830. output = self.app.post("/test/pull-request/100/update")
  1831. self.assertEqual(output.status_code, 404)
  1832. # Invalid input
  1833. output = self.app.post(
  1834. "/test/pull-request/1/update", follow_redirects=True
  1835. )
  1836. self.assertEqual(output.status_code, 200)
  1837. output_text = output.get_data(as_text=True)
  1838. self.assertIn(
  1839. "<title>PR#1: PR from the feature branch - test\n - "
  1840. "Pagure</title>",
  1841. output_text,
  1842. )
  1843. self.assertIn(
  1844. '<h4 class="ml-1">\n <div>\n '
  1845. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1846. '<span class="text-success '
  1847. 'font-weight-bold">#1</span>\n '
  1848. '<span class="font-weight-bold">\n '
  1849. "PR from the feature branch\n",
  1850. output_text,
  1851. )
  1852. self.assertNotIn("Request assigned", output_text)
  1853. output = self.app.get("/test/pull-request/1")
  1854. self.assertEqual(output.status_code, 200)
  1855. csrf_token = self.get_csrf(output=output)
  1856. data = {"user": "pingou"}
  1857. # No CSRF
  1858. output = self.app.post(
  1859. "/test/pull-request/1/update", data=data, follow_redirects=True
  1860. )
  1861. self.assertEqual(output.status_code, 200)
  1862. output_text = output.get_data(as_text=True)
  1863. self.assertIn(
  1864. "<title>PR#1: PR from the feature branch - test\n - "
  1865. "Pagure</title>",
  1866. output_text,
  1867. )
  1868. self.assertIn(
  1869. '<h4 class="ml-1">\n <div>\n '
  1870. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1871. '<span class="text-success '
  1872. 'font-weight-bold">#1</span>\n '
  1873. '<span class="font-weight-bold">\n '
  1874. "PR from the feature branch\n",
  1875. output_text,
  1876. )
  1877. self.assertNotIn("Request assigned", output_text)
  1878. # Invalid assignee
  1879. data = {"csrf_token": csrf_token, "user": "bar"}
  1880. output = self.app.post(
  1881. "/test/pull-request/1/update", data=data, follow_redirects=True
  1882. )
  1883. self.assertEqual(output.status_code, 200)
  1884. output_text = output.get_data(as_text=True)
  1885. self.assertIn(
  1886. "<title>PR#1: PR from the feature branch - test\n - "
  1887. "Pagure</title>",
  1888. output_text,
  1889. )
  1890. self.assertIn(
  1891. '<h4 class="ml-1">\n <div>\n '
  1892. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1893. '<span class="text-success '
  1894. 'font-weight-bold">#1</span>\n '
  1895. '<span class="font-weight-bold">\n '
  1896. "PR from the feature branch\n",
  1897. output_text,
  1898. )
  1899. self.assertIn("No user &#34;bar&#34; found", output_text)
  1900. # Assign the PR
  1901. data = {"csrf_token": csrf_token, "user": "pingou"}
  1902. user.username = "foo"
  1903. with tests.user_set(self.app.application, user):
  1904. output = self.app.post(
  1905. "/test/pull-request/1/update", data=data, follow_redirects=True
  1906. )
  1907. self.assertEqual(output.status_code, 403)
  1908. user.username = "pingou"
  1909. with tests.user_set(self.app.application, user):
  1910. output = self.app.post(
  1911. "/test/pull-request/1/update", data=data, follow_redirects=True
  1912. )
  1913. self.assertEqual(output.status_code, 200)
  1914. output_text = output.get_data(as_text=True)
  1915. self.assertIn(
  1916. "<title>PR#1: PR from the feature branch - test\n - "
  1917. "Pagure</title>",
  1918. output_text,
  1919. )
  1920. self.assertIn(
  1921. '<h4 class="ml-1">\n <div>\n '
  1922. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1923. '<span class="text-success '
  1924. 'font-weight-bold">#1</span>\n '
  1925. '<span class="font-weight-bold">\n '
  1926. "PR from the feature branch\n",
  1927. output_text,
  1928. )
  1929. self.assertIn("Request assigned", output_text)
  1930. # Pull-Request closed
  1931. repo = pagure.lib.query.get_authorized_project(
  1932. self.session, "test"
  1933. )
  1934. req = repo.requests[0]
  1935. req.status = "Closed"
  1936. req.closed_by_in = 1
  1937. self.session.add(req)
  1938. self.session.commit()
  1939. output = self.app.post(
  1940. "/test/pull-request/1/update", data=data, follow_redirects=True
  1941. )
  1942. self.assertEqual(output.status_code, 200)
  1943. # Project w/o pull-request
  1944. repo = pagure.lib.query.get_authorized_project(
  1945. self.session, "test"
  1946. )
  1947. settings = repo.settings
  1948. settings["pull_requests"] = False
  1949. repo.settings = settings
  1950. self.session.add(repo)
  1951. self.session.commit()
  1952. output = self.app.post(
  1953. "/test/pull-request/1/update", data=data, follow_redirects=True
  1954. )
  1955. self.assertEqual(output.status_code, 404)
  1956. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  1957. def test_update_pull_requests_tag(self):
  1958. """ Test the update_pull_requests endpoint when tagging a PR.
  1959. """
  1960. tests.create_projects(self.session)
  1961. tests.create_projects_git(
  1962. os.path.join(self.path, "requests"), bare=True
  1963. )
  1964. set_up_git_repo(
  1965. self.session, self.path, new_project=None, branch_from="feature"
  1966. )
  1967. user = tests.FakeUser()
  1968. user.username = "pingou"
  1969. with tests.user_set(self.app.application, user):
  1970. output = self.app.get("/test/pull-request/1")
  1971. self.assertEqual(output.status_code, 200)
  1972. csrf_token = self.get_csrf(output=output)
  1973. data = {"tag": "black"}
  1974. # No CSRF
  1975. output = self.app.post(
  1976. "/test/pull-request/1/update", data=data, follow_redirects=True
  1977. )
  1978. self.assertEqual(output.status_code, 200)
  1979. output_text = output.get_data(as_text=True)
  1980. self.assertIn(
  1981. "<title>PR#1: PR from the feature branch - test\n - "
  1982. "Pagure</title>",
  1983. output_text,
  1984. )
  1985. self.assertIn(
  1986. '<h4 class="ml-1">\n <div>\n '
  1987. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  1988. '<span class="text-success '
  1989. 'font-weight-bold">#1</span>\n '
  1990. '<span class="font-weight-bold">\n '
  1991. "PR from the feature branch\n",
  1992. output_text,
  1993. )
  1994. self.assertNotIn("Request assigned", output_text)
  1995. # Tag the PR
  1996. data = {"csrf_token": csrf_token, "tag": "black"}
  1997. output = self.app.post(
  1998. "/test/pull-request/1/update", data=data, follow_redirects=True
  1999. )
  2000. self.assertEqual(output.status_code, 200)
  2001. output_text = output.get_data(as_text=True)
  2002. self.assertIn(
  2003. "<title>PR#1: PR from the feature branch - test\n - "
  2004. "Pagure</title>",
  2005. output_text,
  2006. )
  2007. self.assertIn(
  2008. '<h4 class="ml-1">\n <div>\n '
  2009. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  2010. '<span class="text-success '
  2011. 'font-weight-bold">#1</span>\n '
  2012. '<span class="font-weight-bold">\n '
  2013. "PR from the feature branch\n",
  2014. output_text,
  2015. )
  2016. self.assertIn("Pull-request tagged with: black", output_text)
  2017. self.assertIn(
  2018. 'title="comma separated list of tags"\n '
  2019. 'value="black" />',
  2020. output_text,
  2021. )
  2022. # Try as another user
  2023. user.username = "foo"
  2024. with tests.user_set(self.app.application, user):
  2025. # Tag the PR
  2026. data = {"csrf_token": csrf_token, "tag": "blue, yellow"}
  2027. output = self.app.post(
  2028. "/test/pull-request/1/update", data=data, follow_redirects=True
  2029. )
  2030. self.assertEqual(output.status_code, 403)
  2031. # Make the PR be from foo
  2032. repo = pagure.lib.query.get_authorized_project(
  2033. self.session, "test"
  2034. )
  2035. req = repo.requests[0]
  2036. req.user_id = 2
  2037. self.session.add(req)
  2038. self.session.commit()
  2039. # Re-try to tag the PR
  2040. data = {"csrf_token": csrf_token, "tag": "blue, yellow"}
  2041. output = self.app.post(
  2042. "/test/pull-request/1/update", data=data, follow_redirects=True
  2043. )
  2044. self.assertEqual(output.status_code, 200)
  2045. soup = BeautifulSoup(output.get_data(as_text=True), "html.parser")
  2046. self.assertEqual(
  2047. soup.find("title").string,
  2048. "PR#1: PR from the feature branch - test\n - Pagure",
  2049. )
  2050. self.assertIn(
  2051. "Pull-request **un**tagged with: black",
  2052. output.get_data(as_text=True),
  2053. )
  2054. self.assertIn(
  2055. "Pull-request tagged with: blue, yellow",
  2056. output.get_data(as_text=True),
  2057. )
  2058. user.username = "pingou"
  2059. with tests.user_set(self.app.application, user):
  2060. # Pull-Request closed
  2061. repo = pagure.lib.query.get_authorized_project(
  2062. self.session, "test"
  2063. )
  2064. req = repo.requests[0]
  2065. req.status = "Closed"
  2066. req.closed_by_in = 1
  2067. self.session.add(req)
  2068. self.session.commit()
  2069. output = self.app.post(
  2070. "/test/pull-request/1/update", data=data, follow_redirects=True
  2071. )
  2072. self.assertEqual(output.status_code, 200)
  2073. # Project w/o pull-request
  2074. repo = pagure.lib.query.get_authorized_project(
  2075. self.session, "test"
  2076. )
  2077. settings = repo.settings
  2078. settings["pull_requests"] = False
  2079. repo.settings = settings
  2080. self.session.add(repo)
  2081. self.session.commit()
  2082. output = self.app.post(
  2083. "/test/pull-request/1/update", data=data, follow_redirects=True
  2084. )
  2085. self.assertEqual(output.status_code, 404)
  2086. @patch("pagure.lib.notify.send_email")
  2087. def test_fork_project(self, send_email):
  2088. """ Test the fork_project endpoint. """
  2089. send_email.return_value = True
  2090. tests.create_projects(self.session)
  2091. for folder in ["docs", "tickets", "requests", "repos"]:
  2092. tests.create_projects_git(
  2093. os.path.join(self.path, folder), bare=True
  2094. )
  2095. user = tests.FakeUser()
  2096. user.username = "pingou"
  2097. with tests.user_set(self.app.application, user):
  2098. output = self.app.post("/do_fork/test")
  2099. self.assertEqual(output.status_code, 400)
  2100. output = self.app.get("/new/")
  2101. self.assertEqual(output.status_code, 200)
  2102. self.assertIn(
  2103. "<strong>Create new Project</strong>",
  2104. output.get_data(as_text=True),
  2105. )
  2106. csrf_token = self.get_csrf(output=output)
  2107. data = {"csrf_token": csrf_token}
  2108. output = self.app.post(
  2109. "/do_fork/foo", data=data, follow_redirects=True
  2110. )
  2111. self.assertEqual(output.status_code, 404)
  2112. user.username = "foo"
  2113. with tests.user_set(self.app.application, user):
  2114. output = self.app.post("/do_fork/test")
  2115. self.assertEqual(output.status_code, 400)
  2116. data = {"csrf_token": csrf_token}
  2117. output = self.app.post(
  2118. "/do_fork/test", data=data, follow_redirects=True
  2119. )
  2120. self.assertEqual(output.status_code, 200)
  2121. @patch("pagure.lib.notify.send_email")
  2122. def test_new_request_pull_branch_space(self, send_email):
  2123. """ Test the new_request_pull endpoint. """
  2124. send_email.return_value = True
  2125. self.test_fork_project()
  2126. tests.create_projects_git(
  2127. os.path.join(self.path, "requests"), bare=True
  2128. )
  2129. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2130. fork = pagure.lib.query.get_authorized_project(
  2131. self.session, "test", user="foo"
  2132. )
  2133. set_up_git_repo(
  2134. self.session,
  2135. self.path,
  2136. new_project=fork,
  2137. branch_from="feature",
  2138. mtype="FF",
  2139. )
  2140. user = tests.FakeUser(username="pingou")
  2141. with tests.user_set(self.app.application, user):
  2142. output = self.app.get("/test/diff/master..foo bar")
  2143. self.assertEqual(output.status_code, 400)
  2144. output_text = output.get_data(as_text=True)
  2145. self.assertIn("<p>Branch foo bar does not exist</p>", output_text)
  2146. @patch("pagure.lib.notify.send_email")
  2147. def test_new_request_pull(self, send_email):
  2148. """ Test the new_request_pull endpoint. """
  2149. send_email.return_value = True
  2150. self.test_fork_project()
  2151. tests.create_projects_git(
  2152. os.path.join(self.path, "requests"), bare=True
  2153. )
  2154. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2155. fork = pagure.lib.query.get_authorized_project(
  2156. self.session, "test", user="foo"
  2157. )
  2158. set_up_git_repo(
  2159. self.session,
  2160. self.path,
  2161. new_project=fork,
  2162. branch_from="feature",
  2163. mtype="FF",
  2164. )
  2165. user = tests.FakeUser()
  2166. user.username = "foo"
  2167. with tests.user_set(self.app.application, user):
  2168. output = self.app.get("/foo/diff/master..feature")
  2169. self.assertEqual(output.status_code, 404)
  2170. output = self.app.get("/test/diff/master..foo")
  2171. self.assertEqual(output.status_code, 400)
  2172. output = self.app.get("/test/diff/foo..master")
  2173. self.assertEqual(output.status_code, 400)
  2174. output = self.app.get("/test/diff/feature..master")
  2175. self.assertEqual(output.status_code, 200)
  2176. output_text = output.get_data(as_text=True)
  2177. self.assertIn(
  2178. "<title>Diff from master to feature - test\n - "
  2179. "Pagure</title>",
  2180. output_text,
  2181. )
  2182. self.assertIn(
  2183. '<p class="error"> No commits found </p>', output_text
  2184. )
  2185. output = self.app.get("/test/diff/master..feature")
  2186. self.assertEqual(output.status_code, 200)
  2187. output_text = output.get_data(as_text=True)
  2188. self.assertIn(
  2189. "<title>Diff from feature to master - test\n - "
  2190. "Pagure</title>",
  2191. output_text,
  2192. )
  2193. self.assertNotIn(
  2194. '<input type="submit" class="submit positive button" '
  2195. 'value="Create">',
  2196. output_text,
  2197. )
  2198. user.username = "pingou"
  2199. with tests.user_set(self.app.application, user):
  2200. output = self.app.get("/test/diff/master..feature")
  2201. self.assertEqual(output.status_code, 200)
  2202. output_text = output.get_data(as_text=True)
  2203. self.assertIn(
  2204. "<title>Create new Pull Request for master - test\n - "
  2205. "Pagure</title>",
  2206. output_text,
  2207. )
  2208. self.assertIn(
  2209. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2210. output_text,
  2211. )
  2212. # Check that we prefilled the input fields as expected:
  2213. self.assertIn(
  2214. '<input class="form-control" id="title" name="title" '
  2215. 'placeholder="Pull Request Title" required="required" '
  2216. 'type="text" value="A commit on branch feature">',
  2217. output_text,
  2218. )
  2219. self.assertIn(
  2220. """<textarea class="form-control" rows=8 id="initial_comment" name="initial_comment"
  2221. placeholder="Describe your changes" tabindex=1>
  2222. More information</textarea>
  2223. <div id="preview" class="p-1">""",
  2224. output_text,
  2225. )
  2226. self.assertIn(
  2227. '<a class="dropdown-item branch_from_item pointer" '
  2228. 'data-value="master"><span class="fa fa-random">'
  2229. "</span> master</a>",
  2230. output_text,
  2231. )
  2232. csrf_token = self.get_csrf(output=output)
  2233. # Case 1 - Add an initial comment
  2234. data = {
  2235. "csrf_token": csrf_token,
  2236. "title": "foo bar PR",
  2237. "initial_comment": "Test Initial Comment",
  2238. }
  2239. output = self.app.post(
  2240. "/test/diff/master..feature", data=data, follow_redirects=True
  2241. )
  2242. self.assertEqual(output.status_code, 200)
  2243. output_text = output.get_data(as_text=True)
  2244. self.assertIn(
  2245. "<title>PR#2: foo bar PR - test\n - Pagure</title>",
  2246. output_text,
  2247. )
  2248. self.assertIn("<p>Test Initial Comment</p>", output_text)
  2249. self.assertEqual(output_text.count('title="PY C (pingou)"'), 2)
  2250. # Test if the `open changed file icon` is displayed.
  2251. self.assertIn(
  2252. 'class="open_changed_file_icon_wrap"><span '
  2253. 'class="fa fa-file-code-o fa-fw" '
  2254. 'alt="Open changed file" title="Open changed file"></span>'
  2255. "</a>",
  2256. output_text,
  2257. )
  2258. # Case 2 - Add an empty initial comment
  2259. data = {
  2260. "csrf_token": csrf_token,
  2261. "title": "foo bar PR",
  2262. "initial_comment": "",
  2263. }
  2264. output = self.app.post(
  2265. "/test/diff/master..feature", data=data, follow_redirects=True
  2266. )
  2267. self.assertEqual(output.status_code, 200)
  2268. output_text = output.get_data(as_text=True)
  2269. self.assertIn(
  2270. "<title>PR#3: foo bar PR - test\n - Pagure</title>",
  2271. output_text,
  2272. )
  2273. self.assertNotIn('<div id="comment-', output_text)
  2274. @patch("pagure.lib.notify.send_email")
  2275. def test_new_request_pull_filename_unicode(self, send_email):
  2276. """ Test the new_request_pull endpoint. """
  2277. send_email.return_value = True
  2278. # Create the main project in the DB
  2279. item = pagure.lib.model.Project(
  2280. user_id=1, # pingou
  2281. name="test",
  2282. description="test project #1",
  2283. hook_token="aaabbbccc",
  2284. )
  2285. item.close_status = [
  2286. "Invalid",
  2287. "Insufficient data",
  2288. "Fixed",
  2289. "Duplicate",
  2290. ]
  2291. self.session.add(item)
  2292. self.session.commit()
  2293. # Create the fork
  2294. item = pagure.lib.model.Project(
  2295. user_id=1, # pingou
  2296. name="test",
  2297. description="test project #1",
  2298. hook_token="aaabbbcccdd",
  2299. parent_id=1,
  2300. is_fork=True,
  2301. )
  2302. item.close_status = [
  2303. "Invalid",
  2304. "Insufficient data",
  2305. "Fixed",
  2306. "Duplicate",
  2307. ]
  2308. self.session.add(item)
  2309. self.session.commit()
  2310. # Create two git repos, one has 6 commits, the other 4 of which only
  2311. # 1 isn't present in the first repo
  2312. gitrepo = os.path.join(self.path, "repos", "test.git")
  2313. pygit2.init_repository(gitrepo, bare=True)
  2314. gitrepo2 = os.path.join(
  2315. self.path, "repos", "forks", "pingou", "test.git"
  2316. )
  2317. pygit2.init_repository(gitrepo2, bare=True)
  2318. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  2319. repopath = os.path.join(newpath, "test")
  2320. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  2321. # Do 2 commits to the main repo
  2322. for i in range(2):
  2323. with open(os.path.join(repopath, "sources"), "w") as stream:
  2324. stream.write("foo%s\n bar%s\n" % (i, i))
  2325. clone_repo.index.add("sources")
  2326. clone_repo.index.write()
  2327. parents = []
  2328. try:
  2329. last_commit = clone_repo.revparse_single("HEAD")
  2330. parents = [last_commit.oid.hex]
  2331. except KeyError:
  2332. pass
  2333. # Commits the files added
  2334. tree = clone_repo.index.write_tree()
  2335. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  2336. committer = pygit2.Signature(
  2337. "Cecil Committer", "cecil@committers.tld"
  2338. )
  2339. clone_repo.create_commit(
  2340. "refs/heads/master", # the name of the reference to update
  2341. author,
  2342. committer,
  2343. "Editing the file sources for testing #%s" % i,
  2344. # binary string representing the tree object ID
  2345. tree,
  2346. # list of binary strings representing parents of the new commit
  2347. parents,
  2348. )
  2349. # Push to the main repo
  2350. refname = "refs/heads/master:refs/heads/master"
  2351. ori_remote = clone_repo.remotes[0]
  2352. PagureRepo.push(ori_remote, refname)
  2353. # Push to the fork repo
  2354. remote = clone_repo.create_remote("pingou_fork", gitrepo2)
  2355. PagureRepo.push(remote, refname)
  2356. # Add 1 commits to the fork repo
  2357. repopath = os.path.join(newpath, "pingou_test")
  2358. clone_repo = pygit2.clone_repository(gitrepo2, repopath)
  2359. with open(os.path.join(repopath, "soürces"), "w") as stream:
  2360. stream.write("foo\n bar\n")
  2361. clone_repo.index.add("soürces")
  2362. clone_repo.index.write()
  2363. with open(os.path.join(repopath, "fóß"), "w") as stream:
  2364. stream.write("foo\n bar\n")
  2365. clone_repo.index.add("fóß")
  2366. clone_repo.index.write()
  2367. last_commit = clone_repo.revparse_single("HEAD")
  2368. # Commits the files added
  2369. tree = clone_repo.index.write_tree()
  2370. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  2371. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  2372. last_commit = clone_repo.create_commit(
  2373. "refs/heads/feature_foo", # the name of the reference to update
  2374. author,
  2375. committer,
  2376. "New edition on side branch of the file sources for testing",
  2377. # binary string representing the tree object ID
  2378. tree,
  2379. # list of binary strings representing parents of the new commit
  2380. [last_commit.oid.hex],
  2381. )
  2382. # Push to the fork repo
  2383. ori_remote = clone_repo.remotes[0]
  2384. refname = "refs/heads/feature_foo:refs/heads/feature_foo"
  2385. PagureRepo.push(ori_remote, refname)
  2386. shutil.rmtree(newpath)
  2387. # Create the PR between the two repos
  2388. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2389. forked_repo = pagure.lib.query.get_authorized_project(
  2390. self.session, "test", user="pingou"
  2391. )
  2392. req = pagure.lib.query.new_pull_request(
  2393. session=self.session,
  2394. repo_from=forked_repo,
  2395. branch_from="feature_foo",
  2396. repo_to=repo,
  2397. branch_to="master",
  2398. title="test pull-request",
  2399. user="pingou",
  2400. )
  2401. self.assertEqual(req.id, 1)
  2402. self.assertEqual(req.title, "test pull-request")
  2403. user = tests.FakeUser(username="pingou")
  2404. with tests.user_set(self.app.application, user):
  2405. output = self.app.get("/fork/pingou/test/diff/master..feature_foo")
  2406. self.assertEqual(output.status_code, 200)
  2407. output_text = output.get_data(as_text=True)
  2408. self.assertIn(
  2409. "<title>Create new Pull Request for master - fork/pingou/test\n - "
  2410. "Pagure</title>",
  2411. output_text,
  2412. )
  2413. self.assertIn(
  2414. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2415. output_text,
  2416. )
  2417. # Check that we prefilled the input fields as expected:
  2418. self.assertIn(
  2419. '<input class="form-control" id="title" name="title" '
  2420. 'placeholder="Pull Request Title" required="required" '
  2421. 'type="text" value="New edition on side branch of the file '
  2422. 'sources for testing">',
  2423. output_text,
  2424. )
  2425. self.assertIn(
  2426. '<a class="dropdown-item branch_from_item pointer" '
  2427. 'data-value="master"><span class="fa fa-random">'
  2428. "</span> master</a>",
  2429. output_text,
  2430. )
  2431. csrf_token = self.get_csrf(output=output)
  2432. # Case 1 - Add an initial comment
  2433. data = {
  2434. "csrf_token": csrf_token,
  2435. "title": "foo bar PR",
  2436. "initial_comment": "Test Initial Comment",
  2437. }
  2438. output = self.app.post(
  2439. "/fork/pingou/test/diff/master..feature_foo",
  2440. data=data,
  2441. follow_redirects=True,
  2442. )
  2443. self.assertEqual(output.status_code, 200)
  2444. output_text = output.get_data(as_text=True)
  2445. self.assertIn(
  2446. "<title>PR#2: foo bar PR - test\n - Pagure</title>",
  2447. output_text,
  2448. )
  2449. self.assertIn("<p>Test Initial Comment</p>", output_text)
  2450. self.assertEqual(output_text.count('title="PY C (pingou)"'), 2)
  2451. @patch("pagure.lib.notify.send_email")
  2452. def test_new_request_pull_req_sign_off_view(self, send_email):
  2453. """ Test the new_request_pull endpoint. """
  2454. send_email.return_value = True
  2455. self.test_fork_project()
  2456. tests.create_projects_git(
  2457. os.path.join(self.path, "requests"), bare=True
  2458. )
  2459. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2460. fork = pagure.lib.query.get_authorized_project(
  2461. self.session, "test", user="foo"
  2462. )
  2463. # Enforce Signed-of-by in the repo
  2464. settings = repo.settings
  2465. settings["Enforce_signed-off_commits_in_pull-request"] = True
  2466. repo.settings = settings
  2467. self.session.add(repo)
  2468. self.session.commit()
  2469. set_up_git_repo(
  2470. self.session,
  2471. self.path,
  2472. new_project=fork,
  2473. branch_from="feature",
  2474. mtype="FF",
  2475. )
  2476. user = tests.FakeUser()
  2477. user.username = "foo"
  2478. with tests.user_set(self.app.application, user):
  2479. output = self.app.get("/test/diff/master..feature")
  2480. self.assertEqual(output.status_code, 200)
  2481. output_text = output.get_data(as_text=True)
  2482. self.assertIn(
  2483. "<title>Diff from feature to master - test\n - "
  2484. "Pagure</title>",
  2485. output_text,
  2486. )
  2487. self.assertIn(
  2488. "This project enforces the "
  2489. "Signed-off-by statement on all commits",
  2490. output_text,
  2491. )
  2492. self.assertNotIn(
  2493. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2494. output_text,
  2495. )
  2496. self.assertNotIn(
  2497. "This repo enforces that "
  2498. "all commits are signed off by their author.",
  2499. output_text,
  2500. )
  2501. @patch("pagure.lib.notify.send_email")
  2502. def test_new_request_pull_req_sign_off_submit(self, send_email):
  2503. """ Test the new_request_pull endpoint. """
  2504. send_email.return_value = True
  2505. self.test_fork_project()
  2506. tests.create_projects_git(
  2507. os.path.join(self.path, "requests"), bare=True
  2508. )
  2509. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2510. fork = pagure.lib.query.get_authorized_project(
  2511. self.session, "test", user="foo"
  2512. )
  2513. # Enforce Signed-of-by in the repo
  2514. settings = repo.settings
  2515. settings["Enforce_signed-off_commits_in_pull-request"] = True
  2516. repo.settings = settings
  2517. self.session.add(repo)
  2518. self.session.commit()
  2519. set_up_git_repo(
  2520. self.session,
  2521. self.path,
  2522. new_project=fork,
  2523. branch_from="feature",
  2524. mtype="FF",
  2525. )
  2526. user = tests.FakeUser()
  2527. user.username = "pingou"
  2528. with tests.user_set(self.app.application, user):
  2529. output = self.app.get("/test/diff/master..feature")
  2530. self.assertEqual(output.status_code, 200)
  2531. output_text = output.get_data(as_text=True)
  2532. self.assertIn(
  2533. "<title>Create new Pull Request for master - test\n - "
  2534. "Pagure</title>",
  2535. output_text,
  2536. )
  2537. self.assertIn(
  2538. "This project enforces the "
  2539. "Signed-off-by statement on all commits",
  2540. output_text,
  2541. )
  2542. self.assertIn(
  2543. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2544. output_text,
  2545. )
  2546. csrf_token = self.get_csrf(output=output)
  2547. # Try to create the PR
  2548. data = {
  2549. "csrf_token": csrf_token,
  2550. "title": "foo bar PR",
  2551. "initial_comment": "Test Initial Comment",
  2552. }
  2553. output = self.app.post(
  2554. "/test/diff/master..feature", data=data, follow_redirects=True
  2555. )
  2556. self.assertEqual(output.status_code, 200)
  2557. output_text = output.get_data(as_text=True)
  2558. self.assertIn(
  2559. "<title>Create new Pull Request for master - test\n - "
  2560. "Pagure</title>",
  2561. output_text,
  2562. )
  2563. # Flashed information message
  2564. self.assertIn(
  2565. "This project enforces the "
  2566. "Signed-off-by statement on all commits",
  2567. output_text,
  2568. )
  2569. # Flashed error message
  2570. self.assertIn(
  2571. "This repo enforces that "
  2572. "all commits are signed off by their author.",
  2573. output_text,
  2574. )
  2575. self.assertIn(
  2576. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2577. output_text,
  2578. )
  2579. @patch("pagure.lib.notify.send_email")
  2580. def test_request_pull_commit_start_stop(self, send_email):
  2581. """ Test the the commit start and stop of brand new PR. """
  2582. send_email.return_value = True
  2583. self.test_fork_project()
  2584. tests.create_projects_git(
  2585. os.path.join(self.path, "requests"), bare=True
  2586. )
  2587. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  2588. fork = pagure.lib.query.get_authorized_project(
  2589. self.session, "test", user="foo"
  2590. )
  2591. set_up_git_repo(
  2592. self.session,
  2593. self.path,
  2594. new_project=fork,
  2595. branch_from="feature",
  2596. mtype="FF",
  2597. )
  2598. user = tests.FakeUser()
  2599. user.username = "pingou"
  2600. with tests.user_set(self.app.application, user):
  2601. output = self.app.get("/test/diff/master..feature")
  2602. self.assertEqual(output.status_code, 200)
  2603. output_text = output.get_data(as_text=True)
  2604. self.assertIn(
  2605. "<title>Create new Pull Request for master - test\n - "
  2606. "Pagure</title>",
  2607. output_text,
  2608. )
  2609. self.assertIn(
  2610. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2611. output_text,
  2612. )
  2613. csrf_token = self.get_csrf(output=output)
  2614. # Case 1 - Add an initial comment
  2615. data = {
  2616. "csrf_token": csrf_token,
  2617. "title": "foo bar PR",
  2618. "initial_comment": "Test Initial Comment",
  2619. }
  2620. output = self.app.post(
  2621. "/test/diff/master..feature", data=data, follow_redirects=True
  2622. )
  2623. self.assertEqual(output.status_code, 200)
  2624. output_text = output.get_data(as_text=True)
  2625. self.assertIn(
  2626. "<title>PR#2: foo bar PR - test\n - Pagure</title>",
  2627. output_text,
  2628. )
  2629. self.assertIn("<p>Test Initial Comment</p>", output_text)
  2630. # Check if commit start and stop have been set for PR#2
  2631. request = pagure.lib.query.search_pull_requests(
  2632. self.session, project_id=1, requestid=2
  2633. )
  2634. self.assertIsNotNone(request.commit_start)
  2635. self.assertIsNotNone(request.commit_stop)
  2636. @patch("pagure.lib.notify.send_email")
  2637. def test_new_request_pull_from_fork_branch(self, send_email):
  2638. """ Test creating a fork to fork PR. """
  2639. send_email.return_value = True
  2640. # Create main repo with some content
  2641. tests.create_projects(self.session)
  2642. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2643. tests.add_content_git_repo(
  2644. os.path.join(self.path, "repos", "test.git")
  2645. )
  2646. # Create fork repo with more content
  2647. tests.create_projects(
  2648. self.session, is_fork=True, hook_token_suffix="fork"
  2649. )
  2650. tests.create_projects_git(
  2651. os.path.join(self.path, "repos", "forks", "pingou"), bare=True
  2652. )
  2653. tests.add_content_git_repo(
  2654. os.path.join(self.path, "repos", "forks", "pingou", "test.git")
  2655. )
  2656. tests.add_readme_git_repo(
  2657. os.path.join(self.path, "repos", "forks", "pingou", "test.git"),
  2658. branch="feature",
  2659. )
  2660. tests.add_readme_git_repo(
  2661. os.path.join(self.path, "repos", "forks", "pingou", "test.git"),
  2662. branch="random_branch",
  2663. )
  2664. user = tests.FakeUser(username="pingou")
  2665. with tests.user_set(self.app.application, user):
  2666. data = {"csrf_token": self.get_csrf()}
  2667. output = self.app.post(
  2668. "/do_fork/test", data=data, follow_redirects=True
  2669. )
  2670. self.assertEqual(output.status_code, 200)
  2671. # Check that Ralph's fork do exist
  2672. output = self.app.get("/fork/pingou/test")
  2673. self.assertEqual(output.status_code, 200)
  2674. tests.create_projects_git(
  2675. os.path.join(self.path, "requests"), bare=True
  2676. )
  2677. fork = pagure.lib.query.get_authorized_project(
  2678. self.session, "test", user="ralph"
  2679. )
  2680. set_up_git_repo(
  2681. self.session,
  2682. self.path,
  2683. new_project=fork,
  2684. branch_from="feature",
  2685. mtype="FF",
  2686. )
  2687. # Try opening a pull-request
  2688. output = self.app.get("/fork/pingou/test/diff/master..feature")
  2689. self.assertEqual(output.status_code, 200)
  2690. output_text = output.get_data(as_text=True)
  2691. self.assertIn(
  2692. "<title>Create new Pull Request for master - "
  2693. "fork/pingou/test\n - Pagure</title>",
  2694. output_text,
  2695. )
  2696. self.assertIn(
  2697. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2698. output_text,
  2699. )
  2700. self.assertIn(
  2701. '<a class="dropdown-item branch_from_item pointer" '
  2702. 'data-value="master"><span class="fa fa-random">'
  2703. "</span> master</a>",
  2704. output_text,
  2705. )
  2706. self.assertIn(
  2707. '<a class="dropdown-item branch_from_item pointer" '
  2708. 'data-value="random_branch"><span class="fa fa-random">'
  2709. "</span> random_branch</a>",
  2710. output_text,
  2711. )
  2712. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  2713. def test_new_request_pull_from_fork_fixing_ticket(self):
  2714. """ Test creating a fork to fork PR fixing a ticket. """
  2715. # Create main repo with some content
  2716. tests.create_projects(self.session)
  2717. tests.create_projects_git(os.path.join(self.path, "repos"), bare=True)
  2718. tests.add_content_git_repo(
  2719. os.path.join(self.path, "repos", "test.git")
  2720. )
  2721. # Create fork repo with more content
  2722. tests.create_projects(
  2723. self.session, is_fork=True, hook_token_suffix="fork"
  2724. )
  2725. tests.create_projects_git(
  2726. os.path.join(self.path, "repos", "forks", "pingou"), bare=True
  2727. )
  2728. tests.add_content_git_repo(
  2729. os.path.join(self.path, "repos", "forks", "pingou", "test.git")
  2730. )
  2731. tests.add_readme_git_repo(
  2732. os.path.join(self.path, "repos", "forks", "pingou", "test.git"),
  2733. branch="feature",
  2734. )
  2735. tests.add_readme_git_repo(
  2736. os.path.join(self.path, "repos", "forks", "pingou", "test.git"),
  2737. branch="random_branch",
  2738. )
  2739. # Check relations before we create the PR
  2740. project = pagure.lib.query.get_authorized_project(self.session, "test")
  2741. self.assertEqual(len(project.requests), 0)
  2742. self.assertEqual(len(project.issues), 0)
  2743. # Create issues to link to
  2744. msg = pagure.lib.query.new_issue(
  2745. session=self.session,
  2746. repo=project,
  2747. title="tést íssüé",
  2748. content="We should work on this",
  2749. user="pingou",
  2750. )
  2751. self.session.commit()
  2752. self.assertEqual(msg.title, "tést íssüé")
  2753. user = tests.FakeUser(username="pingou")
  2754. with tests.user_set(self.app.application, user):
  2755. csrf_token = self.get_csrf()
  2756. data = {"csrf_token": csrf_token}
  2757. output = self.app.post(
  2758. "/do_fork/test", data=data, follow_redirects=True
  2759. )
  2760. self.assertEqual(output.status_code, 200)
  2761. # Check that pingou's fork do exist
  2762. output = self.app.get("/fork/pingou/test")
  2763. self.assertEqual(output.status_code, 200)
  2764. tests.create_projects_git(
  2765. os.path.join(self.path, "requests"), bare=True
  2766. )
  2767. fork = pagure.lib.query.get_authorized_project(
  2768. self.session, "test", user="ralph"
  2769. )
  2770. set_up_git_repo(
  2771. self.session,
  2772. self.path,
  2773. new_project=fork,
  2774. branch_from="feature",
  2775. mtype="FF",
  2776. prid=2,
  2777. )
  2778. # Try opening a pull-request
  2779. output = self.app.get("/fork/pingou/test/diff/master..feature")
  2780. self.assertEqual(output.status_code, 200)
  2781. output_text = output.get_data(as_text=True)
  2782. self.assertIn(
  2783. "<title>Create new Pull Request for master - "
  2784. "fork/pingou/test\n - Pagure</title>",
  2785. output_text,
  2786. )
  2787. self.assertIn(
  2788. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2789. output_text,
  2790. )
  2791. self.assertIn(
  2792. '<a class="dropdown-item branch_from_item pointer" '
  2793. 'data-value="master"><span class="fa fa-random">'
  2794. "</span> master</a>",
  2795. output_text,
  2796. )
  2797. self.assertIn(
  2798. '<a class="dropdown-item branch_from_item pointer" '
  2799. 'data-value="random_branch"><span class="fa fa-random">'
  2800. "</span> random_branch</a>",
  2801. output_text,
  2802. )
  2803. data = {
  2804. "csrf_token": csrf_token,
  2805. "title": "foo bar PR",
  2806. "initial_comment": "Test Initial Comment\n\nFixes #1",
  2807. }
  2808. output = self.app.post(
  2809. "/fork/pingou/test/diff/master..feature",
  2810. data=data,
  2811. follow_redirects=True,
  2812. )
  2813. self.assertEqual(output.status_code, 200)
  2814. output_text = output.get_data(as_text=True)
  2815. self.assertIn(
  2816. "<title>PR#3: foo bar PR - test\n - Pagure</title>",
  2817. output_text,
  2818. )
  2819. self.assertIn(
  2820. "<p>Test Initial Comment</p>\n<p>Fixes <a href", output_text
  2821. )
  2822. project = pagure.lib.query.get_authorized_project(self.session, "test")
  2823. self.assertEqual(len(project.requests), 2)
  2824. self.assertEqual(len(project.requests[0].related_issues), 0)
  2825. self.assertEqual(len(project.requests[1].related_issues), 1)
  2826. self.assertEqual(len(project.issues), 1)
  2827. self.assertEqual(len(project.issues[0].related_prs), 1)
  2828. @patch("pagure.lib.notify.send_email")
  2829. def test_new_request_pull_fork_to_fork_pr_disabled(self, send_email):
  2830. """ Test creating a fork to fork PR. """
  2831. send_email.return_value = True
  2832. self.test_fork_project()
  2833. # Create a 3rd user
  2834. item = pagure.lib.model.User(
  2835. user="ralph",
  2836. fullname="Ralph bar",
  2837. password="ralph_foo",
  2838. default_email="ralph@bar.com",
  2839. )
  2840. self.session.add(item)
  2841. item = pagure.lib.model.UserEmail(user_id=3, email="ralph@bar.com")
  2842. self.session.add(item)
  2843. self.session.commit()
  2844. user = tests.FakeUser()
  2845. user.username = "ralph"
  2846. with tests.user_set(self.app.application, user):
  2847. # Have Ralph fork, foo's fork of test
  2848. output = self.app.get("/fork/foo/test")
  2849. self.assertEqual(output.status_code, 200)
  2850. output = self.app.post("/do_fork/fork/foo/test")
  2851. self.assertEqual(output.status_code, 400)
  2852. csrf_token = self.get_csrf()
  2853. data = {"csrf_token": csrf_token}
  2854. output = self.app.post(
  2855. "/do_fork/fork/foo/test", data=data, follow_redirects=True
  2856. )
  2857. self.assertEqual(output.status_code, 200)
  2858. # Check that Ralph's fork do exist
  2859. output = self.app.get("/fork/ralph/test")
  2860. self.assertEqual(output.status_code, 200)
  2861. tests.create_projects_git(
  2862. os.path.join(self.path, "requests"), bare=True
  2863. )
  2864. fork = pagure.lib.query.get_authorized_project(
  2865. self.session, "test", user="ralph"
  2866. )
  2867. set_up_git_repo(
  2868. self.session,
  2869. self.path,
  2870. new_project=fork,
  2871. branch_from="feature",
  2872. mtype="FF",
  2873. )
  2874. # Try opening a pull-request
  2875. output = self.app.get("/fork/ralph/test/diff/master..feature")
  2876. self.assertEqual(output.status_code, 404)
  2877. self.assertIn(
  2878. "<p>No pull-request allowed on this project</p>",
  2879. output.get_data(as_text=True),
  2880. )
  2881. @patch("pagure.lib.notify.send_email")
  2882. def test_new_request_pull_fork_to_fork(self, send_email):
  2883. """ Test creating a fork to fork PR. """
  2884. send_email.return_value = True
  2885. self.test_fork_project()
  2886. # Create a 3rd user
  2887. item = pagure.lib.model.User(
  2888. user="ralph",
  2889. fullname="Ralph bar",
  2890. password="ralph_foo",
  2891. default_email="ralph@bar.com",
  2892. )
  2893. self.session.add(item)
  2894. item = pagure.lib.model.UserEmail(user_id=3, email="ralph@bar.com")
  2895. self.session.add(item)
  2896. self.session.commit()
  2897. user = tests.FakeUser()
  2898. user.username = "ralph"
  2899. with tests.user_set(self.app.application, user):
  2900. # Have Ralph fork, foo's fork of test
  2901. output = self.app.get("/fork/foo/test")
  2902. self.assertEqual(output.status_code, 200)
  2903. output = self.app.post("/do_fork/fork/foo/test")
  2904. self.assertEqual(output.status_code, 400)
  2905. csrf_token = self.get_csrf()
  2906. data = {"csrf_token": csrf_token}
  2907. output = self.app.post(
  2908. "/do_fork/fork/foo/test", data=data, follow_redirects=True
  2909. )
  2910. self.assertEqual(output.status_code, 200)
  2911. # Check that Ralph's fork do exist
  2912. output = self.app.get("/fork/ralph/test")
  2913. self.assertEqual(output.status_code, 200)
  2914. tests.create_projects_git(
  2915. os.path.join(self.path, "requests"), bare=True
  2916. )
  2917. # Turn on pull-request on the fork
  2918. repo = pagure.lib.query.get_authorized_project(
  2919. self.session, "test", user="foo"
  2920. )
  2921. settings = repo.settings
  2922. settings["pull_requests"] = True
  2923. repo.settings = settings
  2924. self.session.add(repo)
  2925. self.session.commit()
  2926. # Add some content to the parent
  2927. set_up_git_repo(
  2928. self.session,
  2929. self.path,
  2930. new_project=repo,
  2931. branch_from="master",
  2932. mtype="FF",
  2933. name_from=repo.fullname,
  2934. )
  2935. fork = pagure.lib.query.get_authorized_project(
  2936. self.session, "test", user="ralph"
  2937. )
  2938. set_up_git_repo(
  2939. self.session,
  2940. self.path,
  2941. new_project=fork,
  2942. branch_from="feature",
  2943. mtype="FF",
  2944. prid=2,
  2945. name_from=fork.fullname,
  2946. )
  2947. # Try opening a pull-request
  2948. output = self.app.get("/fork/ralph/test/diff/master..feature")
  2949. self.assertEqual(output.status_code, 200)
  2950. output_text = output.get_data(as_text=True)
  2951. self.assertIn(
  2952. "<title>Create new Pull Request for master - fork/ralph/test\n - "
  2953. "Pagure</title>",
  2954. output_text,
  2955. )
  2956. self.assertIn(
  2957. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  2958. output_text,
  2959. )
  2960. csrf_token = self.get_csrf(output=output)
  2961. # Case 1 - Add an initial comment
  2962. data = {
  2963. "csrf_token": csrf_token,
  2964. "title": "foo bar PR",
  2965. "initial_comment": "Test Initial Comment",
  2966. }
  2967. output = self.app.post(
  2968. "/fork/ralph/test/diff/master..feature",
  2969. data=data,
  2970. follow_redirects=True,
  2971. )
  2972. self.assertEqual(output.status_code, 200)
  2973. output_text = output.get_data(as_text=True)
  2974. self.assertIn(
  2975. "<title>PR#1: foo bar PR - fork/foo/test\n - Pagure</title>",
  2976. output_text,
  2977. )
  2978. self.assertIn("<p>Test Initial Comment</p>", output_text)
  2979. @patch("pagure.lib.notify.send_email")
  2980. def test_new_request_pull_fork_to_other_fork(self, send_email):
  2981. """ Test creating a PR from fork to a fork of the same family. """
  2982. send_email.return_value = True
  2983. self.test_fork_project()
  2984. # Create a 3rd user
  2985. item = pagure.lib.model.User(
  2986. user="ralph",
  2987. fullname="Ralph bar",
  2988. password="ralph_foo",
  2989. default_email="ralph@bar.com",
  2990. )
  2991. self.session.add(item)
  2992. item = pagure.lib.model.UserEmail(user_id=3, email="ralph@bar.com")
  2993. self.session.add(item)
  2994. self.session.commit()
  2995. user = tests.FakeUser()
  2996. user.username = "ralph"
  2997. with tests.user_set(self.app.application, user):
  2998. csrf_token = self.get_csrf()
  2999. data = {"csrf_token": csrf_token}
  3000. output = self.app.post(
  3001. "/do_fork/test", data=data, follow_redirects=True
  3002. )
  3003. self.assertEqual(output.status_code, 200)
  3004. # Check that Ralph's fork do exist
  3005. output = self.app.get("/fork/ralph/test")
  3006. self.assertEqual(output.status_code, 200)
  3007. tests.create_projects_git(
  3008. os.path.join(self.path, "requests"), bare=True
  3009. )
  3010. # Turn on pull-request on the fork
  3011. repo = pagure.lib.query.get_authorized_project(
  3012. self.session, "test", user="foo"
  3013. )
  3014. settings = repo.settings
  3015. settings["pull_requests"] = True
  3016. repo.settings = settings
  3017. self.session.add(repo)
  3018. self.session.commit()
  3019. # Add some content to the parents
  3020. set_up_git_repo(
  3021. self.session,
  3022. self.path,
  3023. new_project=repo,
  3024. branch_from="master",
  3025. mtype="FF",
  3026. )
  3027. set_up_git_repo(
  3028. self.session,
  3029. self.path,
  3030. new_project=repo,
  3031. branch_from="master",
  3032. mtype="FF",
  3033. name_from=repo.fullname,
  3034. prid=2,
  3035. )
  3036. fork = pagure.lib.query.get_authorized_project(
  3037. self.session, "test", user="ralph"
  3038. )
  3039. set_up_git_repo(
  3040. self.session,
  3041. self.path,
  3042. new_project=fork,
  3043. branch_from="feature",
  3044. mtype="FF",
  3045. prid=3,
  3046. name_from=fork.fullname,
  3047. )
  3048. # Try opening a pull-request
  3049. output = self.app.get(
  3050. "/fork/ralph/test/diff/master..feature?project_to=fork/foo/test"
  3051. )
  3052. self.assertEqual(output.status_code, 200)
  3053. output_text = output.get_data(as_text=True)
  3054. self.assertIn(
  3055. "<title>Create new Pull Request for master - fork/ralph/test\n - "
  3056. "Pagure</title>",
  3057. output_text,
  3058. )
  3059. self.assertIn(
  3060. '<input type="submit" class="btn btn-primary" value="Create Pull Request">\n',
  3061. output_text,
  3062. )
  3063. csrf_token = self.get_csrf(output=output)
  3064. # Case 1 - Opening PR to fork/foo/test
  3065. data = {
  3066. "csrf_token": csrf_token,
  3067. "title": "foo bar PR",
  3068. "initial_comment": "Test Initial Comment",
  3069. }
  3070. output = self.app.post(
  3071. "/fork/ralph/test/diff/master..feature?project_to=fork/foo/test",
  3072. data=data,
  3073. follow_redirects=True,
  3074. )
  3075. self.assertEqual(output.status_code, 200)
  3076. output_text = output.get_data(as_text=True)
  3077. self.assertIn(
  3078. "<title>PR#1: foo bar PR - fork/foo/test\n - Pagure</title>",
  3079. output_text,
  3080. )
  3081. self.assertIn("<p>Test Initial Comment</p>", output_text)
  3082. # Case 1 - Opening PR to parent repo, shows project_to works
  3083. output = self.app.post(
  3084. "/fork/ralph/test/diff/master..feature",
  3085. data=data,
  3086. follow_redirects=True,
  3087. )
  3088. self.assertEqual(output.status_code, 200)
  3089. output_text = output.get_data(as_text=True)
  3090. self.assertIn(
  3091. "<title>PR#4: foo bar PR - test\n - Pagure</title>",
  3092. output_text,
  3093. )
  3094. self.assertIn("<p>Test Initial Comment</p>", output_text)
  3095. @patch("pagure.lib.notify.send_email")
  3096. def test_new_request_pull_fork_to_other_unrelated_fork(self, send_email):
  3097. """ Test creating a PR from fork to fork that isn't from the same
  3098. family.
  3099. """
  3100. send_email.return_value = True
  3101. self.test_fork_project()
  3102. # Create a 3rd user
  3103. item = pagure.lib.model.User(
  3104. user="ralph",
  3105. fullname="Ralph bar",
  3106. password="ralph_foo",
  3107. default_email="ralph@bar.com",
  3108. )
  3109. self.session.add(item)
  3110. item = pagure.lib.model.UserEmail(user_id=3, email="ralph@bar.com")
  3111. self.session.add(item)
  3112. self.session.commit()
  3113. user = tests.FakeUser()
  3114. user.username = "ralph"
  3115. with tests.user_set(self.app.application, user):
  3116. csrf_token = self.get_csrf()
  3117. data = {"csrf_token": csrf_token}
  3118. output = self.app.post(
  3119. "/do_fork/test2", data=data, follow_redirects=True
  3120. )
  3121. self.assertEqual(output.status_code, 200)
  3122. # Check that Ralph's fork do exist
  3123. output = self.app.get("/fork/ralph/test2")
  3124. self.assertEqual(output.status_code, 200)
  3125. tests.create_projects_git(
  3126. os.path.join(self.path, "requests"), bare=True
  3127. )
  3128. # Turn on pull-request on the fork
  3129. repo = pagure.lib.query.get_authorized_project(
  3130. self.session, "test", user="foo"
  3131. )
  3132. settings = repo.settings
  3133. settings["pull_requests"] = True
  3134. repo.settings = settings
  3135. self.session.add(repo)
  3136. self.session.commit()
  3137. # Add some content to the parent
  3138. set_up_git_repo(
  3139. self.session,
  3140. self.path,
  3141. new_project=repo,
  3142. branch_from="master",
  3143. mtype="FF",
  3144. name_from=repo.fullname,
  3145. )
  3146. fork = pagure.lib.query.get_authorized_project(
  3147. self.session, "test2", user="ralph"
  3148. )
  3149. set_up_git_repo(
  3150. self.session,
  3151. self.path,
  3152. new_project=fork,
  3153. branch_from="feature",
  3154. mtype="FF",
  3155. prid=2,
  3156. name_from=fork.fullname,
  3157. )
  3158. # Case 1 - Opening PR to fork/foo/test
  3159. data = {
  3160. "csrf_token": csrf_token,
  3161. "title": "foo bar PR",
  3162. "initial_comment": "Test Initial Comment",
  3163. }
  3164. output = self.app.post(
  3165. "/fork/ralph/test2/diff/master..feature?project_to=fork/foo/test",
  3166. data=data,
  3167. follow_redirects=True,
  3168. )
  3169. self.assertEqual(output.status_code, 400)
  3170. self.assertIn(
  3171. "<p>fork/foo/test is not part of fork/ralph/test2's "
  3172. "family</p>",
  3173. output.get_data(as_text=True),
  3174. )
  3175. @patch("pagure.lib.notify.send_email")
  3176. def test_new_request_pull_empty_repo(self, send_email):
  3177. """ Test the new_request_pull endpoint against an empty repo. """
  3178. send_email.return_value = True
  3179. self.test_fork_project()
  3180. tests.create_projects_git(
  3181. os.path.join(self.path, "requests"), bare=True
  3182. )
  3183. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  3184. fork = pagure.lib.query.get_authorized_project(
  3185. self.session, "test", user="foo"
  3186. )
  3187. # Create a git repo to play with
  3188. gitrepo = os.path.join(self.path, "repos", "test.git")
  3189. repo = pygit2.init_repository(gitrepo, bare=True)
  3190. # Create a fork of this repo
  3191. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  3192. gitrepo = os.path.join(self.path, "repos", "forks", "foo", "test.git")
  3193. new_repo = pygit2.clone_repository(gitrepo, newpath)
  3194. user = tests.FakeUser()
  3195. user.username = "foo"
  3196. with tests.user_set(self.app.application, user):
  3197. output = self.app.get(
  3198. "/fork/foo/test/diff/master..feature", follow_redirects=True
  3199. )
  3200. self.assertEqual(output.status_code, 400)
  3201. self.assertIn(
  3202. "<p>Fork is empty, there are no commits to create a pull "
  3203. "request with</p>",
  3204. output.get_data(as_text=True),
  3205. )
  3206. output = self.app.get("/test/new_issue")
  3207. csrf_token = self.get_csrf(output=output)
  3208. data = {"csrf_token": csrf_token, "title": "foo bar PR"}
  3209. output = self.app.post(
  3210. "/test/diff/master..feature", data=data, follow_redirects=True
  3211. )
  3212. self.assertEqual(output.status_code, 400)
  3213. self.assertIn(
  3214. "<p>Fork is empty, there are no commits to create a pull "
  3215. "request with</p>",
  3216. output.get_data(as_text=True),
  3217. )
  3218. shutil.rmtree(newpath)
  3219. @patch("pagure.lib.notify.send_email")
  3220. def test_new_request_pull_empty_fork(self, send_email):
  3221. """ Test the new_request_pull endpoint against an empty repo. """
  3222. send_email.return_value = True
  3223. self.test_fork_project()
  3224. tests.create_projects_git(
  3225. os.path.join(self.path, "requests"), bare=True
  3226. )
  3227. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  3228. fork = pagure.lib.query.get_authorized_project(
  3229. self.session, "test", user="foo"
  3230. )
  3231. # Create a git repo to play with
  3232. gitrepo = os.path.join(self.path, "repos", "test.git")
  3233. repo = pygit2.init_repository(gitrepo, bare=True)
  3234. # Create a fork of this repo
  3235. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  3236. gitrepo = os.path.join(self.path, "repos", "forks", "foo", "test.git")
  3237. new_repo = pygit2.clone_repository(gitrepo, newpath)
  3238. user = tests.FakeUser()
  3239. user.username = "foo"
  3240. with tests.user_set(self.app.application, user):
  3241. output = self.app.get(
  3242. "/fork/foo/test/diff/master..master", follow_redirects=True
  3243. )
  3244. self.assertEqual(output.status_code, 400)
  3245. self.assertIn(
  3246. "<p>Fork is empty, there are no commits to create a pull "
  3247. "request with</p>",
  3248. output.get_data(as_text=True),
  3249. )
  3250. shutil.rmtree(newpath)
  3251. @patch("pagure.lib.notify.send_email")
  3252. def test_pull_request_add_comment(self, send_email):
  3253. """ Test the pull_request_add_comment endpoint. """
  3254. send_email.return_value = True
  3255. self.test_request_pull()
  3256. user = tests.FakeUser()
  3257. user.username = "pingou"
  3258. with tests.user_set(self.app.application, user):
  3259. output = self.app.post("/foo/pull-request/1/comment")
  3260. self.assertEqual(output.status_code, 404)
  3261. output = self.app.post("/test/pull-request/100/comment")
  3262. self.assertEqual(output.status_code, 404)
  3263. output = self.app.post("/test/pull-request/1/comment")
  3264. self.assertEqual(output.status_code, 200)
  3265. self.assertTrue(
  3266. output.get_data(as_text=True).startswith(
  3267. '\n<section class="add_comment">'
  3268. )
  3269. )
  3270. csrf_token = self.get_csrf(output=output)
  3271. data = {
  3272. "csrf_token": csrf_token,
  3273. "comment": "This look alright but we can do better",
  3274. }
  3275. output = self.app.post(
  3276. "/test/pull-request/1/comment",
  3277. data=data,
  3278. follow_redirects=True,
  3279. )
  3280. self.assertEqual(output.status_code, 200)
  3281. output_text = output.get_data(as_text=True)
  3282. self.assertIn(
  3283. "<title>PR#1: PR from the feature branch - test\n - "
  3284. "Pagure</title>",
  3285. output_text,
  3286. )
  3287. self.assertIn("Comment added", output_text)
  3288. self.assertEqual(output_text.count('title="PY C (pingou)"'), 2)
  3289. # Project w/o pull-request
  3290. repo = pagure.lib.query.get_authorized_project(
  3291. self.session, "test"
  3292. )
  3293. settings = repo.settings
  3294. settings["pull_requests"] = False
  3295. repo.settings = settings
  3296. self.session.add(repo)
  3297. self.session.commit()
  3298. output = self.app.post(
  3299. "/test/pull-request/1/comment",
  3300. data=data,
  3301. follow_redirects=True,
  3302. )
  3303. self.assertEqual(output.status_code, 404)
  3304. @patch("pagure.lib.notify.send_email")
  3305. def test_pull_request_drop_comment(self, send_email):
  3306. """ Test the pull_request_drop_comment endpoint. """
  3307. send_email.return_value = True
  3308. self.test_pull_request_add_comment()
  3309. # Project w/ pull-request
  3310. repo = pagure.lib.query.get_authorized_project(self.session, "test")
  3311. settings = repo.settings
  3312. settings["pull_requests"] = True
  3313. repo.settings = settings
  3314. self.session.add(repo)
  3315. self.session.commit()
  3316. user = tests.FakeUser()
  3317. user.username = "foo"
  3318. with tests.user_set(self.app.application, user):
  3319. output = self.app.post("/foo/pull-request/1/comment/drop")
  3320. self.assertEqual(output.status_code, 404)
  3321. output = self.app.post("/test/pull-request/100/comment/drop")
  3322. self.assertEqual(output.status_code, 404)
  3323. output = self.app.post(
  3324. "/test/pull-request/1/comment/drop", follow_redirects=True
  3325. )
  3326. self.assertEqual(output.status_code, 200)
  3327. output_text = output.get_data(as_text=True)
  3328. self.assertIn(
  3329. '<h4 class="ml-1">\n <div>\n '
  3330. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  3331. '<span class="text-success '
  3332. 'font-weight-bold">#1</span>\n '
  3333. '<span class="font-weight-bold">\n '
  3334. "PR from the feature branch\n",
  3335. output_text,
  3336. )
  3337. # self.assertIn('href="#comment-1">¶</a>', output_text)
  3338. self.assertIn(
  3339. "<p>This look alright but we can do better</p>", output_text
  3340. )
  3341. csrf_token = self.get_csrf(output=output)
  3342. # Invalid comment id
  3343. data = {"csrf_token": csrf_token, "drop_comment": "10"}
  3344. output = self.app.post(
  3345. "/test/pull-request/1/comment/drop",
  3346. data=data,
  3347. follow_redirects=True,
  3348. )
  3349. self.assertEqual(output.status_code, 404)
  3350. data["drop_comment"] = "1"
  3351. output = self.app.post(
  3352. "/test/pull-request/1/comment/drop",
  3353. data=data,
  3354. follow_redirects=True,
  3355. )
  3356. self.assertEqual(output.status_code, 403)
  3357. user.username = "pingou"
  3358. with tests.user_set(self.app.application, user):
  3359. # Drop comment
  3360. output = self.app.post(
  3361. "/test/pull-request/1/comment/drop",
  3362. data=data,
  3363. follow_redirects=True,
  3364. )
  3365. self.assertEqual(output.status_code, 200)
  3366. output_text = output.get_data(as_text=True)
  3367. self.assertIn(
  3368. '<h4 class="ml-1">\n <div>\n '
  3369. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  3370. '<span class="text-success '
  3371. 'font-weight-bold">#1</span>\n '
  3372. '<span class="font-weight-bold">\n '
  3373. "PR from the feature branch\n",
  3374. output_text,
  3375. )
  3376. self.assertIn("Comment removed", output_text)
  3377. # Project w/o pull-request
  3378. repo = pagure.lib.query.get_authorized_project(
  3379. self.session, "test"
  3380. )
  3381. settings = repo.settings
  3382. settings["pull_requests"] = False
  3383. repo.settings = settings
  3384. self.session.add(repo)
  3385. self.session.commit()
  3386. output = self.app.post(
  3387. "/test/pull-request/1/comment/drop",
  3388. data=data,
  3389. follow_redirects=True,
  3390. )
  3391. self.assertEqual(output.status_code, 404)
  3392. @patch("pagure.lib.notify.send_email")
  3393. def test_pull_request_edit_comment(self, send_email):
  3394. """ Test the pull request edit comment endpoint """
  3395. send_email.return_value = True
  3396. self.test_request_pull()
  3397. user = tests.FakeUser()
  3398. user.username = "pingou"
  3399. with tests.user_set(self.app.application, user):
  3400. # Repo 'foo' does not exist so it is verifying that condition
  3401. output = self.app.post("/foo/pull-request/1/comment/1/edit")
  3402. self.assertEqual(output.status_code, 404)
  3403. # Here no comment is present in the PR so its verifying that condition
  3404. output = self.app.post("/test/pull-request/100/comment/100/edit")
  3405. self.assertEqual(output.status_code, 404)
  3406. output = self.app.post("/test/pull-request/1/comment")
  3407. self.assertEqual(output.status_code, 200)
  3408. # Creating comment to play with
  3409. self.assertTrue(
  3410. output.get_data(as_text=True).startswith(
  3411. '\n<section class="add_comment">'
  3412. )
  3413. )
  3414. csrf_token = self.get_csrf(output=output)
  3415. data = {
  3416. "csrf_token": csrf_token,
  3417. "comment": "This look alright but we can do better",
  3418. }
  3419. output = self.app.post(
  3420. "/test/pull-request/1/comment",
  3421. data=data,
  3422. follow_redirects=True,
  3423. )
  3424. self.assertEqual(output.status_code, 200)
  3425. output_text = output.get_data(as_text=True)
  3426. self.assertIn(
  3427. '<h4 class="ml-1">\n <div>\n '
  3428. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  3429. '<span class="text-success '
  3430. 'font-weight-bold">#1</span>\n '
  3431. '<span class="font-weight-bold">\n '
  3432. "PR from the feature branch\n",
  3433. output_text,
  3434. )
  3435. self.assertIn("Comment added", output_text)
  3436. # Check if the comment is there
  3437. self.assertIn(
  3438. "<p>This look alright but we can do better</p>", output_text
  3439. )
  3440. output = self.app.get("/test/pull-request/1/comment/1/edit")
  3441. self.assertEqual(output.status_code, 200)
  3442. output_text = output.get_data(as_text=True)
  3443. self.assertIn('<section class="edit_comment">', output_text)
  3444. # Checking if the comment is there in the update page
  3445. self.assertIn(
  3446. "This look alright but we can do better</textarea>",
  3447. output_text,
  3448. )
  3449. csrf_token = self.get_csrf(output=output)
  3450. data = {
  3451. "csrf_token": csrf_token,
  3452. "update_comment": "This look alright but we can do better than this.",
  3453. }
  3454. output = self.app.post(
  3455. "/test/pull-request/1/comment/1/edit",
  3456. data=data,
  3457. follow_redirects=True,
  3458. )
  3459. output_text = output.get_data(as_text=True)
  3460. # Checking if the comment is updated in the main page
  3461. self.assertIn(
  3462. "<p>This look alright but we can do better than this.</p>",
  3463. output_text,
  3464. )
  3465. self.assertIn(
  3466. '<h4 class="ml-1">\n <div>\n '
  3467. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  3468. '<span class="text-success '
  3469. 'font-weight-bold">#1</span>\n '
  3470. '<span class="font-weight-bold">\n '
  3471. "PR from the feature branch\n",
  3472. output_text,
  3473. )
  3474. # Checking if Edited by User is there or not
  3475. self.assertTrue(
  3476. "<small>Edited just now by pingou </small>" in output_text
  3477. or "<small>Edited seconds ago by pingou </small>"
  3478. in output_text
  3479. )
  3480. self.assertIn("Comment updated", output_text)
  3481. # Project w/o pull-request
  3482. repo = pagure.lib.query.get_authorized_project(
  3483. self.session, "test"
  3484. )
  3485. settings = repo.settings
  3486. settings["pull_requests"] = False
  3487. repo.settings = settings
  3488. self.session.add(repo)
  3489. self.session.commit()
  3490. output = self.app.post(
  3491. "/test/pull-request/1/comment/edit/1",
  3492. data=data,
  3493. follow_redirects=True,
  3494. )
  3495. self.assertEqual(output.status_code, 404)
  3496. @patch("pagure.lib.notify.send_email")
  3497. def test_merge_request_pull_FF_w_merge_commit(self, send_email):
  3498. """ Test the merge_request_pull endpoint with a FF PR but with a
  3499. merge commit.
  3500. """
  3501. send_email.return_value = True
  3502. self.test_request_pull()
  3503. user = tests.FakeUser()
  3504. with tests.user_set(self.app.application, user):
  3505. output = self.app.get("/test/pull-request/1")
  3506. self.assertEqual(output.status_code, 200)
  3507. csrf_token = self.get_csrf(output=output)
  3508. # No CSRF
  3509. output = self.app.post(
  3510. "/test/pull-request/1/merge", data={}, follow_redirects=True
  3511. )
  3512. self.assertEqual(output.status_code, 200)
  3513. output_text = output.get_data(as_text=True)
  3514. self.assertIn(
  3515. "<title>PR#1: PR from the feature branch - test\n - "
  3516. "Pagure</title>",
  3517. output_text,
  3518. )
  3519. self.assertIn(
  3520. '<h4 class="ml-1">\n <div>\n '
  3521. '<span class="fa fa-fw text-success fa-arrow-circle-down pt-1"></span>\n '
  3522. '<span class="text-success '
  3523. 'font-weight-bold">#1</span>\n '
  3524. '<span class="font-weight-bold">\n '
  3525. "PR from the feature branch\n",
  3526. output_text,
  3527. )
  3528. self.assertIn(
  3529. 'title="View file as of 2a552b">sources</a>', output_text
  3530. )
  3531. # Wrong project
  3532. data = {"csrf_token": csrf_token}
  3533. output = self.app.post(
  3534. "/foobar/pull-request/100/merge",
  3535. data=data,
  3536. follow_redirects=True,
  3537. )
  3538. self.assertEqual(output.status_code, 404)
  3539. # Wrong project
  3540. data = {"csrf_token": csrf_token}
  3541. output = self.app.post(
  3542. "/test/pull-request/1/merge", data=data, follow_redirects=True
  3543. )
  3544. self.assertEqual(output.status_code, 403)
  3545. user.username = "pingou"
  3546. with tests.user_set(self.app.application, user):
  3547. # Wrong request id
  3548. data = {"csrf_token": csrf_token}
  3549. output = self.app.post(
  3550. "/test/pull-request/100/merge",
  3551. data=data,
  3552. follow_redirects=True,
  3553. )
  3554. self.assertEqual(output.status_code, 404)
  3555. # Project requiring a merge commit
  3556. repo = pagure.lib.query.get_authorized_project(
  3557. self.session, "test"
  3558. )
  3559. settings = repo.settings
  3560. settings["always_merge"] = True
  3561. repo.settings = settings
  3562. self.session.add(repo)
  3563. self.session.commit()
  3564. # Merge
  3565. output = self.app.post(
  3566. "/test/pull-request/1/merge", data=data, follow_redirects=True
  3567. )
  3568. self.assertEqual(output.status_code, 200)
  3569. output = self.app.get("/test/commits")
  3570. output_text = output.get_data(as_text=True)
  3571. self.assertIn(
  3572. "<title>Commits - test - Pagure</title>", output_text
  3573. )
  3574. self.assertIn("Merge #1 `PR from the feature branch`", output_text)
  3575. self.assertIn("A commit on branch feature", output_text)
  3576. # Check if the closing notification was added
  3577. output = self.app.get("/test/pull-request/1")
  3578. self.assertIn(
  3579. '<span class="text-info font-weight-bold">Merged</span> just now\n'
  3580. " </span>\n by\n"
  3581. ' <span title="PY C (pingou)">pingou.</span>\n',
  3582. output.get_data(as_text=True),
  3583. )
  3584. @patch("pagure.lib.notify.send_email")
  3585. def test_internal_endpoint_main_ahead(self, send_email):
  3586. """ Test the new_request_pull endpoint when the main repo is ahead
  3587. of the fork.
  3588. """
  3589. send_email.return_value = True
  3590. tests.create_projects(self.session)
  3591. tests.create_projects_git(
  3592. os.path.join(self.path, "requests"), bare=True
  3593. )
  3594. set_up_git_repo(
  3595. self.session, self.path, new_project=None, branch_from="feature"
  3596. )
  3597. gitrepo = os.path.join(self.path, "repos", "test.git")
  3598. repo = pygit2.init_repository(gitrepo, bare=True)
  3599. # Make the main repo be ahead of the fork
  3600. # First commit
  3601. newpath = tempfile.mkdtemp(prefix="pagure-test")
  3602. repopath = os.path.join(newpath, "test")
  3603. clone_repo = pygit2.clone_repository(gitrepo, repopath)
  3604. # Create a file in that git repo
  3605. with open(os.path.join(repopath, "testfile"), "w") as stream:
  3606. stream.write("foo\n bar")
  3607. clone_repo.index.add("testfile")
  3608. clone_repo.index.write()
  3609. # Commits the files added
  3610. last_commit = clone_repo.revparse_single("HEAD")
  3611. tree = clone_repo.index.write_tree()
  3612. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  3613. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  3614. clone_repo.create_commit(
  3615. "refs/heads/master", # the name of the reference to update
  3616. author,
  3617. committer,
  3618. "Add testfile file for testing",
  3619. # binary string representing the tree object ID
  3620. tree,
  3621. # list of binary strings representing parents of the new commit
  3622. [last_commit.oid.hex],
  3623. )
  3624. # Second commit
  3625. with open(os.path.join(repopath, "testfile"), "a") as stream:
  3626. stream.write("\nfoo2\n bar2")
  3627. clone_repo.index.add("testfile")
  3628. clone_repo.index.write()
  3629. # Commits the files added
  3630. last_commit = clone_repo.revparse_single("HEAD")
  3631. tree = clone_repo.index.write_tree()
  3632. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  3633. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  3634. clone_repo.create_commit(
  3635. "refs/heads/master", # the name of the reference to update
  3636. author,
  3637. committer,
  3638. "Add a second commit to testfile for testing",
  3639. # binary string representing the tree object ID
  3640. tree,
  3641. # list of binary strings representing parents of the new commit
  3642. [last_commit.oid.hex],
  3643. )
  3644. # Third commit
  3645. with open(os.path.join(repopath, "testfile"), "a") as stream:
  3646. stream.write("\nfoo3\n bar3")
  3647. clone_repo.index.add("testfile")
  3648. clone_repo.index.write()
  3649. # Commits the files added
  3650. last_commit = clone_repo.revparse_single("HEAD")
  3651. tree = clone_repo.index.write_tree()
  3652. author = pygit2.Signature("Alice Author", "alice@authors.tld")
  3653. committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
  3654. clone_repo.create_commit(
  3655. "refs/heads/master", # the name of the reference to update
  3656. author,
  3657. committer,
  3658. "Add a third commit to testfile for testing",
  3659. # binary string representing the tree object ID
  3660. tree,
  3661. # list of binary strings representing parents of the new commit
  3662. [last_commit.oid.hex],
  3663. )
  3664. refname = "refs/heads/master:refs/heads/master"
  3665. ori_remote = clone_repo.remotes[0]
  3666. PagureRepo.push(ori_remote, refname)
  3667. shutil.rmtree(newpath)
  3668. user = tests.FakeUser()
  3669. user.username = "foo"
  3670. with tests.user_set(self.app.application, user):
  3671. csrf_token = self.get_csrf()
  3672. output = self.app.post(
  3673. "/pv/pull-request/ready",
  3674. data={"repo": "test", "csrf_token": csrf_token},
  3675. )
  3676. self.assertEqual(output.status_code, 200)
  3677. data = json.loads(output.get_data(as_text=True))
  3678. self.assertEqual(sorted(data.keys()), ["code", "task"])
  3679. self.assertEqual(data["code"], "OK")
  3680. @patch("pagure.lib.notify.send_email")
  3681. def test_fork_edit_file(self, send_email):
  3682. """ Test the fork_edit file endpoint. """
  3683. send_email.return_value = True
  3684. # Git repo not found
  3685. output = self.app.post("fork_edit/test/edit/master/f/sources")
  3686. self.assertEqual(output.status_code, 404)
  3687. tests.create_projects(self.session)
  3688. for folder in ["docs", "tickets", "requests", "repos"]:
  3689. tests.create_projects_git(
  3690. os.path.join(self.path, folder), bare=True
  3691. )
  3692. # User not logged in
  3693. output = self.app.post("fork_edit/test/edit/master/f/sources")
  3694. self.assertEqual(output.status_code, 302)
  3695. user = tests.FakeUser()
  3696. user.username = "pingou"
  3697. with tests.user_set(self.app.application, user):
  3698. # Invalid request
  3699. output = self.app.post("fork_edit/test/edit/master/f/source")
  3700. self.assertEqual(output.status_code, 400)
  3701. output = self.app.get("/new/")
  3702. self.assertEqual(output.status_code, 200)
  3703. self.assertIn(
  3704. "<strong>Create new Project</strong>",
  3705. output.get_data(as_text=True),
  3706. )
  3707. csrf_token = self.get_csrf(output=output)
  3708. data = {"csrf_token": csrf_token}
  3709. # No files can be found since they are not added
  3710. output = self.app.post(
  3711. "fork_edit/test/edit/master/f/sources",
  3712. data=data,
  3713. follow_redirects=True,
  3714. )
  3715. self.assertEqual(output.status_code, 404)
  3716. user = tests.FakeUser()
  3717. user.username = "foo"
  3718. with tests.user_set(self.app.application, user):
  3719. data = {"csrf_token": csrf_token}
  3720. # Invalid request
  3721. output = self.app.post(
  3722. "fork_edit/test/edit/master/f/sources", follow_redirects=True
  3723. )
  3724. self.assertEqual(output.status_code, 400)
  3725. # Add content to the repo
  3726. tests.add_content_git_repo(
  3727. os.path.join(pagure.config.config["GIT_FOLDER"], "test.git")
  3728. )
  3729. tests.add_readme_git_repo(
  3730. os.path.join(pagure.config.config["GIT_FOLDER"], "test.git")
  3731. )
  3732. tests.add_binary_git_repo(
  3733. os.path.join(pagure.config.config["GIT_FOLDER"], "test.git"),
  3734. "test.jpg",
  3735. )
  3736. # Check if button exists
  3737. output = self.app.get("/test/blob/master/f/sources")
  3738. self.assertEqual(output.status_code, 200)
  3739. self.assertIn(
  3740. "Fork and Edit\n </button>\n",
  3741. output.get_data(as_text=True),
  3742. )
  3743. # Check fork-edit doesn't show for binary files
  3744. output = self.app.get("/test/blob/master/f/test.jpg")
  3745. self.assertEqual(output.status_code, 200)
  3746. self.assertNotIn(
  3747. "Fork and Edit\n </button>\n",
  3748. output.get_data(as_text=True),
  3749. )
  3750. # Check for edit panel
  3751. output = self.app.post(
  3752. "fork_edit/test/edit/master/f/sources",
  3753. data=data,
  3754. follow_redirects=True,
  3755. )
  3756. self.assertEqual(output.status_code, 200)
  3757. output_text = output.get_data(as_text=True)
  3758. self.assertIn(
  3759. '<li><a href="/fork/foo/test/tree/master">'
  3760. '<span class="fa fa-random"></span>&nbsp; master</a>'
  3761. '</li><li class="active"><span class="fa fa-file">'
  3762. "</span>&nbsp; sources</li>",
  3763. output_text,
  3764. )
  3765. self.assertIn(
  3766. '<textarea id="textareaCode" name="content">foo\n bar</textarea>',
  3767. output_text,
  3768. )
  3769. # Check for edit panel- Fork already done
  3770. output = self.app.post(
  3771. "fork_edit/test/edit/master/f/sources",
  3772. data=data,
  3773. follow_redirects=True,
  3774. )
  3775. self.assertEqual(output.status_code, 200)
  3776. output_text = output.get_data(as_text=True)
  3777. self.assertIn("<title>Edit - test - Pagure</title>", output_text)
  3778. self.assertIn(
  3779. "You had already forked " "this project", output_text
  3780. )
  3781. self.assertIn(
  3782. '<i class="fa fa-code-fork fa-fw"></i> View Upstream',
  3783. output_text,
  3784. )
  3785. self.assertIn(
  3786. '<li><a href="/fork/foo/test/tree/master">'
  3787. '<span class="fa fa-random"></span>&nbsp; master</a>'
  3788. '</li><li class="active"><span class="fa fa-file">'
  3789. "</span>&nbsp; sources</li>",
  3790. output_text,
  3791. )
  3792. self.assertIn(
  3793. '<textarea id="textareaCode" name="content">foo\n bar</textarea>',
  3794. output_text,
  3795. )
  3796. # View what's supposed to be an image
  3797. output = self.app.post(
  3798. "fork_edit/test/edit/master/f/test.jpg",
  3799. data=data,
  3800. follow_redirects=True,
  3801. )
  3802. self.assertEqual(output.status_code, 400)
  3803. self.assertIn(
  3804. "<p>Cannot edit binary files</p>",
  3805. output.get_data(as_text=True),
  3806. )
  3807. # Check fork-edit shows when user is not logged in
  3808. output = self.app.get("/test/blob/master/f/sources")
  3809. self.assertEqual(output.status_code, 200)
  3810. self.assertIn(
  3811. "Fork and Edit\n </button>\n",
  3812. output.get_data(as_text=True),
  3813. )
  3814. # Check if fork-edit shows for different user
  3815. user.username = "pingou"
  3816. with tests.user_set(self.app.application, user):
  3817. # Check if button exists
  3818. output = self.app.get("/test/blob/master/f/sources")
  3819. self.assertEqual(output.status_code, 200)
  3820. self.assertIn(
  3821. "Edit in your fork\n </button>\n",
  3822. output.get_data(as_text=True),
  3823. )
  3824. # Check fork-edit doesn't show for binary
  3825. output = self.app.get("/test/blob/master/f/test.jpg")
  3826. self.assertEqual(output.status_code, 200)
  3827. self.assertNotIn(
  3828. "Edit in your fork\n </button>\n",
  3829. output.get_data(as_text=True),
  3830. )
  3831. @patch("pagure.lib.notify.send_email", MagicMock(return_value=True))
  3832. def test_fork_edit_file_namespace(self):
  3833. """ Test the fork_edit file endpoint on a namespaced project. """
  3834. tests.create_projects(self.session)
  3835. for folder in ["docs", "tickets", "requests", "repos"]:
  3836. tests.create_projects_git(
  3837. os.path.join(self.path, folder), bare=True
  3838. )
  3839. # User not logged in
  3840. output = self.app.post(
  3841. "fork_edit/somenamespace/test3/edit/master/f/sources"
  3842. )
  3843. self.assertEqual(output.status_code, 302)
  3844. user = tests.FakeUser()
  3845. user.username = "pingou"
  3846. with tests.user_set(self.app.application, user):
  3847. # Invalid request
  3848. output = self.app.post(
  3849. "fork_edit/somenamespace/test3/edit/master/f/sources"
  3850. )
  3851. self.assertEqual(output.status_code, 400)
  3852. output = self.app.get("/new/")
  3853. self.assertEqual(output.status_code, 200)
  3854. self.assertIn(
  3855. "<strong>Create new Project</strong>",
  3856. output.get_data(as_text=True),
  3857. )
  3858. csrf_token = self.get_csrf(output=output)
  3859. data = {"csrf_token": csrf_token}
  3860. # No files can be found since they are not added
  3861. output = self.app.post(
  3862. "fork_edit/somenamespace/test3/edit/master/f/sources",
  3863. data=data,
  3864. follow_redirects=True,
  3865. )
  3866. self.assertEqual(output.status_code, 404)
  3867. user = tests.FakeUser()
  3868. user.username = "foo"
  3869. with tests.user_set(self.app.application, user):
  3870. data = {"csrf_token": csrf_token}
  3871. # Invalid request
  3872. output = self.app.post(
  3873. "fork_edit/somenamespace/test3/edit/master/f/sources",
  3874. follow_redirects=True,
  3875. )
  3876. self.assertEqual(output.status_code, 400)
  3877. # Add content to the repo
  3878. tests.add_content_git_repo(
  3879. os.path.join(
  3880. pagure.config.config["GIT_FOLDER"],
  3881. "somenamespace",
  3882. "test3.git",
  3883. )
  3884. )
  3885. tests.add_readme_git_repo(
  3886. os.path.join(
  3887. pagure.config.config["GIT_FOLDER"],
  3888. "somenamespace",
  3889. "test3.git",
  3890. )
  3891. )
  3892. tests.add_binary_git_repo(
  3893. os.path.join(
  3894. pagure.config.config["GIT_FOLDER"],
  3895. "somenamespace",
  3896. "test3.git",
  3897. ),
  3898. "test.jpg",
  3899. )
  3900. # Check if button exists
  3901. output = self.app.get("/somenamespace/test3/blob/master/f/sources")
  3902. self.assertEqual(output.status_code, 200)
  3903. self.assertIn(
  3904. "Fork and Edit\n </button>\n",
  3905. output.get_data(as_text=True),
  3906. )
  3907. # Check fork-edit doesn't show for binary files
  3908. output = self.app.get(
  3909. "/somenamespace/test3/blob/master/f/test.jpg"
  3910. )
  3911. self.assertEqual(output.status_code, 200)
  3912. self.assertNotIn(
  3913. "Fork and Edit\n </button>\n",
  3914. output.get_data(as_text=True),
  3915. )
  3916. # Check for edit panel
  3917. output = self.app.post(
  3918. "fork_edit/somenamespace/test3/edit/master/f/sources",
  3919. data=data,
  3920. follow_redirects=True,
  3921. )
  3922. self.assertEqual(output.status_code, 200)
  3923. output_text = output.get_data(as_text=True)
  3924. self.assertIn(
  3925. "<title>Edit - somenamespace/test3 - Pagure</title>",
  3926. output_text,
  3927. )
  3928. self.assertIn(
  3929. '<i class="fa fa-code-fork fa-fw"></i> View Upstream',
  3930. output_text,
  3931. )
  3932. self.assertIn(
  3933. '<li><a href="/fork/foo/somenamespace/test3/tree/master">'
  3934. '<span class="fa fa-random"></span>&nbsp; master</a>'
  3935. '</li><li class="active"><span class="fa fa-file">'
  3936. "</span>&nbsp; sources</li>",
  3937. output_text,
  3938. )
  3939. self.assertIn(
  3940. '<textarea id="textareaCode" name="content">foo\n bar</textarea>',
  3941. output_text,
  3942. )
  3943. # Check for edit panel - while the project was already forked
  3944. output = self.app.post(
  3945. "fork_edit/somenamespace/test3/edit/master/f/sources",
  3946. data=data,
  3947. follow_redirects=True,
  3948. )
  3949. self.assertEqual(output.status_code, 200)
  3950. output_text = output.get_data(as_text=True)
  3951. self.assertIn(
  3952. "<title>Edit - somenamespace/test3 - Pagure</title>",
  3953. output_text,
  3954. )
  3955. self.assertIn(
  3956. "You had already forked " "this project", output_text
  3957. )
  3958. self.assertIn(
  3959. '<i class="fa fa-code-fork fa-fw"></i> View Upstream',
  3960. output_text,
  3961. )
  3962. self.assertIn(
  3963. '<li><a href="/fork/foo/somenamespace/test3/tree/master">'
  3964. '<span class="fa fa-random"></span>&nbsp; master</a>'
  3965. '</li><li class="active"><span class="fa fa-file">'
  3966. "</span>&nbsp; sources</li>",
  3967. output_text,
  3968. )
  3969. self.assertIn(
  3970. '<textarea id="textareaCode" name="content">foo\n bar</textarea>',
  3971. output_text,
  3972. )
  3973. @patch("pagure.lib.notify.send_email")
  3974. def test_fork_without_main_repo(self, send_email):
  3975. """ Test the fork without the main repo. """
  3976. send_email.return_value = True
  3977. tests.create_projects(self.session)
  3978. # Create a fork with no parent i.e parent_id = None
  3979. item = pagure.lib.model.Project(
  3980. user_id=2, # foo
  3981. name="test",
  3982. description="test project #1",
  3983. hook_token="aaabbb",
  3984. is_fork=True,
  3985. parent_id=None,
  3986. )
  3987. self.session.add(item)
  3988. self.session.commit()
  3989. # Get fork project
  3990. project = pagure.lib.query._get_project(self.session, "test", "foo")
  3991. # Pull-requests and issue-trackers are off for forks
  3992. # lib function is not used here so mannually turning them off
  3993. project_settings = project.settings
  3994. project_settings["pull_requests"] = False
  3995. project_settings["issue_tracker"] = False
  3996. project.settings = project_settings
  3997. self.session.add(project)
  3998. self.session.commit()
  3999. tests.create_projects_git(
  4000. os.path.join(self.path, "repos", "forks", "foo"), bare=True
  4001. )
  4002. # Create a git repo to play with
  4003. gitrepo = os.path.join(self.path, "repos", "test.git")
  4004. self.assertFalse(os.path.exists(gitrepo))
  4005. os.makedirs(gitrepo)
  4006. repo = pygit2.init_repository(gitrepo, bare=True)
  4007. # Create a fork of this repo
  4008. newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
  4009. gitrepo = os.path.join(self.path, "repos", "forks", "foo", "test.git")
  4010. new_repo = pygit2.clone_repository(gitrepo, newpath)
  4011. tests.add_content_git_repo(gitrepo)
  4012. # UI test for deleted main
  4013. output = self.app.get("/fork/foo/test")
  4014. self.assertEqual(output.status_code, 200)
  4015. self.assertIn(
  4016. "Forked from a deleted repository", output.get_data(as_text=True)
  4017. )
  4018. # Testing commit endpoint
  4019. output = self.app.get("/fork/foo/test/commits/master")
  4020. self.assertEqual(output.status_code, 200)
  4021. self.assertIn(
  4022. 'Commits <span class="badge badge-secondary"> 2</span>\n',
  4023. output.get_data(as_text=True),
  4024. )
  4025. # Test pull-request endpoint
  4026. output = self.app.get("/fork/foo/test/pull-requests")
  4027. self.assertEqual(output.status_code, 404)
  4028. # Test issue-tracker endpoint
  4029. output = self.app.get("/fork/foo/test/issues")
  4030. self.assertEqual(output.status_code, 404)
  4031. shutil.rmtree(newpath)
  4032. def _set_up_for_reaction_test(self):
  4033. self.session.add(
  4034. pagure.lib.model.User(
  4035. user="jdoe",
  4036. fullname="John Doe",
  4037. password=b"password",
  4038. default_email="jdoe@example.com",
  4039. )
  4040. )
  4041. self.session.commit()
  4042. tests.create_projects(self.session)
  4043. tests.create_projects_git(
  4044. os.path.join(self.path, "requests"), bare=True
  4045. )
  4046. set_up_git_repo(
  4047. self.session, self.path, new_project=None, branch_from="feature"
  4048. )
  4049. pagure.lib.query.get_authorized_project(self.session, "test")
  4050. request = pagure.lib.query.search_pull_requests(
  4051. self.session, requestid=1, project_id=1
  4052. )
  4053. pagure.lib.query.add_pull_request_comment(
  4054. self.session,
  4055. request=request,
  4056. commit=None,
  4057. tree_id=None,
  4058. filename=None,
  4059. row=None,
  4060. comment="Hello",
  4061. user="jdoe",
  4062. )
  4063. self.session.commit()
  4064. @patch("pagure.lib.notify.send_email")
  4065. def test_add_reaction(self, send_email):
  4066. """ Test the request_pull endpoint. """
  4067. send_email.return_value = True
  4068. self._set_up_for_reaction_test()
  4069. user = tests.FakeUser()
  4070. user.username = "pingou"
  4071. with tests.user_set(self.app.application, user):
  4072. output = self.app.get("/test/pull-request/1")
  4073. self.assertEqual(output.status_code, 200)
  4074. data = {
  4075. "csrf_token": self.get_csrf(output=output),
  4076. "reaction": "Thumbs up",
  4077. }
  4078. output = self.app.post(
  4079. "/test/pull-request/1/comment/1/react",
  4080. data=data,
  4081. follow_redirects=True,
  4082. )
  4083. self.assertEqual(output.status_code, 200)
  4084. # Load the page and check reaction is added.
  4085. output = self.app.get("/test/pull-request/1")
  4086. self.assertEqual(output.status_code, 200)
  4087. self.assertIn(
  4088. "Thumbs up sent by pingou", output.get_data(as_text=True)
  4089. )
  4090. @patch("pagure.lib.notify.send_email")
  4091. def test_add_reaction_unauthenticated(self, send_email):
  4092. """ Test the request_pull endpoint. """
  4093. send_email.return_value = True
  4094. self._set_up_for_reaction_test()
  4095. output = self.app.get("/test/pull-request/1")
  4096. self.assertEqual(output.status_code, 200)
  4097. data = {
  4098. "csrf_token": self.get_csrf(output=output),
  4099. "reaction": "Thumbs down",
  4100. }
  4101. output = self.app.post(
  4102. "/test/pull-request/1/comment/1/react",
  4103. data=data,
  4104. follow_redirects=False,
  4105. )
  4106. # Redirect to login page
  4107. self.assertEqual(output.status_code, 302)
  4108. self.assertIn("/login/", output.headers["Location"])
  4109. class TestTicketAccessEditPRMetadata(tests.Modeltests):
  4110. """ Tests that people with ticket access on a project can edit the
  4111. meta-data of a PR """
  4112. def setUp(self):
  4113. """ Set up the environnment, ran before every tests. """
  4114. super(TestTicketAccessEditPRMetadata, self).setUp()
  4115. tests.create_projects(self.session)
  4116. tests.create_projects_git(
  4117. os.path.join(self.path, "requests"), bare=True
  4118. )
  4119. set_up_git_repo(
  4120. self.session, self.path, new_project=None, branch_from="feature"
  4121. )
  4122. # Add user "foo" to the project "test"
  4123. repo = pagure.lib.query._get_project(self.session, "test")
  4124. msg = pagure.lib.query.add_user_to_project(
  4125. session=self.session,
  4126. project=repo,
  4127. new_user="foo",
  4128. user="pingou",
  4129. access="ticket",
  4130. )
  4131. self.session.commit()
  4132. self.assertEqual(msg, "User added")
  4133. def test_unauth_cannot_view_edit_metadata_ui(self):
  4134. """ Test that unauthenticated users cannot view the edit the
  4135. metadata fields in the UI. """
  4136. output = self.app.get("/test/pull-request/1")
  4137. self.assertEqual(output.status_code, 200)
  4138. output_text = output.get_data(as_text=True)
  4139. self.assertIn(
  4140. "<title>PR#1: PR from the feature branch - test\n"
  4141. " - Pagure</title>",
  4142. output_text,
  4143. )
  4144. self.assertIn(
  4145. '<i class="fa fa-fw fa-pencil"></i></a>',
  4146. '<a class="btn btn-outline-primary border-0 btn-sm '
  4147. "issue-metadata-display editmetadatatoggle pointer inline-block"
  4148. '"><i class="fa fa-fw fa-pencil"></i></a>',
  4149. output_text,
  4150. )
  4151. self.assertNotIn(
  4152. '<form method="POST" action="/test/pull-request/1/update">',
  4153. output_text,
  4154. )
  4155. def test_admin_can_view_edit_metadata_ui(self):
  4156. """ Test that admin users can view the edit the metadata fields in
  4157. the UI. """
  4158. user = tests.FakeUser(username="pingou")
  4159. with tests.user_set(self.app.application, user):
  4160. output = self.app.get("/test/pull-request/1")
  4161. self.assertEqual(output.status_code, 200)
  4162. output_text = output.get_data(as_text=True)
  4163. self.assertIn(
  4164. "<title>PR#1: PR from the feature branch - test\n"
  4165. " - Pagure</title>",
  4166. output_text,
  4167. )
  4168. self.assertIn(
  4169. '<i class="fa fa-fw fa-pencil"></i></a>',
  4170. '<a class="btn btn-outline-primary border-0 btn-sm '
  4171. "issue-metadata-display editmetadatatoggle pointer inline-block"
  4172. '"><i class="fa fa-fw fa-pencil"></i></a>',
  4173. output_text,
  4174. )
  4175. self.assertIn(
  4176. '<form method="POST" action="/test/pull-request/1/update">',
  4177. output_text,
  4178. )
  4179. def test_admin_can_edit_metadata_ui(self):
  4180. """ Test that admin users can edit the metadata in the UI. """
  4181. user = tests.FakeUser(username="pingou")
  4182. with tests.user_set(self.app.application, user):
  4183. data = {"csrf_token": self.get_csrf(), "user": "foo"}
  4184. output = self.app.post(
  4185. "/test/pull-request/1/update", data=data, follow_redirects=True
  4186. )
  4187. self.assertEqual(output.status_code, 200)
  4188. output_text = output.get_data(as_text=True)
  4189. self.assertIn(
  4190. "<title>PR#1: PR from the feature branch - test\n"
  4191. " - Pagure</title>",
  4192. output_text,
  4193. )
  4194. self.assertIn(
  4195. '<i class="fa fa-fw fa-pencil"></i></a>',
  4196. '<a class="btn btn-outline-primary border-0 btn-sm '
  4197. "issue-metadata-display editmetadatatoggle pointer inline-block"
  4198. '"><i class="fa fa-fw fa-pencil"></i></a>',
  4199. output_text,
  4200. )
  4201. self.assertIn(
  4202. '<form method="POST" action="/test/pull-request/1/update">',
  4203. output_text,
  4204. )
  4205. self.assertIn(
  4206. '<input value="foo"\n name="user" '
  4207. 'id="assignee" placeholder="username" >',
  4208. output_text,
  4209. )
  4210. def test_ticket_can_view_edit_metadata_ui(self):
  4211. """ Test that users with ticket access can view the edit the
  4212. metadata fields in the UI. """
  4213. user = tests.FakeUser(username="foo")
  4214. with tests.user_set(self.app.application, user):
  4215. output = self.app.get("/test/pull-request/1")
  4216. self.assertEqual(output.status_code, 200)
  4217. output_text = output.get_data(as_text=True)
  4218. self.assertIn(
  4219. "<title>PR#1: PR from the feature branch - test\n"
  4220. " - Pagure</title>",
  4221. output_text,
  4222. )
  4223. self.assertIn(
  4224. '<i class="fa fa-fw fa-pencil"></i></a>',
  4225. '<a class="btn btn-outline-primary border-0 btn-sm '
  4226. "issue-metadata-display editmetadatatoggle pointer inline-block"
  4227. '"><i class="fa fa-fw fa-pencil"></i></a>',
  4228. output_text,
  4229. )
  4230. self.assertIn(
  4231. '<form method="POST" action="/test/pull-request/1/update">',
  4232. output_text,
  4233. )
  4234. def test_ticket_can_edit_metadata_ui(self):
  4235. """ Test that users with ticket access can edit the metadata in the
  4236. UI. """
  4237. user = tests.FakeUser(username="foo")
  4238. with tests.user_set(self.app.application, user):
  4239. data = {"csrf_token": self.get_csrf(), "user": "pingou"}
  4240. output = self.app.post(
  4241. "/test/pull-request/1/update", data=data, follow_redirects=True
  4242. )
  4243. self.assertEqual(output.status_code, 200)
  4244. output_text = output.get_data(as_text=True)
  4245. self.assertIn(
  4246. "<title>PR#1: PR from the feature branch - test\n"
  4247. " - Pagure</title>",
  4248. output_text,
  4249. )
  4250. self.assertIn(
  4251. '<i class="fa fa-fw fa-pencil"></i></a>',
  4252. '<a class="btn btn-outline-primary border-0 btn-sm '
  4253. "issue-metadata-display editmetadatatoggle pointer inline-block"
  4254. '"><i class="fa fa-fw fa-pencil"></i></a>',
  4255. output_text,
  4256. )
  4257. self.assertIn(
  4258. '<form method="POST" action="/test/pull-request/1/update">',
  4259. output_text,
  4260. )
  4261. self.assertIn(
  4262. '<input value="pingou"\n name="user" '
  4263. 'id="assignee" placeholder="username" >',
  4264. output_text,
  4265. )
  4266. if __name__ == "__main__":
  4267. unittest.main(verbosity=2)