test_pagure_flask_ui_fork.py 186 KB

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