From d037ae2b2b3623faa8600696fe6433ba925ad94a Mon Sep 17 00:00:00 2001 From: Roberto T <61755417+RobertGlobant20@users.noreply.github.com> Date: Fri, 21 Jul 2023 09:46:30 -0700 Subject: [PATCH 1/6] PackageManager Lucene Crash (#14179) * PackageManager Lucene Crash After opening the Package Manager and closing it was crashing due that the LuceneSearchUtility.Writer was null (the second time we don't reach the PackageManagerSearchViewModel constructor so the InitializeLuceneConfig() was not called). Then for this fix if the PackageManagerSearchViewModel was already created then we have to call again the InitializeLuceneConfig(). * PackageManager Lucene Crash Removing empty space --- .../PackageManager/PackageManagerSearchViewModel.cs | 12 ++++++++++-- src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs index 09804b59aee..0f8535ce028 100644 --- a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageManagerSearchViewModel.cs @@ -483,10 +483,18 @@ public PackageManagerSearchViewModel(PackageManagerClientViewModel client) : thi { PackageManagerClientViewModel = client; HostFilter = InitializeHostFilter(); - LuceneSearchUtility = new LuceneSearchUtility(PackageManagerClientViewModel.DynamoViewModel.Model); + InitializeLuceneForPackageManager(); + } + + internal void InitializeLuceneForPackageManager() + { + if(LuceneSearchUtility == null) + { + LuceneSearchUtility = new LuceneSearchUtility(PackageManagerClientViewModel.DynamoViewModel.Model); + } LuceneSearchUtility.InitializeLuceneConfig(LuceneConfig.PackagesIndexingDirectory); } - + /// /// Sort the default package results in the view based on the sorting key and sorting direction. /// diff --git a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs index b164c6601e6..7b01c2b8e85 100644 --- a/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs +++ b/src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs @@ -1444,6 +1444,10 @@ private void DynamoViewModelRequestShowPackageManagerSearch(object s, EventArgs { _pkgSearchVM = new PackageManagerSearchViewModel(dynamoViewModel.PackageManagerClientViewModel); } + else + { + _pkgSearchVM.InitializeLuceneForPackageManager(); + } if (_searchPkgsView == null) { From 6af24b13672351c78608c31f0909d9728e3b56c7 Mon Sep 17 00:00:00 2001 From: Roberto T <61755417+RobertGlobant20@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:27:07 -0700 Subject: [PATCH 2/6] DYN-6049 Fixing Github Actions Security (#14184) After a external researcher ran a vulnerability scanner over Dynamo github actions found vulnerabilities with the variable env.event.issue.title due that was used as a parameter for a powershell script (after was parsed), then the suggested fix (https://securitylab.github.com/research/github-actions-untrusted-input/) was to use a local environment variable and then instead use the environment variable as parameter for the script. So I've applied this fix in several github actions that had the same security bug. --- .github/workflows/Issues_workflow.yaml | 8 ++++++-- .github/workflows/disabled/cherry-picking.yaml | 7 +++++-- .github/workflows/issue_type_predicter.yaml | 8 ++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.github/workflows/Issues_workflow.yaml b/.github/workflows/Issues_workflow.yaml index 1af3fd6c588..285d228f20b 100644 --- a/.github/workflows/Issues_workflow.yaml +++ b/.github/workflows/Issues_workflow.yaml @@ -27,9 +27,11 @@ jobs: replace-with: '-' flags: g - name: Check Information + env: + ISSUE_TITLE_PARSED: ${{steps.remove_quotations.outputs.replaced}} id: check-info run: | - echo "content_analysis_response=$(pwsh .\\.github\\scripts\\title_analyzer.ps1 "${{ steps.remove_quotations.outputs.replaced }}" )" >> $GITHUB_ENV + echo "content_analysis_response=$(pwsh .\\.github\\scripts\\title_analyzer.ps1 "${{ env.ISSUE_TITLE_PARSED }}" )" >> $GITHUB_ENV - name: Label issue if: env.content_analysis_response != 'Valid' #Uses DYNAMOBOTTOKEN to allow interaction between repos @@ -99,9 +101,11 @@ jobs: #Checks for missing information inside the issue content - name: Check Information + env: + ISSUE_TITLE_PARSED: ${{steps.remove_quotations.outputs.replaced}} id: check-info run: | - echo "analysis_response=$(pwsh .\\.github\\scripts\\issue_analyzer.ps1 "${{ env.template }}" "${{ steps.remove_quotations.outputs.replaced }}" "${{ env.acceptable_missing_info }}" )" >> $GITHUB_ENV + echo "analysis_response=$(pwsh .\\.github\\scripts\\issue_analyzer.ps1 "${{ env.template }}" "${{ env.ISSUE_TITLE_PARSED }}" "${{ env.acceptable_missing_info }}" )" >> $GITHUB_ENV #Closes the issue if the analysis response is "Empty" - name: Close issue diff --git a/.github/workflows/disabled/cherry-picking.yaml b/.github/workflows/disabled/cherry-picking.yaml index 43f98ea222b..3c5d35da6c7 100644 --- a/.github/workflows/disabled/cherry-picking.yaml +++ b/.github/workflows/disabled/cherry-picking.yaml @@ -33,9 +33,11 @@ jobs: #Checks the message looking for a cherry-pick request and extracts the target branch name - name: Check Information + env: + ISSUE_BODY_PARSED: ${{steps.remove_quotations.outputs.replaced}} id: check-info run: | - echo "destination_branch=$(pwsh .\\.github\\scripts\\cherry_pick_check.ps1 "${{ steps.remove_quotations.outputs.replaced }}" )" >> $GITHUB_ENV + echo "destination_branch=$(pwsh .\\.github\\scripts\\cherry_pick_check.ps1 "${{ env.ISSUE_BODY_PARSED }}" )" >> $GITHUB_ENV #If a target branch was found will run the action - if: env.destination_branch != 'invalid' @@ -50,6 +52,7 @@ jobs: env: #Token used for the pull request. Corresponds to the DynamoBot account GITHUB_TOKEN: ${{secrets.DYNAMOBOTTOKEN}} + ISSUE_BODY_PARSED: ${{steps.remove_quotations.outputs.replaced}} #This represents the title and description of the pr in Markdown format #Everything before the first blank line will be the title #Everything after will be included in the description @@ -60,4 +63,4 @@ jobs: [Commit](https://github.com/DynamoDS/Dynamo/commit/${{github.event.after}}) ### Pull request: - ${{ steps.remove_quotations.outputs.replaced }} + ${{ env.ISSUE_BODY_PARSED }} diff --git a/.github/workflows/issue_type_predicter.yaml b/.github/workflows/issue_type_predicter.yaml index 5f9221a67ae..55a98a6c830 100644 --- a/.github/workflows/issue_type_predicter.yaml +++ b/.github/workflows/issue_type_predicter.yaml @@ -36,17 +36,21 @@ jobs: #Checks for missing information inside the issue content - name: Check Information + env: + ISSUE_BODY_PARSED: ${{steps.remove_quotations.outputs.replaced}} id: check-info run: | ls -la - echo "analysis_response=$(pwsh .\\.github\\scripts\\issue_analyzer.ps1 "${{ env.template }}" "${{ steps.remove_quotations.outputs.replaced }}" "${{ env.acceptable_missing_info }}" )" >> $GITHUB_ENV + echo "analysis_response=$(pwsh .\\.github\\scripts\\issue_analyzer.ps1 "${{ env.template }}" "${{ env.ISSUE_BODY_PARSED }}" "${{ env.acceptable_missing_info }}" )" >> $GITHUB_ENV #Remove sections in the issue body like "Dynamo version", "Stack Trace" because won't be used to predict the issue type - name: Clean Issue Body + env: + ISSUE_BODY_PARSED: ${{steps.remove_quotations.outputs.replaced}} if: env.analysis_response == 'Valid' id: clean-issue-body run: | - echo "parsed_issue_body="$(pwsh .\\.github\\scripts\\issue_body_cleaner.ps1 "${{ steps.remove_quotations.outputs.replaced }}" )"" >> $GITHUB_ENV + echo "parsed_issue_body="$(pwsh .\\.github\\scripts\\issue_body_cleaner.ps1 "${{ env.ISSUE_BODY_PARSED }}" )"" >> $GITHUB_ENV #The IssuesTypePredicter program receives as a parameter a json string with the issue content, then It's creating the json string in this section based in the issue body - name: Create Issue JSON String From d5c6bfd81e6e2540f4507fa973d0cc9bba8ce9ff Mon Sep 17 00:00:00 2001 From: Jorgen Dahl Date: Fri, 21 Jul 2023 15:32:53 -0400 Subject: [PATCH 3/6] Add missing legacy files (#14185) --- .../bin/CSharpAnalytics.Net45.dll | Bin 0 -> 78336 bytes extern/legacy_remove_me/bin/NDesk.Options.dll | Bin 0 -> 22016 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 extern/legacy_remove_me/bin/CSharpAnalytics.Net45.dll create mode 100644 extern/legacy_remove_me/bin/NDesk.Options.dll diff --git a/extern/legacy_remove_me/bin/CSharpAnalytics.Net45.dll b/extern/legacy_remove_me/bin/CSharpAnalytics.Net45.dll new file mode 100644 index 0000000000000000000000000000000000000000..bc270afb872e47f088d8f3c06740994df5e340b9 GIT binary patch literal 78336 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⋙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 literal 0 HcmV?d00001 diff --git a/extern/legacy_remove_me/bin/NDesk.Options.dll b/extern/legacy_remove_me/bin/NDesk.Options.dll new file mode 100644 index 0000000000000000000000000000000000000000..df458789570622f8283493ab3e6e5282b87398c6 GIT binary patch literal 22016 zcmeHvdvsi9k!RgU-+TLZtD|l`jb*9*Ok1`U`H{FK%a&xxj+OYONQobLI4!9yx82f} zyIYB6M~O@zke5kvfD;0lJRr+tfhDt$0cKzpW=sy52?HF4*KPt~$pUA{Oqdz6%xp68 z{;Iy)57|!O9M0K4cDJ3b`&E7QRn=EjUwz-bx0PK7A0UH>OnlFsBl;q){OJ++&R`DR zk(NJ;(C35ST>M3C=QkG*AIaq7Q#o%umzs!=rY0x7LVP40&rMIpGn4WDJwx#cZ!Fzb zRpl=8Mep54v{N(a6OaGPj-s}gDY7`ESwy=*VZ-^m2ERjlQbrfHE(l zYWc5x^-*TPr!h{nhZ}Q5Np{5fpT~*9=hJ=8uAvvGs9uvaDfzD?U9$TPsj$o?BiW z2fg&^iL2&8|H{~Iw0S-k{~YS`a{bxtu2g1{Ci0_RE}d>0%Vw!4NzI$hxp@=Ok#$6x zFNpE~lb^$S9;)4008>xEB3CzNaWPwoI`vabHcZb2y_MD}+-nkyO87z_-|qJZf!_xi z3nAkQUxtUkLqr+3&%=@0++Wri5JG7@Vmxm=@{)14zLl2fh6fugpcUg6%^x39{KYvS zCwO?-o+?Es>yOMIf64sub^dtP|BmyjfF1-}Su)eW;Dfh<90)wEwiE8#=_DD{Sl%@geUIP5xUaKzkB1e|iuf|`@ACEOLL z?~*wE12d~Q8MAPZsT&RVBhj?w^)0tO>cQ#mEKpN7XOWMl9+-tR%rJ2|jF?3Vn))fG zbRym1TqbmgzMuwuB3<;Uu1>Tm(6EJ>bAJhrzFWO;R!xpikA0jGd&Fkx6V{v|)A6?$i()s8d5*~3{*dC*k z=!e4Sw-JDai4~Z90txB5G2^W|CIv%!2i!oG?j=BfifN&j*toFal~eaWL#s;NvLJ6I z1{my6iv#F4oqQJvCtrdDvRk8E<9c}#`0&h-hlEm0tN}sNkOv$i&IgVLU)ke)ch$Z02zwYd88^>k!Y)pc`gs$&hGWFI^7yGYS#6@XOtW(j}F#HO>Z^2pR_ul zn5-c1HNblqDj6HV-1_RY}itUI^wM1Z=pf;RitKl-T1?{q)Nj&7o({+iaVFr=MI=O_2lw~+>Lyl zWe+B?RD2Z;J=g=tuJ^e7D4$7Ds#T2AwmmK^Lat`>TofA8>(UkuRm8!LIit23yf#VPm8?nTq6xSee1?4ATg{xa{ zSxB%|`3^89dVL#D>bW04O}>-Wz{NP&VCRDNS@;f%zEwAB%><&hs+C~B8OZPE;k$Ua z>O&fo`u3LkV5mn86G#!Wa_uzMC4=jkF@4)WM<6T zMFCvcZb;36HPH)X!M7+_uKN-eHN8{?u%gy|iPKF=7zdr9#+*5N^%+0*_o~-6R;ogwgOopsijC~GTr|b z$p!s4v5r1;BYCcZj-slC(DNh&q4-@mucBk}{l3Z-C6%hne#G#$u>nQY!zSd40mZT1 zFTjA8U>L2iJU($&C3$6FL2L&SRugcPuQVO|FjdDsT3PmuuQBxy`_MEL3%!eKGzD& zVy7{!Qw-Gs;(g`RF&mK2s3@!QS3_)m6eB{`DQw@UudGP5{Tv;frwbl{E{qjj$9!Gb z+@Oo$g}NG{3oB~AE)>j?E^cF;=i{tsVf$kG8Kk?MH{LZOzs^J4tcH;6Qej=4AYhg& zXA&Rh1eStYTV?P#wlZ-_C|TF(2S)v#ZrMa|rY;E=>Hi;_nm{yA+I-<=;%^cQ5vQL7`fU}03g0KWEb2jJ2lhGM;&sC|6L5sp!7c@EHTWkB z+X*IagzhI3NLJTOz(qwS-0^V^Y@~n16+)v%2Sh+G&(_<(j8gq82=yN7hMQzh6crdx zhU_z$DxB?VLA9MnTxGZ=hRaDR*!@3{zKZOD%TFb_@7u%$-`BwYXy_>uRIVlAI^P-R z58l#?F14BEzK5_^sE}irFBd6bsbd)*_~eLf%8}Z?5v*xnN*{wH91vBk-G=TntW?Ik z4F}|$)Us+57v}SbYkJ1m2D84ziyg~d9#Uz5;#^Dv_q>6tbk0P#234-jxrd9jSG zBvt~-HVR^j?J)zknw%q3MakntQ^hfADnA7L#g%&yCMZSsnQ&oZ1f1%q0eP-UAh)|3 zX(eklB+CZs`0Td~x>3m3k#fTYZZ2a1T^xy|Ux;}B0=(7mqs|Z3+)(ma;I=o0wp$<8 z4J)Rz->goqvB`%4oR&phTsV!Ec*`Q^Kt2st?=XOD*M^4;*Ok6g%wTjFxgJtmFyvXBO zr@RS>SWy>BhJf4kT_}NsoivnuNa6hoSNb;bARXOmmztFwHD|*aQo{VQ$s4gHF7hT> zc#`Y2rQ43}-<%5-DzTDSrPMt>5{h1&@|hTsF=|4}#v~}rg2yFN9J;IEM9cHo9q`j4 z`W5=I6C~uQ7v4Tvrc<>p_1*iw0WO$Q~RG zB#yHj&Pov7O>8JHpCtQ2C|u_nAgAF#m8CmD$Dbt}>PF3uRp_;r*I1U+(S`%dYwV~M zwWZM3I8jG!uGj!v4>{}xi_=qUN;#m#?eXIh_O0#i^dog{w68a+iJBT_aS~pAkTp#7u-kb5px!0k{>0~Rr)Dz`cF)zVRtLtgR$xva^U=1 zFg)G8Re12wo*Qahy}ZgW5(va9Z>A)pQS@I-#wp>cyeH95F>Ss$2jUc^!B>FTukvo^ z!MpwE>2KjFGSMumv^!$ao9n0 z+Y+LF_-E<0L-f^^L=R(fOSfh{lvdimPQA-qdgZkPyxfZ)7^3Yv^kgW=YjHmw>7o4a zY`gGf5+*~)H2M&}T$#?`%W29>h55Loa`wO+T7WNS6koXyvSkb}B3@BM%K}Vis*BTs zg(o~6fIYMw&qLlT^gj~HCqS|2E7Jafz<(E5tucSI#$%63`#ynxB=Bj0&kFoAK$m{3 zy{fsS>#yPsal6iAJN0e4MR({d;luhLqy2S2mu#cTuxPch1u$=L?eE#gy&&zMRk6(1L1AAn z2vh}vC2Xf)2E|E3U=9NN44&?+q|@L$Dt%#KTD+Q$0~^E+)hSX=18YXid&tnL>0W54 zr3M-m>|wzgDJ|G11zUjUM+Rj6DX<{kDP#ouTfv&>m|#B_teGanmbakcS!yN^`W9HP z=o-bXUjeo{TMdoYI{VPxZEZ*U3TFT?ZtXHG>-)}j?5}H6+OP2=UhjuG?2Ir2rOfR@^1{Txpu4%zJffsCs?}c6pJgplP2>;Z^ zoWcW!LCeCwMEf$dUyZZ3?`&L6uYuE9%-B!0CDvxFhDL=2hpk7kh7vyZZtEk!O&@!P z0!B53m+)+Vu8p8CMokI}{tF#N-mLbqe}?uNYWF!Gz#FR?>i4lJss%ReV;Ndt)Y6!b z9YBWFQ$euPq&b{#@ui|KIHIl78)?6f9ncmS3+RYocTttoVl1Q+KDJuB6xjO(dyekc zU!jHcxavd12GRFrg*lzhKBI}w`q(z-24LUzvAxbKsEa@Ju|rN8*egCZ=^RDYzUpJQ z!_H>?DO+rw$APou$vBub=t_J5AqpZ!oq~0*`e#4yP$& zT}c~C*p#({dP>+S>neJ@gq^W=(Wgt;Bi0@YuMrK}e{=tnbq&=Db{8__bHL(l-1i{; zoBLgBh;9(`Gvx z^h=x~SY}XLXCJ1<^^Dy`*N3|7qr`8rc-(a8I{O&CayerU(g#Bsdy*QjP}o!Els!eO zee6@AlXjl=%jxDpIvcvjzJ=!G4&XuhZs=kARyx6VVvzD;=vn&&Rd+JRvHd&y6eR^a zOPptS(9TldQ`#I&RrK9S50v`8rM-tfU(xqI`gN&q(0D(Yn^?o0^moP`+TGMB80#A} z?xEFw-!IU2FYPGxX>=d$_4|ISC$#%m1a>qYw_dy7$DY%IT2AA8Gwyp%yD9t|`@s@+ zCagPr!s305;SN9@`y01^a{*+!K980)SxzsYM&-6aJB4z+^xk|y zyC4*$mye>n+ZXLIt z;&aFX8o_q~PO;5^Q`pcK&D>%bV+Lu1_7JpmXdeOGu00Cv z2Q)stjc8A>H0>rziJUf$FVOor|}EGTKa-<67a8#M?rf5r}loaZNJp;8^F04h6@EQ0sOd@0DQOk2BaO+*9m>2-Y;6-<7-(>{d$M?l$k~pKV_ok0j5RTRp6hZ zLBMCteR{9P^X=8XXC6fRdu9rd&#r^?qIpC=PJeGs=mXlDW=_8k_V&{U0dv|7(*Bs- zvwT8eLe7q#7W(Hwd0PLnKt)&Ztc*PkjcK}D;DZ7`BJc@;PYe7LfnNgbbG|0+=K(eP zj#lvUDRFL0B@VBDwsp+T!2NLm zmBPYZjE$(^htn2*Yew(3@Zg*tv$=iN-T+wZbO64~Vajr6GvLuc7VtC9alkK1@9Dra z+Gm}Ufaiit54sEw2A%_~b6LVt_iq4K3RGi%6Z$LIV&EU|4FSL~Y|(J97DT&BU@h+P zbUf>;0=)_MZ949BE|`ts=ElVi8g_IBTds^($~q+I*L?^`F`YIU!peA^AcSi8KA$Q zu7Q7to899m$pN|H3*hL1>HR%cOmUM5yZ_vPGKAkJzGL}BE z=P>nolLh>mKTo}5W3+8@dLo@mvGgm`g$k@UmrKpiK-n0Ko0=K+s4tsNB#~caSMz}=WbrdvbzCJKvg}>B;fJkrG3>v+oFIIW(2cu;U8r*J0k?WSWL&rqXl`W{{akb9+Z> zax9x>-!Zm5=S}z&MoW_{M`>aTQYH(#@OLs<5!Rp1kLEH{egMiN{1!{}9aFY#S9)S3 zog0`u>=gxHlRoU{j7)lWY9bA@CEmT0Gc+_kl9z|h(#uoJSB6#`>}wf9z9F(FC93mO zs7bfYW8k2rQxkZc4SVHpUf>B|5?U%@`%{G!C);(Y>~xyC_DG%#r3+g|4;@;MBppwm zD9&RTe>T$w%5*lB+je3qm(J&T9njV3neR)?QuR&ea)=`B!aCc{f9cbo$xnHBf8T{^^0YQkuSkNf zBI)u{N+Z^wdsBzD9iN7)3s`0q3lB!HtP~QTcBKlVN9f9&H$5fh3{8)Y!X=7Qo`m!X zSDyM(Q-$eVT1d*_h|DM!l!}UEw2DBUO&FL=7mZ-w@5^PdCX3D;*h4~4aAyYjzina) z_9|Ihr!(2HGB=N>-l?hdUz1La?U~HZP;Z`1 zMJi{;u))c0t~SRC9+Bgzopq9{IyN_v<0mW7Lw=L%m1;`)FZT#q?p3ywyUVtz(L?hz z$V$um=_-;Gml~zoJ`bmaitwRBw3~NJ)t$Pz_eZS zL|vIKuqqVSG{btZQ+Yt8t@CYC zI?vY!BlD^8G|D$0xR{4BlQ<`qD_e$-2BZFttb(vFGlp{x{)m(}cNA?As=CBMyOhwK zB?hUmk3^xH5aoAyr_ht+PMCl00?nV--PViSK;NiSW$^dR` z<^^8vTHC4i!7YSl*OuWO14CN~$wx-83lm5wipf}IQ<#Zn7P<7DmOJ%bosnKJEbWjbL>T~1JrTFqVW@cxG zGleW}CUATlnT94VT1>8(_Jy5@`Qgm?w7NC8Sog$KYI5en4uoWEdbDt12XA$`%=nRu zbPeZHW9f-h?%0K+;GWdXP-cAc!Y)p2?BL}N|4h%z6Gz{X44=!&z5Zt4Ghydd`#;XY zw`7pX)So__g45K&ygY2rNZ#YcUZxaBmQD`ku5px>%DrWnhG8WQtCSxen4Fp}&@gVR z_{yJ6d+@}mfaioBmO-Du0-gb#0Idyw^{X$Q27qWX^zw?Es^dMUc1<8!2qPu4D(#cN%iwin%Y$7pm0W zg26n&IE234P@cqLaJ1uFoK~gd%Ib#w3AE8QkU8Hu${oLJTxCBy6O%gihuW=N{`=d$ z8}prn{T!k${==_{Vc+%aDb!#|kOI6hKe$KG!|9R*7l-~*Jo@EFNO2reE5kWIaVpa$ z&pKyR(6W%k$;fHJ64<6&L^9)*fsfP8rL^KS@z7sPr8s)lBH_xjpKmjdTvtrUtG898 z)_gwPh@cM#D@aOVcAPOq+w$PFY?8 zqgV0-4ZL7AHscS(1~A1eo+m1a>?9R9<*?sniwX>{Q69xkisM7t@J1H#g!J3EZptm2bFL^%cjJ z=eq?qv|_|cXj_J#!BvKjR#w^;$0A9IZ#gkIJ&Gx_7~@iY5^x$*fNiBHC(<~QhkYhB zDp;Hi1&gBzZ_+t_6e`<9>1`OvRWm1PvmLFX2a6G_v~&Ivi_@*LoY~V{*}39YCa794 z9AVfvI6vP;d_BCxDP!8TO-@H+TR?I6Wc z%FBZ6I3RnBuf>1jL*shb2@V5)g%G+9Z`gLywX_W**bkhcr|_L6>KK47-DD1>(BqG@&U#Z*t;P7maE) z6yQt5LU*jr34j%(xTfR%0!WK$h-pp@F#|3vD*{E171wIOYSqP->yZfF0z@KBL3Gx| z)`$ecP>ZRHn7s*K9fCxhu0^0vTNGJj1gkaOS=5X-nTCrOT8kojGe&8#-srZ{Oc)=C z^+IzKi;CD}LRS-Jq&bTW%q!yX6!8{?4DP_p52y)6VuL)1*p1N?7+@ukNK>Gl4KQ6c z8-%7tyDpZ|Be7aFMU6cZn^1E*u7S*0tkz}nH2hMdVZbyGVBw6LalFK^+VRdV=9n%3 zhRonn)vg(_rbvXbWC6 zYJ$bHm?S$yIZ_;~I}t~>I9Rc{Ck%Con55z7)c^*DI*tPqX5jC-SQ0kaGIf7$h&JNe zOp#a^lNTb-J1D&DIGL4r5Z#Qa$>PmCUX5!EbO!t@U}%|u77RsN;}4p`2*1V_mhlOM;M+4*r(Jp(fM8Kr|dQA`ZmX>K0#`@Rh|7!;&HP z3zXGzQ*f|@h;b2aKnle$Dq3w=5N$1jr#Q+EUYu!RI}jUarr01SIRr$jLw3NBS-`n2 zff4iOgtbk_F$~CxRs$@8!7L;;`0gcLcst2eYeFg*pKZB54}qo*9lW>X@ozKsq#^9A zs>)4ZPhg%=R6wp6yotBHgQO*R^Q4Y0MGY)(ExudO(?tUp9m|KFKU6;-AN+4MttHobAbJ0T~a6qy3SS{9$=_jneS7@;&E{H|B5mdEeokJe$vDLBK zkl)KiAzbWcg!|joS_+5b*e|dqrIf{NtZH3wSRu=|3I#wGN31p$hM0gJsrLV|7!*6$ ziAo%HZ7YILtTtNBmV;v3CW@ScN?<@~ENs~Zq(;KFgK2@)Frw8#6dA~s(vS5$_b8iC zt12NDB@Dv~#dz+it#%+15+m4WuxCY_Al5E=svRk>4m#`rYs7AZIt$E1(ZrH=NKGUa|4$2nCLzU5(6ONlKii3w;MQW?`u_Fyzi&Vv-0= zLV?EhOEHbA=D&lWdi;c_Z)sdT3yRCbyBtnA0S%QEKe-@tU3)uz`iOFgdd)x8AJ*&l zzN!HjI~&x90IfLNets8ZF1~1+UGg-8Zi-OM(b9V^W-B`bSg!3!rYj5#yyVOweoY1>{IlOCCh!tu-pa!XYhTe{K z&L>hn?D@ zIO>cl; zhPm=@@pv~Pc!hQC@qNMfkUZC-{fw~%?__TqV#s%~{Qr^Rc$NLEGKlXFc>l=3U-Bne Z5;w5_-|>m7|7WDm&iwzM|K~jLzX3<;8NmPm literal 0 HcmV?d00001 From 380bd8e408c804e70aa08f0dc74991f551fe78e0 Mon Sep 17 00:00:00 2001 From: Roberto T <61755417+RobertGlobant20@users.noreply.github.com> Date: Fri, 21 Jul 2023 14:42:07 -0700 Subject: [PATCH 4/6] DYN-5806 lucene node autocomplete (#14169) * DYN-5806 Lucene NodeAutocomplete Added functionality for enabling the use of Lucene Search in node autocomplete, also I've modified the LuceneSearchUtility class for supporting in-memory indexing. * DYN-5806-Lucene-NodeAutocomplete Changes for indexing (in memory RAMDirectory) a subset of nodes every time that the node autocomplete search functionality is executed so the search will be executed using only the subset of nodes indexed (and not over all the 3000 nodes). * DYN-5806-Lucene-NodeAutocomplete Code Review Adding brackets in else statement and removing the Distinct() due that all the nodes should be different then there is no need to use this function * DYN-5806-Lucene-NodeAutocomplete Code Review 2 Rolling back the code for SearchViewModel.Search() due that tests are using this method (Lucene indexing is not done when tests are executed - IsTestMode = true). Also I've modified the part in which Node Autocomplete is initialized so it will calling the Lucene search to initialize the results. * DYN-5806-Lucene-NodeAutocomplete Code Review 2 Removing unnecessary Distinct() * DYN-5806-Lucene-NodeAutocomplete Regressions Trying to fix regressions generated when trying to initialize NodeAutocomplete with Lucene Search. * DYN-5806-Lucene-NodeAutocomplete Regressions I've added an extra validation for checking if the StorageType is RAMDirectory or FSDirectory otherwise it won't do things like create the indexWriter or get a new Lucene Document (due that previously were skipped if IsTestMode is True). * DYN-5806-Lucene-NodeAutocomplete Regressions Fixing comment * DYN-5806-Lucene-NodeAutocomplete Regressions re-triggering pullRequestValidation job --- .../Utilities/LuceneSearchUtility.cs | 43 ++++++-- .../Search/NodeAutoCompleteSearchViewModel.cs | 103 +++++++++++++++++- .../ViewModels/Search/SearchViewModel.cs | 4 +- 3 files changed, 134 insertions(+), 16 deletions(-) diff --git a/src/DynamoCore/Utilities/LuceneSearchUtility.cs b/src/DynamoCore/Utilities/LuceneSearchUtility.cs index d40097b681b..982e1d0c508 100644 --- a/src/DynamoCore/Utilities/LuceneSearchUtility.cs +++ b/src/DynamoCore/Utilities/LuceneSearchUtility.cs @@ -21,6 +21,16 @@ internal class LuceneSearchUtility internal Lucene.Net.Store.Directory indexDir; internal IndexWriter writer; internal string directory; + internal LuceneStorage currentStorageType; + + public enum LuceneStorage + { + //Lucene Storage will be located in RAM and all the info indexed will be lost when Dynamo app is closed + RAM, + + //Lucene Storage will be located in the local File System and the files will remain in ...AppData\Roaming\Dynamo\Dynamo Core\2.19\Index folder + FILE_SYSTEM + } // Used for creating the StandardAnalyzer internal Analyzer Analyzer; @@ -36,23 +46,34 @@ internal LuceneSearchUtility(DynamoModel model) /// /// Initialize Lucene config file writer. /// - internal void InitializeLuceneConfig(string dirName) + internal void InitializeLuceneConfig(string dirName, LuceneStorage storageType = LuceneStorage.FILE_SYSTEM) { addedFields = new List(); - DirectoryInfo webBrowserUserDataFolder; + DirectoryInfo luceneUserDataFolder; var userDataDir = new DirectoryInfo(dynamoModel.PathManager.UserDataDirectory); - webBrowserUserDataFolder = userDataDir.Exists ? userDataDir : null; + luceneUserDataFolder = userDataDir.Exists ? userDataDir : null; directory = dirName; - string indexPath = Path.Combine(webBrowserUserDataFolder.FullName, LuceneConfig.Index, dirName); - indexDir = Lucene.Net.Store.FSDirectory.Open(indexPath); + string indexPath = Path.Combine(luceneUserDataFolder.FullName, LuceneConfig.Index, dirName); + + currentStorageType = storageType; + + if (storageType == LuceneStorage.RAM) + { + indexDir = new RAMDirectory(); + } + else + { + indexDir = FSDirectory.Open(indexPath); + } + // Create an analyzer to process the text Analyzer = new StandardAnalyzer(LuceneConfig.LuceneNetVersion); - // Initialize Lucene index writer, unless in test mode. - if (!DynamoModel.IsTestMode) + // Initialize Lucene index writer, unless in test mode or we are using RAMDirectory for indexing info. + if (!DynamoModel.IsTestMode || currentStorageType == LuceneStorage.RAM) { // Create an index writer IndexWriterConfig indexConfig = new IndexWriterConfig(LuceneConfig.LuceneNetVersion, Analyzer) @@ -77,7 +98,7 @@ internal void InitializeLuceneConfig(string dirName) /// internal Document InitializeIndexDocumentForNodes() { - if (DynamoModel.IsTestMode) return null; + if (DynamoModel.IsTestMode && currentStorageType == LuceneStorage.FILE_SYSTEM) return null; var name = new TextField(nameof(LuceneConfig.NodeFieldsEnum.Name), string.Empty, Field.Store.YES); var fullCategory = new TextField(nameof(LuceneConfig.NodeFieldsEnum.FullCategoryName), string.Empty, Field.Store.YES); @@ -153,7 +174,7 @@ internal void SetDocumentFieldValue(Document doc, string field, string value, bo ((StringField)doc.GetField(field)).SetStringValue(value); } - if (isLast && indexedFields.Any()) + if (isLast && indexedFields != null && indexedFields.Any()) { List diff = indexedFields.Except(addedFields).ToList(); foreach (var d in diff) @@ -248,7 +269,7 @@ internal string CreateSearchQuery(string[] fields, string SearchTerm) internal void DisposeWriter() { //We need to check if we are not running Dynamo tests because otherwise parallel test start to fail when trying to write in the same Lucene directory location - if (!DynamoModel.IsTestMode) + if (!DynamoModel.IsTestMode || currentStorageType == LuceneStorage.RAM) { writer?.Dispose(); writer = null; @@ -257,7 +278,7 @@ internal void DisposeWriter() internal void CommitWriterChanges() { - if (!DynamoModel.IsTestMode) + if (!DynamoModel.IsTestMode || currentStorageType == LuceneStorage.RAM) { //Commit the info indexed writer?.Commit(); diff --git a/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs b/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs index 66748db5eb3..68677882d28 100644 --- a/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Search/NodeAutoCompleteSearchViewModel.cs @@ -18,6 +18,9 @@ using Dynamo.Utilities; using Dynamo.Wpf.ViewModels; using Greg; +using Lucene.Net.Documents; +using Lucene.Net.QueryParsers.Classic; +using Lucene.Net.Search; using Newtonsoft.Json; using ProtoCore.AST.AssociativeAST; using ProtoCore.Mirror; @@ -39,6 +42,9 @@ public class NodeAutoCompleteSearchViewModel : SearchViewModel private bool displayLowConfidence; private const string nodeAutocompleteMLEndpoint = "MLNodeAutocomplete"; + // Lucene search utility to perform indexing operations just for NodeAutocomplete. + internal LuceneSearchUtility LuceneSearchUtilityNodeAutocomplete { get; set; } + /// /// The Node AutoComplete ML service version, this could be empty if user has not used ML way /// @@ -602,6 +608,61 @@ private NodeSearchElementViewModel GetViewModelForNodeSearchElement(NodeSearchEl return null; } + + /// + /// Performs a search using the given string as query and subset, if provided. + /// + /// Returns a list with a maximum MaxNumSearchResults elements. + /// The search query + /// Temporary flag that will be used for searching using Lucene.NET + internal IEnumerable SearchNodeAutocomplete(string search, bool useLucene) + { + if (useLucene) + { + //The DirectoryReader and IndexSearcher have to be assigned after commiting indexing changes and before executing the Searcher.Search() method, otherwise new indexed info won't be reflected + LuceneSearchUtilityNodeAutocomplete.dirReader = LuceneSearchUtilityNodeAutocomplete.writer?.GetReader(applyAllDeletes: true); + if (LuceneSearchUtilityNodeAutocomplete.dirReader == null) return null; + + LuceneSearchUtilityNodeAutocomplete.Searcher = new IndexSearcher(LuceneSearchUtilityNodeAutocomplete.dirReader); + + string searchTerm = search.Trim(); + var candidates = new List(); + var parser = new MultiFieldQueryParser(LuceneConfig.LuceneNetVersion, LuceneConfig.NodeIndexFields, LuceneSearchUtilityNodeAutocomplete.Analyzer) + { + AllowLeadingWildcard = true, + DefaultOperator = LuceneConfig.DefaultOperator, + FuzzyMinSim = LuceneConfig.MinimumSimilarity + }; + + Query query = parser.Parse(LuceneSearchUtilityNodeAutocomplete.CreateSearchQuery(LuceneConfig.NodeIndexFields, searchTerm)); + TopDocs topDocs = LuceneSearchUtilityNodeAutocomplete.Searcher.Search(query, n: LuceneConfig.DefaultResultsCount); + + for (int i = 0; i < topDocs.ScoreDocs.Length; i++) + { + // read back a Lucene doc from results + Document resultDoc = LuceneSearchUtilityNodeAutocomplete.Searcher.Doc(topDocs.ScoreDocs[i].Doc); + + string name = resultDoc.Get(nameof(LuceneConfig.NodeFieldsEnum.Name)); + string docName = resultDoc.Get(nameof(LuceneConfig.NodeFieldsEnum.DocName)); + string cat = resultDoc.Get(nameof(LuceneConfig.NodeFieldsEnum.FullCategoryName)); + string parameters = resultDoc.Get(nameof(LuceneConfig.NodeFieldsEnum.Parameters)); + + + var foundNode = FindViewModelForNodeNameAndCategory(name, cat, parameters); + if (foundNode != null) + { + candidates.Add(foundNode); + } + } + + return candidates; + } + else + { + return Search(search); + } + } + /// /// Filters the matching node search elements based on user input in the search field. /// @@ -617,9 +678,25 @@ internal void SearchAutoCompleteCandidates(string input) } else { - // Providing the saved search results to limit the scope of the query search. - // Then add back the ML info on filterted nodes as the Search function accepts elements of type NodeSearchElement - var foundNodes = Search(input, searchElementsCache.Select(x => x.Model)); + LuceneSearchUtilityNodeAutocomplete = new LuceneSearchUtility(dynamoViewModel.Model); + + //The dirName parameter doesn't matter because we are using RAMDirectory indexing and no files are created + LuceneSearchUtilityNodeAutocomplete.InitializeLuceneConfig(string.Empty, LuceneSearchUtility.LuceneStorage.RAM); + + //Memory indexing process for Node Autocomplete (indexing just the nodes returned by the NodeAutocomplete service so we limit the scope of the query search) + foreach (var node in searchElementsCache.Select(x => x.Model)) + { + var doc = LuceneSearchUtilityNodeAutocomplete.InitializeIndexDocumentForNodes(); + AddNodeTypeToSearchIndex(node, doc); + } + + //Write the Lucene documents to memory + LuceneSearchUtilityNodeAutocomplete.CommitWriterChanges(); + + var luceneResults = SearchNodeAutocomplete(input, true); + var foundNodesModels = luceneResults.Select(x => x.Model); + var foundNodes = foundNodesModels.Select(MakeNodeSearchElementVM); + var filteredSearchElements = new List(); foreach (var node in foundNodes) @@ -635,10 +712,30 @@ internal void SearchAutoCompleteCandidates(string input) } } FilteredResults = new List(filteredSearchElements).OrderBy(x => x.Name).ThenBy(x => x.Description); + + LuceneSearchUtilityNodeAutocomplete.DisposeWriter(); } } } + /// + /// Add node information to Lucene index + /// + /// node info that will be indexed + /// Lucene document in which the node info will be indexed + private void AddNodeTypeToSearchIndex(NodeSearchElement node, Document doc) + { + if (LuceneSearchUtilityNodeAutocomplete.addedFields == null) return; + + LuceneSearchUtilityNodeAutocomplete.SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.FullCategoryName), node.FullCategoryName); + LuceneSearchUtilityNodeAutocomplete.SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.Name), node.Name); + LuceneSearchUtilityNodeAutocomplete.SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.Description), node.Description); + if (node.SearchKeywords.Count > 0) LuceneSearchUtilityNodeAutocomplete.SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.SearchKeywords), node.SearchKeywords.Aggregate((x, y) => x + " " + y), true, true); + LuceneSearchUtilityNodeAutocomplete.SetDocumentFieldValue(doc, nameof(LuceneConfig.NodeFieldsEnum.Parameters), node.Parameters ?? string.Empty); + + LuceneSearchUtilityNodeAutocomplete.writer?.AddDocument(doc); + } + /// /// Returns a collection of node search elements for nodes /// that output a type compatible with the port type if it's an input port. diff --git a/src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs b/src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs index 9f5aaaea7ce..c3a1a0f7a2f 100644 --- a/src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Search/SearchViewModel.cs @@ -995,7 +995,7 @@ internal IEnumerable Search(string search, bool useL /// Full Category of the node /// Node input parameters /// - private NodeSearchElementViewModel FindViewModelForNodeNameAndCategory(string nodeName, string nodeCategory, string parameters) + internal NodeSearchElementViewModel FindViewModelForNodeNameAndCategory(string nodeName, string nodeCategory, string parameters) { var result = Model.SearchEntries.Where(e => { if (e.Name.Equals(nodeName) && e.FullCategoryName.Equals(nodeCategory)) @@ -1034,7 +1034,7 @@ private static IEnumerable GetVisibleSearchResults(N } } - private NodeSearchElementViewModel MakeNodeSearchElementVM(NodeSearchElement entry) + internal NodeSearchElementViewModel MakeNodeSearchElementVM(NodeSearchElement entry) { var element = entry as CustomNodeSearchElement; var elementVM = element != null From a040b60d7ed2140214c424048aa0e60ce6205674 Mon Sep 17 00:00:00 2001 From: Roberto T <61755417+RobertGlobant20@users.noreply.github.com> Date: Mon, 24 Jul 2023 06:51:57 -0700 Subject: [PATCH 5/6] Dynamo Add Comment action fix (#14190) The ben-z/actions-comment-on-issue action is failing in Dynamo and also in a external repo then I updated the action to use peter-evans/create-or-update-comment@v3 so the action can add comments successfully. --- .github/workflows/move_issue.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/move_issue.yaml b/.github/workflows/move_issue.yaml index d6140238a0a..a385146c114 100644 --- a/.github/workflows/move_issue.yaml +++ b/.github/workflows/move_issue.yaml @@ -23,10 +23,11 @@ jobs: #Adds a comment to the issue before moving it - name: Add comment if: (github.event.label.name == matrix.label) - uses: ben-z/actions-comment-on-issue@1.0.2 + uses: peter-evans/create-or-update-comment@v3 with: - message: ${{ env.bot_comment }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{github.event.issue.number}} + body: ${{ env.bot_comment }} + token: ${{ secrets.DYNAMOBOTTOKEN }} #Move the issue depending on its labels - name: (Label ${{ matrix.label }}) Move to ${{ matrix.repoName }} From 8712988ae6761232c5808810233912a0524b7d1e Mon Sep 17 00:00:00 2001 From: Jorgen Dahl Date: Mon, 24 Jul 2023 11:51:42 -0400 Subject: [PATCH 6/6] Sign tool is now using CommandLine.dll (#14193) --- .../DynamoVisualProgramming.SignDynamo.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/NuGet/template-artifactory/DynamoVisualProgramming.SignDynamo.nuspec b/tools/NuGet/template-artifactory/DynamoVisualProgramming.SignDynamo.nuspec index 4bb98f33805..f37be820b43 100644 --- a/tools/NuGet/template-artifactory/DynamoVisualProgramming.SignDynamo.nuspec +++ b/tools/NuGet/template-artifactory/DynamoVisualProgramming.SignDynamo.nuspec @@ -19,7 +19,7 @@ - +