From 216bf157341689880d37d4f34cffced423ac805a Mon Sep 17 00:00:00 2001 From: UncleGedd <42304551+UncleGedd@users.noreply.github.com> Date: Tue, 21 May 2024 11:17:05 -0500 Subject: [PATCH] chore: removes bubbletea tui (#626) --- adr/0004-tui.md | 28 +++ docs/.images/bubbletea-tui.png | Bin 0 -> 26363 bytes go.mod | 10 +- go.sum | 8 +- main.go | 2 - src/cmd/common.go | 30 ++- src/cmd/dev.go | 3 +- src/cmd/root.go | 2 - src/cmd/uds.go | 27 +-- src/cmd/viper.go | 1 - src/config/lang/lang.go | 1 - src/pkg/bundle/deploy.go | 10 +- src/pkg/bundle/tui/common.go | 32 --- src/pkg/bundle/tui/deploy/handlers.go | 190 --------------- src/pkg/bundle/tui/deploy/model.go | 298 ------------------------ src/pkg/bundle/tui/deploy/model_test.go | 114 --------- src/pkg/bundle/tui/deploy/views.go | 256 -------------------- src/pkg/sources/remote.go | 15 -- src/pkg/sources/tarball.go | 5 - src/pkg/utils/utils.go | 31 +-- src/test/e2e/commands_test.go | 19 +- src/test/e2e/main_test.go | 2 +- src/test/e2e/tui_test.go | 58 ----- src/test/e2e/variable_test.go | 8 +- src/types/options.go | 1 - 25 files changed, 69 insertions(+), 1082 deletions(-) create mode 100644 docs/.images/bubbletea-tui.png delete mode 100644 src/pkg/bundle/tui/common.go delete mode 100644 src/pkg/bundle/tui/deploy/handlers.go delete mode 100644 src/pkg/bundle/tui/deploy/model.go delete mode 100644 src/pkg/bundle/tui/deploy/model_test.go delete mode 100644 src/pkg/bundle/tui/deploy/views.go delete mode 100644 src/test/e2e/tui_test.go diff --git a/adr/0004-tui.md b/adr/0004-tui.md index 9bf57947..59e3bd43 100644 --- a/adr/0004-tui.md +++ b/adr/0004-tui.md @@ -19,3 +19,31 @@ The UDS CLI team has decided to refactor the existing TUI implementation with [B ## Consequences This refactor is large and will be implemented one `uds` operation at time, starting with operations most likely to be performed during and after bundle installation. + +# Amendment 1 + +Date: 20 May 2024 + +## Status + +Accepted + +## Context + +After experimenting with BubbleTea for a few months and creating a prototype for `uds deploy`, the team has decided to revert back to using the Zarf TUI. Our original assumption was that the simplified (and beautiful!) TUI would make our downstream users' lives easier, but this has been invalidated. Turns out, most if not all downstream users are using UDS CLI in a CI environment and/or inside a Maru task, which is incompatible with BubbleTea (noting that it may be possible to make BubbleTea look better in CI but the output just isn't helpful). + +### Example +For historical context, here is a screenshot of the BubbleTea TUI: +![tui](../docs/.images/bubbletea-tui.png) + + +### Technical Problems +Although the basis for this amendment was user feedback, it's helpful to also note technical issues with BubbleTea that we encountered: +- If BubbleTea panics, this is a chance that the terminal will be left in a bad state. The team attempted to get around this issue by introducing a panic handler that called `reset` before exiting the program, but this solution felt hacky and was heavy-handed. Also, this is potentially disastrous if invoked in a regulated/classified environment where terminals aren't standard. +- Dev'ing was cumbersome because for any change to the TUI code (even things like color changes), the entire program had to be re-compiled, which is very slow. +- There isn't a great way to test the TUI. Although the Charm team has an experimental testing lib, it's not very mature and the team found it difficult to use. We did find ways to test the TUI but it didn't inspire as much confidence as we would have liked. + +## Decision +- The UDS CLI team will revert back to using the Zarf TUI by removing the BubbleTea TUI code. +- We have decided to keep the `uds logs` feature for now because we believe it still provides value +- Potentially in the future, we will evaluate other scroll-based (non-interactive) TUI approaches diff --git a/docs/.images/bubbletea-tui.png b/docs/.images/bubbletea-tui.png new file mode 100644 index 0000000000000000000000000000000000000000..e52414d226693688d29a5db65a5841cb68b87d64 GIT binary patch literal 26363 zcmeFZWmFwa*RY9ea3?qcf;++8-CY6%m!QElxVr{-4{&gIcMC4THMo;$^4z(fcV@mH zv*y>VS>IXftnO1?Ro%5~S9R63_dcPD@)Af0_y}NNU`SGuqRL=k;B&wi9u5Xb=@x6t z0}kMh$`Zn0mE!~lzz-u6O(|13IWQXF91aXT*a8gdH4E^?2fkonP;o(Eu)q-=_$p?D zgFymE@Yn0v5Px%m&t*gYdkzm=2NO~ek&*(AD#i{bCbo{|pPfD-iz5RC=Pgt>iCe~V_7B+x*fP3(> zaIo|K$^U=5^4~lDkCK}IEy>2g^*>Agk1PMzl4_174kDjzfLl88|F>uUDf~Y#{!@^b z@wMguLlXZH^Pf~e&in|xjQ{o-Kf><#oIekg6;Au^y}^mf8*f0X(X*IVn6U zH!Nq;iK0@gRfW?=F`)*tR^BWhOQtcG- zpUNYA!%;sfJEO&XL;71?Xa2C)Yq>w!?a&}(OBo>IY7PHZm!jH)^6#@T2>VLSi3vJz z{H+cwp62#Hw*`uKior3JG{Z@b2mP(?qw)^_Yn%RLZ-fIkz}Ycoddp~u&+lh>Cl-_C zB3FuqDw5h%L|9mXHJS4BAiKA5-yOPfTvJ?!eRWz08USYUJqC=Wr9~^W(8jm$8%Mkba(0;>_f*mO+2cEm)+}|#o zcPig6j59zG&8QwN91BrRdxLcF+J{~nBkhOEQ|suH&L z8n?vV%`HCp?yojwNBbrxN53E;SFpU^S_;*&+U(1jD&DWA+<*FS0ULtoof_C)EPeID zJjT}iYs1)ud!M|?oDW@79i{-_<$|ANFo zf|o95!r$&^iUd^AVvrO3Z;|Y1Ac3EOVEC_2q=*9w#rEmjzX~`h;VY#^jDu|QSN~+m zJM%5^S>*p!qkSNuG#WAZkN93w3(-C*vm@bA{W}7#fP}e$KoPvZnmGgLWm-@K#y^V4 z1n~eQ9RBRi`L}Hrz>ty?>4*P!%yX_SP0)eMUYs$O=LZ%Rckw6njM0b@;Y{A3fC~ zp@+|#%|G@?k%>$sf2(OlTdF%JcnXUE&)*E`M%Vv(+ z_VRE9`f{S}eppgeZ2z;L&E-_rjW{1+i_`7m-B^}DmU_9Sp;U0ZcAe$a&u9U8a)~HV z4Cyohw^Im_+cuiC!iNuoblRX0VPRo9ll;QM>1OAn{b+%gY`Js}t!_U1>4wh+X&g5A z8GIh|!lm>&_4(8)g_>asva;o>`AZENdhRbJng~eewKAo@ADbChnJB}ao+|OR1Y=zI zK!F_A^3@=Pv+al2*sERi93gUW)g-gC? zEpPmmR!^MG+H|5@JX9Dk#<)9I<>}0I3JyTF*$VUcy}Yb# z|5T}YXGoh?RfXf`u^gQz7v4Cykd)0^5oAl7IrVE{ZAqaE$tRmj;9Gq}%lj(Ww zGMxR4xquz}c+_FvZ52I~bw}5NAWwW;+eHhgGAL_%-arGd{g7A!UJ zxvKJc9swO_6f6)`C&8cKC|Bw8ja0xAx%%=yU#WzJh1CQg5%cQ?Sq$Cg1QX>lw%_@` zTonmOv7VHwmF+jId&e(TQRHxfpOY%A=rlP{cwNtF%;t!|+F;J?@p;_jPYC?hO&g8f zTQKmkQCSYUC$ty1-^M^JEJOswZY&NgPtVWwSnPDi!K3C@=qJk-{j8;AVi|qqM=5hv}v+;3JkwxFOhd_?2 zgUU+5D52SMv_VR{i=j32Jo8c6hF{60`Z_h3%gjnHbQ@t+zyz)lo-Ewh0NN>+)Wm&bh#!7;}#^2I=PAY0((%^~ws^1ze_} z#n#yDYiO6K%_MU$5Q`rrBhA5Fy0MF8JCu;xy29DvcDwHZ`ff9&T0NhVno7N(mXp(M z2n%(L;Mat=yMA-BJTsX?!MNBT`IcU*!E#P|t>?i?SlIs!Y!?~-pguf7_{Xq*6ssX7 zv!48?$ zo0bm<=SgVsxSY}@n(68i%$2C*l0Mws4Z0_UZS+EWPBVcCcz&iG9;C~DTU0?EkH|*F zNh{Y}jb20!Gt3Hyj4*xp(Nurh!4LqY%e?)GQ*8BRu#A*ZSIV5>yAObapQZM($)le zUz@)mBnv?8?%_<8uqKxn>lRatC%{J@wEVt7oA~;konC>n6HBoO*%0LVLW0kEh@xG~ zzlgrD4<7=f{qZQNZim}kHooS$z$4l2;jZoU;{FWtq%kIq_Q>tBxBu!^<909?Q1d`z z1ECV5^HyK3UU!>0$tKfZv})fY5%Zoq;l?$?2QDpVN;%qi9f|eEX)GS)e&&{#HE@Hx zk}t6t-p=i9(1didSCo|Q`LU}=_5>mApjj179+SjV%H?KxKS)^`->x_+P**66Gu`hU z6lEn@HQHf9Gzsa5y^If^uC^2`FwFaGIzf+tREp$Tcw8A2QkaA?JMOl^10IYoHp+c5 ziM_6rq>3lyt6{>4Ww)4&*PR#i#!YQF2}iTmz1MWmY2e^`b0}m!&E{&+54SL-BA?-k zRK2u`(*8c8Z7G06KNWFw-8fC+EI4qn$@cC^R?5m5*{-YgDO9j9BAu;-#Gdhu^-;X_ zllipPK}VNLKzi1}KPQiU-r#ebBk$!?^y3t9XX&#Yy@C7H%REQ;0Lkk2orzh{b5&Ba z|J_>pq8R$&s0*^9X!t$ZxTpK=Z{#7Sig|NZR}_)5 zAVHDH(9l?Xj>>8*IGb+wgNN%Qw0CV@hNrf(#j&j%m$3KL6}66g<5xG!pJiAAZ`q-i zYU?_m-VzYdv8$TT?j*LHn%fRR1i0@@2JL8PeOFqC-T+mpwJ)ds8-`4@sNNyh3CBz=IGtZAP5q`Vo^Q+X1 z6ZDbdm$w?_KJji=Y}evqAjob=>u{1^)pCTU@&*p+YUjgE*q-JVds%DBRC@>vh1VCs zb@!`f6i7+ym0WjcnQvP$RK2o1pq(Y2_4ZoPqh?!0NDJ{`@d#pq-W3Y*bJit&K;Pew zo8Km{XJ*@G^uUX9Ta8PFMU|4$qfL&R{XR=*$=>uVLxoTiR-u3YKF0LDnZ4Rt>)u3i z%6<&WX!l4GeI6dGDe64iy62^w1w_C4TkBeT^^cY>FOO#jpM4(R@}2i$u)ICdF41pa zdajtiMIqq)2=AYVChCSy3jr0nx2?-gOT_bKG_HSCO0;*bjy(aKB`_7Aa-%00W#(X} zXyj9{jY!AumzEXo0N2Wd#{h|v%x?osR9Jg6o7B)~U^GwKC-gjI;AmKKKdmb5ltgvV%Y#r$ z5qhen^2$sXNj9z3KJfY;20Vs8V9y{MTJk#O2ds>NMAAFjF5QGh`d;Q@mR_!|@@x(k z&R{1kstX@hFsg6j5|1*Ko+9cO%mtXjSn+Q&NaT6fNgJ;0d>9sds+1G9ir8hR8s*&b%zQeT4AU?5J<`Sd5t&qL&$fZ-!IcrgWQ>mR^}0? z*Y@z=Xe+c@PT@~xk^~X!D1Njc2SSF0-Wp*O-40jwaEYy zY7UsyyMVGN4VJA$fxYqM6jej*6EfNF^?=e@?-&wBIsb&8Sr~S<;xv-Wm<`w%yc{<8 znP30qMptUJe8zBfR*N|-YwD)-iQpPCk26p2JIzz`dq2vR$q?IA0&;fsfV}l;CJ4c7 zY4cJNKCy3h`%1avHa33X@WwhwlIXd-UTFNzhpLv7*?z;)M9cLyw9(__jjOpG(&MSRo`^j+Cl*^cNP7#M+vxlq&;q+MX0DSevaaODyi=^J1HLC9g^Gqxrs z#wRvMdsduxx1sRg3A+C_LQ=QV*Ekp@%JCC&^sv~~PrbVQeMCwqVh3K+EkTxz_rB|4 zUePc&U}Ho&#+ZtwU>8<`Y{xH*{)3&mgZh_KhAECs@X}S3WkK^kxhl?wk4Ty)_XLIK z#cJ0)<;KJH8d*IOtoemV5_IMEme42Q_AN4pa22>mop$4XLyog@W!stRF{Wml?@j2n z7AY{AZM(aMwCvfv#UK5&zWKpI>39D4fHX4HO+hj8X1qRQMvn(h6;BSUP@D6p^>UoY z;TiR-XM^qPcD!b5;}so|evN_meZlOHkK=)Kn%_IOnh_gJ=uRhA-oVM$Eot=3c)a)A>*`yE{dBGTS9=k4BhVQ!w zpABX4t>I-s=EMZwe5aD=b>Q$Br;X(>t-62YUJlb%q28?Iws)c)_1K-JaXA)Nly0H=tL#hXc28lXL@Md7WMTl*^R{zxxp;Ws(F6<8SI zEXw)vu4wzvy9t4KtJ9tRmwxp_>+JrT_iqwHPF15^4rPYX=E~j)U~&k*JR2F8X0(+p zCfT=|&m6yi`CXFqx-IF8?@A68RMyObq89o-whe3!lRo)dnP~TM)mMH@AANa#JlM{Z(c@4vK2KNL%Y+2~tbg{ejp zO~hC=#P{8%kTT^MFHgQbBO-}OtmD0Zl1IxjA03n&S>pIshgpJ8zwpL;-g&ZxV+mz+ z;|)Y0JbqSd!22<^Do^AxZ#cmMv`dlOk%-EJtG@a;@EqO(AuE4KqA@=j5OML2BB_Cy=iNG(=Czs-sU2jTHa6j!_c8dHW=fYVf(XuW>K9`Ix)Vi7b5MI zUql@W^(7%MX=QV9_j7WD9Rri{s7TbyOE!BRNyIha*f`9o!NJ#@p0-W&;(~6O;Ru$P zM`KdnB}l}e-0T=V!csz;^>UY2a3mKI*l5?`XgWcMGT&soOY25vO?fM#aau7u&vBNF z#ZT~s3nr4QO?3AZFuxMF4K4uf@CDbkNSC5VNuOHs?v4DVQH|&Tz|zPaa{H696He6% z$Xa&&bFZKEAB6e8GyLIS|4#&k5?`83do=zZS=x<}OmbataVJ;bq**99+k^y5)irmI zo|wL3zD|A!9&|HhQ9FUh*gM+-iO#S2+Oqmv#EAdFhJsp9()|NlH6J+hrAYw>O3%Ph zs@!R3@(1tzVuRq7cgMG1NZtdk(2bK5p9wBB_&R=it#|`puycVY1R>n9$}dUvj1qvL z;i6{eHy34V=8i{y%76FsO~xe-54h<14}RUes!_*xo?y^#3_V}2l2oDqntxtM68 zb{U^nc?GGp2yw+h1|kY|;Uj-AdA9Uxp0JvWarF{zN0SjU;34J4S7fWN&**g^k^e#I z+1Q&Z)YOiA84Lm?T&o9?FwXO~$p( ztBEhdNcc1Ar=^&uRx7tsbB5qQXj?iMtbPI$YfnY{##`HS8%A2zKQoeJ;GliDu@Fl=xK7s{7ZXZ;jY^#C-mPU z+2KF}10BKO-|>|Kz}-1s({KKNi%g0Ev=;{(`A=`XGT_ly+DpVL-}Sf1J{drJ5fNek zrM#iQ}A!wI(Y%wyUYAviTE-A3C-W_NdC6%|2yLN#h%scNS*c}w9vL%uEbatmqKqe zr%wlYrYn!inRbIhINbT{zt6pa2Sr1O<9v!Mk+IZ}lbNxkn3t_fBgrp(znDCA zW;MC1q6ISV;pcWe2AQF5DgP^_uW+ge$`u+^5!`ha;*iatd_xf!r3@G}RZUIFKVyXy#BC4|qOfR%D zc6D{lwzzx_1Gc;Zx>*7~YkASx@)_K-?Or_63JOK7t-R4mHf7%n<wmMu+rZDeGS3WWfDSa=w0mPgg-vzOt6{`^4?y-c3~*^w9mtGRHgM#&2w zLn9bqGw*q*f-f#EiTkiA>m4n>eT=V_OoZJejMAJ^|xzYlH-UjPMGFXQq{M}qp zq_-UTz@ln8mDTJ$Il0KLHXw-bG_&{Vlaq>}Li+lZ%j@tWSPnw@z+KQXf8Lz%3~vX8 z+BVqg!RMDko$cm|b&L!ZA<#}#iv)Axvzoqnz8I+jeO~8R(aI6{ax@?L^z=k`0Q3gM zVS{9pL6V?71Uwy% z!jCZRW)noi;`v6qyT0G1lEP)^W*R6ON$45`R|r{7nsO8TbSw}Oy8 z(Sc~i3~(Te8F9-TnIyV7n~NZ%w+H)Ec?nrrjAuU|01TeLzi;k8?|r@{w(2AfsZ(z) zlnZ@m&}Gzb4Ty`6r(fVa zn92(__t9b2F_3$HxXuegBH#A)Z)BpjC;+hLY^@ne(@RjDqOAB*T{uOXXWhYZMuXLY z{BEdoPOaHQ(h%Yj3@B`|wxd?olZn*d?G2>5r)TTvnl%q9@x+^x_h-$Ou`fm_kSBb3 z&!xby3ut6I=?MtEcKBFry-1w&k~`KQlRQ3KZ7i`U@twnESGIN57v!b=mUs^s=-4k{ zZK494^gqc)Wt+qw!)eb&2uWjOV=qEnG!)9~B<{=zc)sYCR}2ij=;X~%OOR`#zZv~v!d zCAzB5ZP)4-x3?OLc>G2|o|j`PpYVE)cqkQ%py#CGW3cZ(THu8(rFPhIZ+O z(ZRN=zBvo43`oyhN;*3y*Vy~KFBv;H5-@S0!+3B)2x3eku!)xs2~KVfMBvf$NmZ*G zi)TB7MRPgsYO@)|5Wsk*)Xa{$?~UtqAMA5mPUQynjed1D%wKJCG%F!9gz2vO`pbIG zvb=yyuSt*xm}|+avWI;0bC_u*7{qudaScr&;MW`{_>?{7M<&d1FSM$S3L=m%p8zW< zJU;TM{dh>;mrfyQ$km4R@uW1UVStf7=6~6ebu)bopJE}nF7tZ4L8Lb~qb|ba%yT|l zlSAGg9tNBCPYT-$sq-r6`nXm2VMzG7`OAqgfLfC=TC#jz3T8Qw@^Z}^R`-c`3JHUZdW%)M)H1yprhN!k(18(0QwYw74zf(I7@y$NjnFHA* zc5RxVz0Px3U$t!Y(XbwIhOQxqg<{sAlZQU!^+IXHWJs_>Ko*nmB!{(mzE?O_p&ypT zAol;&CS05=rsL>jzEPpp<9M)zc@KkCmd4ASLy-Qm+ik z&rj8mjFndMD_-$D0qi9W4AqKCezVINk;Ma)QZ6st_&It8ubZ+y&n0YTwDblhxN-$G zB?qc`xvP>PH%yK&6DQTX-sE&u!yr|M{YgWiQYL2cVv-pNj}zbe@Gl?fkqWusmi%t| z`{z0Il31Vn%t@mjuntki5b$MBmb#2Kt}(EK;)Y1s+$g^L3QlTZ=4>s^&*NE_fs0E? zNnOn-T*?#(ag+ZMW-rQ8#&t9KVHH)1>qm5Obp3kkRDH}I!|!07TILItdfNyCosn-p zpwlU(hz17+4(-{X5 zW7oXZ{Epg2D}8OWsoq+Qb9fsem}Pd#osUB-Wq*WL`)PyCzpGunB5rR>cI{>fJYott zux$AE)BU@q%JRxcqKpGZ@yq$G+=VJ_kU4|w4Ti}V5<%J0*-K$!_1to%B89h(s*pL| zGDH|nrekTt&f6ac zF;ggq<&ENH@%!bufO4J2-?EB!O(v0wn2_A=+QyM!VTTz3I@NR!D?}a^($;>6P7~G2 zUWmwqP)ow?9h|Cl1L-hL6VXw1KI`}>89m1vbVxVU&RuC28_H+Td zf`GMK7b1ADuiK?JO9J71=d7vQ8&h1+iA}~i`biyjLZ~0cu6o66m4QP>Vqo2N83Zfi zs2bCwuuj)IliO214RTKVAnqUNV#2s~b-DA|AVbp$KjLrJBqY!ui~AJjWLnz8QLuiX zV;P*a4=)&4|C|oPj{q6Y@3~KmrM?(tR8?3>JX->q8VAPza)&YU4qP3nAhpypu^!4s zw(Pm|aelyNxjy`P`DlN_r(Gp&OW^U?QRcU}?ms%nNI{{+y((m^7B6~KpGz#4;ar6q6kh53T|UhDX8i;@_#D;=ncY z`s0A5cjOS})Czw@4&n%^!?Kc_Q`gcqL%EKHEk`;WYI2kkhAggf36Ftcb#c9;2@RuR zUe($Q?m}af2gb*aJ1v11W_1~;k{1Fe0d{&}E7zu_c1KK1OgoO|3G~&UOxV?kHZ(L; zsi-h&Qv4%&Kq#@7WN4X6^$xB`(u_w~jU%?#1+S9vprB zwmzcU?2A%b1;-m=F>tis4@VH2OxW)T=P}jANB$^aR!!+_nT9)A@lu$J&EafGjle_( zPf-Mxcps}{KoK{S|4@Bv?yYqiM`Y}xsY&9U{~+QRF$jy&`pOY|f)vbU9EVRscQFp1 zEu!!X5~SpQ(e!Lt5Jzic_j}pBIL44FdJ~xn=vx+t-Vc6av+i}z6gj45CJ0o8f=d`# zV#!XU)h03lSc@`ga&{>BzSrG=?~1g-aw4rpl6H8&e88hk9|y8)G8z5KEG!BUSyf^< zKMa$3^PORKP(7>X9n-;mIJneAM1U46{}?P1<`O!LIJ=_%%4Q5y!JnZmHhzOC$zkQ{b)^Cj;9Qb+mO*ZSfD*8W~{hQU=mj!t!&7G1eV!IMu4 z)k+^5YX?VhET-A%*nvKFKnknx7aAn2>?a&X{kTFVSIttdC>o46G z_`F6}6&^O~6C$$X^=kv188ezRLLp6>kM%uq0hvEMY=PB?{)@XI@a}|BDCaY9Sw#&cd?2Ww ze}l)O`AMUha6f*ZHiO3{DJw|SZBpFuP%U?KSG!!jQkQ~C33qZq_x#NV?aHZ_Erut- zuwPOA`S2KKR&l)n*wY}3h^I|m_z)S3W}49{v>*PO%!LUWzvvWUIU@}r%AnL?kH2b6 zNC*CeqsOyZY4-}|NSWaC1=lcvJ>rK;`95_D>Sy& z*;oApPN3Y!uuaWkd_1XOI!Bh*KsI6caa1+)<{>=n=e~Kpflxd+gE+6A+Pbg@vmvcQ z%UFUHsG|`=fWCcS<#yGDvBIE3s1n2Ktm%TF(MSjTi45@JVof%Qd_L`jn!t&tJPP%r zfwNcS=ik^un5i93j_yY-wv$s+yL9p-Yr9$WY_{kXO#49|*DYyY;q5nl9G=XF@|!0z z`oqq{LQWo@KFDO5S^A4#LkZ3LAQ~Z_fP{ZCynqJWsG~ND`VsHBf0rjB5;Uv&QCrFU zxt??65cKHSWO2@F7bXD)2KiWUic^9_#D>{t|4rFN@nN>~s;L(vHUn~Jwy$k@?Is}o zkiBAEvxo4q^Bz%LqPA0PS*GmkxAsu1Dmb#`*X73UZk^qEtMY|7!96Qq1q(>k*iZ~= z?+vGHAYl_t`@EFgMTz(6<> zvmq%-J>Y2wXrta&Cwql=SOc1YK^6E!CqChcL7y<{OdBFk&GC?q}CdWc*}CSxKqm%8@1hnLdz(}y^&2_*Fb81_lrF*j_*qxF%2LVq z7o=_&LeY3;l?E@5^!;OXVS=y~0XVVEq(lEd#C8q|oO15)rnjl>pM?LN;Xkng{|h;+ zmridi5gJju_tPgG?!Nn0@bk0R$EM0ks#gG7AcG@w$*9{X=y7{mr`vLrpF8ZV;lXL} zhkNV#2_}-xZ6KeN9Q3&8EPZp{0xe594<}I1mTRfVq`Fg8b?~b&{xCKK2M3>Rv^Un$ zS5QS9Jc+AZ{_w^i|>O5c=V z<6tV2FTHN#Ao@7fzi?kTTRG0sPFKg$X@Jd=^8n@{ z&mLAyBX}Um$0rP5SHOSV^PZ5x`<8sCNY5#yKM~Ey$jE%76I>N=2OS<6$pZ+^%yfYa zH7#wKDl-6xax?in6i=4w03z&%Ou#95veY-d)hF|wiwkhQGv}3ofTemxVx%HLil07- z`0r)_bPs@O6y-h5D!P$~qpSAz_S0;{xVVzQJ1!p}G*eN8JS&TD#?$`@D;Q1{|IDD{ zyP~DT?~K{cmn`_-9ogBvuJjQiBJ6&E*+6CC3t>*zk=Ob7P$J3wkjUtGOgKa$mepT7 z{cP&w#J1{ri3#|pVgnPRA2K1gD6kaHIhgrO%E-tl!)|Q6JPojqlJDPRfPJPSdd7Q?J;@ZgVezz*+~So$9yA``xEbuUutMamoE=``S= zGoApKPI-njB%F&N@I1xh{=JMImc|i_FHay58$U2&An!@m=fju0)$tI;K+I=IDbr*B zcy&NOOjP12^9M-Xw(iVmG6PE_hW7ESe9SkSZ2AVd{C^Me) z_Ms2{M{8Vh{SYYTI9Pwnk7c?Fa&S?d6Hs_ww!Kq{DOFL{l`XO27+!CecoDu9f0I+J z1J#AV>JZ++OX<^bKkGD;+iPcs5#3;O4<%s z*dzCfEOrKC$rCa&bC4Vs zo678k`o4QNTQ9P3Y2opFDKDp;FGyxI5IR3UXDH(_>wPuH`Le>PzAqtie^KM^_y{ky z?p@0^)6aWn*3EcyM}1(PK=Lh;1%+VVCRstz!a?vIqY%M$5K``-1x7v>UOvLmicfLx z6D^ye3moWOiu-1Ee&WNmOl56NjmdX1E%P#McodWceQl7Y#JMy@v%}_&+Lvce9v&S_ z2PvsNi?!CQtGGlS*(zO)pSd*fRmUgGE{dX}kkz)UN!fK#c&uss_uB$A2*iJ^fW@d# z!%>|?mEuc5^q{>pDsziZbSEiaK2R{~%L~cnmh@dl&vdpO4bQ?5wJ~AAiq00LRiq_1 zuir%C6hHc(ZKqi(*)n82{BqP@u;Q!;JCYb!^UQLXpiB%q8xEhHRV}HoToBL8%{4)5 zg!OYoAMGJAsOX0aCjFz0UoRc^;sQ#V+MU1C;VjuZIjNR7jEFk1bgDNEjwd#nm%&D$ zqoeO=GZ9oVF?VTXYW^8Q#gb5-qMMBBpP*G2`=A38s?SI$JRc!5?w{Tc^JEGCg5!Ta zSfB~p(X4fQ6Zqv!cFIMz;CrTCeyz%MRfme5E*(~Q1s!bG@8EZb`Ox7M;5z6@KcRMC zJwsKrwef-3wnJ84bN#CbdaE^~!8j(=dIyagcKgz_$eaO1dcm%qxQvY(~@H-7c}s(mVf|FyJ8)gH-D(s0Ro0 zLD%Wd@L1<8H$<3FOX}vJ$oGwHoE%YwKR<)@{ki9g;ZQ_O8| zV@iFy6NI`^^yg${Wi4pJI`WnN=ns&iyxp;MwED4+GLcJbHI948)u*Y{dH9h<7ky~j zhLV!SD;=RHyoQE`AjdrhJm`4v@_YY)4WY6_I1KuBtZ(X3d~G+w&g=|7mX|AZJ}CXZ zafq7)JX@-X?-FJ;{XYE19|0>Aj6<Jq{I5DZi*-jFob zAmeT@PcD5g>#4O>+MZODPJ|wf z0W&~7U}>+5L|XqhHc*zd)2g&^V{7o=m#+F<+yz{{QnJ z8{|eE<}_jy(Z@SGVy`h`2-6dfmRVqi+L>u}`Zj~Rbz^&cJi^0O?x(l)s4Qsvrd zu39FUfz5V>Q(8tQUO;1~Y^+Eu9NTHxra`Gnzik`kYy?>SfRt!fo2cwcoFaD-65oQa zJM1YAvA8~8FIa4J`Xy;&VPZ}KhGFybtv)u78*AY0)v)5YBNdEHxF5xHn!T~{ajC{6 zoVK=-#ci&`o0Hw+$$OaFEsf=d&`GAP=kY2Z+s7^9N!Utdn7GV3X=>;3w{mY|?Do!{ zS?E{plcqg;>E(~V?;D#5E5|3MNpLc*PL`7aE4?^in<@ZSlr8TUrWZlhi*bdrsYdX< zy_bL|aGkD3KZe4FGT!o-GYv7s!ngZ{^>qWXxb$=xV5zx%bR+|Wl@$PCP8u)6usB7P zG;p()GjXlGwG%%aeWzW{lIM_Z7lN9{9@Cz>h0CN_D^uMW{zhdzrdeQq2tb<@+DIc; zo9q9u=K8fiicp5tbTk{-&JS+@2By;Gf+%2(Tu^zUcLzTPyKABmGUYHQ+NG3Qj6;c* ziG3z$d?#czYZ-M~zPARORk$E!3WihVMz4uI|q|oBxny0B2!4$C>7_9emZ#h!5+n(s=PABEf=lBzXnleeXf`+ueVqeYCPEqJ#S28O4{ozl_w|!l z1YBHPIK|^1XaI702UzsvZ^pczACz2O8$Es2JkI!vl7#?EzXGtuD1br2m&}4|O+IVA zjOt@s&67a6x7}Fn-`0X(x;bq*QwDY%JD;=z-&zFY>8iGSeuBC}wTm1sNUp6l{3$9- zH?XOfO6QHYr6E5x0|zXbMS!T#qda?>yNz0wdfGcrcd$j{)+y zwdMYDj0;R8Xj@0{1o=cB$ISOzA8c1NcT2YL=y7%rU&9Xk7|F@MYB$)@XGj6LB>~qD z)y1jF9FZMC^tW$ifd3l+TwbI!JG!&yOH`<2c=M=8Gk(4YX?(b-(iw<@isFYWo1*JS zpWm(Pkj}kAM9cwQ>*TYdZfVMx-;QJ6PU*xc3bks&UYDSW#;VwYqAXvuH&#yD7T}yq z7E8GZp9hvrE__Yjm=$18@X^3yEzw9yhfaMdzKeV0tZ1l?y<;F- zw3M-=GO^xK^y{VV6Z2xxxT54j6sF_vjBSLVKPUdVzrp!Bp4XkDgkpMRhqy&m3`-^QU%lY!u<9N=r#B|%{&`h^oylxN22YB(F z6)>=OTCe{FaAk48IR~uK9{@uag&}zd(3MJM>J^_-N%SdPvxFLfxJnhFpmmhIMopGo z4Dn7Fh{SN!qA=}oj1H3XuZiXXcU%XeOTeD&eyfXX3vfcm##5pmI|0Jea(Dua(M|>K zHomesY)h6P!N9;M1C|{V&nG-)qkwmcqq}ItpJ3xJ_-4@TpOc5Qy@0+TZav8iD ze>q3D+RNy;PcaIB$w*I-eG3y!E0#3aU>aV?#!VFqL%1SZ@%y}$?r?HlKkqo+Y`ZD- z%ODi;3+@<-Ra^C0JB>ZpO@9Zl8t2i*o{N%iy{&#@bv<2M^Nv$pZ>d=YohC$8YSt#j z2EEVcIs<{lNwg!4$s$ecprXAo=tSv-R5{v=}y1SNEH8D9W{?%9g0_<6)`vgNhcuu6~J~ zWjGLyW%G2_Ry@A$)v+)EVT<+Z5eaVz3FSy!%0&!)!BTU1&B5)OmHl0v4-?E2fVV;+ z5Iw3BM?Knyn(}p(lpRV-XqgV%^w%X~@-UeoSaLK$vUX1WsLZm<$OyN{1BUDfu;o-f zT#B6blk5vm<4@IY`vq#A<*PK;(njo`C!`>m9SM#ql^J0c;QKm0rb7bSFH~(Y=E2i9 zvlHOH_sLT6YcvB9iXWM=3B-5_ih5~f{d(~#9`Ij`lYKriYWrFYc!2P3O{7-sDoQrU zcaQR?qPO2?LgbN`jAwhRzN2&tT{ncW)CE0T0`4s=q)7-HgwayP=w=UdKv?#64crA- zNjIi-{qHVoom&JLz&R>;&aa2`Fsv1H4@6x?!@R*Id8XulJZ2Tn8u-*GnbNyAk;OQJ z|0@4ag-^j~cD{mrafdp&U!p_T-OhXDlLgOd(K`;d8kC-fNlAptJ-Xky1N-=UBcoN- zArTb5PpS9*cFf;D?jlabm9jw7no%XL4Wbp&r5M&3-S{4pxZ(Qc(qaPpQXERG4D*2@<6~#iT0fA^-R$BPubm z0*NRprza8(h8eOkBPsA1(>yAK#FC-LAlIl$5Y~`m2h9*~ef>F6n=k!MNDY9+_ zh409Dqh$(w*9q@*N9}SBw5sB1K8uwT;-Q%*7;dfZ!4&p1OL`mS~c`*tVXFOI5;2q@d@WDDH4~i|vd^h<6e} zV6_xBFO^!ZhadT92R3ci0CxFlW_Z>uV9h8Mk7hb&=ky)hRYF*>-tJV<-;bOHo#SX4 z0tu~0}x4jNr%l>UdQ;*_lS1`LeQz;0l_%rP#W=1$Zh0p?1xI2%N%E z`n=Cc`pv)MkPa}-2v>hOKa8)&y^C&rDwLhsto1>=DHLw)bGOo5CsNLf2j4;=@X9U_ z-hh6?JcFFt*+rapugC8xYkBueG^i&|-8WA?zK_pUTI3^t)m(kzosk+sh5<-6DE0oU zci<2?oE#TbPL}yt>EJ}F_guyQ(cW1FMAficm<~Zekd8q@x}>|iyN8k%q@@uU0VSkC zK)M@-mK-`1=|*W}XklnLoA3Wm+?>mEckX9j%S`?yL>Q!g_otA)fX6a+!3 zk-B$P>7w*WI9-Fz?cp;?e5~07OC6Zy>B%5yw8PVv=NvI_6@-xkLMvOt;XZyofE)5N zSNiPlxa4RRo4@}3=_nUAJd5njaSGF$Upyw9?aU#!CyHM%@EG0hyZvh#$w~U6z1JTj z{b0W>;?@JqCD&SctR*b&-LWiT-5P&^-r94t>{gC!zjPQn4|?54*Gc?PjEULbc2XRuPkO;2mSPK46 z;D7`EKT??E=7wi%fk9Xr-p8oj!e~MBCb?GCCXFg0YHQRzub%SBPh(zmKHLZV!3nJr z@nzyk=nsGlcjHUmYO#u@*8vc-%A5s0CT^m}d*F#Paq&M-jSk0ieP^!Vy!CfIVE))& zy6~ty2R258J1mLRRGW7GQy3{##tX0lqY$Q}_{~0a(j1iCLNHc3V}f6;@5jo45lRa7 z4gH-`F~c33dIJnLD(b{H*meBKIq|Zq+}LbT>Jj}MFoe`zO)cj31(hBA?&e}+Iyvk9 z%-M-qEq0zJ+*_@bOQ;wUMaORMR+Zd(d#tNgS27nCl*Q9d z#RocmabkxCYSzwzf{EL>uDcLIUf*k(n?8ILTrSsDa5)(Pv)a!~G={#)xf%i9{R>D6 zdQvq29So2AIIRVd`DFL-5FOUlruTgJoBuY6NROWW$>#ymARonpb2#P%a{|e zKUe|!k+>{8vEgFUZEn-hR6s9R(Lw*h1w;?8o7Q~D`is<%sk*U@Ui@aPuF*KCbTx=n z6_V_x!k9|%Nv)XkX<4w(+Ff=CzWj__yBgynkRJ0oM>*ai*dsZ_ z@2CJ|_4L`DoI2Y1sn>MPG4k_xdW5^pccLT0v2TdeX|_QT+)lJo`jNqJ5z6J+-6!}4 zxd320dROJ|POx1{&H5FXy8?knz$}(tfKDSuVZGS~J-!>PTTqurcMt(epW&{EG~`k1 zV~>%Nr_W{7ui6?|IS(t21vT|qEnwUMc02!e!Y@NiS6 z_`fWf$P-}U;ua1KDV?62xR(zoo#*SausPDbeft(zs!x3n0DMlmdBukk*sxUZGX&pi z1R(ZL9K_ex*Bt=9*9#!jfk;N8;;4X*k1) zKSUoG27Y>}sHnU$4+9#UTvZ6REuuNM&5Ny1#!cH@UIg>AaBxlOIRY$WajWOf2p_Ox zCue1;F==KOUj5yf`b5m8wq+~e0kj4<0)A@hYciy+JA~v|RcQ4YAA=t9(ZMBWXI{j5)i#lM?tFG* zWY=417LLCak1=P|9Y74Dqka0;5+pKW4Q(k8`d# z0H>O_Z4JZIM*2$(KQbUZF|@M*y46oehUCEO=7V@-}Wj??Zz3a>Y3e4MSHlD~ogxq>}z)dRFXgV*%#Z;EDcB(JXn z8iW`k2zTxa-+j|dZ$>8MOR^{%Gk3G9069P-1nl(Ub1JUGCOl##EO?J13lL5JBr|~G zjv1W`Mw+r>?GgYRB4tJ(yrKLkw zfu_&mF<hy|3?96SfL0+baQx z2Sg31k*mHNPgTviTRLtIzv+GRamnDZiD0}1z9=KEflBA)I?iH)V^Ul4U?h!ylqH=p z)b6P{aL0NeJ}Y+vn~Pf4{dEN+=ZMq-_h%~t*&UgsOg={$0O)Sjb%_hQ(0}r0xkqPU z!tht#W>L}i6PI6sANO!~WtDMAbbCK;Ft-Gmj;N~?%Z@*U{|Mw+N+e;5JFNg@DDUj^ zIz13d0mVo|#~gd%`fZ?J=f#@+pY?&N)8$=I!5xzGUadic%aTDN=4{hR;6zR39KLk$ zyH!7?r!->efPr2rm0pr39t6PRFut}GyO~;_&wRBi%OMYUud*jRzKdDVA4PswS!_YZ zB#5dyw{kvsR@`he7)PYmw0m((%KRCrWO>=FUVcyEFAX3on!R1>2*B^}>myUQ;{~U2 zel03SuUC*1@_Y&AGktq+9*d7qd=rR!HDI{5KaMTq6I0-;eG%fDA zyZReaJXNB(kqkKN>cI0Z@vhRaW>sdRnj>fUsOy3AdAJ_A;+?x5=epI{r&t%ZN}P%< zp@mv2NT5M9DOWJs_$IL{1 z6=-(6UIOiUCOr@&$#x~~P`)=tG7O7C=|Z{GZUj9@ctkv7l;aXNZ^|x#%b80(N8&3C z2HPB60J?T41YNVf2R7Qyi(H&O`(e{5@qD?O|HH+Ryfjbjh+Ngmi&U95?|cI;30eLO z!IYQl?=jAq50l=F^u0^Z@!dvW_ang~%1MO9BsxQcp-oN=ARySJm?6kxwb0~}IW6%F z@$2C}jgF2^&-?Y|%~6+T^QwOZ6>go6=l(p;)g*mqb~o}--5^a;63vz8uWa(y z4-RCFY7D}Ftr%8!0$gU+gq_CV0!b$hGKCTOY+Bn*LHBhu;cS@~QsmrAHg9xL)^m6^ z@ObX|6SwkR9d>{v@#RwSI{7gEY!6Tc81+kASit60nCJQEc-M7IcvzSN43f#9d)4}1h!G#q*uVEYy7jHK?s*biB%xieu zspw6X=sOMT{2>f{@`uj z`7`Y9cK|K3K?}!MWDE%Fx%tSH9S`+xpoVIx(f!C4SKajm+OZOcc^of+6RHR}@o5>l zeq!Yp;?CE&1gRnz7#O);4YA7pUgT`uS|PD`Km&W>bHn08DOg-4D~Cx{wO z+9+*r;TlIT9V#*vHB;fOscKnb?$h|eS6iglk6U+cB+$&VE^L!H-4zn@kp;#RWj!0y zbBDJURoGwzc@f)aNpe4_$~A2Jlt5sJ*Z_?Y$QfJ*e)W^o6Q`oiE849pT2z?>;;_;X zZJiAu8CggCT}!Azuf1!_{SqZYHUgIfk3FE!&Jdi$r-Wg`I#3Ecjg6Hk`mkM8u=!Nm z!#%gh8Xdf}Fu1?KUK>}e)tEMGn1PZrHcmE}3RzZuNlLZDZLwc(45)h?P;5zgQu5k0 z)IRYdpfLN$IH=Y-gnHFOfq^`1m59$M72ESuYa$Kk1yfa>2OP+)O{6$!0OffxRW6A* z?S+~(yLQApNmS^PUphxqK|eNY^(gwORwI(UKsl$QJN4RN7i!1OkP@aB4H@KOXs(sx zD=HkL`R6?k_j+%TnmY!C7R|t)2| zGHn`j-}bTo9TeG!Y@*^vb!F)@Scn-8WkWNP<(8gw>L7Er6xT(GCLU`w@#KyoD*O~+ zqSIfGbP8*U^u)pQT=d|P(uQdA{R8J|1FqLL z{YA3BFtCZbUR69dFW{seWuD+ZXzK1(Pk;4dH<_S{9FJPvTL390u1Lv9q4N~8SeVgC zd}tB3;&4fXRi$M3O)aDg9_dTAV`yD=qQ63FEJd(Q0ff!D;+E(9K;A_g83)9 zD|I?zT0WC5=ob1r!e@*bX7yf3$cUD*ua|->4@_LDP$GQ4%)BvDEicCxfj&i5#WE`X z`6=OX!qOMqe0z5HbGCog@6&ui<*H)93Gkb1#N#yZcD$Pe`@;i_Km#`}2hNt%OAtRy>;1Z%9@DtmCWlDNp7%zGgc1Lx>a@K>O2qCmBk_j@vqx!u3|Cu8lP z#ij*OO=V@0i~tCOGyks1V5GeL-gIWa{WUwJO=D#&aDqF@7brS<-CEPkGXuW>FS}!TI|n_WUd=3S%;Xz=VzOucicx zF&O%Tj-B0X*07^u_QJ(H&Ah#icq(@7b2FtP2+6a?au3;o{4@0Iw$x5+%@2qBdHfC9y+kF;u{%#1+MY*a-g&uPPJMgiaP=B&# zMZ6~iU82IZwUP~VpTa;uB8K~P*4Xue%;nRqj)bHc-tBYyKuN3t?V#&RG> z^x{V6B-X6-qxWd4ZCX}xL}Vbh4^n1rt(Iz&wl-t24L^4MGPisFSBCNvmCPKr(S8Wc zILLW(HlzF_D_o&p6f>|v!@&QUb|eHM*Xo0V^I}!-;HE@9T;kJtNaKD29d`g%c9WrD?*-B{V0yB2j7KMhTd$C zeJL7&FE!VkUG~fN2yX&IKRYodX}Yo1)HMW~=r#3my|ipUCbQcSFe9ZcS=Gv;zW#{$ z$=e*aTk`f;w(Ry8oqS*Tv7XpgC`-H2-u3v0{x+^WVjizx*8Z12yh_J!@!NZ0Y!_H+ zJgG&XcJNnhcxZZ-5ZeoLNXcf7N><4p?j94=(Q8nze5LNI*sq)4yv6kbnHB@tcY07; z-o4YVhsh5q&McDWbkrd`vLj+{GsA;w==HMHXIB6m#zYfZjHy#Bs-lKbfgv1JVYKl@e;xL> zLYLvU8sHOSG9K#|H#bpswL*zW>Ep{2qSI)JA(VT3+HL?|i0){olxuC=Oe@K~OWCQ= z0vuLCJHr$0)G!$ekuwotJjXN!Gjq;%S3u5S5P!dRh6xoE3j)|;?4yeUYmfRFWb5nZ zygS$)uh0HDp=><+Dh|~Pw}Czbib~mn4y~+QcFQtV$Gyd@f_%CykF3+6iB(T8FpJW8 z$6eQC7lJE3huKTdD&V3K&UxI_$L zfEEryP_yC-!&{Emdn@sOFdzTcFZ|?7_8f>?V?5Oq!Wtqfj7}Rh`AvWfsIE5FmK?ie zv~E=mq%_|yrJt9vzL|b@G2JRcx8I8|nGE%BZ=ZkVW#Ef$6aPVZem~~v6)<~c9P86p zK@fWij|Y%!Cs%eoH|G)F08gaU%BZJL+{V+?Ka_Rp)}_}@gT!O#20kZP*@s;AJL-5( zSlS9+0Ia+zj^ZjiHgow?Knh-Ptq# zwOJbK8JrQc0XnQ}ioN`m!`Fpog^h-B2%11bt$|uA*&-;@q|9%}3Vx{5RB~U-wc!y> zpqA52Ig5B64?QK8LI>cEy8-$EJCrz!4|dp5#W{r zkMIAeMc|+_SZ+se!Q2YU6nlfX{aF2Bbtd?}RzcW5SYds4%Y_Tq=2I)0dE`HR*hqeazp&dD2Z zD)$ukLwJfPb#g;DtRGaYYTMZ-o}O=+-6SyMICbJTBb8e(W}!(y{qn;+>JJ!Jx-^m; zKC}gjg8#gsIzeHslhfr zswdNn5MDnpjw5S1sD(l_xU*WJ!D$;4gsoOPB1@wW-8!t{Pb$CR*(UtA6km>wvN}`v zby@Adc+dktylepBe@ zEPtbHD%StolH6EX@K)+P!n{Chtd_2ShF;2 0 { diff --git a/src/cmd/dev.go b/src/cmd/dev.go index 765cd701..3f266993 100644 --- a/src/cmd/dev.go +++ b/src/cmd/dev.go @@ -71,8 +71,7 @@ var devDeployCmd = &cobra.Command{ // Deploy dev bundle bndlClient.SetDevSource(srcDir) - - deployWithoutTea(bndlClient) + deploy(bndlClient) }, } diff --git a/src/cmd/root.go b/src/cmd/root.go index 123f0a03..2fb5106d 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -75,7 +75,6 @@ func init() { v.SetDefault(V_INSECURE, false) v.SetDefault(V_TMP_DIR, "") v.SetDefault(V_BNDL_OCI_CONCURRENCY, 3) - v.SetDefault(V_NO_TEA, false) // by default use the BubbleTea TUI homeDir, _ := os.UserHomeDir() v.SetDefault(V_UDS_CACHE, filepath.Join(homeDir, config.UDSCache)) @@ -88,5 +87,4 @@ func init() { rootCmd.PersistentFlags().StringVar(&config.CommonOptions.TempDirectory, "tmpdir", v.GetString(V_TMP_DIR), lang.RootCmdFlagTempDir) rootCmd.PersistentFlags().BoolVar(&config.CommonOptions.Insecure, "insecure", v.GetBool(V_INSECURE), lang.RootCmdFlagInsecure) rootCmd.PersistentFlags().IntVar(&config.CommonOptions.OCIConcurrency, "oci-concurrency", v.GetInt(V_BNDL_OCI_CONCURRENCY), lang.CmdBundleFlagConcurrency) - rootCmd.PersistentFlags().BoolVar(&config.CommonOptions.NoTea, "no-tea", v.GetBool(V_NO_TEA), lang.RootCmdNoTea) } diff --git a/src/cmd/uds.go b/src/cmd/uds.go index 808dbea2..247c3b83 100644 --- a/src/cmd/uds.go +++ b/src/cmd/uds.go @@ -13,15 +13,12 @@ import ( "strings" "github.com/AlecAivazis/survey/v2" - tea "github.com/charmbracelet/bubbletea" "github.com/defenseunicorns/uds-cli/src/config" "github.com/defenseunicorns/uds-cli/src/config/lang" "github.com/defenseunicorns/uds-cli/src/pkg/bundle" - "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui/deploy" "github.com/defenseunicorns/zarf/src/pkg/message" goyaml "github.com/goccy/go-yaml" "github.com/spf13/cobra" - "golang.org/x/term" ) var createCmd = &cobra.Command{ @@ -68,29 +65,11 @@ var deployCmd = &cobra.Command{ return } } - // create new bundle client + + // create new bundle client and deploy bndlClient := bundle.NewOrDie(&bundleCfg) defer bndlClient.ClearPaths() - - // don't use bubbletea if --no-tea flag is set - if config.CommonOptions.NoTea { - deployWithoutTea(bndlClient) - return - } - - // start up bubbletea - m := deploy.InitModel(bndlClient) - - // detect tty so CI/containers don't break - if term.IsTerminal(int(os.Stdout.Fd())) { - deploy.Program = tea.NewProgram(&m) - } else { - deploy.Program = tea.NewProgram(&m, tea.WithInput(nil)) - } - - if _, err := deploy.Program.Run(); err != nil { - message.Fatalf(err, "TUI program error: %s", err.Error()) - } + deploy(bndlClient) }, } diff --git a/src/cmd/viper.go b/src/cmd/viper.go index d242a78c..07ad89c9 100644 --- a/src/cmd/viper.go +++ b/src/cmd/viper.go @@ -25,7 +25,6 @@ const ( V_TMP_DIR = "options.tmp_dir" V_INSECURE = "options.insecure" V_BNDL_OCI_CONCURRENCY = "options.oci_concurrency" - V_NO_TEA = "options.no_tea" // Bundle create config keys V_BNDL_CREATE_OUTPUT = "create.output" diff --git a/src/config/lang/lang.go b/src/config/lang/lang.go index 7d132bc3..ccd3bacc 100644 --- a/src/config/lang/lang.go +++ b/src/config/lang/lang.go @@ -15,7 +15,6 @@ const ( RootCmdFlagLogLevel = "Log level when running UDS-CLI. Valid options are: warn, info, debug, trace" RootCmdErrInvalidLogLevel = "Invalid log level. Valid options are: warn, info, debug, trace." RootCmdFlagArch = "Architecture for UDS bundles and Zarf packages" - RootCmdNoTea = "Don't use the BubbleTea TUI" // logs CmdBundleLogsShort = "View most recent UDS CLI logs" diff --git a/src/pkg/bundle/deploy.go b/src/pkg/bundle/deploy.go index 3f767ebb..653bd328 100644 --- a/src/pkg/bundle/deploy.go +++ b/src/pkg/bundle/deploy.go @@ -15,7 +15,6 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/defenseunicorns/pkg/helpers" "github.com/defenseunicorns/uds-cli/src/config" - "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui/deploy" "github.com/defenseunicorns/uds-cli/src/pkg/sources" "github.com/defenseunicorns/uds-cli/src/types" zarfConfig "github.com/defenseunicorns/zarf/src/config" @@ -77,11 +76,8 @@ func deployPackages(packages []types.Package, resume bool, b *Bundle) error { packagesToDeploy = packages } - // let TUI know how many packages are being deployed - deploy.Program.Send(fmt.Sprintf("totalPackages:%d", len(packagesToDeploy))) - // deploy each package - for i, pkg := range packagesToDeploy { + for _, pkg := range packagesToDeploy { sha := strings.Split(pkg.Ref, "@sha256:")[1] // using appended SHA from create! pkgTmp, err := utils.MakeTempDir(config.CommonOptions.TempDirectory) if err != nil { @@ -138,14 +134,10 @@ func deployPackages(packages []types.Package, resume bool, b *Bundle) error { return err } - deploy.Program.Send(fmt.Sprintf("newPackage:%s:%d", pkg.Name, i)) - if err := pkgClient.Deploy(); err != nil { return err } - deploy.Program.Send(fmt.Sprintf("complete:%d", i)) - // save exported vars pkgExportedVars := make(map[string]string) for _, exp := range pkg.Exports { diff --git a/src/pkg/bundle/tui/common.go b/src/pkg/bundle/tui/common.go deleted file mode 100644 index cdb47c40..00000000 --- a/src/pkg/bundle/tui/common.go +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023-Present The UDS Authors - -// Package tui contains logic for the TUI operations -package tui - -import ( - "time" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" -) - -const ( - // LIGHTBLUE is the common light blue color used in the TUI - LIGHTBLUE = lipgloss.Color("#4BFDEB") - - // LIGHTGRAY is the common light gray color used in the TUI - LIGHTGRAY = lipgloss.Color("#7A7A78") -) - -var ( - // IndentStyle is the style for indenting text - IndentStyle = lipgloss.NewStyle().Padding(0, 4) -) - -// Pause pauses the TUI for a short period of time -func Pause() tea.Cmd { - return tea.Tick(time.Millisecond*500, func(_ time.Time) tea.Msg { - return nil - }) -} diff --git a/src/pkg/bundle/tui/deploy/handlers.go b/src/pkg/bundle/tui/deploy/handlers.go deleted file mode 100644 index ae7b06b1..00000000 --- a/src/pkg/bundle/tui/deploy/handlers.go +++ /dev/null @@ -1,190 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023-Present The UDS Authors - -// Package deploy contains the TUI logic for bundle deploys -package deploy - -import ( - "fmt" - "os" - "strings" - - "github.com/charmbracelet/bubbles/spinner" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/defenseunicorns/uds-cli/src/config" - "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui" - "github.com/defenseunicorns/uds-cli/src/pkg/utils" - "github.com/defenseunicorns/zarf/src/pkg/cluster" - "github.com/defenseunicorns/zarf/src/pkg/message" - zarfTypes "github.com/defenseunicorns/zarf/src/types" -) - -func (m *Model) handleNewPackage(pkgName string, currentPkgIdx int) tea.Cmd { - // check if pkg has already been deployed - var deployedPkg *zarfTypes.DeployedPackage - if c != nil { - deployedPkg, _ = c.GetDeployedPackage(pkgName) - } else { - // keep checking for cluster connectivity - c, _ = cluster.NewCluster() - } - newPkg := pkgState{ - name: pkgName, - } - - // upgrade scenario, reset component progress - if deployedPkg != nil { - newPkg.resetProgress = true - } - - // finish creating newPkg and start the spinners - m.pkgIdx = currentPkgIdx - - // create spinner to track deployment progress - deploySpinner := spinner.New() - deploySpinner.Spinner = spinner.Dot - deploySpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205")) - newPkg.deploySpinner = deploySpinner - - // for remote packages, create spinner to track verification and download progress - verifySpinner := spinner.New() - verifySpinner.Spinner = spinner.Dot - verifySpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205")) - newPkg.verifySpinner = verifySpinner - downloadSpinner := spinner.New() - downloadSpinner.Spinner = spinner.Dot - downloadSpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205")) - newPkg.downloadSpinner = downloadSpinner - - m.packages = append(m.packages, newPkg) - return tea.Batch(m.packages[m.pkgIdx].deploySpinner.Tick, - m.packages[m.pkgIdx].verifySpinner.Tick, - m.packages[m.pkgIdx].downloadSpinner.Tick, - ) -} - -func (m *Model) handlePreDeploy() tea.Cmd { - cmd := func() tea.Msg { - name, bundleYAML, source, err := m.bndlClient.PreDeployValidation() - if err != nil { - m.errChan <- err - } - m.validatingBundle = false - m.bundleYAML = bundleYAML - m.bundleName = name - // check if the bundle is remote - if strings.HasPrefix(source, "oci://") { - m.isRemoteBundle = true - } - return doDeploy - } - - return cmd -} - -func (m *Model) handleDeploy() tea.Cmd { - // ensure bundle deployment is confirmed and is only being deployed once - if m.confirmed && !m.deploying { - // run Deploy concurrently so we can update the TUI while it runs - deployCmd := func() tea.Msg { - // if something goes wrong in Deploy(), reset the terminal - defer utils.GracefulPanic() - - if err := m.bndlClient.Deploy(); err != nil { - m.bndlClient.ClearPaths() - m.errChan <- err - } - return nil - } - m.deploying = true - - // use a ticker to update the TUI during deployment - return tea.Batch(tickCmd(), deployCmd) - } - return nil -} - -func (m *Model) handleDone(err error) tea.Cmd { - cmds := []tea.Cmd{tea.Println(), tea.Println(m.udsTitle()), tea.Println()} - m.done = true // remove the current view - cmds = append(cmds, genSuccessCmds(m)...) - if err != nil { - hint := lightBlueText.Render("uds logs") - message.Debug(err) // capture err in debug logs - errMsg := tui.IndentStyle.Render(fmt.Sprintf("\nāŒ Error deploying bundle: %s\n\nRun %s to view deployment logs", lightGrayText.Render(err.Error()), hint) + "\n") - cmds = []tea.Cmd{tea.Println(errMsg), tui.Pause(), tea.Quit} - return tea.Sequence(cmds...) - } - styledBundleName := lipgloss.NewStyle().Foreground(lipgloss.Color("#FFF258")).Render(m.bundleName) - successMsg := tea.Println( - tui.IndentStyle. - Render(fmt.Sprintf("\nāœØ Bundle %s deployed successfully\n", styledBundleName))) - cmds = append(cmds, successMsg, tui.Pause(), tea.Quit) - return tea.Sequence(cmds...) -} - -func (m *Model) handleDeployTick() (tea.Model, tea.Cmd) { - // check if all pkgs are complete - numComplete := 0 - if len(m.packages) == m.totalPkgs { - for _, p := range m.packages { - if !p.complete { - break - } - numComplete++ - } - } - - // check if last pkg is complete - if numComplete == m.totalPkgs { - return m, func() tea.Msg { - m.doneChan <- 1 - return nil - } - } - - // update component progress - for i, p := range m.packages { - if p.complete { - continue - } - - var deployedPkg *zarfTypes.DeployedPackage - if c != nil { - deployedPkg, _ = c.GetDeployedPackage(p.name) - } else { - // keep checking for cluster connectivity - c, _ = cluster.NewCluster() - } - - // if deployedPkg is nil, the package hasn't been deployed yet - if deployedPkg == nil { - break - } - // handle upgrade scenario by resetting the component progress, otherwise increment it - if p.resetProgress { - // if upgraded len(deployedPkg.DeployedComponents) will be equal to the number of components in the package - if deployedPkg != nil && len(deployedPkg.DeployedComponents) > 0 { - m.packages[i].resetProgress = false - } - break - } - // check component progress - for j := range deployedPkg.DeployedComponents { - // check numComponents bc there is a slight delay between rendering the TUI and updating this value - // also nil check the componentStatuses to avoid panic - componentSucceeded := deployedPkg.DeployedComponents[j].Status == zarfTypes.ComponentStatusSucceeded - if p.numComponents > 0 && len(p.componentStatuses) >= j && componentSucceeded { - m.packages[i].componentStatuses[j] = true - } - } - } - - // always update logViewport content with logs - file, _ := os.ReadFile(config.LogFileName) - m.logViewport.SetContent(string(file)) - m.logViewport.GotoBottom() - - return m, tickCmd() -} diff --git a/src/pkg/bundle/tui/deploy/model.go b/src/pkg/bundle/tui/deploy/model.go deleted file mode 100644 index 6148989d..00000000 --- a/src/pkg/bundle/tui/deploy/model.go +++ /dev/null @@ -1,298 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023-Present The UDS Authors - -// Package deploy contains the TUI logic for bundle deploys -package deploy - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/charmbracelet/bubbles/spinner" - "github.com/charmbracelet/bubbles/viewport" - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/defenseunicorns/uds-cli/src/config" - "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui" - "github.com/defenseunicorns/zarf/src/pkg/cluster" - "golang.org/x/term" -) - -type deployTickMsg time.Time -type deployOp string -type packageOp string - -const ( - doDeploy deployOp = "deploy" - doPreDeploy deployOp = "preDeploy" - newPackage packageOp = "newPackage" - totalComponents packageOp = "totalComponents" - totalPackages packageOp = "totalPackages" - complete packageOp = "complete" - verifying packageOp = "verifying" - downloading packageOp = "downloading" -) - -var ( - // Program is the Bubbletea TUI main program - Program *tea.Program - c *cluster.Cluster - logVpWidthScale = 0.9 - logVpHeightScale = 0.4 -) - -// private interface to decouple tui pkg from bundle pkg -type bndlClientShim interface { - Deploy() error - PreDeployValidation() (string, string, string, error) - ClearPaths() -} - -// pkgState contains the state of the pkg as its deploying -type pkgState struct { - name string - numComponents int - percLayersVerified int - componentStatuses []bool - deploySpinner spinner.Model - downloadSpinner spinner.Model - verifySpinner spinner.Model - complete bool - resetProgress bool - percDownloaded int - downloaded bool - verified bool -} - -// Model contains the state of the TUI -type Model struct { - bndlClient bndlClientShim - bundleYAML string - doneChan chan int - pkgIdx int - totalPkgs int - confirmed bool - done bool - packages []pkgState - deploying bool - inProgress bool - viewLogs bool - logViewport viewport.Model - errChan chan error - yamlViewport viewport.Model - isRemoteBundle bool - bundleName string - validatingBundle bool - validatingBundleSpinner spinner.Model -} - -// InitModel initializes the model for the TUI -func InitModel(client bndlClientShim) Model { - var confirmed bool - var inProgress bool - var isRemoteBundle bool - if config.CommonOptions.Confirm { - confirmed = true - inProgress = true - } - - // create spinner to track bundle validation - validatingBundleSpinner := spinner.New() - validatingBundleSpinner.Spinner = spinner.Ellipsis - validatingBundleSpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205")) - - // create cluster client for querying packages during deployment - c, _ = cluster.NewCluster() - - // set termWidth and line length based on window size - termWidth, termHeight, _ = term.GetSize(0) - - // make log viewport scale dynamic based on termHeight to prevent weird artifacts - if termHeight < 30 { - logVpHeightScale = 0.3 - } else { - logVpHeightScale = 0.4 - } - - // set up logViewport for logs, adjust width and height of logViewport - logViewport := viewport.New(int(float64(termWidth)*logVpWidthScale), int(float64(termHeight)*logVpHeightScale)) - - // set up yamlViewport to ensure the preDeploy YAML is scrollable - numYAMLLines := 10 - yamlViewport := viewport.New(termWidth, numYAMLLines) - - return Model{ - bndlClient: client, - doneChan: make(chan int), - errChan: make(chan error), - confirmed: confirmed, - inProgress: inProgress, - logViewport: logViewport, - yamlViewport: yamlViewport, - isRemoteBundle: isRemoteBundle, - validatingBundleSpinner: validatingBundleSpinner, - validatingBundle: true, - } -} - -// Init performs some action when BubbleTea starts up -func (m *Model) Init() tea.Cmd { - return func() tea.Msg { - return doPreDeploy - } -} - -// Update updates the model based on the message received -func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - select { - case err := <-m.errChan: - cmd := m.handleDone(err) - return m, cmd - case <-m.doneChan: - cmd := m.handleDone(nil) - return m, cmd - - default: - switch msg := msg.(type) { - - // handle changes in window size - case tea.WindowSizeMsg: - termWidth = msg.Width - termHeight = msg.Height - - // make log viewport scale dynamic based on termHeight to prevent weird artifacts - if termHeight < 30 { - logVpHeightScale = 0.3 - } else { - logVpHeightScale = 0.4 - } - m.logViewport.Width = int(float64(termWidth) * logVpWidthScale) - m.logViewport.Height = int(float64(termHeight) * logVpHeightScale) - - // spin the spinners - case spinner.TickMsg: - var spinDeploy, spinVerify, spinDownload, spinValidateBundle tea.Cmd - if len(m.packages) > m.pkgIdx { - m.packages[m.pkgIdx].deploySpinner, spinDeploy = m.packages[m.pkgIdx].deploySpinner.Update(msg) - m.packages[m.pkgIdx].verifySpinner, spinVerify = m.packages[m.pkgIdx].verifySpinner.Update(msg) - m.packages[m.pkgIdx].downloadSpinner, spinDownload = m.packages[m.pkgIdx].downloadSpinner.Update(msg) - } else { - m.validatingBundleSpinner, spinValidateBundle = m.validatingBundleSpinner.Update(msg) - } - return m, tea.Batch(spinDeploy, spinVerify, spinDownload, spinValidateBundle) - - // handle ticks - case deployTickMsg: - return m.handleDeployTick() - - // handle key presses - case tea.KeyMsg: - switch msg.String() { - case "y", "Y": - if !m.validatingBundle && !m.confirmed { - m.confirmed = true - m.inProgress = true - } - return m, func() tea.Msg { - return doDeploy - } - - case "n", "N": - if !m.validatingBundle && !m.confirmed && !m.inProgress { - m.done = true - quitMsg := tea.Println(tui.IndentStyle.Render("\nšŸ‘‹ Deployment cancelled")) - return m, tea.Sequence(quitMsg, tea.Println(), tea.Quit) - } - case "ctrl+c": - return m, tea.Sequence(tea.Quit) - - case "up": - if !m.confirmed { - m.yamlViewport.LineUp(1) - } - case "down": - if !m.confirmed { - m.yamlViewport.LineDown(1) - } - - case "l", "L": - if m.inProgress && !m.viewLogs { - m.viewLogs = true - } else if m.inProgress { - m.viewLogs = false - } - } - - // handle deploy - case deployOp: - switch msg { - case doDeploy: - cmd := m.handleDeploy() - return m, cmd - case doPreDeploy: - cmd := m.handlePreDeploy() - return m, tea.Sequence(m.validatingBundleSpinner.Tick, cmd) - } - - // handle package updates - case string: - if strings.Contains(msg, ":") { - switch packageOp(strings.Split(msg, ":")[0]) { - case newPackage: - pkgName := strings.Split(msg, ":")[1] - pkgIdx, _ := strconv.Atoi(strings.Split(msg, ":")[2]) - cmd := m.handleNewPackage(pkgName, pkgIdx) - return m, cmd - case totalComponents: - if tc, err := strconv.Atoi(strings.Split(msg, ":")[1]); err == nil { - m.packages[m.pkgIdx].numComponents = tc - m.packages[m.pkgIdx].componentStatuses = make([]bool, tc) - if m.isRemoteBundle { - m.packages[m.pkgIdx].downloaded = true - } - } - case totalPackages: - if totalPkgs, err := strconv.Atoi(strings.Split(msg, ":")[1]); err == nil { - m.totalPkgs = totalPkgs - } - case verifying: - if perc, err := strconv.Atoi(strings.Split(msg, ":")[1]); err == nil { - m.packages[m.pkgIdx].percLayersVerified = perc - if perc == 100 { - m.packages[m.pkgIdx].verified = true - } - } - case downloading: - if perc, err := strconv.Atoi(strings.Split(msg, ":")[1]); err == nil { - m.packages[m.pkgIdx].percDownloaded = perc - if perc == 100 { - m.packages[m.pkgIdx].downloaded = true - } - } - case complete: - m.packages[m.pkgIdx].complete = true - } - } - } - } - - return m, nil -} - -// View returns the view for the TUI -func (m *Model) View() string { - if m.done { - // no errors, clear the controlled Program's output - return "" - } else if m.validatingBundle { - validatingBundleMsg := lightGrayText.Render("Validating bundle") - return tui.IndentStyle.Render(fmt.Sprintf("\n%s %s", validatingBundleMsg, m.validatingBundleSpinner.View())) - } else if m.viewLogs { - return fmt.Sprintf("\n%s\n\n%s\n%s\n\n%s\n", m.udsTitle(), m.bundleDeployProgress(), logMsg, m.logView()) - } else if m.confirmed { - return fmt.Sprintf("\n%s\n\n%s\n%s\n%s\n", m.udsTitle(), m.bundleDeployProgress(), logMsg, m.deployView()) - } - return fmt.Sprintf("%s\n", m.preDeployView()) -} diff --git a/src/pkg/bundle/tui/deploy/model_test.go b/src/pkg/bundle/tui/deploy/model_test.go deleted file mode 100644 index 92b00d53..00000000 --- a/src/pkg/bundle/tui/deploy/model_test.go +++ /dev/null @@ -1,114 +0,0 @@ -package deploy - -import ( - "testing" - - tea "github.com/charmbracelet/bubbletea" - "github.com/stretchr/testify/require" -) - -func TestDeploy(t *testing.T) { - testPkgs := []pkgState{ - { - name: "test-pkg", - numComponents: 1, - componentStatuses: []bool{true}, - }, { - name: "test-pkg-2", - numComponents: 1, - componentStatuses: []bool{true}, - }, - } - initTestModel := func() *Model { - - m := InitModel(nil) - m.validatingBundle = false - m.totalPkgs = 2 - m.bundleName = "test-bundle" - m.logViewport.Width = 50 - m.logViewport.Height = 50 - m.bundleYAML = "fake bundle YAML" - return &m - } - - t.Run("test deploy", func(t *testing.T) { - m := initTestModel() - - // check pre-deploy view - view := m.View() - require.Contains(t, view, m.bundleYAML) - require.Contains(t, view, "Deploy this bundle? (y/n)") - - // simulate pressing 'y' key to confirm deployment - m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []int32{121}}) - view = m.View() - require.Contains(t, view, "UDS Bundle: test-bundle") - - // deploy first pkg in bundle with simulated components - m.Update("newPackage:test-pkg:0") - m.packages[m.pkgIdx].numComponents = 1 - m.packages[m.pkgIdx].componentStatuses = []bool{true} - view = m.View() - require.Contains(t, view, "Deploying bundle package (1 / 2)") - require.Contains(t, view, "Package test-pkg deploying (1 / 1 components)") - - // simulate package deployment completion - m.Update("complete:test-pkg") - //m.Update(deployTickMsg(time.Time{})) - view = m.View() - require.Contains(t, view, "Package test-pkg deployed") - require.NotContains(t, view, "Package test-pkg deploying") - - // deploy second pkg in bundle with simulated components - m.Update("newPackage:test-pkg-2:1") - m.packages[m.pkgIdx].numComponents = 1 - m.packages[m.pkgIdx].componentStatuses = []bool{true} - view = m.View() - require.Contains(t, view, "Deploying bundle package (2 / 2)") - require.Contains(t, view, "Package test-pkg-2 deploying (1 / 1 components)") - - // simulate package deployment completion - m.Update("complete:test-pkg-2") - view = m.View() - require.Contains(t, view, "Package test-pkg-2 deployed") - require.NotContains(t, view, "Package test-pkg-2 deploying") - }) - - t.Run("test toggle log view", func(t *testing.T) { - m := initTestModel() - - // simulate passing --confirm - m.inProgress = true - m.confirmed = true - m.packages = testPkgs - - view := m.View() - require.Contains(t, view, "Package test-pkg deploying (1 / 1 components)") - - // simulate pressing 'l' key to toggle logs - m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []int32{108}}) - - view = m.View() - require.Contains(t, view, "test-pkg package logs") - - // simulate pressing 'l' key to toggle logs - m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []int32{108}}) - - view = m.View() - require.NotContains(t, view, "test-pkg package logs") - }) - - t.Run("test deploy cancel", func(t *testing.T) { - m := initTestModel() - view := m.View() - require.Contains(t, view, "Deploy this bundle? (y/n)") - - // simulate pressing 'n' key to cancel deployment - m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []int32{110}}) - view = m.View() - - // model's view is cleared after canceling deployment - require.Equal(t, view, "") - }) - -} diff --git a/src/pkg/bundle/tui/deploy/views.go b/src/pkg/bundle/tui/deploy/views.go deleted file mode 100644 index 55ef3357..00000000 --- a/src/pkg/bundle/tui/deploy/views.go +++ /dev/null @@ -1,256 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2023-Present The UDS Authors - -// Package deploy contains the TUI logic for bundle deploys -package deploy - -import ( - "fmt" - "strings" - "time" - - tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/lipgloss" - "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui" - "github.com/fatih/color" - "github.com/goccy/go-yaml/lexer" - "github.com/goccy/go-yaml/printer" -) - -var ( - termWidth int - termHeight int - styledCheck = lipgloss.NewStyle().Foreground(lipgloss.Color("#00FF00")).Render("āœ”") - lightBlueText = lipgloss.NewStyle().Foreground(tui.LIGHTBLUE) - lightGrayText = lipgloss.NewStyle().Foreground(tui.LIGHTGRAY) - logMsg = tui.IndentStyle.Render(fmt.Sprintf("\n%s %s", - lightBlueText.Render(""), lightGrayText.Render("Toggle logs"))) -) - -var ( - titleStyle = func() lipgloss.Style { - b := lipgloss.RoundedBorder() - b.Right = "ā”œ" - return lipgloss.NewStyle().BorderStyle(b).Padding(0, 1) - }() -) - -func (m *Model) logView() string { - headerMsg := fmt.Sprintf("%s %s", lightBlueText.Render(m.packages[m.pkgIdx].name), lightGrayText.Render("package logs")) - return tui.IndentStyle.Render( - fmt.Sprintf("%s\n%s\n%s\n\n", m.logHeaderView(headerMsg), m.logViewport.View(), m.logFooterView()), - ) -} - -func (m *Model) yamlHeaderView() string { - upArrow := "ā–² " - styledUpArrow := lipgloss.NewStyle().Foreground(tui.LIGHTGRAY).Render(upArrow) - if !m.yamlViewport.AtTop() { - styledUpArrow = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFF258")).Render(upArrow) - } - headerLine := strings.Repeat("ā”€", max(0, m.logViewport.Width-lipgloss.Width(styledUpArrow)-1)) - return lipgloss.JoinHorizontal(lipgloss.Center, styledUpArrow, headerLine) -} - -func (m *Model) yamlFooterView() string { - downArrow := "ā–¼ " - styledDownArrow := lipgloss.NewStyle().Foreground(tui.LIGHTGRAY).Render(downArrow) - if !m.yamlViewport.AtBottom() { - styledDownArrow = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFF258")).Render(downArrow) - - } - footerLine := strings.Repeat("ā”€", max(0, m.logViewport.Width-lipgloss.Width(styledDownArrow)-1)) - return lipgloss.JoinHorizontal(lipgloss.Center, styledDownArrow, footerLine) -} - -func (m *Model) logHeaderView(msg string) string { - title := titleStyle.Render(msg) - if msg == "" { - title = "" - } - headerLine := strings.Repeat("ā”€", max(0, m.logViewport.Width-lipgloss.Width(title)-1)) - return lipgloss.JoinHorizontal(lipgloss.Center, title, headerLine) -} - -func (m *Model) logFooterView() string { - footerLine := strings.Repeat("ā”€", max(0, m.logViewport.Width)-1) - return lipgloss.JoinHorizontal(lipgloss.Center, footerLine) -} - -func (m *Model) deployView() string { - view := "" - for _, p := range m.packages { - // count number of successful components - numComponentsSuccess := 0 - if !p.resetProgress { - for _, status := range p.componentStatuses { - if status { - numComponentsSuccess++ - } - } - } - - var text string - if m.isRemoteBundle { - text = genRemotePkgText(p, numComponentsSuccess) - } else { - text = genLocalPkgText(p, numComponentsSuccess) - } - - if p.complete { - text = tui.IndentStyle. - Align(lipgloss.Left). - Render(fmt.Sprintf("%s Package %s deployed", styledCheck, lightBlueText.Render(p.name))) - } - - view = lipgloss.JoinVertical(lipgloss.Left, view, text+"\n") - } - - return view -} - -func genLocalPkgText(p pkgState, numComponentsSuccess int) string { - text := "" - styledName := lightBlueText.Render(p.name) - styledComponents := lightGrayText.Render(fmt.Sprintf("(%d / %d components)", min(numComponentsSuccess+1, p.numComponents), p.numComponents)) - if p.numComponents > 0 { - text = tui.IndentStyle. - Align(lipgloss.Left). - Render(fmt.Sprintf("%s Package %s deploying %s", p.deploySpinner.View(), styledName, styledComponents)) - } else { - text = tui.IndentStyle. - Align(lipgloss.Left). - Render(fmt.Sprintf("%s Package %s deploying", p.deploySpinner.View(), styledName)) - } - return text -} - -func genRemotePkgText(p pkgState, numComponentsSuccess int) string { - text := "" - styledName := lightBlueText.Render(p.name) - styledComponents := lightGrayText.Render(fmt.Sprintf("(%d / %d components)", min(numComponentsSuccess+1, p.numComponents), p.numComponents)) - if !p.verified { - perc := lightGrayText.Render(fmt.Sprintf("(%d%%)", p.percLayersVerified)) - text = tui.IndentStyle. - Align(lipgloss.Left). - Render(fmt.Sprintf("%sVerifying %s package %s", p.verifySpinner.View(), styledName, perc)) - } else if p.verified && !p.downloaded { - perc := lightGrayText.Render(fmt.Sprintf("(%d%%)", p.percDownloaded)) - text = tui.IndentStyle. - Align(lipgloss.Left). - Render(fmt.Sprintf("%sDownloading %s package %s", p.downloadSpinner.View(), styledName, perc)) - } else if p.downloaded && p.verified && p.numComponents > 0 { - text = tui.IndentStyle. - Align(lipgloss.Left). - Render(fmt.Sprintf("%sDeploying %s package %s", p.deploySpinner.View(), styledName, styledComponents)) - } else { - text = tui.IndentStyle. - Align(lipgloss.Left). - Render(fmt.Sprintf("%sDeploying %s package", p.deploySpinner.View(), styledName)) - } - - return text -} - -func (m *Model) preDeployView() string { - header := tui.IndentStyle.Render("šŸ“¦ Bundle Definition (ā–² / ā–¼)") - prompt := tui.IndentStyle.Render("ā“ Deploy this bundle? (y/n)") - prettyYAML := tui.IndentStyle.Render(colorPrintYAML(m.bundleYAML)) - m.yamlViewport.SetContent(prettyYAML) - - // Concatenate header, highlighted YAML, and prompt - return fmt.Sprintf("\n%s\n\n%s\n\n%s\n%s\n%s\n\n%s", - m.udsTitle(), - header, - tui.IndentStyle.Render(m.yamlHeaderView()), - tui.IndentStyle.Render(m.yamlViewport.View()), - tui.IndentStyle.Render(m.yamlFooterView()), - prompt, - ) -} - -func tickCmd() tea.Cmd { - return tea.Tick(time.Millisecond*250, func(t time.Time) tea.Msg { - return deployTickMsg(t) - }) -} - -// colorPrintYAML makes a pretty-print YAML string with color -func colorPrintYAML(yaml string) string { - tokens := lexer.Tokenize(yaml) - - var p printer.Printer - p.Bool = func() *printer.Property { - return &printer.Property{ - Prefix: yamlFormat(color.FgHiWhite), - Suffix: yamlFormat(color.Reset), - } - } - p.Number = func() *printer.Property { - return &printer.Property{ - Prefix: yamlFormat(color.FgHiWhite), - Suffix: yamlFormat(color.Reset), - } - } - p.MapKey = func() *printer.Property { - return &printer.Property{ - Prefix: yamlFormat(color.FgHiCyan), - Suffix: yamlFormat(color.Reset), - } - } - p.Anchor = func() *printer.Property { - return &printer.Property{ - Prefix: yamlFormat(color.FgHiYellow), - Suffix: yamlFormat(color.Reset), - } - } - p.Alias = func() *printer.Property { - return &printer.Property{ - Prefix: yamlFormat(color.FgHiYellow), - Suffix: yamlFormat(color.Reset), - } - } - p.String = func() *printer.Property { - return &printer.Property{ - Prefix: yamlFormat(color.FgHiMagenta), - Suffix: yamlFormat(color.Reset), - } - } - - outputYAML := p.PrintTokens(tokens) - return outputYAML -} - -func yamlFormat(attr color.Attribute) string { - const yamlEscape = "\x1b" - return fmt.Sprintf("%s[%dm", yamlEscape, attr) -} - -// udsTitle returns the title header for the UDS bundle -func (m *Model) udsTitle() string { - styledBundleName := lipgloss.NewStyle().Foreground(lipgloss.Color("#FFF258")).Render(m.bundleName + " ") - title := " UDS Bundle: " - styledTitle := lipgloss.NewStyle().Margin(0, 3). - Padding(1, 0). - Border(lipgloss.RoundedBorder()). - BorderForeground(lipgloss.Color("#6233f2")). - Render(fmt.Sprintf("%s%s", title, styledBundleName)) - return styledTitle -} - -// genSuccessCmds generates the success or failure messages for each package -func genSuccessCmds(m *Model) []tea.Cmd { - var cmds []tea.Cmd - for i := 0; i < len(m.packages); i++ { - successMsg := fmt.Sprintf("%s Package %s deployed\n", styledCheck, lightBlueText.Render(m.packages[i].name)) - cmds = append(cmds, tea.Println(tui.IndentStyle.Render(successMsg))) - } - return cmds -} - -func (m *Model) bundleDeployProgress() string { - styledText := lightGrayText.Render("šŸ“¦ Deploying bundle package") - styledPkgCounter := lightGrayText.Render(fmt.Sprintf("(%d / %d)", m.pkgIdx+1, m.totalPkgs)) - msg := fmt.Sprintf("%s %s", styledText, styledPkgCounter) - return tui.IndentStyle.Render(msg) -} diff --git a/src/pkg/sources/remote.go b/src/pkg/sources/remote.go index 5c4d8746..aad9c576 100644 --- a/src/pkg/sources/remote.go +++ b/src/pkg/sources/remote.go @@ -13,7 +13,6 @@ import ( "github.com/defenseunicorns/pkg/oci" "github.com/defenseunicorns/uds-cli/src/config" - "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui/deploy" "github.com/defenseunicorns/uds-cli/src/pkg/cache" "github.com/defenseunicorns/uds-cli/src/pkg/utils" "github.com/defenseunicorns/zarf/src/pkg/layout" @@ -58,10 +57,6 @@ func (r *RemoteBundle) LoadPackage(dst *layout.PackagePaths, filter filters.Comp return pkg, nil, err } - // record number of components to be deployed for TUI - // todo: won't work for optional components...... - deploy.Program.Send(fmt.Sprintf("totalComponents:%d", len(pkg.Components))) - dst.SetFromLayers(layers) err = sources.ValidatePackageIntegrity(dst, pkg.Metadata.AggregateChecksum, r.isPartial) @@ -189,7 +184,6 @@ func (r *RemoteBundle) downloadPkgFromRemoteBundle() ([]ocispec.Descriptor, erro layersToPull := []ocispec.Descriptor{pkgManifestDesc} layersInBundle := []ocispec.Descriptor{pkgManifestDesc} numLayersVerified := 0.0 - downloadedBytes := int64(0) for _, layer := range pkgManifest.Layers { ok, err := r.Remote.Repo().Blobs().Exists(ctx, layer) @@ -199,8 +193,6 @@ func (r *RemoteBundle) downloadPkgFromRemoteBundle() ([]ocispec.Descriptor, erro progressBar.Add(1) numLayersVerified++ if ok { - percVerified := numLayersVerified / float64(len(pkgManifest.Layers)) * 100 - deploy.Program.Send(fmt.Sprintf("verifying:%v", int64(percVerified))) estimatedBytes += layer.Size layersInBundle = append(layersInBundle, layer) digest := layer.Digest.Encoded() @@ -229,13 +221,6 @@ func (r *RemoteBundle) downloadPkgFromRemoteBundle() ([]ocispec.Descriptor, erro doneSaving := make(chan error) go zarfUtils.RenderProgressBarForLocalDirWrite(r.TmpDir, estimatedBytes, doneSaving, fmt.Sprintf("Pulling bundled Zarf pkg: %s", r.PkgName), fmt.Sprintf("Successfully pulled package: %s", r.PkgName)) - copyOpts.PostCopy = func(_ context.Context, desc ocispec.Descriptor) error { - downloadedBytes += desc.Size - downloadedPerc := float64(downloadedBytes) / float64(estimatedBytes) * 100 - deploy.Program.Send(fmt.Sprintf("downloading:%d", int64(downloadedPerc))) - return nil - } - _, err = oras.Copy(ctx, r.Remote.Repo(), r.Remote.Repo().Reference.String(), store, "", copyOpts) doneSaving <- err <-doneSaving diff --git a/src/pkg/sources/tarball.go b/src/pkg/sources/tarball.go index 3768050f..f4ab220c 100644 --- a/src/pkg/sources/tarball.go +++ b/src/pkg/sources/tarball.go @@ -14,7 +14,6 @@ import ( "github.com/defenseunicorns/pkg/helpers" "github.com/defenseunicorns/pkg/oci" - "github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui/deploy" "github.com/defenseunicorns/zarf/src/pkg/layout" "github.com/defenseunicorns/zarf/src/pkg/message" "github.com/defenseunicorns/zarf/src/pkg/packager/filters" @@ -71,10 +70,6 @@ func (t *TarballBundle) LoadPackage(dst *layout.PackagePaths, filter filters.Com dst.SetFromPaths(files) - // record number of components to be deployed for TUI - // todo: won't work for optional components...... - deploy.Program.Send(fmt.Sprintf("totalComponents:%d", len(pkg.Components))) - if err := sources.ValidatePackageIntegrity(dst, pkg.Metadata.AggregateChecksum, t.isPartial); err != nil { return zarfTypes.ZarfPackage{}, nil, err } diff --git a/src/pkg/utils/utils.go b/src/pkg/utils/utils.go index fbe0badf..6e4f74c4 100644 --- a/src/pkg/utils/utils.go +++ b/src/pkg/utils/utils.go @@ -10,7 +10,6 @@ import ( "fmt" "io" "os" - "os/exec" "path/filepath" "regexp" "strconv" @@ -25,19 +24,6 @@ import ( "github.com/spf13/cobra" ) -// GracefulPanic in the event of a panic, attempt to reset the terminal using the 'reset' command. -func GracefulPanic() { - if r := recover(); r != nil { - fmt.Println("Recovering from panic to reset terminal before exiting") - // todo: this approach is heavy-handed, consider alternatives using the term lib (check out what BubbleTea does) - cmd := exec.Command("reset") - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - _ = cmd.Run() - panic(r) - } -} - // IsValidTarballPath returns true if the path is a valid tarball path to a bundle tarball func IsValidTarballPath(path string) bool { if helpers.InvalidPath(path) || helpers.IsDir(path) { @@ -64,7 +50,6 @@ func ConfigureLogs(cmd *cobra.Command) error { logFile := writer if err != nil { return err - } tmpLogLocation := message.LogFileLocation() config.LogFileName = tmpLogLocation @@ -83,20 +68,10 @@ func ConfigureLogs(cmd *cobra.Command) error { logWriter := io.MultiWriter(logFile) - // use Zarf pterm output if no-tea flag is set - // todo: as more bundle ops use BubbleTea, need to also check them alongside 'deploy' - if !(strings.HasPrefix(cmd.Parent().Use, "uds") && strings.HasPrefix(cmd.Use, "deploy")) || config.CommonOptions.NoTea { - message.Notef("Saving log file to %s", tmpLogLocation) - logWriter = io.MultiWriter(os.Stderr, logFile) - pterm.SetDefaultOutput(logWriter) - return nil - } - + // use Zarf pterm output + message.Notef("Saving log file to %s", tmpLogLocation) + logWriter = io.MultiWriter(os.Stderr, logFile) pterm.SetDefaultOutput(logWriter) - - // disable progress bars (otherwise they will still get printed to STDERR) - message.NoProgress = true - message.Debugf(fmt.Sprintf("Saving log file to %s", tmpLogLocation)) return nil } diff --git a/src/test/e2e/commands_test.go b/src/test/e2e/commands_test.go index bcc89fda..891cf145 100644 --- a/src/test/e2e/commands_test.go +++ b/src/test/e2e/commands_test.go @@ -106,14 +106,7 @@ func inspectLocalAndSBOMExtract(t *testing.T, tarballPath string) { } func deploy(t *testing.T, tarballPath string) (stdout string, stderr string) { - cmd := strings.Split(fmt.Sprintf("deploy %s --retries 1 --confirm --no-tea", tarballPath), " ") - stdout, stderr, err := e2e.UDS(cmd...) - require.NoError(t, err) - return stdout, stderr -} - -func deployWithTUI(t *testing.T, source string) (stdout string, stderr string) { - cmd := strings.Split(fmt.Sprintf("deploy %s --confirm", source), " ") + cmd := strings.Split(fmt.Sprintf("deploy %s --retries 1 --confirm", tarballPath), " ") stdout, stderr, err := e2e.UDS(cmd...) require.NoError(t, err) return stdout, stderr @@ -141,13 +134,13 @@ func runCmd(t *testing.T, input string) (stdout string, stderr string) { } func deployPackagesFlag(tarballPath string, packages string) (stdout string, stderr string) { - cmd := strings.Split(fmt.Sprintf("deploy %s --confirm -l=debug --packages %s --no-tea", tarballPath, packages), " ") + cmd := strings.Split(fmt.Sprintf("deploy %s --confirm -l=debug --packages %s", tarballPath, packages), " ") stdout, stderr, _ = e2e.UDS(cmd...) return stdout, stderr } func deployResumeFlag(t *testing.T, tarballPath string) { - cmd := strings.Split(fmt.Sprintf("deploy %s --confirm -l=debug --resume --no-tea", tarballPath), " ") + cmd := strings.Split(fmt.Sprintf("deploy %s --confirm -l=debug --resume", tarballPath), " ") _, _, err := e2e.UDS(cmd...) require.NoError(t, err) } @@ -165,7 +158,7 @@ func removePackagesFlag(tarballPath string, packages string) (stdout string, std } func deployInsecure(t *testing.T, ref string) { - cmd := strings.Split(fmt.Sprintf("deploy %s --insecure --confirm --no-tea", ref), " ") + cmd := strings.Split(fmt.Sprintf("deploy %s --insecure --confirm", ref), " ") _, _, err := e2e.UDS(cmd...) require.NoError(t, err) } @@ -182,7 +175,7 @@ func deployAndRemoveLocalAndRemoteInsecure(t *testing.T, ref string, tarballPath t.Run( "deploy+remove bundle via OCI", func(t *testing.T) { - cmd = strings.Split(fmt.Sprintf("deploy %s --insecure --confirm --no-tea", ref), " ") + cmd = strings.Split(fmt.Sprintf("deploy %s --insecure --confirm", ref), " ") _, _, err := e2e.UDS(cmd...) require.NoError(t, err) @@ -195,7 +188,7 @@ func deployAndRemoveLocalAndRemoteInsecure(t *testing.T, ref string, tarballPath t.Run( "deploy+remove bundle via local tarball", func(t *testing.T) { - cmd = strings.Split(fmt.Sprintf("deploy %s --confirm --no-tea", tarballPath), " ") + cmd = strings.Split(fmt.Sprintf("deploy %s --confirm", tarballPath), " ") _, _, err := e2e.UDS(cmd...) require.NoError(t, err) diff --git a/src/test/e2e/main_test.go b/src/test/e2e/main_test.go index a15b5758..b02688ca 100644 --- a/src/test/e2e/main_test.go +++ b/src/test/e2e/main_test.go @@ -115,7 +115,7 @@ func deployZarfInit(t *testing.T) { require.NoError(t, err) // Deploy - cmd = strings.Split(fmt.Sprintf("deploy %s --confirm -l=debug --no-tea", bundlePath), " ") + cmd = strings.Split(fmt.Sprintf("deploy %s --confirm -l=debug", bundlePath), " ") _, _, err = e2e.UDS(cmd...) require.NoError(t, err) } diff --git a/src/test/e2e/tui_test.go b/src/test/e2e/tui_test.go deleted file mode 100644 index fe13093e..00000000 --- a/src/test/e2e/tui_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package test - -import ( - "fmt" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestBundleDeploy(t *testing.T) { - deployZarfInit(t) - e2e.CreateZarfPkg(t, "src/test/packages/podinfo", false) - - source := "ghcr.io/defenseunicorns/packages/uds-cli/test/publish/ghcr-test:0.0.1" - stdout, _ := deployWithTUI(t, source) - require.Contains(t, stdout, "Validating bundle") - require.Contains(t, stdout, "UDS Bundle: ghcr-test") - require.Contains(t, stdout, "Verifying podinfo package (0%)") - require.Contains(t, stdout, "Downloading podinfo package (0%)") - require.Contains(t, stdout, "Deploying podinfo package (1 / 1 components)") - require.Contains(t, stdout, "Deploying nginx package (1 / 1 components)") - require.Contains(t, stdout, "āœ” Package podinfo deployed") - require.Contains(t, stdout, "āœ” Package nginx deployed") - require.Contains(t, stdout, "Verifying nginx package (0%)") - require.Contains(t, stdout, "Downloading nginx package (0%)") - require.Contains(t, stdout, "āœØ Bundle ghcr-test deployed successfully") - remove(t, source) -} - -func TestBundleDeployWithBadSource(t *testing.T) { - deployZarfInit(t) - e2e.CreateZarfPkg(t, "src/test/packages/podinfo", false) - - source := "a.bad.source:0.0.1" - stdout, _ := deployWithTUI(t, source) - require.Contains(t, stdout, "āŒ Error deploying bundle: a.bad.source:0.0.1: not found") -} - -func TestBundleDeployWithBadPkg(t *testing.T) { - deployZarfInit(t) - - // deploy a good pkg - source := "ghcr.io/defenseunicorns/packages/uds-cli/test/publish/ghcr-test:0.0.1 --packages=nginx" - stdout, _ := deployWithTUI(t, source) - require.Contains(t, stdout, "āœØ Bundle ghcr-test deployed successfully") - - // attempt to deploy a conflicting pkg - e2e.CreateZarfPkg(t, "src/test/packages/gitrepo", false) - bundleDir := "src/test/bundles/05-gitrepo" - bundlePath := filepath.Join(bundleDir, fmt.Sprintf("uds-bundle-gitrepo-%s-0.0.1.tar.zst", e2e.Arch)) - - createLocal(t, bundleDir, e2e.Arch) - stdout, _ = deployWithTUI(t, bundlePath) - require.Contains(t, stdout, "āŒ Error deploying bundle: unable to deploy component \"nginx-remote\": unable to install helm chart") - require.Contains(t, stdout, "Run uds logs to view deployment logs") - remove(t, source) -} diff --git a/src/test/e2e/variable_test.go b/src/test/e2e/variable_test.go index f79772ec..7ff5be77 100644 --- a/src/test/e2e/variable_test.go +++ b/src/test/e2e/variable_test.go @@ -52,19 +52,19 @@ func bundleVariablesTestChecks(t *testing.T, stderr string, bundleTarballPath st require.Contains(t, stderr, "shared var in output-var pkg: burning.boats") require.Contains(t, stderr, "shared var in receive-var pkg: burning.boats") - _, stderr = runCmd(t, "deploy "+bundleTarballPath+" --set ANIMAL=Longhorns --set COUNTRY=Texas --confirm -l=debug --no-tea") + _, stderr = runCmd(t, "deploy "+bundleTarballPath+" --set ANIMAL=Longhorns --set COUNTRY=Texas --confirm -l=debug") require.Contains(t, stderr, "This fun-fact was imported: Longhorns are the national animal of Texas") require.NotContains(t, stderr, "This fun-fact was imported: Unicorns are the national animal of Scotland") - _, stderr = runCmd(t, "deploy "+bundleTarballPath+" --set output-var.SPECIFIC_PKG_VAR=output-var-set --confirm -l=debug --no-tea") + _, stderr = runCmd(t, "deploy "+bundleTarballPath+" --set output-var.SPECIFIC_PKG_VAR=output-var-set --confirm -l=debug") require.Contains(t, stderr, "output-var SPECIFIC_PKG_VAR = output-var-set") require.Contains(t, stderr, "receive-var SPECIFIC_PKG_VAR = not-set") - _, stderr = runCmd(t, "deploy "+bundleTarballPath+" --set output-var.specific_pkg_var=output --set receive-var.SPECIFIC_PKG_VAR=receive --confirm -l=debug --no-tea") + _, stderr = runCmd(t, "deploy "+bundleTarballPath+" --set output-var.specific_pkg_var=output --set receive-var.SPECIFIC_PKG_VAR=receive --confirm -l=debug") require.Contains(t, stderr, "output-var SPECIFIC_PKG_VAR = output") require.Contains(t, stderr, "receive-var SPECIFIC_PKG_VAR = receive") - _, stderr = runCmd(t, "deploy "+bundleTarballPath+" --set SPECIFIC_PKG_VAR=errbody --confirm -l=debug --no-tea") + _, stderr = runCmd(t, "deploy "+bundleTarballPath+" --set SPECIFIC_PKG_VAR=errbody --confirm -l=debug") require.Contains(t, stderr, "output-var SPECIFIC_PKG_VAR = errbody") require.Contains(t, stderr, "receive-var SPECIFIC_PKG_VAR = errbody") } diff --git a/src/types/options.go b/src/types/options.go index d2a5cbdc..0c9285ae 100644 --- a/src/types/options.go +++ b/src/types/options.go @@ -70,7 +70,6 @@ type BundleCommonOptions struct { CachePath string `json:"cachePath" jsonschema:"description=Path to use to cache images and git repos on package create"` TempDirectory string `json:"tempDirectory" jsonschema:"description=Location Zarf should use as a staging ground when managing files and images for package creation and deployment"` OCIConcurrency int `jsonschema:"description=Number of concurrent layer operations to perform when interacting with a remote package"` - NoTea bool `json:"useTea" jsonschema:"description=Don't use BubbleTea TUI"` } // PathMap is a map of either absolute paths to relative paths or relative paths to absolute paths