From bfc0e13e8e19bd7d89675f180557a40205e1a369 Mon Sep 17 00:00:00 2001 From: Jheison Martinez Bolivar Date: Tue, 18 Aug 2026 09:33:03 -0500 Subject: [PATCH 1/8] docs(readme): point the demo at the current recording and drop the stale copy --- README.md | 2 +- assets/demo.gif | Bin 249221 -> 0 bytes 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 assets/demo.gif diff --git a/README.md b/README.md index a224115..7b1922c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Set up a git repo the way you actually work — one guided flow for hooks, `.git ### Demo -![Demo](assets/demo.gif) +![Demo](demo/dist/demo.gif) --- diff --git a/assets/demo.gif b/assets/demo.gif deleted file mode 100644 index 004babdcee6828e93475947ed6db400fe26d4907..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 249221 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�&x3 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≈x5=^w09xjWF81T09L0)^Wis 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�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 nXKTi6^P0$r=95xr@eBr9#=$a>eM^Md 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

rMI{+j)w ze;m;=v>I<~AKdYlXbnAn5$y8hkm>+m_TUR_2bv1aT#?&{!pJ$V)%EMf_9d?3u#7s5 zpWz5~b_5_W&X_i3VUPmItc(R(KIK*hkeBVRT(uQLp`$fo<17=B{8L3NA|Th3m9s4^ zNRUwM4QYlVPZWX13{`%(O5Q!b}1)QOu+<6ZMZS`=2bc$Nz0n!iH7(Ot!g(G&o{}7IhbtWaf4)4VLXT zSollF2Jo>QPz=lh1l*PeGN=QLO>-1v5JYV#JAOplF|6*sXGFZ*UseC-LBHnzj^%$- z3?{S8;F*Y+SeU^x3H=AZ%`Hr%OgK!K|24n=Rx!Fcn2G`Ur(%fxQ!zAQ2s-({Qw$En zf3Fz-T&8aPAAtT!Ig=J956sSDvh{ZA zY~JUxuj*Dw{_GAep1P@j{Px8!cc)qYV4(kNQN76wQ29TJA2Z2+i;5W?Gpo$x|5fk5 zF*1W?#>fni$pSO9zXrnps6{gWDSl<7rY6G={U;T3f`2azw$vQT?CqsBtp8k1(krSW z%l^q7p9Tow%QRh|hqHqd;Iu>+?|bL`sU}pC(t`<^=bb&PgKwu|UdOIO*TRSwBqQTM z9%hL~=b}bvy1-fKQjye!45MKf59{9U`oW_USek9zplBzr+jGfKk?`P|KiUQEZVo% zQgbKcelPjy_h9JR2Tqf*Q#KVnU<|sQ3=12h^ef@u_)xSmXHxK_<4gcvG{X_OACzwUc zECpsx{@eQeSE~bJ|DToLgvZ=Dj+fA|YTin6oQH|PSV`SITu|-I+g`)3RmTMJEX+sO z;B`s`gUQ^qZP9Ab5ZPLj;=k_jsKq|t?%3rNC~ z47a6ApIgccK3U5K z)1mrnRWaSnzwRf~s$#lQ|MWT&m~Iu*`egc7Op}UfTm8SWst<@1hIgX|$KVPvHw3`~ zy3Vwr9ILp}DRYY9H^|q0cwn(zi5>R2$8L5d$w8J||BVfm2!ntjJnRuRhz z{cA&|lyf^FSXOOVSMye{+u3i~fHrQJ*#XR{z=OcX27vytBHN}aQ%k(7X@i;<&LtB& z)YzM%tB8vUBpF5$21BGIBua-UNBt^U0h@romYH9zCIb1V|HFkcbW89V-+9!35OoFC z# zGGA8!X$lTDcTCQ;9kjwJ)P+x79m-TF|7$}Jnzdo zBtbtTaEI=tDdcI=Szs>2)Aj`JYQA{~?o=>YB1!TpN-gk{6rFGXYeR_zs4X7*0cc-I zAf&H8fn!K`3UU;i3bdb z^f0(g$D0V6RK32)bfGqAnpSX$D{+=>b;kY`t}iH7FHArOVt}wTizVojlhy*-i(Jc> zOt!xA+C}+}vp5(v-aV2*BjAaWmz`v2Qp5VPE4jw}LAB!6mv_D63Uwl``74ptZ@2XR^GmDv7GqO05Xygh-Ua{YjRsrB1o^ zml$IV>;^BOL%@Mc3z1US18EAVUSfacoEs*lk-r z={Wpr36Gb%xgMy7)UWX6vBr$`Fo;Wo_7qh4HH%ijyh>9W1VYm&U`MeAAbmt6)*qC2 zcl0Io$fcsY;W zuN6Oa?;P)rCK4>qAKlMCwvZ;%+P!@K(Nru3ZcpcNiq`g=1?NBD+f}}=ytThhOATY! z;np5X1#xn06D_N|wtjqQ8&&@Kv2!Nu;OA!ddh5@vzVBNEQa)SJz;$$rJ6j3}pn09w6=>MNEE*uK6EqsS z?#g>?8}MdXgCQdTl^mXMFi^~*0yE@SBLe8X9D?$m0PL_|5)fDw+P^LKwc9N9=bkf* z3g$NVpVdTEn)fcMW60!}OuCx2xnhG1$3a`0{-5zha94@m4;^ndKKO|{Kw>Uk(FlMv z8!HTAjtm-~Vh>Ii7Ca=IZmMyRWe9`Ugh*m>TsBoUO9gKQg{0HDZzKS`xs;Hh_38^C z=FoT%z(WLN5e8b!awm^sKRp*#8mk8@tUQoj0z{}GxFgR%c4EV0X39PJF?{T+EymJG z(~oy_2IX>Bj}&Bd4Sn>BYhOM2P#bZ?WK93fauP(jO-E&AT{B46rurpA;(LRC>gsro z`q`2!&`P}&S1h+0#GbRon3HPbLWd;rDJdML@ok5g{H&+g7S&o`qM1u2%aheutQW7` zwV+1 zWu5y=vqUh#FbeEzAd?1(*UQ^b{Fz#lWS(F3Lnlo#xRA%l@fIps_g$;CbW&k@w7f|B z6k))>{rai4BUZ>@4Cm5OkBd9(t=<_c4{^v{+-{pj0R=1%FldOXaJS0~V`Ou)(POxq zm9zH8((gK3-RrzwZkXxv#PJxvXe65X^y-)w{$*l0zSTpGMhVEA=}x!YUjYrRAf9iVmY(1?adj8Lg5Tme=Nz4u5;#u=* zeMnI&?}DJ{9$31%Tz*(~&zCK8?la)e_7*@Ai?4 z#c^MUl4)AO&bx*0E1j~k=;^{9C0%do02Oo1TI~Os(VXLL| zQ2*AM=AW;(r6IlkYg@6eelF}yboGCK^6BEwpKk!}ZaS;&c7pJ)MYvt}puj}<>ftS} zV=YGf!hy*n`X1Z@GwyF5=I$tjh=`4!>K;3B9G#ik_x957%6lBa=-h(=1KHD~qXWn@ zmn#pi@JKHD1Zsb-P^ey!t~7kI^f5&$dSmU9%OK;-a76jDUu(FVT|QY`Uz%8b-rCMw z6<&LCAiMh{9%FElMw}6%3b@C#r-wA_|1Zuf+;l5)UU2X&m@-@~BiQ1U6I#ONQ*Prmy zN*E|>LQ=$xut%VSQ{NtesK4ufxc>w$!5pxa1Q0Jn-J3!}m`5B#9;u)RST4hP3BbYa zJ4W0Ma@o25=XgNn9T#5DNI$2m3r_)+gtOyk6TZ$wa0>u++wSwXd6lRTbBb8#6xZBI z!OP)*0}}7gD*FKGIpHr{Gy}2t1{4k~LW-Z~J(7M>5Jd!zMmpRs6fR|m-N=o` zMwq!X+=D675JxfQ-~&{9Vgs_qXGuE?)$3b6CLW9U0;!^+yEly*c zy%2bjH4Dc-jq6S<4dYSI_+w%+8lF4fz+?w##YS#8 zyb=g2q^2t3rEX%N@2QE77--^T;_M-zJgFq(2Wi9kStYdOZESie0BsIWKDVRYNW9!c zPkx%pW0ib)3hnfMz-#tUPPJ?{|9F)6jJ698=ua%}eHzD=l|*|&THglBfq|MNaXEZR zmj|WP(36&~Kz4SJxyW=6vLN_eYB5P7=V(EWy1Zx*%=rsjM<)!$1F{H+`b0(2+hDIt zQdFqC8ncML_yLbI*}Lm);reM1bUs;h_+`?^o9| z7CH}B3uRw;5o(J=-Z}7Xi%Yu{jj=|ZK3gPp+w?#XK?ZfrSiPbI36U)D+Cve ztHM9j(bdWpK6U0So|Z;2l6YCI{G*y6RHLR_qv2Mg8CRoSR-@ZfbNFS=5jXW}tTcq6 zDjX4?5Q~b#B1UIe8}E{-f^tS>m7*D}q*Kt9FEuWw*sZE#==NN%1`@(n6a0yXcmrb` zU)E+|V9kNm+-|VuG$|il=w(*8Oj+If-THS<;$E)RL)-4YS{iYb>u#(U&u!O}O6#rT z8e%NV6l2rGNjTo`NkSkJL9&cG2nd5oZb_{6WTLhpz=#2f>g2bFr^!)CvFr6Oy^(4A zMpK|eEJT#iv-p+S+G-F&ZXn@YkkP^UXWSfl5Iac_CW{H^`C_wO2S%AV&%nr_ZDdgrNa zPRD(Ag{DozSIvY@4RBcB(Yn=CPF%;KWFh6t3VqW#lSWtj{4Tz_qDJM(3g#31_`dbZ zfKTVXUG$D1uqa@1O9H~1%yXtJy6nd9HR;n!X&8b$n ztZ~7gx5tg45T&vP)63p){)sL*^})cvNTeCO>Bpp@*%*QMYh05#3LA!Q=8 zWsaXF7Zp>vdUs_$5v0N_oQ!ueF~XS!c-bw2xW-k#s7F2lKLpE`gocsF&o+1YJvu!> z_LS4pcsko*z1>kIaO)c`O&lSj#M+kJBYW{mSD;Xv1Eq7;`VU(^b4wU^0A9A+P@c=f*uZ+4bg;$~;fSPE!A7pd#L1^kZ{&04YeU9?0pH%|%{o z>XyCbCul>xTSB|*`}6+K5hWQtx_qYS)7fm+`4|vcp?JW@p4iTJd;qxGMJC`;kGou! zyH-AA90$wZIWPLED#va+Q!+mz$=l~$6gk=GE`S~Srf1dPi~I4ROGS~*Mdktf`qdLH zwmgTfhRi7>>%{7{RLB~IazDF~<8v#?l8y7H;9)*TVJ$H$>!Bwy9k;KJU5ZQ$e;7;U zsk>@eJfCWEf(O&t4g5+1@~C{Ma51_0$U1vJ6q(}RSH7D%Qr|ejHkz!UUaO&-M&X3#>y+&dFB-LANOgPsG}QO9JY~@mT7-+)35O2vDlngY9ENu36f3^g@cfW|<70iX zO=#ASp!y$opC8EEOut>b9ix%rM2GPMs`m^tZvrAEQHcHy;b>@s@sdiY$>39OP);3p z2;}HV_G8OmAj1r;KVVh$V2&JV(3gR#h0Lj9dNPkJ!ks45m5%JWE76GP7DBY$5N-?5 z4;K~Ysa%|jCIOW+VA^oF_OoEj5@31;QBDYEC9HuF>&e)1?z9gG63UfV}%{RL>fbm#9 zzLH(L#mIWefaBTOqL<`9E8?wVE;`Llw#%Pf&OD4g#FU6v&m4WOzPXLc(RXG$YhHS( z%A4?dt))3RM>KP;D%Vcn#lnF>M6cCW?`7Bi;dL9c^DNqz!;o4c z_=C$v&g{>MhT4rJCts#)B0|Bp9kD#Ys-32-Fx3)eH19$vQrTB2KZ9fWqSuS&iyp_6 zmpM0{3@7+R$=lDUYKw!u zWrz_+V};i*m*p#A9H6C_2Bda99d{RCUZgDnd(erDg=b>h>Z6l0*{AzabviajZuEwR z^6*@0Pd7dTf)4h!HK!9!Z&n^e zU9Q~!(7qqiyIaToBafe3BqHSeIqrQx7Cz|GV1^cU0EsQ-!14ezPX_0XAR0N<`-w+d zbRVU%110jLZty~hKd9-O7=Qg0KjtXWic&KBrMHjnGwsJWCk82w<943NeGZ1 zktmroNTn$p=IDP)^+}_H`B5w#7%%Bwi`8;2trwd=y7g^s!*kmh+elT1h`jd69Ue8u z$o!6}&nWeyX9~V3f!|%eObeu9IkK!aZuksP9=>1PZYGU^XvAnP@?as)u^lc75y&cu z1-Qc+3&#LB)JO-IW01@bbM6y?EASWAZ7LEdenine~6>?j( zI@5@hZ&GNAN^E}{3q90>!h#VT`^c|0hmDjgYEef_+x5k+{y7wV@B@9ysqtvzv7%{W zbq58SLB1^I=Qc(e3KPo=^aCZy!;wfV^U#g+7#TZuI4ZkQP0}-*r;%+DAse-rw|d=NaJ;HWgATIKlqgGhvaW0piZ? zK8$WAjk~veN)b8s*hRAjfBMP(&tXZ6vRFeg{wZ=MuJ7EpH9vSxWb}u4Wh2;c(fHV% zx8rt7Y0{+{P?M0;!T?&+%kV^hKZ$>v&cnvW`D7wn76Tn42GILcYVewPJY}T$VOrau z^m>w@NgDN{yrk4vTK-A3&F-Txz5R#6c|$0h!#u;lf+gi34bmU?s0cExy{fMROUp#C zD4W+E0?E51Bm^3x=v6@5vR$iG)JnTnRl;028{CbJh7IJ9l`3Rm@K$4cdx*4z5`Y3w zwK#I=Rfr-yeRo5>6_tfi=I0I`5_n%<qM*zWIT+ImM0`;T0HA>`OtL$iXJf{1wg(MZvWa|BBMJ zve16P_44S2()Ef9e*`yZ$zo+2)t8S5y{p|9^ySInjEF-uC+`*5SBrJL;z7w&fz=$yCy^U-$GA+LnrrnGiEF@^GGFGt$yJ{Q&dZX)Jf*JqxPa*D{1gK@Rfxjr zhJ5tADaQm937Glda{_#`FkZQ*VGYC@OQ*aN z!m-g$G<;9$`$)wDWak425}VUCWN69rCCMNGF|+OlmBX)ZH* z`gK$Mg}0e^P!b^dc`NX#bW^EOC+V1h*636PqP*qZ%NtRR&I!zK0j9$kjX$3Q#Wnz# z?RF0YN>8}i@>uf2HdK&Ak&Tc@5dX5OX@;P%H@*XxW~E}vAwwV(fHRuIMUmbVU^MkH@*u|jj%II3bD zWs6A9bVL?GwT2YZ_xxK&+K zp~}5b0UOX`{Byei~4CYzf_oDK|&G_hI z5OX>w?Q$xXB6sfmt1#lyeKt08_RQ~^eWzGe7+7V1?gU}`nh*veaW91YkdPXG;95K_ zY^WV5>!(&vqp+vM$wW*2!LVtv+Z#r5vguvOkL}%1-O*$i+d1FKwwP!mXm7lFTXunu zMan)Yi=Rw|=2~+2G34!2kw|q)JG_0#&@MO{CP}UXpX}x`53-z8{1FKFcIMJ@sWsOw zuDHVCQ-Gq>Y^MHYj;vc9){+#C804<9-`B2Jp z&~{3$%LN`V_=$F#BKA>{zDGs7o0kmX50;3A=tC&9RA@oM>)@fD^fDOK< z_68)dNBWOR#6|{x58E4(^NPqkA@WvmW^Y7iAtL9J$O=wif6T%w zvY=9ARqpuy!=o2@bjnXt(!1dw2Cv++jQ_-={YLzka(lrP4lI@AIrP}oE2`X|)RDIx zd8jr6excapSYa*$U#?!7wp z+JlkB+TF>=G6f*L7sfSN>8qK))fVP17^_IAW*6~$Clh_ux?3mnpMYJ6xhQ}7_@zp6 z-Q`wNfSYVOCv{C+4+gC$OGEQ)H@J@OyZD76hbMe zQN*3vhUuqQ$~k`dFkBRGHuPYJQdYv#7Vmv~C-ZTQE3!E{@PTlE9~WWt;)~#`h6JaT zDu+Ac4PxUG4NGuLo9LQtSBJu8$(F(?f?CtbmTJzb=|%WLHKL78MAt{*7=eS3yj^Vz zdt+}`-O$}bt9ZzLNSVShA`3mwphw|fOQ&nha(k;7mvfkxft+< za5(zr=C=TmlJQsC$g~al>c!>;hG7wSP^vE}Hxj{R=Rn4jL9v4dee{NWs}w93yL?;p zUYl^I<=n_+1lR!sS-r7^AVDM&VIS<*nzY3xWxgGd>sk|0GSb>9!EF4W+C_4BSI0Tn zcIe;UIhHm5<~RNc=iqy=V>@j{cx)#mLSySThu_L&J%bPHrX@ej7Pw3h9@yCFPR!d| z#@Ml72goyQ% z=mq*}Yk&9KV}50Fw@}U}B~?JO%tx$>ehvP5i2Q!XNNsj8;cEnT?CO9hvl zG?%3d%PtDKv4XG`&0zc5G-JhN5}3=-toDGR7Vr=kUM2N*5a6PtH&EDgLrW3jdjChT zPixph{VwB_9vD{}=7SweQaGj{AdB@(SSf=gaNndA zV0ES`O*sxE9J=ZgkRY4+0N=+$(1sj3jaORr4sWd;F;B*%-BKq#JN#wkqS%s%Z30qp z)FQ#ZSjblw+bD-i_f~!*m<)SZm93XSv*ri~2H#zs!YW`)L9)5hmph#zW+`m3nzqlPm^O)?)=l|pYLRWKinA>&G`nFsM02tf z%&|Q5*4)Ix>PqKE$Mo^+gzpP2Mj>E!@lQw244dyJ9KZPWMDDWB!%h+~^t^6ufo6rbe`C?%d?LkHu7u!F8-xlRZTlCsX>v(JTFq~#;Q;B>7V`fJa@s2u0 zOPE8)grDnu>-^w|c0Ql%_~Agq@ynLun*uvXkW6smA2eQ^(A1%*CFC9MAlk(g~ zM#IdNPpqZLt>~%DT%psBziXbX9jk&vDVV+Hw%e)`&s%4gcIUU9yT|X@o)C6A(c5bJ zVE5>5puy(SadQy!Cc?O?wpFH z9lw8sl*Q>7?-RFmo8*F64+ZFj1!(PhuHLrUhzb~WvVP@!e4j7yO1R_xZ7&(B2l896 zaAycNpUpsFV5R1p>N_4%1h43W%kgN)oS%oziLD5K+1W>=!DW};4{ zkS}QjQZ@9?6gjVZ9~Z8Pmcm8sE?wFiSZ%yD3}mS#CfbBLeeOH{D?Q9ly$0kJDPC-w5-%WrI7c1}&~(l2chWY8 zw4isdgnuMu)zT*G!NDuQj%-!1IrQR*){fW$vHGw$xhghGYW%R~d1{f15u3^jE~w`f zzZ1t3o`2!1R=ebV?Ckh0@sfj-IQ?g0FI2YwfVM-BY&@hr?b$i})6n-zmK|!Y^cgwW zQ}!QPr<`28lvg`6a>Vwmk%*@}g_p$!Uy!)4+smo&tZp}blaP4rlMWKGQeUeU>e8;z zPJPQCWstTIpxDai#Df7zHk{`Il=?U+xSnHt2%PWA14HyIzgc`|EYC&_k^`IMkk4Z{3j|K&a4s3VT?ZbgrB9X!@0R2@2VCZL<#{my zbhIKDT66ENtVRwvjyhX(Kjqwaglp{Gt-vW&8sRgrLqC#E&kusrs?syY^zTqH@#6r> zLE3QnysNpG$Csod2j`9sFKWdP!Nxxne-ARCU3c&S?bR;{cAu^6&YIykr;A8 zw^)m}kB>j-y;1XHu;RqNX__py!nGN>s6f~VO={P%BVDVcHu;z&@=`83n{(l5GBpXm zn@ILaWP_0Xg$>&ZC@B+VE1iOvEU_ghLXM@8z%Gd@mvJ<9DttBh;?;A8r(AzJg1}%m zjlH?zb1Q5k4NivU7}mk}eUdf8$@gB|bjV__esgv#Ef6W+iCr;FR8-&G5>=0RT;>DMN2at^B5eX=h3u!>KJ$iq^(N>na_Q zwrLJq=17bE-9QCH6C@1>5MoO9agKaE@6znwz8CuW(Zd3>@?+0MN>t@$>rJ}Jm}HWy zja7Jcua(bv6vHZ8vF%Y$;)JgKW0l_2-uEGU&UY-);yO3<0y)wk)nS8OOp2GJupbWw zThAow`@aP(0HQpg2RDJ61G%&0)sZ9|LWJfCvlb$nmxE%0&2q#YhOya{*2}4`Ws4>c zTPu=YNx1rB`f<1F8N?NO^~blLvzice9P3$ygaPxAzU8#J{n)Vi95_}p!0;YNQubhx za0WipG1`=RN36|U=*Wodm0$K8cA>Hed_pt7Udj7h&>7iN+q#kFeUkaRO9Ej0hgdfx zD=B_B?&=)`eA9vJy@e(W%#Tx%|KM` ze-ZWjG1t+4r^#pG-t*fjY28Z`>-)ZK4NsvY!$^-&C1lU{Ffbg_y5<+;dLaLYeDoTm zaReQSwa&Lxj=T?0WMZ&cMg{E-{FBcBuQ0p%bo!t4Adg#|{wCuz27(d#} z_)pk@b6j~c6PT<##?{fK;^#+(AZsp%UrD$Y!3R0l5`BvGHVtJ~URR^Vyq>G1s&+3uzcrYH>=!M4wQ9lPU+a#R z7mThkFLjg-ow_oK!R)vQ1n9qhXO4kOF6M{`zxC8UWoa4s9q}9D_%-**PW+PhW>n`QXqm%e zSsEKV5WGBrhY=4;l;vGj{id2{fJk7E{3Ff(Ao!)}gi_P`CjK_@!a#_@gj!_^w`IRu z`xB*0+oDIMk6ik8zNC`>YSFC&>5o27j_QAaip}2o@C0SbR=oko(`e&fB!=XXBy3lC z^vl;`a4>W3ANjBl8^o_YPy_&**L; zY`HU|Yd}JZ*e_9|Ipaj}(qdw8S!+%m)k*yb5Q9^Zv(b4fT{I{~NzRSWJ1j;HZfuX= z#Oc5#vnHmdxD+vPZ4r`nr=h4xS`1YT2e4=`I5&k%oI3EUy3%6Ajcj~NOdignc8>Fr zsM2AACW|80Zb0;$>G``ta>Cu2*{3zVWjNQLNsk$Qo^UL;E_&&yrY%L|F;5dwlr_q% zI-L4TELuKoogJqx%0jO;h10+UI6ZXWErDIppS4K?K#oZm5Z-nGSwpSjl!7gOLRI8S zd8t9Cu2{smS}!%CD`wckw~=yHYI9@~bSBllSpUF-?GR5PtK6u(PjJ;W$1p@qv?&KR zcKeL2Try2}S0TlZlH|r_7tQk`TwJm1^%UNeBe&w7MB|Isy0rpC2+g$h9do3b5XH%Q zeCKPvLVdMT$HGLWKjghhEFh*Bh~4Q}C5*x1j-YdERSOv+T$5QeaR)a@cr=xuSEP89 zhI|1H8NOj)yl1NFLHJ0eJZ1UqDMg8@ak=FH7x7&r779ZIFiwE6h5rjh_`~pPZHr)l z6-@~phMBROGXNHKQ98haGN&zCyAS!1P9{1eqp4hUEh?~vQ%iG&SucvQ2z-SC9w_Za z3Iska;VgW5XuyJpO?h^Pnm{|bcn}0dZddTIJCQ1K#mdaQd~Or%m%YIDG%VDXI7We9 zWk<+V=>Xs;5kh$aik=RU;OiTmM)EaSPmCK6$s0f?@7*HHf`?Dpu~%$4BAHWt@lu)AWe@#~=!MhH_a8@|^u8aXi{elqJ(;+6 zx*0z29_;e%fTw!qht|e}-fQ>1y*l&e-uE|&1_)4I>WL$h&#Yr% zFV9Zg|NZ@K4nJ{p?Lm!mPL4j&Z@gDXz32T!Uhho`w$X^ z=CQ1L8v|TIG~m}yESpu}Aa6AxS>6N3?!GZ7Fi1#IE5~sLGYy4hLaOdOj{E$^197lw znxP1uCo^zJ04E3Hx-leUsG8wej^}F*99HmA&2%eVioUZktdgLbb>w3;=275? zdNof18yy0wSix9(4A@CnONf359Mwz7VO}?SCSFzrX#W^@i4~E=u?LO0g#?3tW8dP0 z-;J3ayyUTGKHq@XVHvmbQ7dqDqFl>X7glg}ET|TdlFJ!`&w2V<)OkoLxQ{gb#3F%gcvY`ki4?U#S-(8`=9ycVMk|lmA3wjdl zqki?}ytG#DyC0R`gZL!7@oYE$}j{%5qRyQ_e8CDXCW*6i%Z^LMZxoI#@a z{cDE6h~o{rW5M_BbK+Lz5z;-aQIqoQ(7coF9gE@^%>-5<&k$S728tAt!j)sw=@pJ} z5JnHo_R}r!uJ&N)8c}HOD}*_=qftt6K+G0Q7kH3%BOveP96Cp{!Ay)huP9^|>UCYx z2`G{3TTU`^1v>REgR{Az*?@Ti2b|()453u~bmEnO;D-3MCyAK=wun<_TE@LeV?-1O zx}f6(EpfcLCxWMQ zAGbtR=^5Os5L}ud;98$h@oXSap3(hK)uFQ_T7*-%q_j$8>g_>>#@bDcc+d7(PiaI zhpaT~>2b&)<6axH{E-q@_aK=U<{84h&llrgJ%8{;|B|f3757t=BrV+yG6Sph)b4gi*oD+7 zx9Qc7gH6vXOD8>SomXT&ksi~qG1$nJO(w7EU1}Bale~Za`vdcWNK!S3z@vbfW z=j_n4tl;z;iAk2mAC^(Mq%B&UpQ>wv_U(Hq6nO&b7SU=?wlLBqR?99Y8dECPhOG7b z<^H8ftHY4>PmwN0q_=~0@1qtR3YmPpAkqvLLm(rMoih?@Qu>)XpxWy97f#duDn!^nH+EA!aZ2LC}szG_m$#+st zq|bxT40z*0Ul@G8fJ||MMPNOLt)x6&jcq%e@FSV-r?a&Rrkc|ia5!oBLY6n#^)LcGmm-FhW8b?CU^LTq<2)D`xpz4&l$lbD5^y zPGB2ETq9Iyo4af_V!-x9mN9|u^apUCV+%<7bg2nQaRS^R9J)u-cfyL$7p2rH>2j2D z!g##@i*-)E%_m;l!(tlw{Oh+D4!%g)Oa94JVHgWaS67yRW{`mL6rXE31h?Y-BQ#Ao z1ZUP#F7RR$oW7)8h~tQ%x?>O=aT2o8g|KBm2d0g%7q}mjWeM#PS~<*A~Y-eCn=D40XBc zF()CA3w&+hYh{<}%qLR!izngJF6$}IaieAwpDK~j6p3wZbr{TeBC0`baXA1n zBw4r~YdL__@Hz0ys{i$znj9lzUB8w*wUU=RsW??Zk6;Z2*Ra4mSYMJV>64ax;IqHX zbf*Itu^E*v#85wKYvAZ(3{8>{T!8TFeOyQG(wrFC!+ubEo$>-uG?27>y?@f)_n#vW@yvCLaZYSRi26sZ4{KehGO0? zn$1KdRSIbjf`CLY@LqgL;`+1|%N|?ri=0tYTq@}!YCA{#oOjO=;-nPio#KE4j56kE zG&R|r4zDYgz9#DN(Q&qA3r!pyxfUUqi7ZSS?GV~Drm&O@Pf2IlhLrZo5A>9oJyJuz zc=6$df#1z{BI!5Bq z&Qf50Bw6egx;?}BSv&HHhwl>AR78kaW zv9*yO_O5K}U3J*|rmgoKVIO+7J`9F^e7N>J^L^N1o|*UF%xBG^8(Ul3 zP0!q;xyzH8^9(+H=0EL;Q^sRYyTMhyINoG_ZJk@;;B%o@I0JIhiHfd7micjU+NQ!Z zEk4^2>;#lYsTdF;ZSg64YPOOanc~~ylZx+D)3QM!Ds3V*Qyi=hk9`78I>0#xhWRP? ztpN=kVwxnh{zfRRXhIbYoYfvcwkQY!H;6Koo-gR)b@yfq4~bf16Z?(LE*!DqOgg%cakfx z;1cuJ=#djY+JaZM`K~y;ffm1pOo_QHe{~wmh!!C9jf$-Tntl z`8h-XtoE8aOTdaU|A%(I0naegB*GS`{4&eg`MGOy0nx-yuuQT@%3G!R#G8fSld*%d z=+7ZzmlYPa#DY6`pJ4wi8S=%pFN6Ho#uJmjtt~!Z6Y5%e%potr!V0qK_$a$m02_0XH)i1HAxj+MogUd#b2_pmi{<}g?!CgIin?s=T?q;(pvXBR87z<-i=1;t zK#&|Ii-20>oI#0F`cme*oEh!dLB5g?5xioN_S%|^qC)(cmGK+O_+`ZNk0OO)^_sg8sv%N$Lt zlC(makIzVD#6Htsf1jo-WuzE8<$^@$Njm}EX|w1Cz)XeB}f~5`O3h83u>=}ULZtNhM2O2vyh2I6?A?m-r@qj znrn73Jrb9`VFr=LLHB~K{7!8`!)>EaZR5l3(ogO3!|h8??W@Bbn!BVJ)_!(|{{q$= z7N9qZ5grPrXHk$f?iu1s$B*WZx~?4M9IY;ViCFl$pDSHmn59wZD5&9q(vXx64yT6R^3sxLmD?a_$;cUnDQA~!S1>Q%i~Y_*?m%Fa3ZP?rT8 zb@fTYMej+M6pdPO?Fu=KA>aoWvhRjaJa1PYgHUX#=m_oO3IEM6?0U%ZoTRD9ddt_t zNs@De!+sJ1%q`zb%=vSEk7#fwOT^}h<&=1bo<X6MQ8IS|9fY}oKoBlKa28Ye3Ku;uk{d}*kwmlN{f-Lnf@SL1FB~W zC_D4&5#X3{h*6C%LA&$XJr2icuUnh-WcOBmN2Ai?IQ4De_(~?!uxWfu-~!Y<@Y&Ts zSg28ZOs*p>H`5EMGBXs3l=LY2S-lkgWJh~9VY1_C!g$8_cN+F%rcoL%r{-y|a(bPw zFz%G!)>k)dD|Rs=(dO3NqE`_rRp|kc68ql5*jPSFc2z#6VaOV>`m19x?tZ z-q#`8@(-ZrOL)hA=637+rm66Ad@3TZ73m+hdhc*he=;}V`f z!kV7O(vzb|l2?fPTe%J)Uo*bG{;i5i@OCKA<7wTfk<0g5MIJBRj;FmTKYVI}b`on) z&x#h6mcvZKe%$H0Ii__ntmxUZ;>!)c>FW4|ZeQkk@rU*qOMcy$o)zm@uZ9Rf5v=CM z`L$jxEHUA^O$_rxSIMM+9rbtD?3KQemOZlk9c>cn<0FYHN55aIRUNT zFi0#nGXRi7s+KYE3>;Sa2OQbBFbRLx={!go3put^Mo?6uX->MITX{)tmuJx=daIie zF|;Jh5`*H6s&VxYNK>*%T!JQKL@uKM+>(J1Q^D zw9rERH(A4@Z0w~tQ)$(0A^n95g0#~5zK5wLbC$B%yfRXdk?IG1tM@&g64yUm?hOvt zR?ibx?{GGCNlFYd^1asvFk*4O)_@J*(1;$Wn=|H6ky?l?rNt5~1@*>y`{lGV;sw)7 z2A5#l>0Ch?&)r+APM=q8!5 zEe&tYw$E8_t2u*F;De9=4Fn%aC#N=Lq6r+%tJ}eOE^|(Z9x;Tyn65vne^oVcM|W?M z0JYwu4Z=bxq>l+*RXDOiMQ&g|g*;7?m&<(sTF;sfJzv0(9#$J=_p>@;YxK4HDA^!J z{YmHm?h*n91pe!*WPNYf}5a1?ER)kni zRK0Lta$~NLou&pz^_2-@o)66>CztN8T6DWY0lrqboXI$H%psXBuRWughUnDnXbTmF z9}j@gsiM&~m;e@sQ?uN@)H20rIYB3as>R`C-cjtR8grs|Q9Os{waPGo-j+OoM*7ss z%F8~090?a}h zsAf>D*f^z~T=UC(QjqLAwx@bPtaBHe;UZV;uX?nwNvtP?VlQ~PTV7%?JT?SUu*~ry zaB6J9IH#Xd&h4)CxIJ7TC&ED+ejJJn;_ek2A=+M+!~#!hc#{E&Bp1s&Fp`{jas)l{ zK9Ea+wC6{VNU%^%(PQe}h0Syh$O~%i6b4ANR0;dB62gSNoOqh=hY&4;AE|d5u?n$P zHic2XP0c1<`;bi|JTkvyXr#ta71L-r&}?fXXJ>#dUAAc-#mMIop|&7_1)XI zz*n<~w|;%uxPAN2&u_%r0Ern6#_s~5jKsnP%wj3rU0@vNSfq|w99@kILL7-D@&3rL zflvG)ajuR|GE1_!R*3ZNe;BY3~)4j8^@b z_a}{q$YgSR*B(!#`Aq}*UG!kiD5s8jnq}F&JVHKmf|({zeGWg+xsHPGkJ?jt9*d*%=i)9SLAI@4@mqy|k z?-bX1N${qLKQvP<(cNM$%Es6^G}2ew@AC6^ znwM=Z)?BOgb9#F|FLGz?e)OAWsx9(?gfr{*_zV87l+ku$0yYoQJ^bA`e%ejy*gVXy z_4g2uwx9L1>CivrzU4r}AcyO&ZbyqttSG2t??G85W^bqjAxxKXP4Jwj%Pv77VeB_n0D3l7e?=>ic5hjdpO zxgXK83}u}mHBc^|hP(-zi`)+v=8h#1?cmi`?fF8|c&H%`B?xVoQE=KxJ8RgJ=@x*K z*Ng*{m4xw$t5>0pI|M6aF}kQdH|w|EMg3|il|`G;xP)RYp-Y4sF&C-_P9#r^qE8s8 z(EFYIAE59Cf*px1MD>84N;pwqUUA(*MBc?h>i!bIzLN~M!cXfCu=fd=C$M#7Ng3>4 zx)Z3=^+0w@{?nGY-E)1b!KS6I+PXcZ6N7aN;`N?()$p6m!oKF&+j&vO;Z0A|wOo?> z@b9YPNELChDB=Jw!>t_#88ZP%Mry*in;)gq{o@{<)kyzai=E5ps0#`9{;@ksyG|Vn zXQlmkrndvxQ`ISZR4(XG>gh5gtgIxw#c2g)&zW94w@vSRVc=Y}zU0_vC;8qtsj_cfq~~;1y~$)? zi1x@iQE{#OPk6<|(!0>weWg$7kiBjwr3p?a29M*4RQ}4kj*Xl8BV{m+-yc-XwlQ^I z;c3%LB67SYPlqqhg=HJKJL?9S_vj2?_kRCVtqGM)!@Y1_rKXfaN6*t6FGEHa+a{9- zi5FsZbbyKx*bgP2cvJ;Fu#m1~k>a7j@sv&Z_xgp+rq~GOS&>EitSX>nv&M3JTwu9Q zC3?iKW{qnx77Ny`v>Xv$s^T~M6<&5%7YgXj%*V7wzx*JQaVw{c%l6%;jm(3MA@wD- zLUcCaDmhc8m2z`Kf2O2Bhgd)un+%1d57R~@sUWw)o;-!X<$@F%5HWDJL4quMEjtFeGF-Nyv_p=4SNg{0mOasts;!u@-6qRvNCNO0i9?M2)@% zSbZqIJy%1p9j4~>Lxi7J_*2M8mXzXqKUGS?MVg$vP?pC(*$RFcLQ8fY6OJFdXtu6c z(B&RwMQLR5H{=B?z{n$W+e=j7@{CHt@Ig#Q=$0J$FpD)1e+{Efw#2uU(p_l3U%uqp^LKgP|^{Eukpq#?cej_y1_Tli6kT$n;RxnM5#;W4w27$e& z4Xpket^-5%B{EJ=`w*7}G0I(n{EDJt6Po-2;2HkLV4;*!!!(^^mhEyt5V~`c%v4(4605$_oK`I~{&^BgXPzkEi>YaZg`|%! zwNG+5(q4WqFiETu#_>dI2NO=yV37Vk*7phxs!*$$u!ZSD}h?YhP1(OUl36?>V zX1~TV%Z&JX8(h2xo+E25@I6~APof(Po0apDS7*mC33pIK5~!j^+)Oo!G?8tNvUG%h zK*J3_?fT5XUUa&7V6cY%iAalqkJdC_%Y>g|gMXR8D`i1fH-m$ixidDMrhzy#0icUS zAhEc#cUnI+XO`2S9G@#+8_{+)8~j2}zBWoSn?Ods!-iHChw7P@NhPBO6a~*y$X?A) zrre1RMN3X5-E59S;FIBpxnH&965-l2E9A7_vjtf=ri6w8b13(;1nPu(=&6x}5JK?L zf)u9w{XltJ90|v(p5qqW>|z4{EA`flso{bJ!AW6)OFlKxkHWpB_A9w&tznsw!HB#6 z;xModq9?J$1LZ}CQ2sM=jk+yzIiC{0QZv4h<2es_3OO=&ds523i}6s`Hu2 z&I|3Op{Wn(w9**OhZ)D*6T#oZzGS4hmPYzpi+(zROghd0fws^$rdS0s^rGv+m$$KkesgMbk{{Y+UMcqNK3L(0b zrFq+wCOoYby*&Cn_;vVejJj}!B*p!vJt>jH71ErLcIQMu&Dl-bk z`UL%M>SyE9oIw*bg~7)#yFb%_LaOh_tEWRm?WSQC9O?PP;lU{~jb~%!j?=A}q;y*1a9S33T2XmEl6TROCT@YI&7=|0=9*Y%o_;s?-X%?^XV1AL zpO3w;Tl-U|5y$${lQw?G;58`gsyKP>Y&VFX}?;{KGyOO*UCt3%3&$O(7KnXk(V&ea?*m7 zqACD_d=);sLsY@t-IXflbs#!Xeo4H-LcEU{`c5|4Fe&K0u!=?ju2QnkX?5k}ix#^N{B!0l4+sr2AjS;h5?&yN|R_YZR7zRDIbHUwXU0+Ln@B5*O zJQa+8Tlpc(*s?%NcKFeY*DwR(GZhoY6p3E-fwI)TmUNB79{3p5QVev~U0D~O`NMlE z_Av9K#})2hf>gyWR%x$1K6+L7?(@zxUB$yA9|5JO?Rm`Qybm zV~9|}k)j#k%yhmJnFIP>7DBt7lgc$GC7RZYazL9zZ;Hg`p*eFL$t2Cnh(yDFeC~_P zygIM7D)Eiqwb7n$tC`s)FAQRO4@*q^c%}AmNt8A<@aP{tGk$3!`egN=^~@(FDOwNr zJhUi4_~^d3=H%ez27)ZH_g!Ju!B&ud{o8i{hwpXlL+WFLUSv5i-~F=x$s)*F z?eN;9jem>h``DeplF!A{Cvs=b?=CcESDYt8+JOKasMavkEfT%Ab#JRVFSXc_n*6?Z z99%t~`8>)O!!RS+Mf6!r0=SA5;Ky4fid0Dt8lHEaNYQ*uf6L7x8qqoOhttrEgZpAx z9i*gYtN23pV)eaa!}w!syU*|cBncbFFH}yE5*VDE6LY3c&|IMl;p$Rqp)58aTOJ4J zcD2Na8Kx^& z@tUp*>QQKCX;TpsW|SOu!Ck^6Y2@Y7k`eXkXLC`5x>q_^7_^zfu}p2;_i;6aGKNu| z*jbTKMGgb=Yefug;KoFNR|BRnUEns85rVZ-QGYN=$cKsY|L$Th1mA|+W)pArvpUt) zO+W}0D+@GM5@$)u@cO2g1hsHL9A(8UBMN!QVlA?IN1a-XNY=5FRL(6|jBX2b8tGE8 z{TXvsnGx}T&(T-+tLMBCS(XD^O%hvG!stp0FWOf}f{?J$uh^ha%dbftZ*md!G-lfP zIsN=?>eJk|JC15u{!uMa~AdduC`>Zt12K84Vgf%9fBi$3ZnynE5Q#JV;vTT;v+pPyIgv`M@y zj$$+Q8gyIpQ97&_z#Goo^ZX*HcXo!277s7CuKs?Z{1>0Lg-^1@?8UG-VzjGfoa~?# zyA;l7lh?Yno57VoLZU3l1*Q;?XN;e$=y+7D@M zqp~B7J*P5tbLijm0O*}5-e znFjT%O{ZydzCF+Gf1{vEf3o-RdxlB##{2G{l-V-}U;BP%EgXIOHAJLl76Ok=ct^@J z;`PpsiMVqli?D*ey-#BuvrA{MHa18LAEaR5;2V`zBJxB*0D~uI6IC+2OyNmz34-k4 z^~ca=7)%a;j|`Fwa>Wo@W?Mq&ptN=eo9gwAfsHm@r(dh8Jjjcvw?fc`Y8ed%mAWHc?*Gd)i^Lc?Pf$CZ;JRr7o{Gt zZpnAQ-|FO2`IsEA1cM`@e$HFb9v?2i`7?A%LqlSyP$BlO*_q~|UPQQOWdYWu;jSB~t;W11Y%tvUZl3un*k4Y%A zfM62Ku5fi-ALISRFtOtG%_+q-X>BbY2d57jGxc#o;IYZ{31bdsAtzsOD)cP}6mSM> zZmcQg{cqf^`a;KKP-G;pfpla5Q&Ex*XR5p1sXRA>*J6U(hNJ~09($Q6I&xS+Uov@WG5)v3^y^S$ecK^z8Wh*IMeirXzTM7zfFLK?S5mr zyOlRA*#4rgW3tGOo^9fR5r6vgZad@`f5FwbuOI22lRs!-`Eo1$n%Dw|EABpxROw~l zk4`Vw;}4v<=`n_5Y4>gPyh8{Ct7n%J9wi2RzDUr*Qea1P%o5=eMEuyym<+w((luHd zuF3~@CY_#!3`tp5r2-5*5i9_M@|{)ak$xhjv#c!vC2Lve9hyTX=JEyF#M@M^C3reA zwk&IDRaoILc(n_78}Rg)MuU0@Q?=u9gC0Um{B{S8%z0GC%MA;{!DVf0n$V$iOW~Os ztD!w}ih=z-now@SPVx0CPrFw7ErNQoNE>d-7r)%fIPcbI<2#wXr$%c8fj-dKgrJR1 zzrCU=lEAi9NxKl_>)k>Zp;YwT5>{w_7e(kF-vAW6zL*L-s~uF}t7WelfO4j=o7tan z&o>%_AmmrE*Jgbw3-clG*Nvcv$%fqpsHn?&$i!@`u_Teqh?|xsnmQH>-{1#2A%n); zF_0!&=fc~B`5@#&=iP+%e6ku5ei%h6>>h0q!pJ3DN+SoLTm<0mesb0!fT=2}#^RK? zc8QQqPJ~8LwjGr^MNum6F|Fuo=Y3=t%ZLfiM)F)9m8^H3TzTH1e4gQ@QpHTZ*>L^A z;{;OhBs>pze`B7Jd^+7hFawYs)b{;*VzTxkZ&ngUE(KK?r`3B`^D2S?|NFJWq@*Fm zX%aP0j%23hxi0dP9nuxy!QQmHMf2N&UOQ|?VR=bcVVWm)%hgls)#jF9PUKx8ASIW` zlHEbhPje{dN>l8(OY^5v^bfN^+SG~m6^R@SL(RO=A-#~9JWbvKbN#AbNY#8=! z=8~6Y5f;uXEUO9`wQ9JBbE*LexMe)##0;;S_74sAW}vKpy-DZHz+ z$JMR_&^*AKh9+;EoB^?ur(T>dVEuajIH5%Vy>r2{2}wz+h4&#UWj=!n;gG2K43~_% zZ;Q^lCDx^kLp3)BAIi5pSzSclg$u}7exsQV$_EvTWu7zxxJXZOsG4ZIjlMdXMX zNTyYr%y%ZFIZKy|Uac4I@W8bPRB>&H*uW*?aRg<{qD0}Pi@&9)wBKtZQ&$7$cg z^_Bxz{bH}NS}H9Ev%J8Z&vfWN7wTWqS1pgNSJ*Q(y~5lUT=pPOYS0c&Vq56vvStK7 zZKiz~xfkjdUD}Z3t=wt2BInz{ z^>gx;HZxYsr8%DzlL>@b02McCM9@$Dq1sUoYEQT!AyS?X?|$qI_`Tr~ZY&5*``X#4 z;@dl29<|ouobhLQ`<>lP)OzRruGVXrM~+8P8v`G^+HO<6ccF;h9FypNP~9$;@7uSi zl{j)Kgqhwv|E?R`YoZVRi01>JyXsBL5}Mrz%@5*bEp*p4H8;8WNhUZin*?9>>TnY= zvZ*YcTKrShFD?k@NFSJN8x~rX?y9yJRcMHaVZz@yf_@!bEO%=(0lVk`hs@pDD+^Yth-TF=B2` zrdrHOJo@sLNTpmEOG&iw8!bI1--AV7=%y{-2pO8-Y8h*+JT6<#uXUQtuKktz#|9Ub zB%H)N>+0jS0UX8e&PYbMcP`!-$4# zNxj^qyXxW6*38y$a|pSjh52k;lCn1(z34o9Ci(E3>lDpTbs~X|OTEi{wdzpH(lrA= z>^jt7J@uK<+uhpfF!94#h+VFw!K<5Vnxc;w%=xwG{v@!E12h7K$sD?tLx8qiQSwOv zku61rc72cW<(rJWF~MK1jIy)vabJCoi+#~Il zy0l(Skl0E#J~y4751`)C9%#r+krt!uVH2*G2k*<|NyQ$>iWy4fZA8MIFTv9b&GQN@ zt(U9@r9+pQ$*wS`U(__v#L}q6@jj|_ETxf8uTClk7?u+wQ--rWrSzhZTpuU(W9hT! zG1(?E#`z3fd=UAgV7aAXVWBj_uI5w_tNPH%63v(wsHFIf@-lfN!l1yM5UP-fe}Ae_I$nUEa5Kkft~w9j_yeK zIUP;xR?x=QU4hghzPEOwQw6tqET=5^`pEq9eaL>jQjyXYxYo%T`@l4}Gle0S4c(q} z;p@#O7N*5JdAzpzWH}U1mM$ML%RN$03A3|E#}(EfY+{yG+*V7T6;h+@uIU9`d``#5 z@~)6iQk2xEOedkt1x^pNm+N5cqTKjw_a$ZbsAQ%E1)+{e}GV0;k@oz=U(o0Qi@`?k-u^AVpnup%qZa=&| z5n5Xan0!Chx>4;W6Guf8%<{dFF2+W!hX=!$%b-{(i#*X{es`%hi5R(rm%Se4kR0Ef z!y*qYs@STMJsK`VTGY#oFz`1TesZH`I8ln8CMVfJk_5|Fk14Nc(Qb>hQ}GoRST%a; z>ks4TQMt{6H0W&$nut+tCs>R3o2q0!Nll+iUTY8Lo9K)>XrB23FQV+(LCmr{wXY^n zuBjkD{_vDfpGa{2B41z)X^#l)knJ=@zG@-C%SODGuRQDUjAK%(Qvbx#n$L|{imy5k zrIJlhB6U&mC{Tgqh!obSy*8jFUj*WqtbL9|n41}PR~Y+gOVrco`&dc}rGxmF=);xT z@#}3@(y`asde@hOJ?$j@@>G<<#eQf8{eaz=_314LqZIHZmW0H*21WyieBB|URN|rB zjbnF1N(~}Jdw;AvDm?(Kp}n{ByMHd3|Iifdtp+|7_aOIxCPTquC8~aV#)6o!Q`ro3CK|&Obr~r9f-#Px0t~DRS@Hn0GEZY z1y({lR&6V~_7qBXtQ)_WhS)xikF^h3Zyx%V{`h<;na{Ur#9JP~7CQ5DWj_RYwL=WH@Y={9rF==H9gJ;2~ zexsQ8V~Xq=f26A4wo{#0V{-W5)+p55or}E)lvM%KIDi?TvsN1e9AaG8RwT9E;A9R` zPnmnzrs_W|hM$&drarMXjVU?kv5Ynf4-`#}71P@19W`FBT)Q)@AU0lpRS3zze|f6V zC83S#Djf?&bLl8La=3Y)jBF)pGr`MC8bhU6C%e@xz>C=3Kbw0 zUb63nAK1cm&$=HqMJBXNid~o_#Lr}kiIC=4L0pnyKTBGQZGU4R0VM*zF=Rg-y;{x|45W{jf!vVT{_xoolI@1iJfy$ZnX^$2&f*&)CIUCVy`azdjM<3Rt+AF_RQCX?1g^TGmdwMDB2*at(f(|pYbK;!)bUR!kgM4X6e%VGd^KeJ1iA&u*L3$bYYy$4h*e)JA zNEu${etT2uKsM~{gAW1H8P3k_Z&N0B7*_Pu}fi-{L(mSa&{1MDJRWW^scqb6d@nUm} zbBH~8#2$C#aU8-}y}HTyIB$yh&f@saZ6|B$vb1M&?^$QLuAd%}h0Gpf=pPy0we|N7zRkL1WOnO9O6 z1$KJV1zzL6MYpGjCUc2sel_KRMm5 zt*Ql!i2yBa5ae7y9I<5Vu!JNFVxa|waPAO}5d-2QcfU`UBG%EerJu*~>KWa~FE|0? zaW!dnS~`A)GmK3N>yLJ}oHFRTr^n9jt;hpY|GOXHcHG-4PoVLJe{xezg+LX zPf}1iFyoj;w&~d(Y=>!O}pO_zz;m@uU)nC+FO-7qi|msoD{%A&{U8(2saul1xYw4aOkoqT=6Ve z4AWtHkxGw8^AAy^oGBR40G{XZS{<;WsGGk?V&kJm^)}@}ocZ(})8(UAGzkK!j&B5EF51&q)*x)EB zj>TeQ>}O9lI^Bn5LNm#5%d!L~P8!_K_+}20g4x~OOnpl_6D9P^$99RKMQ~z39_Etw zlvag-IY{vUbGea+f5!Oai)0N41XC~Viw~|)P^M!|4J`Kwi&lN(RSu(AL z)(q|VTd}74E#loSE;_1j481JLeBoi4xSnriQlk9kjfdx#R!I9axe`BrEUC+tbdR$+ z9{qtF8(wv*V|~W7m)pNgIIw5vT|L;r#^Z|Hw~4=hDo7M57QNC;xjhhMS|`LEN>;oU z*n}#X;ik>T{%Tm%7PYlVhY9A}8H}h4^l7+Yp9(Aq$f+hR2`kGQu(#*(%{%A=@3@B- z6jvJZsnp(;^}en+YF9es_fQtDN<})i@ZP^D@LueW-)gAeV9#{?g1%6^y9a?tKv~X8 z5~uht-Q84F7tC3ne^w=#(7iH~%l@dSk!2>yWgI~HxzF&ZKF7VLhi3)vj#Fz(X)>AW zd>!dh%bn7Sy@#T(qYS&%N>ppe@;nXZ$RP>|N<*+kFm{_yo4giOBp z!C)BP{HPeJseNRaUt;Ml2@T7v>2`{aet?5)imq&VRc6|33;J)xi7Kzs4vOWkmLaS1=OaTgc^G z_Wib4Q-wDokqBIL^7bmRoxa`a3jNkFZ%L*T_ zeIrZeQ4K(<>6ER%?^rTXx(Ju841_Aa!|0Gh1n^6=0!$~c-mhm;z_q(yO?Ij8ek?mq zhYKJnV|ilB8awCKCDU<|Nw_z1D5@RhOsBMVLXBVgdW5L!13m0u=zsp;fd z;en>^$hE*0ec-FmVq~0u*OKX#->1PU+2jSZLf`hipL?172_wh8_TeW|E#{QB)ZxVc z*!vq+KeX#u%~ca&$KfvP15n7Oswh9+7-TOEbiyeCA zUcs~0oJ8?3p2zfYvJxLIat5T}uaG~arn>K@>)X$x+A9OMD)^A7Exk*VTQn9qrk{k} zHhg`q31}dAsZS1Fw^jABbt2Qv7_4@ghM9FFA6|s~`SR-P*IlhY89@NmCXbTN;ke{O zJ_xxt06i$uRr#2kee>&UE(nXBI#pgyqVygQO|hP~L|(3qd{zuAi~b2bJ1MVo?}8-R zgziW2{5v)7j7ls9=2^4>r6@{amhV#rRe6Q2VIH@PiaTvdEWmqoI^T!~Pu;a!h84*4 zW&Nn@nEvx?QG*fXERkDm%+#dSf@QEMLnUvle-$7{63HHoK&FnzwDE_X~Qw{OcNbl|Mtq#x?f7{T7~+?$dC1|?Lwd6VYU}i96dGBH@)pE ztL;*J$?Le*ggj=VU!2iO521dG1zNs)5gKDV@cZ=Bt*jY~91U9oTBmE?m-@`#-Vd)7 zu@3S+rEoBt_}cI-{LpLV#}&$JMa6agx=9MZsQx4sja^70y+J19w;PjTH!dC_$*A07 z`*X-{EU@+@^9s8QyV}x((phjy_^;Ot-|Qx}8L#DJI#M$V7Ed)${u9fb90c16fS}?; zT{9yg5!v(e&maaCWY~fvSdi%oGGPD0VE+N=efbn*690wr`uGNcd{+<*3o>s(1nytx zD~N0U%YX%;um4JX1#zz+>lGx&g3MS27ZVT$3o>9q04xZP{Y#DoQL+DTNU#S4T#!7R zIeU`dg5a;1YF2CYwuKx&*0}C{^J?PdfS&J&`J7;8KvKR|G0gD}C}bd81* zjzH1?ks1sktlF1J$tYlCFlf>>4JH!KF#pRi3UYwdsL)L-n#J=fTo+Z4teHweUuKDb zB6Q*R?`Y76FmzgU_v-Z3IBB9eNthZfq0Kr}{k0k_B<$#U3sgmAb=wdLPlf|2Z64Xm z6B`JcorM3E135J%5>ETx8p6lHu|3_zvg1;5_o6Ggo%b;z4hJKdDj{pTeP`tsK!&@a#+uuMVMK$}3zK+N%9>M>aKpk@ERu*vFQY`Xgn z_w&BfnSQ1Go%K#JRuQAo#j4?8>CBrsVgAgLEXe|?a|W1KV};5|CEPW8m3#UyIE?p4 z0Y8fT^)V}!9trpRrsbY5H@g)1JGEbv=HKcG1sbLP?~DTL2{Z)s;cpFr#RR$mVz0sO z0Qv@+_Ll?=a;`z^K#RbZ0TvMGB^9(-G;_eO2`hJ7U95v}b?LQ0}xL`Xsgm~qWH*z?zglCg+LGhI#vfA4WWQZAP|q5 zz4RLMYHBA&r=%yID9xG9R46^?Vxd~;rk?_h~z3<6=4>{)$s3QvA;0tJfB&Q6-=LU%JqlxOFH8v%Jki` z{l7Asq=!7$Dd+GQde#KM;iNaj^r)yHWU!1(l0+8^ZTDc2f;`M!P3;`c%Z~gdN@ezc z>ka{cZ=e|euMPTdqCv&~cm_FnfQmugpxnRh3zQ402X%u&L6x8fpn6a@C>q?O|E*|* ztqXTnwaY!B#;O*4UcisE6NQy7QC8BjY*<`dw-7x&H6L#d9XEI=6YA^oM{C#>B_!qq zv%i+v8~|zF6}K_>%w)&;bm{wIkSafn)m}gTC3@v{T&&DL1!x0m`S+mszX5_OKslfg zP!ZU5z-9kU5>y1H_pgfnHkvF|R6HZQYUXgbDpFq}>ixKx>BpOPli?2fah!ck z^?naNZ7yFb+?EuZ>VNTCJ0|a+p7<{R!R@~*1XuERAA=5qYm2xZ11=I=Fu1(GwFVjv zF7Iz8{!dnja0lJ4ak(ehNaEdp2Xy;^^2WZ=YsH!Lv|;SY=9(6qG&YBs*$qNMz=$Y2 zAqiI#>9`@3$kQ}d7Ai7AtUsGJ@ZND)L{WbCg_tXLaTkUl(SRZOoK%t(Q{~h$bki~~ zI{lONzW*0t|LQxK!C#Soi|MZ(P}|><`YZT|b!wJyHok9Kw_DF$dc9_0bYU6veTEnSP^EXB$07>O$H8Xv@&G$~u zF11f{bgFmn^8Q;J_5^is|7ShmZ{_<2{Ue>on_yQ46@ZohH=}>-f}S357l495m0+3u zBdO~#|Ain#64)m9n9ICHTEs37T@@h>pnTln&@We9t>k?1tQvvPv;>dmLDMGiUsy0g zB=N9gc@+pR9O@E$HKMrziuH@w2jUMu?ogrlYa*3c^Z>HULTo zOA;Jmz}P^c;MV!yogfAD08|WG^4E#~O8S4=2^h)#r4y`UnCYos^W@O6lfaNrhyP0_ zVEjiX2>HKvf+SGOf7S`WW&bV2zq8oi>ikCo@C^cWffB#~LA_wef8zzU{1-wzL;Vm} z{_Zm&aG!~`)JBg~E3dTt-u+?njd$F&(`C<}7wf9U%p!Nce<{}gLKdP9EKPTx67{D08b^IzV%dHi z1LrN(-D!{e@eKz*yAsr|PDg6JE0C+p!X-!{=DpG+nK7(}!Z_@OTp@T!!e_<$CCq5Eh;B(`@{Xs&+f|HLJYxZPK z$dtcg#bQI4L90XCW=q7(hp5Lp?U6T@aZQJ7aJF! zkeHO5lA4yDk(rg9lbe@cPJF$LnElU^?qCXgNGfRUEMvs zkNWxt28SLKhDS!n#wVUkPEF6u&do0@E-kODuB~ruZe1mTkw9J|VA?MYU{DVz;`K|& zkvZb6-kuJ0SM&WB-~Ii+ z+&4QrJF_#pv(NMSz$0|6`D@BE%Csa(w{J2g)B%a%%CvGr+esc96X9<6Bo}0@_KX7G z+XSKcH(m?Okd{nFFp*r41F1gx|0U*Xu&Z5v85B<$pF|&nx1epwl1kOUIYOC#h)rKU0?Upf$RUeAG)P)KwbNW&Kkz%@{CmwRDf zRAiL=U6D4^Ri=6hlgw2pl|2pL1&|4;6bC@bgenB!=-+7Y5gm33_=h@N(3oH&1R&Gn zV@8Ec<#pUe$vssNIr5h7YPd5SgEN#s4($Y~y%?JZD84{IPYE($K#r5>5icZzpWy&5 zeOb#v;X0nQ|8Hg|jN4k$?KgNS&FzMRJy97?gELt)7DOcT^58Wk2|OA&{v3`{A*QRN zE8tcmPOz@Qegxo5}f(e_upweBn6Duf*MkSYd^+l34!zmhSYXtJ~S_HcQowRaBktDJPs>=(AF_1)gc z+Vl7AS%Xz}3#Cr$@9wP~6n0&aBpaa3*z9f^E6c6oKu`&}S`25bAPTyaUfhaUen}fW zl~fTLw)am|OSR;%pJH0ZYxSPW@j6*H}}_DfBPupA@`hWxb)PoWfMFUy92{d zJiY5>7wx$TMAQyyqS9Lz`rk`N@ED>+kWe3E&*?D$K}zOnfkYIcau~o~I_^N{b$Hs{ zS4gE<^oJ+DF`rW?DZ=vvfV1g{K!J$~m8B0Uvpz^?fl`u(MsYimFPNAOimwbICAFf{ z;m*psc)m(1s-341o5xxRmK&<@Wg(Hhk5<3MG@7oH@zg*`Fxj?UfPJgd{#P#%Fy+Un z_*c(1SKJCTS1Am-y+?Rwh3yj?RXJ$EQN*QX&xVgkiE|>cAjTiaPrPG;G=0K>pXbWX z!rR))R3JLGjh{$(enW6TwPcJpN1qv5st30MbtC!?2JB5uDIJ<3JrhLpM_G z-0Xch3{C0a;e)u(=s=4VsCKg zNpFx-X5KpcKWnBwNLZHQ8BTeA{B_K)M^{sWZlA2M(A8{e4h(Pg$;3YFo9lCFma^v* z8wI8MS8rqxY;~`xG>+LZoSD?^b>Nv))n`xxkVc?(pZ_B~l?oZ1pEI$YKiu_e#ArTf zsFiYTFKJWGH(V8ry73S)_`T$S>@6v)IWsq)2#(c}LXSYu2Sroi5KyL|U98$|<&c!d zdlfj%u)_;)p_KA_0jqknl(V2adKt&rpa^3j9A!Eyz4gqOXm@?KWuifNpp{M z(NN?7~JL%E0VX~mwP?;Fe7zJfNk>NPcjwdU6Q7PH{J``?Ec|weWwa(oAUeK z>~qBw7zhp@1uClt&1c!blFc zpf=Bf`kw4Y?ndQHI2J&-`SQJg(k$qWppSg+iV$q@Xqa{jl(knd!5u`KGRAev%W1^D z_Vt1wJ0LDD`yQumQk!>G~kH;48=Ph%jG$bOLBeP9I5-eC=9CM`OqX_-9g zT1`e!7Col3J4{P#k`?m-PYGoEH)78AqKUAYdli8`#Y<*Bxjo)^$R6)jYx^oM#1b%r zy9}H8BWL{~QFmbPNACA&kkc=4Hm8tNW+48;XPTbX-Ijk^NIN`wvpLWSBky$ZlxJ3Xu?D2vy(&D%v8pXS?Yh}-dYQijOh0ATKu43qiwWKCk1Icj@}5`V6rgSOcHGX( zn!T#5X`2?U{>_di-1)fCSyd>b^kiz^MJI=`=Wtmq?1lgE!S%tjH`e-k+$9-FHQr@? zLlt5XV;`GXcUu0gd~Lq_Z@M4Cg$8lXKzgr8vvMCE&rpo*oBaL}tl#g;O8pc|6@u$- z6}Q;*{%uFb$4$5XOZgi-ihY)s7VlqP&Ab%kPH`Y|w4un7^g;+?hJc(niJZL~VPG7G zgh^6w&~0VN*@yuoBH?9uiAq92Q<=q_o_*CegG3b9g4ifvgUW`sUpk&0~v{^Ly` zTMg+|S;q#R{W>>rkx3_aOE0UHQ96r}spxos|G+WIEa!NI!c0z`J8DM{+OO|z8# z1o5^kogp&6ImQ$}WX`43oe}8R(DKg=8NmkAkrbJ60W}|?0L~x_$au`|r;BIDNwq7K zP9b2oXi)h@05p@GV$W$V9Wkctp5@2jMMqJ|Mn(?G{ie@NGvkG`(@&8wfA;kt(>od3 zECbdD7~x3!qb!EJ?q|3C8s8J-gg^`e7TIJR_Ay~jA{2SLzFxo4`L=YdFn|va9i*oS zQ206rW--|18(hOdt_jqHb{3zFgYV2Do-1;-mNV0A@>glnYMZeNCuh!tq*NtE_*fJf ziah56z{WGWKi&|3b1lNUk+$>$(3XcU@Y8$Fi~4(tXEz>yPBc9)C!QEDUa%~QQ zSn{=}5fI|URY^1D!}cRuxVGeM6}MqkiX8C(lFGkjhH~~i=Ys@ zS4#Q;2je997umn0;0xEv*Xoo@OUjTG2=KYc1!H@0oq$8P1Vzsz_RR%oqRQ0JfKD}J z@yhq%QW@@$XtxS_u}HRkof;BQoWSY*%PGaX0J@kB{NOHoX6N@)(}&cOjN&CqH=|sL z2&!`ci;B*gzAs|;#10VV<@XwV*tBg1ggpz8_es!0{)=P9`*EK%r9-L|jQ1N(67 z7W^oXD*2^;Gqg!i9H7Z)kZ<)7m_>jT<)t>ONiJ?cngLVue$ zRnt^<8vxVsZtG$oL~vY%Y|2F<Em=Ff_y(9s3}KC(IEPm(tVQEULgV1PuR{qYF9Omv%O z7*8OZxC9NCjA)R1G6Wy~n%k&Cx8)(ZKA^!tm(l)^+2wVUn1d1=L@uJThh%|aTBW!} z0b-EMCW|tqpl>-J;30*ZGb$YaEGP8CnR25uOQn_c5u7WcoiDXHQ=~dR>tTS{gVWu> zzfLt(!}7vvYOLLySHRP8&hC4&YM3h)+n@I&R1;3-G8DyH_poeGRT<;a&>Y&weT(yTt}Bk>eT5b)XReI{~J^;#N^nlqA!rmBa2I6`%|IS2y|k=Lo^GG%BjC!i&Mg>u;t4*Z)d3<_Z9vwm%%n{o53Q1hKjHds_Cu6|>!Pz}iQ!GFe_%u{H@B8O}-H zmFy~gqg`ckfm((p{ju`;&Nc#4?Wmy@DLXq$E9sJPrKPnvdnc36ssL?Gfilt3YT|F| zDQ$_BZWL^|nTNX>hZ6=|yh+c;tn%W|Tlki<2}_lF$~1qz|D0%H8_ui%W!aB=#6o)p zL`}RE7_q_kx^JUrhSJ)4<-4Bl1 z4=vpf_lAKKpC!H=lenL7_4J{@C1F(*S(+i-?(oYl}Rn)gAU}d`as0pGDyI? z@cCx7XF*MZCE{#1-L{CwF66B&{tuXsQ?qQjF1g`(mDI$vhuxv|>`}#89UL zCY2!Y&kKo^Ld^L0m9n1zQX>8cdu7VUE~w8{4{vDittydfp_>d=bs&S0@0OnWNin##Yv(SYysM z(jz#h&v;qC-Ag)$qL&Ykl*t8&Zw`v4cndGH*!&9aUaL(&6kv0>2@qWOjFo;v6KHS(fyhF=|_dxbSYV)jnDDp zX;)-n;udAxhX;MGIM#iXO|#?2j9+m4%2SRU3f&6%?YUG7why`4`oHXdE);L+y*l$r zybaR2F?&3A?dp^K;bw3omJS07=cUekc0C{2887DI`C%E-!(FoQd*$c#m4kfXW6|JO zC{nvWzaV$#eZ!bfm*{&poU>;?3sTxXj1f)#jP$wt;QX(l3t~c{4OBi#exU85JH(X8 zdg96rSvcQn$kI{YZr#7Nb{qp?|3krHK$6Plj0_bw=;M}nSdJ2|ZnXR=rBbTZx;FPP z-MPW?b#Tjp(0ihMZGI`jB?hI#l^gMc#a%o_FL!;qyr+_&KO;a9N)-N2rwE`MBxF1 z2YfB+8~v2gL~wj@BLIj7K_D_2TxeqoO(I^6BmkWcw;`cK%yLF!;|SkzM(60aE>pR? zWY7`kG*;)h-sc-1+A*r>a8yjUX*VHrGpu@4C>4aerE;gBWEIIMXvak3;o)(^m+u3f zOM=8ilS*KN6g&c8;uBF3IxD)(H{xZ#dmEYoVhl&?z|m%XJs2iI4WKn2#U2(vKEyY| zjTwE&eAmc0Pya+{UgEL%gsi*kY=vgN)YG?mNfaFLWwvvQpCyy6Za#%Jj3M4@yp>%(Hw|&YbmQFl5PoWBjvC0Y~)^P6x`(&8v)(`xvPTk3r<}!LU=$P?K#Va7d;=uQ=!)dg!9Q@A(V!NpR}!M^lr$`N z@OOP+_2|Mx%Qj?9kVpNVP2TbqXBfni4J3wbNJ-M)sL+C7q}ajt*-SX-TS?HE58R{) zg@F-<(&}X+2U#TU5N2uHkOt0c94R7EiDpu%=r8TYKBpfB9m57U%;e!ld(jGuaiOB| z$TWr<@TdSZ2o=phJNGpAv!r>H&y?F*XyK-tnBoti3R`=;D0=5_V(Ap@T)n4H^0`=O zkTH1tXmE5XR0a@ztg1k7@FGC6qb=`+5dCDPym**-e&T1uu}kCg!sBMWqCyP-%?CDN z_h;GKYz{0FNWo{1lJ*F;PzxcOIVnl|^0=%y)jcEsd4x}PD#iTq0BItTCmSVi^Vd#5 z{~v6S1&+*RV3R>U5K!tLn(o2F{TX@p+S6jK1pHyjHkW?t{>wp|XYw6G6tRCy2)Vf( z{D|m)+RCDcLSzM)7ha14g^tNE209j&=5K%LRFGP%RQ|8`#q+-`e;k)Ozm*n|rQXam zlx}X){32W;(LPzrs;L9#4l1IVg*r+yPn&wKBrSNz@<4q!qB_-NE z-}}Wc4GLiDe7;L3q(r_@apo3sM3}J`-`MTm>QY$W#D$0cVAoaeb*Vj>nEB2lUY< z?dA}m?{W~-qC-hehvg44p41@G$_#1NyL`A7ly0_^GPmWOV16DLxWvJwI2K*kh6 zd6Ar;40byGCo{p&jbft=NVlnKKA-_+RgoLnvQvd@Ybc4rqfq~A^J<~)Yn?ZAGStok5uY;&oZHo2rRpD zfpy1q;Ee4;LsPZgiIB*@Fmzyy4i#X)cza)*Ldf3A1^QJ!YmD4J!vw~ja%_EJzo@y< zSpyt2AfDZttxWK=huYS60ll@(X$ud9LOFHhbL(iz+kww8EhND)6KZ{TT* zk>3_2vO}|3OMrQtlZwITRvakLdmxeLUCvqYlTai$6&Qq0)~-mU30WiThPG0^WZ^E- z?}IT|1k;;(Jz%7J_kE#wSBel4XT}(9w(#)Lym3j1SaX#UIvR@H zC&Zc3s>Dx+BZk7io$L!gdn@O^3ASiUGtK8l+i~imz}`%IkPe)Iuo@qjBhGQFRR56@ z6t0`Nf?7m3U=enubWC3D@&K%d zHoXF)QK3-FbYvHhPhM~=g~$S4KNi{EALB?+bLDYZp;rX|0=Rb9$)9zb z(!#jDt>rxkI`cm17LYw#R>ZD3iiP5%*&M5EQLCSIm5ENPzN;toCLekO_)CA!@KNYp z1HUkg*nfnnE@+5C>o0>?mWZn&VJ^DO-vXY&SFt{R+q6DmleGPp$5|k@+iiRpk!E4)k!P&5z_9AwNv$1qSl7Y={7JodwJEmOfx>C&8s> znWbv(tTDNwMh#iUem1Sa!D63*ce1J<8AeD!w?;T&iM-=X`13;rxurSFxfje1wv3wc zboyA}q&>?5GV^7pNt*&YJ<>a1za6VK_S`Sv#3fL1DmnldFihWwUr3YAqp#ME>PH;- zAB0yBJKF_o7a8a)1&}#Dzm+}_nT{t{Z!+6X$RJ0C?niS$HgpA({f3UH6R;W0ySfaU zfV%))A3sswB;RhkUi7c|WPU{I z0@-gNV#uki`Y}pEwLy(yLnfe>C5C0_lp4Oc`?ok)*`-jNvym~YSqm$X87g^pRlPcx z_AB5dt$-tCbk+kiJPLdW12-qZJhgHC)z3HlV|MP=^+lP`|5n9umKrHoX8vwMFbhiT zQ%1-*C1YL%tM(;UplJFM(~#x~JHZ`mpAfOe9cafH?3s(uj(hE;AiHyF3Cpn5eKizO zu%4GFHCvU6RdDAJ1@YMoDX)%(T?*0Cg{90XX&s!(9{=z;+6d8b=sW%;DqXbCpaqpm zt5rV?K?^%^2_|jRFgp7RPZIX=8^JDN-iKf$zU2%l6$<=xheW3lX`h$LV6sgKsVfBUd>|nKcqNU#_A0*UjJ@MY^Gjmyno||3rJigBcThkR}){ znCyp*r`DI7<8w9cN@5{tShRnAD1_XKvW75T|v96P|5y6ewt_i70&$XnjKYOi5Gpz)84CuFBV z>L7i=1#lB+ZP&rL6CZii@W)>%CeQO!1+oXTY2l*(l>eX^SqKKioggun85l}Vw5A0+ zyN1XgEo0b#flMN{01GZ0$%&MKR%i(`_XaSteg=O^<|Rafsj%=@*q6Q%>K@+V{16Ze zN+qKbltTC*&+coZo!Z0}m*l{GxPx>y5@c8>^meWij=j&mVe;qrPP@~C=8=J0q2ybq5T%UV!6*Tptk}RuPf5SRbhc+R5WPgr&BOE+BlS&kZilM zv|;Dk3wgO^p%Y`7O#KQwu;W`(9ttv~wPQa}tSvtV?SYDY@o{oL4FfxN&Bs9IeDdAi z8dQ09CqP_J(?#*rcccBo>+Z( z@|eci(bU!V6GTHoc!);meWahq58P@>tzEpNl$)J1RPxS7*c)te-9#3eOYz5df7 z#?+PKx$EJvUBig`PrGf?Gxrixsmi>!)uz9r$k5NFJg$&#;$Mf0)iI*U3=k##GbSNBvU;!Z4>`7;+Oh4ur$$w zpcZp0wVgKnOgquf>)Q8jiUCI3#4laPEuCt}?a^A}qhaPYNQf=JwmDM^lH3m1*$Wt) zVz|z8`E2A>ljtrY9gz9NUH6Tj$6`?7{NWtb=LdIq{dI7UcG%6iw@$j%F+r%`jxR0-gj~(;UJ9{($UpSY4=i?; znpli1`(>?0=DkNdjxS@e`i9~CC$~oLh|~}_XidUaNEmrHgXu^x?$@BosH+ezKk8IE zgm_V`vSy^ED}b=TP0xH1gCDW|CPp#Tza%kCp*xt3b z*^S##$RSuYkc=z1XwmBlT}b|t%f-~%(e;CrG0DQEl-G2r?dGX(3Q~KQQa{k84VtHo z7NmV#N}HxjpEplmq)UL=*)0OeOXkmK9lPEow(QZpSdOK;DtJ+}ZCO}<5gvVE=M}>5 zaG8R>kUAESn3kb=A&8HD?tBVHF25@G%Hrtx*Na@dEy(_cmNAUcut{OLPC-t(G_Hoe zbJt|cfICQ0SB(&H_)Z5S6Y@tq^2!YG)qhhW)5IV2ys+SJ+Vkj2qDVyGNUCBWQZ%D7 zL%tv+_h1KktuJ5oxt3|<@=IA0`yiv&Q7HwBADLN43!L{9qA&XFh6>w-?dY$!)UIEC zHrJdu<6W6Wc_r{SX%9sby&9bFy-8s^>ks`(k6A|4#uXOrhrK@vd-eS{|CL3VG$ptt zeFbb;4nmHG=U{f}*F5)%Y-Ahrl8WDde=8%zF6UMLpy%aays%Q?dkm)X3#QAtO;FQ`f0uv_r-hjUmj$FXq6mFR~d4-_44K3AbyjGP$M^2PwF z4SBEq%(OPxl4g2sPksbL+5;X$u#k>>uBAYaX^D`n{mvVr*s=ngrY!-WMuP<%P!pMY zk$MLu3^6py(wDVwvfNp=fE4rTu!yV!awarb*p8jjw}ti2@%v`_PYjTf+#E&TCT`U( zUDW4ED2*nsadchOJaE5r4eFJm zx~nxgWQk(*l6CytqS##bDeNE7DP+5=sn#vG=*|1e*n6>uwX+^3qjqI?o~%&g_Pb6> zx}KsUiHw=Z&?AG>@b1=V)~=0)k_Y^G52UktJ$q^1R`hz^yGi~>={vovco)Gatn!Xn z#{KWgd#JU??+CuHX9SB#&l6eoJkF0!Co2vfWhK4UeW;ojIHzppCD?syZ|a+#Z$&8; zaZmEtN?1Zk%o2x`<(M+e-O9R0HtvSJ20a_@i1|N_aGmw{RE9KsdR)r+=!h8 zP0KrSq+gMU7fCcvOX*yu0sT>$W=_>^U?dQNk1{+ZkZk)qkXqrI@6EG+hS z3|O%c`j8(x6!jWDb$?<{zeL5E^$jaNu3hz)cYJoPo+Q2aY59!LaNqIB)a^&H`Zt}~ z7a_i0=CLL3!j(J2z-x)iw85`=X8R@LB&9>Q|0JdFeG1957U4;Jf!1)}Vn)`0uPL6g zDPDQ|sxV@z|M`NE^_@w_m(0 z`FB2325Yb~ZL{?Cx14dqQ|vSIC}QUReXD0t>|xD|U&U>Ff+FLl)=q<4Q(Kbu~Y|Eg#+F1xAF`e4QXz4r0Uw`{jrvv8Jlon~g2 zhgF9?_MzS7hcy02vm3>;v|7%a<)0#qI*&GqC21)>GsoP4xcYfu|K-K(A>4bSg}$BX zD7bgOaa1i%&}6xK(sY>rz?(88DS0s&gmbHU^IbhZK0bcc#{A%yGh43hZ2*fukMJd7 z$UNVx!0-RvyjY*{`LYi!^-*}nh^*l~UMH^pk3{!d(z|mEuM45&Lw!-a6FvqQ3~n3dTe^S0a%;%SA6#j#n)jR2sKIUjfbg}h{Bft9n@P3l z!VA*+_}`!ZLivT?Hnsj$tR@7D{ghOt(QZWvx}!;)^PYs$YBM09re zbGUq<{}Wep*V{8uaELsh|3p`fRIo{yNu~QOAsw6x(BOH^M`2F-@0jTO$r^v;7K&F; z)#>4y_mW?sC;Jq&?x#Soz5nY{b6{jXyx-V|0vrA3EPAfyJiWsB^!ju=p2w_NzZ((u z_J^>ol6tkLDtpkFJ#T1&8e)jIHSe8e@2&kG-u+$WRDx$h#vMS4x&b8t2@;7`Y6U}> zL^ikqP)VsSr%3lqS`vbogn>y0ldcB_;b<6;_DUOoVYLP~Z?|vm01cP!EWH5%28hQu ztGSh1&VXZ|kt!cG6$G3Qhe!PWdD1Yk`z=%S!PJAa?k&fGTV5$O>QINhk>}E}Uw%s8 zQ%}|92{@Bv2s+4eFqQ74?fv;KFH(GzyTqT;*-=JlI*=#=7QOYgmLATJDYRHKgvpH& z*(>Hkh#=gg2D`1a(x4cFCh+?Z-ALl1~xm5AuA=r#QLphlDAD)f9urlkB*m7mI9-@mQ z$H?$^rJadds9}=1|8iCS;~4ttf&dNK>Oz-tP0mEOw&m&~pMgSd@YJwHO-YDtSWRif z<#NrdXJCd}Of15(wk(nTWo>z?*w@;M7fK9umDz@tbyfKeFYBs{{J+-KyozC{udT?k ztgovnfBCNh(e|~z;q?H6M}g9WWkb`Ot#H1kp3AQduRnCj7N=nmR*kKrVm+HJV`3|f z?bCb8dP*~fR!yCY_hA%WEB-4@O=4$9P2JmBD|OLoc}2}{k9EVFyG{leU%!j-Pndi6 zYpdvW$)HyC>kl|^T9qa})Vc-NPry;!GC(Z8+A>J4%+xwWX=L3xOzT+OI>H#R+B(V_ z%hWc;k!{^J&Qnp`HW5PB!jgwiWuyucB`D@8ZKH4ZZ`yqRTZi#0jP4N`|ztNUHjw3p!2n66gQUeMlS(W-ZDWdDhgCUEM+u+M zMjf9Y@_Q$S@%gBvwmb^}PGX!b-Ycf;$L^?PC_LCr_;@CuL&+ksAwU^r`aS*cy1ZBR z&pm60%a;~oky`hluk&#_*pKfC*A}z4mpps>oc~@=-LYhx&$zrtB0oQ1wHLdVKZlrr z1w{ec@s6ib;Pb~J=nySI&<83N-cdqb-Xa7X0|j};M}f~Z#Fp5x?ArFE>cn=q3Fqit z!O@^=LJaj+@mFS<1IMrtH+WuJH-#raBvs58T&ba+Xnef#ppQ2wX|j zt-w&NXGBOX=)vzn3K$i5;SwD$?Pn6nxsn_~2Y$;8eHXB{&3?d+4GbX@k>$9Vgr5{7 zA-GZLoE=Z1V=*z}000tD$&gVe#?lpKkmM_(KqkENG*1#xO^V-HWI7-MG3|7W@0}%} z(Hf=2=AF5?z!#aBCnYFeisrusoS6|}vz+2R<#M5IO7?DAF>r9F{<@l_WPJvqN%UCy z$sWzYiXQsXJRZN>2X1OjvTQDsZyl5A9BFPzmxJoK$LYoRsLXn0>!w%;n+_u=m&c$z40m4DJqG(z0-!JlZ}Qn%a=+%{@_m4oN$0p^`Nt5?)unp|@38iIVl4 z>&-)Yg^@-g9R54}Hs+ixxrb54OasD&GmoUK(ZFK#H>D<65;V)NFhs+dy16yM4XhvK zAIGiMUl^CZ8fPc_j{4;JGJ{zC>AJdpdI;7YIcGRnlcu~X=$fFZRGkw(> zhbwKC{pW3t%4u zM`eeO0xu&x_2dl$4h>BDCqYWlty=|HEfw#RM<`k-614L4QFXJQyMRgE%VK_$EOtIt z^3-4Nf-Ozz_0##&&#x(TFA3_e1;4rbyOP&Exen3LX;SPWU^jwiw#`R)B}TqYf@xr1 zIC}B2vV=pRlLYxsI0RhEljGj92Q)t|SzEpi@94W$0Y)R0#j1PTQJ*?GTNn79#*<+u zh2j=?x#0XY_6jOB&LAjMl!8MO~lvUYp$0c~i9ZQFzF86nB#H zksr`b$jc@FnZq?DOScqZ`b`^BYrl$zUNg*d?0t*lc0cN;c`*I<2&dhC8dn}I+wjiG!yH- zU86crUuSmqnyUfL6)p_}5HeKs){YoR;PVLZ4`U*1g?Xal`uL@QZ^^$m9Ol>okR#7}x+PWt7a4*g#Dp(ey+>$`Z-JoIES`i7oy_nO8okMZ9l)qs1(t z)zJDFBsV0u-M!Y)V~7I`D^_Mc%2*L-%Ejq96<+E*#i2 zx))X`{jn1CI2RH;9F5&}l?IO6wBq%h8xaxaDSABA*4=rh-+~L+o)Sz)Xz#qy8)NIk z*TL@+wPmZ5EDd((Q(Iqua_|b;C+${hqO%`0%JN5sukL?t@c!B0D1U7E zFmI29=i31E=?9gG5^APJPP}4kukMC7OuqTo)AnbLAuSyKEA;Lr1sG=(|&OOv(-L03`un7V6?D1wcR=%I98!fb8H*8_M| z*kFePgUfo>&KE}-=f7`Vuk4x;G1M{ChB}V313l5yhtDB~&(`HzG=fk`_n5oZIw#ubp9{x;0hqd%7 zMF?8r1upOKD)v~6GBx3gYh$S~!z_GgabwzDm?aL61pTyoQkPdTMt&HN3I*9QB>0p@ ztgCD(2|!59m{immRn$Lry!c3mCAtrk_h*W1>QZK{iKpv;w6Ty{lNq{2u!H?`*uR=| z>>t>iLw70l$=V&2^3Cij1(m+>E=39mEdxQTQ1`>WQt#X>dlO~@c9a$rijYbcUQKC$!$(Gz#HmJYD{ij^Ylmlc`QtVSA zv8GIbd5#*J`Su;j zVt7vaw6PKEaI7UYx?9s|5{vh+3xq4+RJx4?bfqY13Sg7#~{4-A| zqGO>-a7#tAN@mtuiXAQto#BqzC*40~PP^ky7F&b$yB6K8FfN-F{Two0DNgGHHXtw_ zPoDs+kBa0p+yelp1|AL^X{Di=p-DQd`_6((WLNz^1XKit*qZ}9DX92j#@R3s^f1^O zWk9vJ^|S2N^6-im=XNOb*>6Y2!d=P}93>c^wZ2SwT^^H05(g8~Xa8UeG2l>|187BSR{Uwath&FgB5zq!U|EzL04+gQ@ zot04SlV0V)(He>EqiV*I4`mvJ%3v-8g&AoI}}z_?M}l{Km~d1Yk}yo-t=a%0W_= zYx2v37P{$#_tvM+TP%mbNoH*lC~bcX(^u0S21-3)^O6yNl3Z8l`V zY>m&+V7rdOy(ygu!(cF4H#V%}-b76vmtZ|OY?;Pn4U^Za+#7bZfn~u~xk)qYphXoU zFWn4YxWAnczvZiTcCX8Wv8^$bn;vF$!%M>T%D}Tt!=~9o=X?TlU8CzN8a>|df04hSbqrnfj9$!n%h!LF-ACq`Q^Lc$ zd_aq@F0fHKdgl3bit?kSTMtVv=cbVow^R71#<9)H3H!PsS^jZ$$aEC`XDyF((86e$ zTVIu+7vGDTa3;gfmtzzAAIXjeM8_yBR>y2ldj{$$-A+n`j}}r^Kerr(AMz)58S!s2 z;KIur+rJ*=2FERY)hJUyEW9nycko<`(ijl?%-(alJ||S4WVsfjH{|wF2g>wC>q~d( z6Ft$xd+*Gn{LD(umcAc04TYV$+S9ny34Tj?5mF|EWfRh7@>=Kjcu6KapCbHK*iC0u z@Hj!JMdkqxVq`0p@lrE2@fi1h2XqbM74k3W?lYgJjAeo z!^(c2f|@K`3O7)^j!?xk4EuKbA6**OJIZ^!@_yN1e_FlwHKAUp{^{w;(INbiYyJ4? zufF=5+s0=(-^s+&304j}Y#Z?gPCE^Sa+Uo0|F$%&zb5waoH`TXnL59p?p958(Yw%M zRP_QxU|sw5(NAxt-_~a>Qb$$ItySU0KZ!2>zV&Wb@Y@&x*Ba=#q(85d$(!xZS9Hl&;m_Z2$=~iT(A%a2 z`*ihu&2@m;m+F(0G2@F#l8VlLp$}qwZwUS~U%{iEk`_*m)@WC^%g zZG(I2U+<-gnVx)`lnFrOY|98IBa&*~Ta0LyFvVEnYlE?PsCLQTT5y^j)zT+N*UG=L8>$^HzH zQ0W+JZmmh((koc@ZwZbH<0}cTuN`nD%IW5VEqFz(Ys}KpjdgbebO$@wBvRIAVQeVS zPz7`26y(M(s?R-81`WcJurNEdm!u<@oI+KU_so&1FLR(Yq}zgkDfY)SRsw{;LL>mA z{B(WFpDk-eAVGA{9LfFOS+;*4KZ_Cxw#p}=x)j#-kiS$=|7}HMqsfI)++Ap*c{FV(vJHaPGh_1Z!UG-^dW5a4jYizz|j^#Z^C$r$Rlt3?ze(Qkiv$-ichbnJ8TLq5% z2i0A#;+aK0eV(%}qtd3-he55gcD+6v{Dn`^xd$`ONS?ER%ms~=?@C4p09jQu#k-H@sll zB?Q3y=4^9ipG|5O9x5r(g`lf_YOWaC96UP{7?sLvs)4qoTMEx0!|h{pEL0=_fB|gX z1hG_o>`rfJJ(D2M8BS+y6nkR)C-4&X6k|le@Z<;^0 zyJwkbW~4bV`ywLLqW+V)-98Qdx7iH!Fsea3xq5mDw7&{=n>U``1hnU8OYqq`f-cdo zvFDv4_AfLh=2RBus+ z_Y1naeYL~3LCv-|(GcwiojkttFl@d0gKwS@dx%~z>x2C8-cs~~2tg?0zkTcZ_5-SF zBcTYULg5)>W$KmiA}zX;!4{#PTfMDKO!#Y{tzFJc6hf^X)*cJ-X&PY5LRfLf3%Uhnmw2M#npk8QcTR(n4d@%ee9qs3Y| z=YaS&0OuJQHeE8LN*c|~e0umc6{WvA66-hpK_Dak{3~(G$O!F*@E- z?DKCCIzKfsusG&e3IbszfL0=3!$3av?uDFE)Lwe_{{l-TwAwt;L*;|JvLtK@GqUf4 zNF)Rjn!_q`@HJkD6O>qIq-xO6vG54K1gzZ_Dca3e&uj66z^mH z>5nUVtXFCN`#XfGkt`1LukdoKFZHc1RR8fAG zmKvIh6qh8VqlS8!N>$y$hO?l)GP-l)S+r@@u4P;QajT#Ka8vcktoGk0)Q={CV{0)vssY-u-*{@#W8_U*Gx?GqlJmD=aL+K?hq|?kX%ObOa;LMijpT|z)YP2Jt%IrxRpK8n=EE{@| zEYUtx=t?h>3X(`N%jC|;(yHPxMto{3=%)}FgLBTGSfldI&W^Gwt9mS3O-?%XIc7{V z3pErvG=*w&(4g9!GNF3xJP1ojBdya$5+Mbs7CxPnR6^3cqI5E`ygc+&RL}IY(n(3v zs!CHgjr7iY=*cY3D3&ZIEP}Kg4b&Ss^%1jFi#66dBXLe4BbR(~$}6}0a?CT=d~?n__xy9vLl=E?(n~k} z^dSsjAlIMGG7Ev#iC7@^Ore;a;oBI{9WN&s;GIg{8F0>$zfd>+@&yLKqk`Us7(jp{ zig$V8hN&mS0s*owq5$Zve?ocx+(*h@06Ur>UuOWu&%+Y%w-fky_^U%e0Rr1P{4!%Z~y@WK!66sfdB=lfB+=Wk^qcD0^P%({$v=6BMN|d1o+^VQ1O6DIADtw zxJf$5N4#oCzyc;r-vBHy69-ygiwCHHPD+7?V<_Wyf)SqGK;{_`VQp+gQ)Jh2_{iWm zz!{i8Kmkx9y8;wo0uadmWEq?EJP0(P0TF1PI0_JfIS7G!3K&2GCSVOSI7gDIOkDwH zNd$0^vJDj!l_t0m#X;QU0jE4b_xSL}Lnv?p4RF8#@F#!+M4%;h2*3m!PykoLk`I8y z1UC|33+^GtT{vo_+0s_GUJB}hkYp!Yo>v!nJkLuekrELU2mxIj00P@oA@>IG1v!+G zdq@~45h9>~KJ2qMWK#x7`k(-OenA1o{6Y(b00C`A z0D7-Zzmn8S8+OBX#&jd{G{g8xNz+Ww^A?!ko^EhC$pFx_rzRz!Dvi0lqXOUn-fg=F6)S*J1WF3D>(4;Oke^c6oZlfv~_Uf`bf8EGuA5ixUU3l~}C( z763aktWZ@6rnO~nFNEmTz7BSt5s(li-&h0+QWK*_C5dr|;Mn6DRD}S*E<0*5heha< z783>UA`bfh-&BTSz~!qh9jF=9GIUcKwlKf|rctVt9;9XGmFrGix8C-qcniv)00NR1 zU+I1UqYV(AUw-R z1QbAH-f>Tf29SUX6&n(8V0Qqyk#Khr0X^LnL6G1)=~p83C48xKTyKJiB3q_nJX0hA z#mpWNpEthj;V%FNK;;ve@`wdc6?zKz-~tLQ05no|B!zGw_ZGoDKx@wo379AWZo)f6 zVz?3yC?)}@nhr;2uY7yX-UP}B=|DWugbUDyM=u=IVj3X=^kp+*mR1>a$~k~+DkqBb zd~C7*4Z4&fd;$W>ID`c(`xmziAYE9JgdVQY#U3dD9a9&W5dwfWtYckVMQkq-trOYn z&cfSXCL7+-x`s+<-)-WpT(r=T-TOY);n-ru4Kmsa+(WH1z0Gfghpw(^(aSXtK81!$ zJK+%58u6bz|)y+i5yt9(-{Ar9pPj7-$2x##51#NIl(GPV_wXV}a?S!AYZ+(9fNtnc?O^bo2k+AP zGdvFr6f7|3A)h(~h}8fEXk`-^Ab}*;STGkDK#mvVuD8lgceodQUYx^w2V6sS&}IM~ z7a&%|<2}WCH_8I)cj!K}K>{=>0vpzVKdRzEtudUy_5sz0a1vkw7X4>w^{_$c;X&<2 zI4o-@@I)tCz=L>5$q;b~1_;_9XIj5$7%WfVsv*E0{-XfDI)DkFpFj{dB>`4LSqeY6B5efRN}!A^=6@*{ccy#T!|}Gms=^@Ir8FlLUCYvKlL<>%K~SM8iwL z3c4)_qq#t2r$Ouk16TkB@~KBLz>gpz?+b(KqACTTfE>#PUo$JGxQ+Y&1GHaEgiGX# z=R+ks=szEdrckWJc6^C5prE1}E0id}^bw+Uq%X57s5|5dTJ%Ev!-MUML+??7ehfSL zBEx7vErE=$WK>3V8HA-8DI4^wA|nLNs)O&#ivd_a^9ulOvMh}m1XAmbDm;jCbd{1& zApzi|OzNa}Tsu1eq}$LcY2-o^YRQ*`$$jJ^cSMDMEUVnuNof3s9-2cus6!+;$Qs(i z3W^4z?6!xLsbv%bRN^3~xP^C0#F>mV9(;wok|2v@l{YM(Gt>hbNy%WzB9Gc6nLL8t zkb{{-C^Ga$Yr`%AXg%kF34Z)ZL@>3;kR*6=7$P`Iq*ThLYq=8tGyI3WJ zwffrzZ_}qDzzaJVEj;XvYPg0k)PrRJfZG%|;p9u743#&C4BW7QK`6?5fr93=yBgv{ zUQ#PM8b`=99=Mv8l^cXM5TYu=Cm~P<)M7!SlB4qMgOIe#k~mFC!aX74CG-rqP*{Lh zlD{QbB@uMNK0qY`umC5zDS#s)kbEKuK#93jfC|{6kWxJ`;0EjxPy(%>SF|*c^vg4# z10h1AP18UMs0o-zr=)2D4>dLZnYYkFEnb=*2dw}G>&{32`p$^xlA+j24|@c$8UO>Z zI@rrIPEeG&XOnkgHI)oq{0BMUo4Zi3^e)p*`fNJ1IoW zF4$GEYXUz7whJPZT(#9$38gt7oWx<(u_$Oh*djZ1V*p(+3?yhqQ(@IaGz9^&1ahsmeocf| zg|_*7Rf5%5{Cc>@95!SvNMvBChE=I~fRcAzk9egD3YdT;Iz#~2Go@-CT+1FMQU!1* zC6FWl1_S^Jz`Wfwzb7iAY8=<}=^k{2%ZY-fAe&5&>OiuapFYDvJCeE&l8N*|T0$s* zGTT+IIAhGiqj1b5_ja|>=t83y5S+OxEsZ+9d>L86G2j}V^kW2-6vXO%_i?bXo#1vae z7%&OcE7x=dL=`%uon1~tU zospHsL1B2EkpQ3ou?mEGxX^7AOBof@p{UdfecC{9y#@!6P_gt0LmE zt0?kPt2z88Tx^pAHi*?(Vtxe}7D5E4T(+SygZks8JmBIX{^FNumJ(}{5}Ox0VHZ_i znG*hzHD+TAdKeDO;5oL)I*wUeF05s{VL3>{BUn&As9ztpEFe}Y5beIKQe;OsA0|2i4O(NLEK~gRm6J%ZsfC2l0Xz05fkzma8C;*t>vGfvW zegr{N1&4-+6zbR!<`J$s0}1fNPBz?#0!fzqX7TZ73VOu2CuG%rVVY)Gs>-WjZYH}Z z!=8{@!dFZmJOo5f{DQ9kjxtaqHby#|a{^xz)!t&88@sO7oE8pu!D{`0F>Y=aA-7?SSm}+gaVME7c>GwD<)O+3nzl8D2!+*cDk*| zMBFxQLLjtzv|=wxE%mbNPz<99utxzRBV9-#0hoZNlkNmSBLi{+aVTv%0;mY6t~xCu zqlxS=o~yhG6uo7N%Dz@?#pxwj*a@NR^9b5Iqs~Wd@7k*AV32QefxbPLv znE~%sQ#nZkdclLrq(M5nOu~XS#JXcHg4i~Ks|xaUoe?m1I{db93pa9aO>-A-ax-7@ zb{(%ZzY#DuT;DoIEf{1pUxF`paH%noIgbJekMm>wZ?Qp)Tm;2pd;A`3u(3Mh3mV(+NfTb1f*H6f9wVHPWio5m|5M5nu=fvZ6SiMUlJ z<(Vjx8~~K)FL9G~OqW7_Cm*uv&+8*KZ%BkJCj<#tDhS|V0dl|rK&7Vx$^Gm|vl^@S zVn%?cb>bDu&E%e4d!jK@R^SWYRRVcoM}p_EpXcpG`gy!QPzE-5rRLc_e&^xbf;5PN z0AAxNjc;D@`RtTv0|Z57B-xBmJ3q(X+H$(v^Ims!C-QhVFqo-@1z1o`$PA3?paM;V z#L5I@0tEn5g29Yv35=nyjp&>R1FHIF4*CKKR(P#iJ@4X#iZ-f9YbaQ}hPv-Z2-6-w zyHTV6il~v!MIvC~c_7V)(gy2Wt`B;92y67+gf`{UEjX+wp zRTN3==&JAYd548UcmR{d+fVe$u!Jv%Ix{j2Fphv7C9}J=SHE0lp>art4K`^I4oO4E z`zvOlZ_+Eqr3p{m(<_hJD_^OR9$wXbp*MKdnJt1}zCkyrL44M0VBUt{L9HwHKFvQH zb%uR0E;^-mX@^;T*zy#aX7kif^w4LBZi~$@He2V)Eg%3C0z^PjFdzm1Orf9&jW!Jg z!Gti85|U5?p=b~km`G!wAU1oMMKi#wGzZFY^pHGg7Kdx8G_Kbs=X3{926fnka3G-n zK!E@i(AQ+w`}$WK<$BBOy6Y>u z1gL8p2TYsmr@YME?EDNJEj>+LZGDZMt-Z~?J>2#!3_zja;5NvMRFsew_hh`J?ur&2 zF%jz7#nlA2RB4!pNF^eDz%A(~j0l}QVrG>YqtM7CKWGFzv1k$9AUh88Ao3Wczyk%C z^h_kwWPpGLn#}xjVv9)w0STH&V8wAufK{zx29gzsR?wlihMj9Q^cd2gNq6xYq_mdN zZd9vUy^1xf)~#H-h7-ywf&f8Djv!GzTA}F#}u? zfM_=(zsd6B1w_*32K`|u=R*XVj zC*x5w=H_CHEMn%4(g9$-pOo1gU*!$VC@bE z1at|Q9!zG`L>65V5Mcl{S;S60tO2sX1Wz0g!5Sy-grAXeAUUd%q)M0MFGz}->XEBT z_0y}#lp4&bMBa*PuDb5p&8e{Vq+&wjC4c}+5f*@KvIRtFL;=>tv_L-37|=ih21FaF z5}B|`NhWR;VGe+{Ai(B4$pWyR5(pGfA-1zP+aW~D20-pJQ;iCRyPt%z?ik53TYv)% zRQOZ0(ngyAc!4_s0CkaL&xfte+v%oGZ@uI>mF)LJv)J(MB&f^U%LGLqG)sln7cgOCRlA z(@zT!wbU$A&2`sae+_obNeew|GX)IrzyQ)BXlvM9ot^gDZqH43-FDxNciwvM&3E5^ z{|$KHf)7r3;f5cMc;bpL&UoXFKMr~1l21-~<(6NLdFGmL&Uxpae-3)+qK}>{(6w!C z9*gFyVpSXhWhTPPvbi^t4l_i0w685jBDB4n?Rq)@0@$| z(obI`?ZAV~JKMYcUj6pMbAQ+IHb73(P9`e`^lujA@}B{~QK9u{Z3`p|fC3*F69p~+eP#30sUT4z zCdiKsEP0RqN+>`g5DZNxbe{`f*txcyP6?Ap*%%Ul9z&q10;G5Xx0djLE?Hzd0k8l7 z>O`L|5THaBF-HI#z=%4DA)#3LO_xNC}nDr zSSI3R$aTC-5indc3^YujCJxi#VLZ}GPnHCb%xq@j1W614%!FGuLqnnzK@%m+gjtR7 z$pIcvgax?e4F@PB7W81e=KcN|1eVqyYaoC(p03J#jISO6kbC53}VVI~x)Oo{UG4k(1dX{uBSNFq}T z%P63pyC491Ds!lP#uG~jpn#L=I6*RE@}-oCDI~fGjwDs@MLR)_K?OifGR)H>V^L{6 zB?{H3){UY@kU#<|P#Bc;=p{_Jgk>nRo{)n72m*PiOgSOqIzVPBj2o zkId;gTv}4Me!?9qise`JDkCB&@2I;_=o^^21+_|bv5Wx zf-Eu(eb_EKUY1q5^k$nW!r`bf=-F$P(t8xzXM2s zG88z#S)G@uIt{=AmsF;enh=2lSRfDo3+`_DnreY9iI*7k7{Hk_ykP)zSegP@t_0Zo zU#-E42o^QoD%o%;K%8d73YdULB1{1oyE0b|V=@>lh5;Vn1qgJ}4d4;P z2E7mg?lK_(eVkCI2$0C}sLd4#_%al@{4O~api>Y)0GEGuHu07DBn`;2+V(NE_vS)d zm%-n&FeRD@xH$?Aa9x;ARII(v+^WrODR8OKW=5obI%zKMm?o zi+a?gF14vojp|gZdey9MwX0tZ>sZTr*0kPRrk`>>8Jli+K*H!U44}Yf6i|P-~sVx$BtP{>`>qyY->53`!b z2nk#O3awLc>j;Jbmm3iZ4|qV(n*@=mEiGjU=n@6iqK874ycjA0L_izih29piO8{7I zlKV&vOhAoi_GGvn+OlFa+SC5_7`uJ=%KwwB zg2H^@6a4PeQyEyUW6=u_N0z>L(oSDN3USTiCLmhjE>r?k4cSEyqsc>rF5wCCF9v|| zsi08ch>-^Qd!^?=%?(4NMuOFF`X?i2@+VE`_7pjS zYpNm~5l4M46dgQr3l)$S6Sx@LH6BV35N6;d=pXrcUZ)7Dec9!)JUQh zfMxS;6ljV^@qsp?fme8jX!tp1=o?5>TqMY1M3hk}VN_Kz2;yXN7U*3^kOvwPHEfho zX%Ggz7zmMJ7WfAzdl(bP_%l#odkG~zgp^qzkv-7nfLi!op2&?1ScdynfvU(d;pU5D z2!Y6kcCN_(K4S-hPm*PxAO+ zBID>mF3FCe6CAYSSK_Bt!>|_+vH%xQAzuOjUIl(uVqRFo5;e6#kI@DyApr(p01Z}@ zE!ZIqh8iQq05s=0%~*(OW-~IBBe?BN1nJF*!LHwQ+eSd<&3-Yl0^6xK72O zN~EIyM;37pT_9k3;ZWRi2^J9n*0v_&beUFwKZ>}LN~W5#umEDw2=x>p79mA)V3pa{ zIyl87N5l>s`C54CmwNecW`}URSSa)EzcL#`=)YCzEHx2cId4=GO zlCdn$;2IZ05!@CDm1O|id5T&y4aGzew&-4`GoBVloGN)05a*HRV{r!8krTI`(b+yT zBcDIwgw3!X6s9`)xrNWPBl?M;Tfv|8=_CKi3@&vj2k?jwH+=<)IA58d8A=rk$}{6h z4b-AGg|sUbYM~c;m>P=D-}tH~xie=PZfshu<7%ux%7EKym?rhjXno31G>Ynxd+&aSELLIz@#lee+tc1uHoBDlz~YE76Ln)A?9_ zx~J5+uyL2Lq6(=7i?LvXuwfWE;+nA^`#1NBp&hHFAZxOEBeK)FI39blEo(O$%Q-CT zvNIbtFuOT2OS3u4H8!g`IIFWi3$#Hiv_ng@MQgN2i?m6rv`fphP3yEz3$;-zwNp#A URcp0Zi?vy+wOh-zqZR}JJK%%Ig8%>k From eafee0ee4f4e5afd208e84ad8f419448adb7ebb6 Mon Sep 17 00:00:00 2001 From: Jheison Martinez Bolivar Date: Tue, 25 Aug 2026 16:37:26 -0500 Subject: [PATCH 2/8] fix(hooks): recognise outdated builtins instead of freezing them as hand-written --- src/hooks/builtins.rs | 6 ++ src/hooks/mod.rs | 162 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 149 insertions(+), 19 deletions(-) diff --git a/src/hooks/builtins.rs b/src/hooks/builtins.rs index ace4936..ecc8f8e 100644 --- a/src/hooks/builtins.rs +++ b/src/hooks/builtins.rs @@ -69,6 +69,7 @@ esac const CONVENTIONAL_COMMITS: &str = concat!( r#"#!/bin/sh +# gitkit-builtin: conventional-commits # Validates only the first line (the subject). grep matches line-by-line, so # without this the whole message would pass if ANY line looked conventional, # not just the first. @@ -100,6 +101,7 @@ fi pub(crate) const AI_VENDOR_NOREPLY_ADDRESSES: &[&str] = &["noreply@anthropic.com"]; const NO_TRAILERS: &str = r#"#!/bin/sh +# gitkit-builtin: no-trailers # Rejects commit messages carrying AI attribution trailers: a Co-Authored-By, # Assisted-By or AI-Assisted-By line naming a known AI vendor no-reply # address, a Claude-Session line, or a "Generated with" line. Genuine human @@ -120,6 +122,7 @@ fi "#; const NO_SECRETS: &str = r#"#!/bin/sh +# gitkit-builtin: no-secrets # Detects common secret patterns. Not exhaustive — use dedicated tools for production. patterns='(AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|ghp_[0-9A-Za-z]{36}|sk-[0-9A-Za-z]{48}|password\s*=\s*["'"'"'][^"'"'"']{8,})' if git diff --cached --diff-filter=ACM | grep -qE "$patterns"; then @@ -130,6 +133,7 @@ fi "#; const BRANCH_NAMING: &str = r#"#!/bin/sh +# gitkit-builtin: branch-naming branch=$(git symbolic-ref --short HEAD) pattern='^(main|master|develop|release/.+|hotfix/.+|feat/.+|feature/.+|fix/.+|chore/.+)$' if ! echo "$branch" | grep -qE "$pattern"; then @@ -147,6 +151,7 @@ fi // actual scan lives in `no_invisibles.rs`, is pure Rust std library, and is // unit-tested directly there. const NO_INVISIBLES: &str = r#"#!/bin/sh +# gitkit-builtin: no-invisibles # Rejects added lines carrying invisible Unicode: zero-width characters, # bidi controls (also the "Trojan Source" vector) and Unicode tag # characters. Only lines this commit adds are scanned, not the whole file — @@ -156,6 +161,7 @@ exec gitkit hooks scan-invisibles const NO_BODY: &str = concat!( r#"#!/bin/sh +# gitkit-builtin: no-body # Rejects a commit message with a body. A conforming message is one line, # with any number of trailing newlines. The only body this hook allows is a # blank line followed by a BREAKING CHANGE:/BREAKING-CHANGE: footer (case diff --git a/src/hooks/mod.rs b/src/hooks/mod.rs index 1c6fa63..d564951 100644 --- a/src/hooks/mod.rs +++ b/src/hooks/mod.rs @@ -89,9 +89,33 @@ pub(crate) fn valid_hook_names() -> &'static [&'static str] { VALID_HOOKS } -/// Identifies which built-in (if any) an installed hook file corresponds to, -/// by exact script comparison. Built-ins are written verbatim on install. +/// Extracts the builtin identity marker from script content, if present. +/// The marker is a shell comment line of the form `# gitkit-builtin: `. +fn extract_marker(content: &str) -> Option<&str> { + for line in content.lines() { + let trimmed = line.trim(); + if let Some(name) = trimmed.strip_prefix("# gitkit-builtin: ") { + let name = name.trim(); + if !name.is_empty() { + return Some(name); + } + } + } + None +} + +/// Identifies which built-in (if any) an installed hook file corresponds to. +/// First tries the machine-readable marker (`# gitkit-builtin: `), which +/// survives script changes across versions. Falls back to exact-content match +/// so hooks installed by pre-marker versions of gitkit keep being recognised. pub(crate) fn detect_builtin(hook_file: &str, content: &str) -> Option<&'static builtins::Builtin> { + if let Some(name) = extract_marker(content) { + if let Some(b) = builtins::get(name) { + if b.hook == hook_file { + return Some(b); + } + } + } builtins::ALL .iter() .find(|b| b.hook == hook_file && content.trim() == b.script.trim()) @@ -176,8 +200,9 @@ pub(crate) fn list_parts(hooks_dir: &Path, hook_name: &str) -> Vec { /// Ensures `.git/hooks/` is a gitkit dispatcher, migrating any /// pre-existing content into `gitkit.d//` as a part first: -/// - if it's a script matching a known builtin verbatim (the pre-composition -/// damaged shape), it's absorbed under that builtin's name. +/// - if it's a known builtin (by marker or exact content match), it's absorbed +/// under that builtin's name with the **current** script — so an outdated +/// builtin is replaced, not frozen as an untouchable hand-written hook. /// - otherwise (a hand-written hook) it's absorbed as [`PRESERVED_PART_NAME`]. /// /// A no-op if the dispatcher is already in place. @@ -189,15 +214,27 @@ fn ensure_dispatcher(dir: &Path, hook_name: &str) -> Result<()> { let content = fs::read_to_string(&hook_path).unwrap_or_default(); if !is_dispatcher(&content, hook_name) { fs::create_dir_all(&parts).context("Failed to create gitkit.d parts directory")?; - let migrated_name = detect_builtin(hook_name, &content) - .map(|b| b.name.to_string()) - .unwrap_or_else(|| PRESERVED_PART_NAME.to_string()); - let migrated_path = parts.join(&migrated_name); - if !migrated_path.exists() { - fs::write(&migrated_path, &content).with_context(|| { - format!("Failed to migrate existing '{hook_name}' hook into gitkit.d") - })?; - set_executable(&migrated_path)?; + + if let Some(builtin) = detect_builtin(hook_name, &content) { + let migrated_path = parts.join(builtin.name); + let is_outdated = content.trim() != builtin.script.trim(); + if is_outdated { + println!("Updating outdated builtin: {}", builtin.name); + } + if !migrated_path.exists() || is_outdated { + fs::write(&migrated_path, builtin.script).with_context(|| { + format!("Failed to migrate builtin '{}' into gitkit.d", builtin.name) + })?; + set_executable(&migrated_path)?; + } + } else { + let migrated_path = parts.join(PRESERVED_PART_NAME); + if !migrated_path.exists() { + fs::write(&migrated_path, &content).with_context(|| { + format!("Failed to migrate existing '{hook_name}' hook into gitkit.d") + })?; + set_executable(&migrated_path)?; + } } } } else { @@ -581,11 +618,14 @@ pub(crate) enum HookHealth { } /// Classifies an installed hook file's health for `gitkit status`, by -/// comparing its content against the builtin catalogue via [`detect_builtin`]. -/// Reads the file itself rather than trusting a caller-supplied string, so -/// non-UTF-8 content is classified `Modified` instead of erroring — git runs -/// a hook regardless of its encoding, so an unreadable-as-text file is not a -/// failure, just content gitkit can't match against a builtin. +/// comparing its content against the builtin catalogue via exact-content +/// match. A hook with a marker but hand-edited content is `Modified`, not +/// `Active` — health reporting cares about byte-identical content, not +/// identity. Reads the file itself rather than trusting a caller-supplied +/// string, so non-UTF-8 content is classified `Modified` instead of +/// erroring — git runs a hook regardless of its encoding, so an +/// unreadable-as-text file is not a failure, just content gitkit can't +/// match against a builtin. pub(crate) fn classify_hook(hook_name: &str, path: &Path) -> Result { if !path.exists() { return Ok(HookHealth::Absent); @@ -593,7 +633,9 @@ pub(crate) fn classify_hook(hook_name: &str, path: &Path) -> Result let bytes = fs::read(path).with_context(|| format!("Failed to read hook '{hook_name}'"))?; let is_builtin = match std::str::from_utf8(&bytes) { - Ok(content) => detect_builtin(hook_name, content).is_some(), + Ok(content) => builtins::ALL + .iter() + .any(|b| b.hook == hook_name && content.trim() == b.script.trim()), Err(_) => false, }; @@ -1799,4 +1841,86 @@ mod tests { let _ = std::env::set_current_dir(orig); } } + + // ── GK-E: outdated builtin recognition ───────────────────────────────── + + #[test] + fn detect_builtin_by_marker_with_stale_content() { + let stale = "#!/bin/sh\n# gitkit-builtin: no-trailers\necho old-version\n"; + let detected = detect_builtin("commit-msg", stale); + assert!( + detected.is_some(), + "marker must identify the builtin even with stale content" + ); + assert_eq!(detected.unwrap().name, "no-trailers"); + } + + #[serial] + #[test] + fn installing_over_outdated_builtin_replaces_it_without_preserving() { + let dir = tempfile::TempDir::new().unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + std::fs::create_dir_all(&hooks_dir).unwrap(); + std::fs::write( + hooks_dir.join("commit-msg"), + "#!/bin/sh\n# gitkit-builtin: no-trailers\necho old-version\n", + ) + .unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + install_builtin("conventional-commits", true).unwrap(); + + let parts = list_parts(&hooks_dir, "commit-msg"); + assert!( + !parts.contains(&PRESERVED_PART_NAME.to_string()), + "outdated builtin must not be preserved as 00-preexisting: {parts:?}" + ); + assert!(parts.contains(&"no-trailers".to_string())); + assert!(parts.contains(&"conventional-commits".to_string())); + + let nt_content = std::fs::read_to_string( + hooks_dir + .join("gitkit.d") + .join("commit-msg") + .join("no-trailers"), + ) + .unwrap(); + let current_nt = builtins::get("no-trailers").unwrap(); + assert_eq!(nt_content, current_nt.script); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[test] + fn detect_builtin_exact_content_fallback_for_markerless_script() { + let no_secrets = builtins::get("no-secrets").unwrap(); + let detected = detect_builtin("pre-commit", no_secrets.script); + assert!( + detected.is_some(), + "byte-identical script must still be detected" + ); + assert_eq!(detected.unwrap().name, "no-secrets"); + } + + #[test] + fn every_builtin_carries_a_marker_matching_its_name() { + for b in builtins::ALL { + let marker = extract_marker(b.script); + assert!( + marker.is_some(), + "builtin '{}' is missing its marker comment", + b.name + ); + assert_eq!( + marker.unwrap(), + b.name, + "builtin '{}' has marker for '{}' instead", + b.name, + marker.unwrap() + ); + } + } } From 914ab41a8f0d0a5fd9467212d62aded5649815d6 Mon Sep 17 00:00:00 2001 From: Jheison Martinez Bolivar Date: Tue, 25 Aug 2026 18:59:54 -0500 Subject: [PATCH 3/8] feat(hooks): add message-rules commit-msg builtin for user-defined regex rules --- Cargo.lock | 39 +++ Cargo.toml | 1 + docs/hooks.md | 95 +++++- src/hooks/builtins.rs | 60 ++++ src/hooks/message_rules.rs | 571 +++++++++++++++++++++++++++++++++++++ src/hooks/mod.rs | 57 +++- 6 files changed, 812 insertions(+), 11 deletions(-) create mode 100644 src/hooks/message_rules.rs diff --git a/Cargo.lock b/Cargo.lock index f6e55ec..0951658 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,15 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "1.0.0" @@ -341,6 +350,7 @@ dependencies = [ "clap", "flate2", "inquire", + "regex", "serde", "serde_json", "serial_test", @@ -663,6 +673,35 @@ dependencies = [ "bitflags 2.13.0", ] +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + [[package]] name = "ring" version = "0.17.14" diff --git a/Cargo.toml b/Cargo.toml index 4deb0cf..82d7c92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" tar = "0.4" toml = "0.8" +regex = "1" ureq = "2" [dev-dependencies] diff --git a/docs/hooks.md b/docs/hooks.md index 41b174e..414edae 100644 --- a/docs/hooks.md +++ b/docs/hooks.md @@ -1,6 +1,6 @@ --- title: Hooks -description: Built-in hooks (conventional commits, no-body messages, AI trailer rejection, secret detection, branch naming, invisible Unicode detection) and custom shell commands. +description: Built-in hooks (conventional commits, no-body messages, AI trailer rejection, secret detection, branch naming, invisible Unicode detection, user-defined message rules) and custom shell commands. order: 4 --- @@ -15,6 +15,7 @@ Built-ins are embedded in the binary — no network required. | `conventional-commits` | `commit-msg` | Validates Conventional Commits format | | `no-body` | `commit-msg` | Rejects a commit message that has a body | | `no-trailers` | `commit-msg` | Rejects commit messages carrying AI attribution trailers | +| `message-rules` | `commit-msg` | Validates commit messages against user-defined regex rules in `.gitmessage-rules.json` | | `no-secrets` | `pre-commit` | Detects common secret patterns in staged changes | | `branch-naming` | `pre-commit` | Validates branch name matches convention | | `no-invisibles` | `pre-commit` | Rejects added lines carrying invisible Unicode characters | @@ -65,6 +66,98 @@ with" line. Genuine human `Co-Authored-By:` trailers are left untouched — a rule in a prompt is advisory, this hook is not. The commit is refused with the offending line and its line number; it never rewrites your message. +### `message-rules` + +Validates the commit message against **rules you define** in a committed +file at `.gitmessage-rules.json` in the repository root. Each rule is +a regex pattern with a direction (`must_match` or `must_not_match`), a +scope (`subject` or `whole_message`), and a message shown when the rule +fires. Because the rules file is tracked by git, it travels with the +repository and applies to everyone who clones it. + +#### Configuring rules + +Create `.gitmessage-rules.json` in the repository root with a JSON +array of rules: + +```json +[ + { + "name": "jira-prefix", + "pattern": "^[A-Z]+-\\d+", + "direction": "must_match", + "scope": "subject", + "message": "Subject must start with a JIRA ticket prefix (e.g. PROJ-123)" + } +] +``` + +A negative rule — forbidding something — uses `must_not_match`: + +```json +[ + { + "name": "no-trailer-in-subject", + "pattern": "Co-Authored-By:", + "direction": "must_not_match", + "scope": "subject", + "message": "Subject must not contain trailer lines; move Co-Authored-By to the body" + } +] +``` + +Commit this file to the repository so every contributor shares the same +rules. + +#### Directions + +- **`must_match`** — the pattern must match the scoped text. A JIRA prefix + rule is a positive match: the subject must contain `^[A-Z]+-\d+`. +- **`must_not_match`** — the pattern must not match. A forbidden-trailer + rule is a negative match: the subject must not contain `Co-Authored-By:`. + This catches what `no-trailers` misses — a trailer smuggled into the + subject line after a semicolon. + +#### Scopes + +- **`subject`** — only the first line of the commit message is checked. +- **`whole_message`** — the entire commit message (subject, body, trailers) + is checked. + +#### Installing + +```bash +gitkit hooks add message-rules +``` + +If no rules are configured, the command refuses with a clear message rather +than installing a hook that always passes. Patterns are validated at install +time — a regex that does not compile is rejected immediately, naming the +rule and the compile error, not deferred to commit time. + +#### Regex flavour + +Patterns use **Rust's `regex` crate** syntax, which is ERE-like: character +classes, alternation, grouping, anchors, and quantifiers all work. **No +lookahead, lookbehind, or backreferences** — if a pattern uses these PCRE +features, it will be rejected at configuration time with a compile error. +When in doubt, test the pattern with `rg ''` (ripgrep uses the +same engine). + +The installed hook delegates to `gitkit` itself for regex evaluation, so +the same engine that validated the pattern at install time evaluates it at +commit time — no lossy conversion to POSIX ERE. + +#### Multiple rules + +All rules run on every commit. The hook reports **every** failing rule, not +just the first, then exits non-zero. Rules compose — a JIRA prefix rule and +a subject-length rule are separate rules that fire independently. + +Revert (`Revert "..."`), merge (`Merge branch '...'`), `fixup!` and +`squash!` commit messages are auto-generated and are always accepted +regardless of rules. + ### `no-invisibles` Rejects a commit that **adds** a line containing an invisible Unicode diff --git a/src/hooks/builtins.rs b/src/hooks/builtins.rs index ecc8f8e..ad7e41a 100644 --- a/src/hooks/builtins.rs +++ b/src/hooks/builtins.rs @@ -42,12 +42,35 @@ pub(crate) const ALL: &[Builtin] = &[ description: "Rejects a commit message that has a body", script: NO_BODY, }, + Builtin { + name: "message-rules", + hook: "commit-msg", + description: + "Validates commit messages against user-defined regex rules in .gitmessage-rules.json", + script: MESSAGE_RULES_PLACEHOLDER, + }, ]; pub(crate) fn get(name: &str) -> Option<&'static Builtin> { ALL.iter().find(|b| b.name == name) } +/// The four message prefixes git writes itself, never a human: `git revert`, +/// a `git merge` conflict message, `git commit --fixup` and `git commit +/// --squash`. A convention meant for hand-authored subjects must not reject +/// them. This is the single source of truth — the shell macro below and the +/// Rust evaluation in `message_rules` both derive from this list, so the set +/// can only drift if someone edits this constant without updating its users. +pub(crate) const AUTO_GENERATED_MESSAGE_PREFIXES: &[&str] = + &["Revert \"", "Merge ", "fixup! ", "squash! "]; + +/// Returns true if `subject` starts with one of the auto-generated prefixes. +pub(crate) fn is_auto_generated_message(subject: &str) -> bool { + AUTO_GENERATED_MESSAGE_PREFIXES + .iter() + .any(|prefix| subject.starts_with(prefix)) +} + /// The four message shapes git writes itself, never a human: `git revert`, /// a `git merge` conflict message, `git commit --fixup` and `git commit /// --squash`. A convention meant for hand-authored subjects must not reject @@ -218,6 +241,18 @@ done "# ); +/// Placeholder script for the `message-rules` builtin. The actual script is +/// generated dynamically at install time (see `message_rules::generate_script`). +/// This placeholder is only used for registration in `ALL` and for health-check +/// matching — the installed script always starts with the same marker comment, +/// so `detect_builtin` identifies it by marker, not by exact content match. +const MESSAGE_RULES_PLACEHOLDER: &str = r#"#!/bin/sh +# gitkit-builtin: message-rules +# This is a placeholder. The real script is generated by gitkit from rules +# configured in .gitmessage-rules.json. +exit 0 +"#; + #[cfg(test)] mod tests { use super::*; @@ -367,6 +402,31 @@ mod tests { ); } + #[test] + fn shell_exemption_macro_covers_every_shared_prefix() { + let exemption = auto_generated_message_exemption!(); + for prefix in AUTO_GENERATED_MESSAGE_PREFIXES { + assert!( + exemption.contains(prefix), + "the shell exemption macro must contain every prefix from \ + AUTO_GENERATED_MESSAGE_PREFIXES — missing '{prefix}'" + ); + } + } + + #[test] + fn is_auto_generated_message_matches_the_shared_prefixes() { + for prefix in AUTO_GENERATED_MESSAGE_PREFIXES { + let subject = format!("{prefix}something"); + assert!( + is_auto_generated_message(&subject), + "is_auto_generated_message must return true for prefix '{prefix}'" + ); + } + assert!(!is_auto_generated_message("feat: hand-authored")); + assert!(!is_auto_generated_message("fix: also hand-authored")); + } + #[test] fn no_body_is_registered_as_commit_msg_builtin() { let builtin = get("no-body").unwrap(); diff --git a/src/hooks/message_rules.rs b/src/hooks/message_rules.rs new file mode 100644 index 0000000..cb0c72c --- /dev/null +++ b/src/hooks/message_rules.rs @@ -0,0 +1,571 @@ +use anyhow::{Context, Result}; +use serde::{Deserialize, Serialize}; +use std::path::{Path, PathBuf}; + +use super::builtins; +use crate::utils::find_repo_root; + +const RULES_FILE: &str = ".gitmessage-rules.json"; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub(crate) struct MessageRule { + pub name: String, + pub pattern: String, + pub direction: Direction, + pub scope: Scope, + pub message: String, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub(crate) enum Direction { + MustMatch, + MustNotMatch, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub(crate) enum Scope { + Subject, + WholeMessage, +} + +fn rules_path() -> Result { + let root = find_repo_root().context("not inside a git repository")?; + Ok(root.join(RULES_FILE)) +} + +pub(crate) fn load_rules() -> Result> { + let path = match rules_path() { + Ok(p) => p, + Err(_) => return Ok(Vec::new()), + }; + + if !path.exists() { + return Ok(Vec::new()); + } + + let content = std::fs::read_to_string(&path) + .with_context(|| format!("failed to read rules file: {}", path.display()))?; + + if content.trim().is_empty() { + return Ok(Vec::new()); + } + + let rules: Vec = serde_json::from_str(&content) + .with_context(|| format!("failed to parse rules file: {}", path.display()))?; + Ok(rules) +} + +pub(crate) fn validate_rules() -> Result> { + let rules = load_rules()?; + anyhow::ensure!( + !rules.is_empty(), + "no message-rules configured — create '{}' with at least one rule \ + before running 'gitkit hooks add message-rules'", + RULES_FILE + ); + for rule in &rules { + regex::Regex::new(&rule.pattern).with_context(|| { + format!( + "rule '{}': pattern '{}' is not a valid regex", + rule.name, rule.pattern + ) + })?; + } + Ok(rules) +} + +pub(crate) fn generate_script() -> String { + r#"#!/bin/sh +# gitkit-builtin: message-rules +# Validates the commit message against user-defined rules from .gitmessage-rules.json. +# Delegates to gitkit itself for the actual regex evaluation, so patterns use +# the same Rust regex engine that was validated at install time. +exec gitkit hooks scan-message-rules "$1" +"# + .to_string() +} + +/// Pure rule-checking logic: iterate rules, regex match by scope, collect failures. +/// Shared by both `evaluate_message` (production) and tests. +pub(crate) fn check_rules(rules: &[MessageRule], full_message: &str) -> Vec { + let subject = full_message.lines().next().unwrap_or(""); + + if builtins::is_auto_generated_message(subject) { + return Vec::new(); + } + + let mut failures: Vec = Vec::new(); + + for rule in rules { + let re = match regex::Regex::new(&rule.pattern) { + Ok(r) => r, + Err(_) => continue, + }; + let text = match rule.scope { + Scope::Subject => subject, + Scope::WholeMessage => full_message, + }; + + let matched = re.is_match(text); + + match rule.direction { + Direction::MustMatch => { + if !matched { + failures.push(format!("ERROR: [{}] {}", rule.name, rule.message)); + } + } + Direction::MustNotMatch => { + if matched { + failures.push(format!("ERROR: [{}] {}", rule.name, rule.message)); + } + } + } + } + + failures +} + +pub(crate) fn evaluate_message(msg_file: &Path) -> Result<()> { + let rules = load_rules()?; + let full_message = std::fs::read_to_string(msg_file) + .with_context(|| format!("failed to read commit message file: {}", msg_file.display()))?; + + let failures = check_rules(&rules, &full_message); + + if failures.is_empty() { + Ok(()) + } else { + for f in &failures { + eprintln!("{f}"); + } + std::process::exit(1); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn make_rule( + name: &str, + pattern: &str, + direction: Direction, + scope: Scope, + message: &str, + ) -> MessageRule { + MessageRule { + name: name.to_string(), + pattern: pattern.to_string(), + direction, + scope, + message: message.to_string(), + } + } + + fn evaluate_rules(rules: &[MessageRule], message: &str) -> (bool, Vec) { + let failures = check_rules(rules, message); + if failures.is_empty() { + (true, failures) + } else { + (false, failures) + } + } + + #[test] + fn positive_must_match_rule_accepts_matching_subject() { + let rules = vec![make_rule( + "jira-prefix", + r"^[A-Z]+-\d+", + Direction::MustMatch, + Scope::Subject, + "Subject must start with a JIRA ticket prefix", + )]; + let (accepted, failures) = evaluate_rules(&rules, "PROJ-123 fix the thing\n"); + assert!(accepted, "expected acceptance: {failures:?}"); + } + + #[test] + fn positive_must_match_rule_rejects_non_matching_subject() { + let rules = vec![make_rule( + "jira-prefix", + r"^[A-Z]+-\d+", + Direction::MustMatch, + Scope::Subject, + "Subject must start with a JIRA ticket prefix", + )]; + let (accepted, failures) = evaluate_rules(&rules, "fix the thing\n"); + assert!(!accepted, "expected rejection"); + assert!( + failures[0].contains("jira-prefix"), + "failures: {failures:?}" + ); + assert!( + failures[0].contains("JIRA ticket prefix"), + "failures: {failures:?}" + ); + } + + #[test] + fn negative_must_not_match_rule_accepts_clean_subject() { + let rules = vec![make_rule( + "no-trailer-in-subject", + "Co-Authored-By:", + Direction::MustNotMatch, + Scope::Subject, + "Subject must not contain trailer lines", + )]; + let (accepted, failures) = evaluate_rules(&rules, "fix: the thing\n"); + assert!(accepted, "expected acceptance: {failures:?}"); + } + + #[test] + fn negative_must_not_match_rule_rejects_matching_subject() { + let rules = vec![make_rule( + "no-trailer-in-subject", + "Co-Authored-By:", + Direction::MustNotMatch, + Scope::Subject, + "Subject must not contain trailer lines", + )]; + let (accepted, failures) = evaluate_rules(&rules, "fix: the thing; Co-Authored-By: bot\n"); + assert!(!accepted, "expected rejection"); + assert!( + failures[0].contains("no-trailer-in-subject"), + "failures: {failures:?}" + ); + } + + #[test] + fn subject_scope_does_not_fire_on_body_only_match() { + let rules = vec![make_rule( + "no-trailer-in-subject", + "Co-Authored-By:", + Direction::MustNotMatch, + Scope::Subject, + "Subject must not contain trailer lines", + )]; + let (accepted, failures) = evaluate_rules( + &rules, + "fix: the thing\n\nCo-Authored-By: bot \n", + ); + assert!( + accepted, + "a subject-scoped rule must not fire on a body-only match: {failures:?}" + ); + } + + #[test] + fn whole_message_scope_fires_on_body_match() { + let rules = vec![make_rule( + "no-ai-trailer", + "noreply@anthropic\\.com", + Direction::MustNotMatch, + Scope::WholeMessage, + "Message must not contain AI vendor attribution", + )]; + let (accepted, failures) = evaluate_rules( + &rules, + "fix: the thing\n\nCo-Authored-By: Claude \n", + ); + assert!( + !accepted, + "a whole-message rule must fire on a body match: {failures:?}" + ); + } + + #[test] + fn whole_message_scope_includes_subject_line() { + let rules = vec![make_rule( + "body-keyword", + "BREAKING", + Direction::MustMatch, + Scope::WholeMessage, + "Message body must mention BREAKING", + )]; + let (accepted, _failures) = evaluate_rules(&rules, "BREAKING: fix the thing\n"); + assert!(accepted, "whole-message scope includes the subject line"); + } + + #[test] + fn multiple_failing_rules_all_reported() { + let rules = vec![ + make_rule( + "jira-prefix", + r"^[A-Z]+-\d+", + Direction::MustMatch, + Scope::Subject, + "Subject must start with a JIRA ticket prefix", + ), + make_rule( + "min-length", + r".{15,}", + Direction::MustMatch, + Scope::Subject, + "Subject must be at least 15 characters", + ), + ]; + let (accepted, failures) = evaluate_rules(&rules, "fix: short\n"); + assert!(!accepted); + assert!( + failures.iter().any(|f| f.contains("jira-prefix")), + "failures: {failures:?}" + ); + assert!( + failures.iter().any(|f| f.contains("min-length")), + "failures: {failures:?}" + ); + } + + #[test] + #[allow(clippy::invalid_regex)] + fn uncompilable_pattern_rejected_at_validation() { + let result = regex::Regex::new("[invalid"); + assert!(result.is_err(), "an unclosed bracket must not compile"); + } + + #[test] + fn generated_script_starts_with_shebang_and_marker() { + let script = generate_script(); + assert!(script.starts_with("#!/bin/sh")); + assert!(script.contains("# gitkit-builtin: message-rules")); + } + + #[test] + fn generated_script_execs_into_gitkit() { + let script = generate_script(); + assert!( + script.contains("exec gitkit hooks scan-message-rules"), + "the installed hook must exec back into gitkit for real regex evaluation: {script}" + ); + } + + #[test] + fn exempt_revert_messages() { + let rules = vec![make_rule( + "jira-prefix", + r"^[A-Z]+-\d+", + Direction::MustMatch, + Scope::Subject, + "Subject must start with a JIRA ticket prefix", + )]; + let (accepted, _) = evaluate_rules( + &rules, + "Revert \"feat(x): add thing\"\n\nThis reverts commit abc123.\n", + ); + assert!(accepted, "revert messages must be exempt"); + } + + #[test] + fn exempt_merge_messages() { + let rules = vec![make_rule( + "jira-prefix", + r"^[A-Z]+-\d+", + Direction::MustMatch, + Scope::Subject, + "Subject must start with a JIRA ticket prefix", + )]; + let (accepted, _) = evaluate_rules(&rules, "Merge branch 'develop' into main\n"); + assert!(accepted, "merge messages must be exempt"); + } + + #[test] + fn exempt_fixup_messages() { + let rules = vec![make_rule( + "jira-prefix", + r"^[A-Z]+-\d+", + Direction::MustMatch, + Scope::Subject, + "Subject must start with a JIRA ticket prefix", + )]; + let (accepted, _) = evaluate_rules(&rules, "fixup! feat(x): add thing\n"); + assert!(accepted, "fixup messages must be exempt"); + } + + #[test] + fn exempt_squash_messages() { + let rules = vec![make_rule( + "jira-prefix", + r"^[A-Z]+-\d+", + Direction::MustMatch, + Scope::Subject, + "Subject must start with a JIRA ticket prefix", + )]; + let (accepted, _) = evaluate_rules(&rules, "squash! feat(x): add thing\n"); + assert!(accepted, "squash messages must be exempt"); + } + + #[test] + fn whole_message_anchor_semantics_match_rust_regex() { + let rules = vec![make_rule( + "must-start-with-breaking", + r"^BREAKING", + Direction::MustMatch, + Scope::WholeMessage, + "Message must start with BREAKING", + )]; + let (accepted, _) = evaluate_rules(&rules, "not breaking\n\nBREAKING: smuggled in later\n"); + assert!( + !accepted, + "^ under Rust regex must anchor to start of whole message, not match any line" + ); + } + + #[test] + fn message_rules_exemption_covers_all_shared_prefixes() { + for prefix in builtins::AUTO_GENERATED_MESSAGE_PREFIXES { + let msg = format!("{prefix}something\n"); + let rules = vec![make_rule( + "jira-prefix", + r"^[A-Z]+-\d+", + Direction::MustMatch, + Scope::Subject, + "Subject must start with a JIRA ticket prefix", + )]; + let (accepted, _) = evaluate_rules(&rules, &msg); + assert!( + accepted, + "prefix '{prefix}' must be exempt — AUTO_GENERATED_MESSAGE_PREFIXES and \ + is_auto_generated_message must stay in sync" + ); + } + } + + #[test] + #[serial_test::serial] + fn validate_rules_rejects_when_no_rules_configured() { + let dir = tempfile::TempDir::new().unwrap(); + std::process::Command::new("git") + .args(["init"]) + .current_dir(dir.path()) + .output() + .unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + let result = validate_rules(); + assert!( + result.is_err(), + "validate_rules must refuse when no rules are configured" + ); + let err_msg = result.unwrap_err().to_string(); + assert!( + err_msg.contains("no message-rules configured"), + "error must name the missing config: {err_msg}" + ); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[test] + #[serial_test::serial] + fn validate_rules_rejects_uncompilable_pattern() { + let dir = tempfile::TempDir::new().unwrap(); + std::process::Command::new("git") + .args(["init"]) + .current_dir(dir.path()) + .output() + .unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + let bad_rule = MessageRule { + name: "bad".to_string(), + pattern: "[invalid".to_string(), + direction: Direction::MustMatch, + scope: Scope::Subject, + message: "bad pattern".to_string(), + }; + let json = serde_json::to_string_pretty(&[bad_rule]).unwrap(); + std::fs::write(dir.path().join(".gitmessage-rules.json"), json).unwrap(); + + let result = validate_rules(); + assert!(result.is_err(), "uncompilable pattern must be rejected"); + let err_msg = result.unwrap_err().to_string(); + assert!( + err_msg.contains("bad"), + "error must name the rule: {err_msg}" + ); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[test] + #[serial_test::serial] + fn load_rules_returns_empty_when_file_not_present() { + let dir = tempfile::TempDir::new().unwrap(); + std::process::Command::new("git") + .args(["init"]) + .current_dir(dir.path()) + .output() + .unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + let rules = load_rules().unwrap(); + assert!( + rules.is_empty(), + "no rules should be returned when file is not present" + ); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[test] + #[serial_test::serial] + fn load_rules_parses_json_from_tracked_file() { + let dir = tempfile::TempDir::new().unwrap(); + std::process::Command::new("git") + .args(["init"]) + .current_dir(dir.path()) + .output() + .unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + let rule = MessageRule { + name: "jira-prefix".to_string(), + pattern: r"^[A-Z]+-\d+".to_string(), + direction: Direction::MustMatch, + scope: Scope::Subject, + message: "JIRA prefix required".to_string(), + }; + let json = serde_json::to_string_pretty(&[rule]).unwrap(); + std::fs::write(dir.path().join(".gitmessage-rules.json"), json).unwrap(); + + let rules = load_rules().unwrap(); + assert_eq!(rules.len(), 1); + assert_eq!(rules[0].name, "jira-prefix"); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[test] + fn rules_file_path_is_tracked_constant() { + assert_eq!(RULES_FILE, ".gitmessage-rules.json"); + } + + #[test] + fn rule_serialization_roundtrip() { + let rule = MessageRule { + name: "test".to_string(), + pattern: ".*".to_string(), + direction: Direction::MustNotMatch, + scope: Scope::WholeMessage, + message: "test message".to_string(), + }; + let json = serde_json::to_string(std::slice::from_ref(&rule)).unwrap(); + let parsed: Vec = serde_json::from_str(&json).unwrap(); + assert_eq!(parsed.len(), 1); + assert_eq!(parsed[0], rule); + } +} diff --git a/src/hooks/mod.rs b/src/hooks/mod.rs index d564951..d0da50b 100644 --- a/src/hooks/mod.rs +++ b/src/hooks/mod.rs @@ -5,6 +5,7 @@ use std::{fs, path::Path}; use crate::utils::{confirm, find_repo_root}; pub(crate) mod builtins; +mod message_rules; mod no_invisibles; #[derive(Subcommand)] @@ -51,6 +52,13 @@ pub enum HooksCommand { /// `no-invisibles` pre-commit hook; not meant to be run directly. #[command(hide = true)] ScanInvisibles, + /// Internal: evaluate commit message against user-defined rules. Execed + /// by the `message-rules` commit-msg hook; not meant to be run directly. + #[command(hide = true)] + ScanMessageRules { + /// Path to the commit message file (passed by git) + msg_file: String, + }, } pub fn run(cmd: HooksCommand) -> Result<()> { @@ -66,6 +74,9 @@ pub fn run(cmd: HooksCommand) -> Result<()> { HooksCommand::Remove { hook, yes, dry_run } => remove(&hook, yes, dry_run), HooksCommand::Show { hook } => show(&hook), HooksCommand::ScanInvisibles => no_invisibles::run(), + HooksCommand::ScanMessageRules { msg_file } => { + message_rules::evaluate_message(std::path::Path::new(&msg_file)) + } } } @@ -217,12 +228,17 @@ fn ensure_dispatcher(dir: &Path, hook_name: &str) -> Result<()> { if let Some(builtin) = detect_builtin(hook_name, &content) { let migrated_path = parts.join(builtin.name); - let is_outdated = content.trim() != builtin.script.trim(); + let current_script = if builtin.name == "message-rules" { + message_rules::generate_script() + } else { + builtin.script.to_owned() + }; + let is_outdated = content.trim() != current_script.trim(); if is_outdated { println!("Updating outdated builtin: {}", builtin.name); } if !migrated_path.exists() || is_outdated { - fs::write(&migrated_path, builtin.script).with_context(|| { + fs::write(&migrated_path, ¤t_script).with_context(|| { format!("Failed to migrate builtin '{}' into gitkit.d", builtin.name) })?; set_executable(&migrated_path)?; @@ -324,6 +340,8 @@ pub(crate) fn classify_part(dir: &Path, hook_name: &str, part_name: &str) -> Res let recognized = match std::str::from_utf8(&bytes) { Ok(content) => { part_name == PRESERVED_PART_NAME + || (part_name == "message-rules" + && content.contains("# gitkit-builtin: message-rules")) || builtins::get(part_name).is_some_and(|b| content.trim() == b.script.trim()) } Err(_) => false, @@ -414,9 +432,16 @@ fn add_builtin_part( let dir = hooks_dir()?; let part_path = parts_dir(&dir, builtin.hook).join(builtin.name); + let script = if builtin.name == "message-rules" { + let _rules = message_rules::validate_rules()?; + message_rules::generate_script() + } else { + builtin.script.to_owned() + }; + if part_path.exists() && !force { let existing = fs::read_to_string(&part_path).unwrap_or_default(); - if existing.trim() != builtin.script.trim() + if existing.trim() != script.trim() && !confirm( &format!("Hook '{}' already exists. Overwrite?", builtin.name), yes, @@ -428,14 +453,11 @@ fn add_builtin_part( } if dry_run { - println!( - "[dry-run] Would write hook '{}':\n{}", - builtin.hook, builtin.script - ); + println!("[dry-run] Would write hook '{}':\n{}", builtin.hook, script); return Ok(()); } - install_part(builtin.hook, builtin.name, builtin.script)?; + install_part(builtin.hook, builtin.name, &script)?; record_applied(builtin.name); println!("Installed hook '{}'.", builtin.hook); Ok(()) @@ -449,7 +471,13 @@ fn add_quiet(hook_or_builtin: &str, command: Option<&str>, force: bool) -> Resul "'{hook_or_builtin}' is a built-in hook — no command needed" ); let _ = force; - install_part(builtin.hook, builtin.name, builtin.script)?; + let script = if builtin.name == "message-rules" { + let _rules = message_rules::validate_rules()?; + message_rules::generate_script() + } else { + builtin.script.to_owned() + }; + install_part(builtin.hook, builtin.name, &script)?; record_applied(builtin.name); return Ok(()); } @@ -483,7 +511,13 @@ fn resolve_hook<'a>(hook_or_builtin: &'a str, command: Option<&str>) -> Result<( command.is_none(), "'{hook_or_builtin}' is a built-in hook — no command needed" ); - return Ok((builtin.hook, builtin.script.to_owned())); + let script = if builtin.name == "message-rules" { + let _rules = message_rules::validate_rules()?; + message_rules::generate_script() + } else { + builtin.script.to_owned() + }; + return Ok((builtin.hook, script)); } let cmd = command.ok_or_else(|| { @@ -764,6 +798,9 @@ mod tests { #[test] fn resolve_hook_all_builtins_resolvable() { for b in available_builtins() { + if b.name == "message-rules" { + continue; + } let result = resolve_hook(b.name, None); assert!(result.is_ok(), "Failed to resolve builtin: {}", b.name); let (hook, script) = result.unwrap(); From 4d0d644d96e38b21c0f9c5bab438e9e8228511e3 Mon Sep 17 00:00:00 2001 From: Jheison Martinez Bolivar Date: Tue, 25 Aug 2026 19:23:10 -0500 Subject: [PATCH 4/8] feat(lock): extend lock to pre-rebase and add opt-in --refs axis --- docs/lock.md | 89 ++++++++-- src/lock/mod.rs | 403 +++++++++++++++++++++++++++++++++++++++++-- tests/integration.rs | 229 +++++++++++++++++++++++- 3 files changed, 691 insertions(+), 30 deletions(-) diff --git a/docs/lock.md b/docs/lock.md index 3efbdea..3791205 100644 --- a/docs/lock.md +++ b/docs/lock.md @@ -13,6 +13,7 @@ committing to a repository, locally, for the duration of a session. gitkit lock # block commits until `gitkit unlock` gitkit lock --push # block pushes instead of commits gitkit lock --all # block both commits and pushes +gitkit lock --refs # block reference updates (strongest lock) gitkit lock --reason "Agent session" # custom message shown on a blocked operation gitkit lock --timeout 30m # auto-expires after 30 minutes gitkit lock status # show whether a lock is active @@ -27,10 +28,10 @@ or modify which operations are locked without removing the existing lock. ## How it works `gitkit lock` writes a small JSON state file at `.git/gitkit.lock` and -installs `pre-commit` and/or `pre-push` hooks that read it. The hooks are -pure POSIX `sh` — no dependency on the `gitkit` binary — so they stay fast -on every commit and push. A missing, empty, or malformed lock file is always -treated as unlocked: a corrupt lock never blocks an operation. +installs hooks that read it. The hooks are pure POSIX `sh` — no dependency +on the `gitkit` binary — so they stay fast on every commit and push. A +missing, empty, or malformed lock file is always treated as unlocked: a +corrupt lock never blocks an operation. By default, `gitkit lock` blocks commits only. Use `--push` to add push blocking, or `--all` to block both. You can call lock multiple times to @@ -44,10 +45,60 @@ removes the backups. The lock is per-repository, local only, and never committed or pushed — it lives entirely under `.git/`. +## Axes: what the lock covers + +The lock has four independent axes, each controlled separately: + +| Axis | Flag | Hook installed | Bypass with `--no-verify`? | +|----------|-----------|-----------------------------|----------------------------| +| Commit | (default) | `pre-commit` | Yes | +| Push | `--push` | `pre-push` | Yes | +| Rebase | (always) | `pre-rebase` | Yes | +| Refs | `--refs` | `reference-transaction` | **No** | + +`--all` enables commit and push, but **not** refs. Reference protection +is a separate, stronger axis that must be opted into explicitly with +`--refs`. This is a deliberate product decision: silently freezing refs +when a user typed `--all` would surprise existing users. + +### Rebase blocking + +`gitkit lock` always installs a `pre-rebase` hook alongside whatever other +operations are locked. There is no `--rebase` flag — rebase blocking is +part of every lock, because a lock whose purpose is to hold a repository +still while an agent works in it should also hold rebases still. + +Like commit and push, rebase blocking can be bypassed with +`git rebase --no-verify`. + +### Reference protection (`--refs`) + +`gitkit lock --refs` installs a `reference-transaction` hook that rejects +updates to `HEAD` and `refs/heads/*` while allowing `refs/remotes/*` so +`git fetch` keeps working. This is the **only** lock axis that cannot be +bypassed with `--no-verify`, because git does not apply `--no-verify` to +the `reference-transaction` hook. + +**Trade-off**: this is the strongest lock gitkit offers, but it is also +the most intrusive. A `reference-transaction` hook that rejects too +broadly can make a repository feel broken in ways that are hard to +attribute. gitkit rejects narrowly (only `HEAD` and `refs/heads/*`), +but you should still be aware that enabling `--refs` changes the +behaviour of ordinary git commands like `git commit` (which updates +`HEAD`) and `git switch -c` (which creates a new `refs/heads/*` ref). + +**Branch creation**: with `--refs` active, `git switch -c new-branch` +and `git checkout -b new-branch` are blocked, because they write to +`refs/heads/`. Create branches before taking the lock, or use +`git update-ref` on `refs/remotes/*` if you need to record a position +without touching local refs. + +Every rejection message names `gitkit unlock` as the supported way out. + ## Status output Both `gitkit lock status` (human-readable) and `gitkit lock status --json` -(machine-readable) show per-operation status. This lets you see at a glance +(machine-readable) show per-axis status. This lets you see at a glance which operations are currently locked: ``` @@ -56,9 +107,12 @@ Locked at: 2026-01-01T10:00:00Z Expires at: 2026-01-01T10:30:00Z Commit: locked Push: not locked +Rebase: not locked +Refs: not locked ``` -This shows that commits are blocked, but pushes are allowed. +This shows that commits are blocked, but pushes, rebases, and ref +updates are allowed. ## Machine-readable status: `lock status --json` @@ -79,7 +133,7 @@ rely on a key being renamed or removed without a version bump): | Key | Type | Meaning | |---------------|-------------------|--------------------------------------------------------------------------| | `active` | `bool` | Whether the lock currently blocks the operations it lists — `false` if there is no lock, the lock file is malformed, `operations` is empty, or the lock has expired. | -| `operations` | `string[]` | The operations the lock covers. Can be `"commit"`, `"push"`, or both. Empty when there is no lock. | +| `operations` | `string[]` | The operations the lock covers. Can be `"commit"`, `"push"`, `"rebase"`, and/or `"refs"`. Empty when there is no lock. | | `locked_at` | `string \| null` | RFC 3339 timestamp the lock was set, or `null` when there is no lock. | | `expires_at` | `string \| null` | RFC 3339 timestamp the lock expires, or `null` for a lock with no timeout (or no lock at all). | | `reason` | `string \| null` | The `--reason` text, or `null` when there is no lock. | @@ -113,7 +167,7 @@ below is the supported contract for either path. | `locked_at` | `string` | RFC 3339 timestamp the lock was set. | | `expires_at` | `string \| null` | RFC 3339 timestamp the lock expires, or `null` for no timeout. | | `reason` | `string` | The `--reason` text, or empty string if none was given. | -| `operations` | `string[]` | The operations the lock covers. | +| `operations` | `string[]` | The operations the lock covers. Can include `"commit"`, `"push"`, `"rebase"`, and/or `"refs"`. | Notes for a direct reader: @@ -129,9 +183,16 @@ Notes for a direct reader: ## Limitations: `--no-verify` bypass -Both `git commit --no-verify` and `git push --no-verify` bypass their -respective hooks, including the lock checks. **This is expected and not -treated as a bug.** The lock's threat model is an AI agent following its -instructions, not a human deliberately working around a local safeguard — -so no attempt is made to defend against `--no-verify`. If you need a -guarantee that survives a determined bypass, this is not that guarantee. +`git commit --no-verify`, `git push --no-verify`, and +`git rebase --no-verify` bypass their respective hooks, including the +lock checks. **This is expected and not treated as a bug.** The lock's +threat model is an AI agent following its instructions, not a human +deliberately working around a local safeguard — so no attempt is made +to defend against `--no-verify` for commit, push, or rebase. + +The one exception is `--refs`: the `reference-transaction` hook is not +affected by `--no-verify`, so reference protection survives it. This is +the entire reason `--refs` exists as a separate axis. + +If you need a guarantee that survives a determined bypass for all +operations, this is not that guarantee. diff --git a/src/lock/mod.rs b/src/lock/mod.rs index b7c172d..a02aad1 100644 --- a/src/lock/mod.rs +++ b/src/lock/mod.rs @@ -50,6 +50,98 @@ fi exit 0 "#; +/// The pre-rebase hook gitkit installs. Same shape as the commit hook: +/// checks for `"rebase"` in `operations`, reads the lock file directly, +/// fails open on any missing/malformed/expired lock, and chains to a +/// backed-up user hook if any. +const REBASE_HOOK_SCRIPT: &str = r#"#!/bin/sh +# Installed by `gitkit lock`. Blocks rebases while a lock is active. +# See `gitkit lock status` / `gitkit unlock`. Bypass with `git rebase --no-verify`. + +git_dir=$(git rev-parse --git-dir 2>/dev/null) || exit 0 +lock_file="$git_dir/gitkit.lock" +orig_hook="$git_dir/hooks/pre-rebase.gitkit-orig" + +if [ -f "$lock_file" ]; then + ops=$(sed -n 's/.*"operations":\[\([^]]*\)\].*/\1/p' "$lock_file" 2>/dev/null) + if printf '%s' "$ops" | grep -qF '"rebase"'; then + expires=$(sed -n 's/.*"expires_at":"\([^"]*\)".*/\1/p' "$lock_file" 2>/dev/null) + blocked=1 + if [ -n "$expires" ]; then + now=$(date -u +%Y-%m-%dT%H:%M:%SZ) + if [ "$now" \> "$expires" ]; then + blocked=0 + fi + fi + if [ "$blocked" -eq 1 ]; then + reason=$(sed -n 's/.*"reason":"\([^"]*\)".*/\1/p' "$lock_file" 2>/dev/null) + echo "gitkit: rebase blocked - ${reason:-Agent session active}" >&2 + echo "gitkit: run 'gitkit unlock' to remove the lock, or 'git rebase --no-verify' to bypass it" >&2 + exit 1 + fi + fi +fi + +if [ -x "$orig_hook" ]; then + exec "$orig_hook" "$@" +fi + +exit 0 +"#; + +/// The reference-transaction hook gitkit installs with `--refs`. Pure POSIX +/// `sh`, no dependency on the `gitkit` binary — git calls this on its hot +/// ref-update path, several times per operation, so spawning a process here +/// would make ordinary git commands slow. Reads `gitkit.lock` directly. +/// +/// Rejects updates to `HEAD` and `refs/heads/*` while allowing `refs/remotes/*` +/// so `git fetch` keeps working. This is the only lock that `--no-verify` +/// cannot bypass. +/// +/// Git feeds ref updates on stdin as ` ` lines. We read them +/// all, check each one, and reject the whole transaction if any ref is +/// protected. +const REFERENCE_TRANSACTION_HOOK_SCRIPT: &str = r#"#!/bin/sh +# Installed by `gitkit lock --refs`. Blocks ref updates to HEAD and +# refs/heads/* while a lock is active. Allows refs/remotes/* so git fetch +# keeps working. This is the only lock that --no-verify cannot bypass. +# See `gitkit lock status` / `gitkit unlock`. + +git_dir=$(git rev-parse --git-dir 2>/dev/null) || exit 0 +lock_file="$git_dir/gitkit.lock" + +if [ ! -f "$lock_file" ]; then + exit 0 +fi + +ops=$(sed -n 's/.*"operations":\[\([^]]*\)\].*/\1/p' "$lock_file" 2>/dev/null) +if ! printf '%s' "$ops" | grep -qF '"refs"'; then + exit 0 +fi + +expires=$(sed -n 's/.*"expires_at":"\([^"]*\)".*/\1/p' "$lock_file" 2>/dev/null) +if [ -n "$expires" ]; then + now=$(date -u +%Y-%m-%dT%H:%M:%SZ) + if [ "$now" \> "$expires" ]; then + exit 0 + fi +fi + +reason=$(sed -n 's/.*"reason":"\([^"]*\)".*/\1/p' "$lock_file" 2>/dev/null) + +while read -r old new ref; do + case "$ref" in + HEAD|refs/heads/*) + echo "gitkit: ref update blocked - ${reason:-Agent session active}" >&2 + echo "gitkit: run 'gitkit unlock' to remove the lock" >&2 + exit 1 + ;; + esac +done + +exit 0 +"#; + /// The pre-push hook gitkit installs. Same shape as `LOCK_HOOK_SCRIPT`, but /// checks for `"push"` in `operations` instead of `"commit"`. Git feeds ref /// update lines on stdin; this hook never inspects them (decides purely from @@ -113,6 +205,16 @@ const PUSH_HOOK: HookSpec = HookSpec { script: PUSH_HOOK_SCRIPT, }; +const REBASE_HOOK: HookSpec = HookSpec { + name: "pre-rebase", + script: REBASE_HOOK_SCRIPT, +}; + +const REFERENCE_TRANSACTION_HOOK: HookSpec = HookSpec { + name: "reference-transaction", + script: REFERENCE_TRANSACTION_HOOK_SCRIPT, +}; + #[derive(Args)] pub struct LockArgs { #[command(subcommand)] @@ -129,6 +231,11 @@ pub struct LockArgs { /// Block both commits and pushes #[arg(long)] all: bool, + /// Block reference updates to HEAD and refs/heads/* (opt-in, never + /// included in --all or the default). This is the only lock that + /// --no-verify cannot bypass. + #[arg(long)] + refs: bool, } #[derive(Subcommand)] @@ -146,20 +253,25 @@ pub fn run(args: LockArgs) -> Result<()> { match args.action { Some(LockAction::Status { json }) => status(json), None => { - let ops = target_operations(args.push, args.all); + let ops = target_operations(args.push, args.all, args.refs); lock(args.timeout.as_deref(), args.reason.as_deref(), &ops) } } } -fn target_operations(push: bool, all: bool) -> Vec<&'static str> { - if all { +fn target_operations(push: bool, all: bool, refs: bool) -> Vec<&'static str> { + let mut ops = if all { vec!["commit", "push"] } else if push { vec!["push"] } else { vec!["commit"] + }; + ops.push("rebase"); + if refs { + ops.push("refs"); } + ops } pub fn unlock() -> Result<()> { @@ -170,6 +282,8 @@ pub fn unlock() -> Result<()> { } uninstall_hook(&COMMIT_HOOK)?; uninstall_hook(&PUSH_HOOK)?; + uninstall_hook(&REBASE_HOOK)?; + uninstall_hook(&REFERENCE_TRANSACTION_HOOK)?; println!("Unlocked. Commits and pushes are no longer blocked by gitkit."); Ok(()) } @@ -226,6 +340,13 @@ fn lock(timeout: Option<&str>, reason: Option<&str>, ops: &[&str]) -> Result<()> if lf.operations.iter().any(|op| op == "push") { install_hook(&PUSH_HOOK).context("Failed to install pre-push hook")?; } + if lf.operations.iter().any(|op| op == "rebase") { + install_hook(&REBASE_HOOK).context("Failed to install pre-rebase hook")?; + } + if lf.operations.iter().any(|op| op == "refs") { + install_hook(&REFERENCE_TRANSACTION_HOOK) + .context("Failed to install reference-transaction hook")?; + } println!("Locked: {}", lf.reason); println!("Locked operations: {}", lf.operations.join(", ")); @@ -343,6 +464,8 @@ fn status_report(lf: &LockFile, now: &str) -> Vec { let commit_locked = !expired && lf.operations.iter().any(|op| op == "commit"); let push_locked = !expired && lf.operations.iter().any(|op| op == "push"); + let rebase_locked = !expired && lf.operations.iter().any(|op| op == "rebase"); + let refs_locked = !expired && lf.operations.iter().any(|op| op == "refs"); lines.push(format!( "Commit: {}", if commit_locked { @@ -355,6 +478,18 @@ fn status_report(lf: &LockFile, now: &str) -> Vec { "Push: {}", if push_locked { "locked" } else { "not locked" } )); + lines.push(format!( + "Rebase: {}", + if rebase_locked { + "locked" + } else { + "not locked" + } + )); + lines.push(format!( + "Refs: {}", + if refs_locked { "locked" } else { "not locked" } + )); lines } @@ -1305,6 +1440,7 @@ mod tests { reason: None, push: false, all: false, + refs: false, }); assert!(result.is_ok()); @@ -1327,6 +1463,7 @@ mod tests { reason: Some("ci".to_string()), push: false, all: false, + refs: false, }); assert!(result.is_ok()); assert!(dir.path().join(".git").join(LOCK_FILE_NAME).exists()); @@ -1350,11 +1487,12 @@ mod tests { reason: None, push: true, all: false, + refs: false, }); assert!(result.is_ok()); let content = std::fs::read_to_string(dir.path().join(".git").join(LOCK_FILE_NAME)).unwrap(); - assert!(content.contains("\"operations\":[\"push\"]")); + assert!(content.contains("\"operations\":[\"push\",\"rebase\"]")); if let Some(orig) = original { let _ = std::env::set_current_dir(orig); @@ -1375,11 +1513,12 @@ mod tests { reason: None, push: false, all: true, + refs: false, }); assert!(result.is_ok()); let content = std::fs::read_to_string(dir.path().join(".git").join(LOCK_FILE_NAME)).unwrap(); - assert!(content.contains("\"operations\":[\"commit\",\"push\"]")); + assert!(content.contains("\"operations\":[\"commit\",\"push\",\"rebase\"]")); if let Some(orig) = original { let _ = std::env::set_current_dir(orig); @@ -1389,18 +1528,43 @@ mod tests { // ── target_operations ──────────────────────────────────────────────────── #[test] - fn target_operations_defaults_to_commit() { - assert_eq!(target_operations(false, false), vec!["commit"]); + fn target_operations_defaults_to_commit_and_rebase() { + assert_eq!( + target_operations(false, false, false), + vec!["commit", "rebase"] + ); + } + + #[test] + fn target_operations_push_flag_locks_push_and_rebase() { + assert_eq!( + target_operations(true, false, false), + vec!["push", "rebase"] + ); } #[test] - fn target_operations_push_flag_locks_push_only() { - assert_eq!(target_operations(true, false), vec!["push"]); + fn target_operations_all_flag_locks_commit_push_and_rebase() { + assert_eq!( + target_operations(false, true, false), + vec!["commit", "push", "rebase"] + ); } #[test] - fn target_operations_all_flag_locks_both() { - assert_eq!(target_operations(false, true), vec!["commit", "push"]); + fn target_operations_refs_flag_adds_refs() { + assert_eq!( + target_operations(false, false, true), + vec!["commit", "rebase", "refs"] + ); + } + + #[test] + fn target_operations_all_with_refs_does_not_duplicate() { + assert_eq!( + target_operations(false, true, true), + vec!["commit", "push", "rebase", "refs"] + ); } // ── status_report() per-operation reporting ────────────────────────────── @@ -1684,4 +1848,221 @@ mod tests { }; std::fs::write(path, lf.to_json()).unwrap(); } + + // ── rebase hook script sanity ──────────────────────────────────────────── + + #[test] + fn rebase_hook_script_is_valid_shell_shebang() { + assert!(REBASE_HOOK_SCRIPT.starts_with("#!/bin/sh")); + } + + #[test] + fn rebase_hook_script_references_lock_file_and_backup() { + assert!(REBASE_HOOK_SCRIPT.contains("gitkit.lock")); + assert!(REBASE_HOOK_SCRIPT.contains("pre-rebase.gitkit-orig")); + assert!(REBASE_HOOK_SCRIPT.contains("--no-verify")); + assert!(REBASE_HOOK_SCRIPT.contains("\"rebase\"")); + } + + // ── reference-transaction hook script sanity ───────────────────────────── + + #[test] + fn reference_transaction_hook_script_is_valid_shell_shebang() { + assert!(REFERENCE_TRANSACTION_HOOK_SCRIPT.starts_with("#!/bin/sh")); + } + + #[test] + fn reference_transaction_hook_script_does_not_invoke_gitkit_binary() { + assert!( + !REFERENCE_TRANSACTION_HOOK_SCRIPT.contains("$(gitkit"), + "reference-transaction hook must not spawn the gitkit binary" + ); + assert!( + !REFERENCE_TRANSACTION_HOOK_SCRIPT.contains("exec gitkit"), + "reference-transaction hook must not exec the gitkit binary" + ); + } + + #[test] + fn reference_transaction_hook_script_rejects_head_and_refs_heads() { + assert!(REFERENCE_TRANSACTION_HOOK_SCRIPT.contains("HEAD|refs/heads/*")); + } + + #[test] + fn reference_transaction_hook_script_mentions_gitkit_unlock() { + assert!(REFERENCE_TRANSACTION_HOOK_SCRIPT.contains("gitkit unlock")); + } + + // ── status_report with rebase and refs axes ────────────────────────────── + + #[test] + fn status_report_shows_rebase_and_refs_axes() { + let lf = LockFile { + locked_at: "2026-01-01T00:00:00Z".to_string(), + expires_at: None, + reason: "agent session".to_string(), + operations: vec![ + "commit".to_string(), + "push".to_string(), + "rebase".to_string(), + "refs".to_string(), + ], + }; + let lines = status_report(&lf, "2026-01-01T00:05:00Z").join("\n"); + assert!(lines.contains("Commit: locked"), "status was: {lines}"); + assert!(lines.contains("Push: locked"), "status was: {lines}"); + assert!(lines.contains("Rebase: locked"), "status was: {lines}"); + assert!(lines.contains("Refs: locked"), "status was: {lines}"); + } + + #[test] + fn status_report_shows_rebase_and_refs_not_locked_when_absent() { + let lf = LockFile { + locked_at: "2026-01-01T00:00:00Z".to_string(), + expires_at: None, + reason: "agent session".to_string(), + operations: vec!["commit".to_string()], + }; + let lines = status_report(&lf, "2026-01-01T00:05:00Z").join("\n"); + assert!(lines.contains("Rebase: not locked"), "status was: {lines}"); + assert!(lines.contains("Refs: not locked"), "status was: {lines}"); + } + + // ── lock with refs installs reference-transaction hook ─────────────────── + + #[serial] + #[test] + fn lock_with_refs_installs_reference_transaction_hook() { + let dir = TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + lock(None, None, &["refs"]).unwrap(); + + let content = + std::fs::read_to_string(dir.path().join(".git").join(LOCK_FILE_NAME)).unwrap(); + assert!(content.contains("\"operations\":[\"refs\"]")); + assert!(dir + .path() + .join(".git") + .join("hooks") + .join("reference-transaction") + .exists()); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[serial] + #[test] + fn lock_with_rebase_installs_pre_rebase_hook() { + let dir = TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + lock(None, None, &["rebase"]).unwrap(); + + let content = + std::fs::read_to_string(dir.path().join(".git").join(LOCK_FILE_NAME)).unwrap(); + assert!(content.contains("\"operations\":[\"rebase\"]")); + assert!(dir + .path() + .join(".git") + .join("hooks") + .join("pre-rebase") + .exists()); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[serial] + #[test] + fn unlock_removes_reference_transaction_hook() { + let dir = TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + lock(None, None, &["refs"]).unwrap(); + assert!(dir + .path() + .join(".git") + .join("hooks") + .join("reference-transaction") + .exists()); + + unlock().unwrap(); + assert!(!dir + .path() + .join(".git") + .join("hooks") + .join("reference-transaction") + .exists()); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[serial] + #[test] + fn unlock_removes_pre_rebase_hook() { + let dir = TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + lock(None, None, &["rebase"]).unwrap(); + assert!(dir + .path() + .join(".git") + .join("hooks") + .join("pre-rebase") + .exists()); + + unlock().unwrap(); + assert!(!dir + .path() + .join(".git") + .join("hooks") + .join("pre-rebase") + .exists()); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[serial] + #[test] + fn lock_with_commit_only_does_not_install_rebase_or_refs_hooks() { + let dir = TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + lock(None, None, &["commit"]).unwrap(); + + assert!(!dir + .path() + .join(".git") + .join("hooks") + .join("pre-rebase") + .exists()); + assert!(!dir + .path() + .join(".git") + .join("hooks") + .join("reference-transaction") + .exists()); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } } diff --git a/tests/integration.rs b/tests/integration.rs index 935ba50..180343f 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -996,10 +996,6 @@ fn lock_status_json_exit_code_zero_when_unlocked() { assert!(stdout.contains("\"active\":false"), "stdout was: {stdout}"); assert!(stdout.contains("\"expired\":false"), "stdout was: {stdout}"); assert!(stdout.contains("\"operations\":[]"), "stdout was: {stdout}"); - assert!( - stdout.contains("\"locked_at\":null"), - "stdout was: {stdout}" - ); } #[test] @@ -1038,7 +1034,7 @@ fn lock_status_json_exit_code_nonzero_when_locked() { "stdout was: {stdout}" ); assert!( - stdout.contains("\"operations\":[\"commit\"]"), + stdout.contains("\"operations\":[\"commit\",\"rebase\"]"), "stdout was: {stdout}" ); } @@ -1396,3 +1392,226 @@ fn status_lists_both_builtins_installed_for_one_git_hook() { ); assert!(stdout.contains("no-body"), "status output was:\n{stdout}"); } + +// ═══════════════════════════════════════════════════════════════════════════ +// Lock / pre-rebase integration tests +// ═══════════════════════════════════════════════════════════════════════════ + +fn git_rebase(dir: &std::path::Path, onto: &str) -> (bool, String) { + let output = Command::new("git") + .args(["rebase", onto]) + .current_dir(dir) + .output() + .expect("Failed to run git rebase"); + let stderr = String::from_utf8_lossy(&output.stderr).to_string(); + let stdout = String::from_utf8_lossy(&output.stdout).to_string(); + (output.status.success(), format!("{stdout}{stderr}")) +} + +#[test] +fn lock_fixture_pre_rebase_blocks_and_unlock_releases() { + let dir = TempDir::new().unwrap(); + init_git_repo(dir.path()); + let binary = gitkit_binary(); + + let (ok, _) = git_commit_allow_empty(dir.path(), "initial commit"); + assert!(ok); + + let status = Command::new("git") + .args(["checkout", "-b", "feature"]) + .current_dir(dir.path()) + .status() + .unwrap(); + assert!(status.success()); + + let (ok, _) = git_commit_allow_empty(dir.path(), "feature commit"); + assert!(ok); + + let status = Command::new("git") + .args(["checkout", "master"]) + .current_dir(dir.path()) + .status() + .unwrap(); + assert!(status.success()); + + let (ok, _) = git_commit_allow_empty(dir.path(), "master commit"); + assert!(ok); + + let status = Command::new("git") + .args(["checkout", "feature"]) + .current_dir(dir.path()) + .status() + .unwrap(); + assert!(status.success()); + + // `gitkit lock` installs pre-rebase unconditionally alongside commit. + let lock_out = Command::new(&binary) + .env("GITKIT_NO_UPDATE_CHECK", "1") + .env("HOME", dir.path()) + .args(["lock", "--reason", "Agent session active"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run gitkit lock"); + assert!(lock_out.status.success()); + + let hooks_dir = dir.path().join(".git").join("hooks"); + assert!( + hooks_dir.join("pre-rebase").exists(), + "pre-rebase hook should be installed by `gitkit lock`" + ); + + let (ok, msg) = git_rebase(dir.path(), "master"); + assert!(!ok, "rebase should fail while locked"); + assert!(msg.contains("rebase blocked"), "message was: {msg}"); + assert!(msg.contains("gitkit unlock"), "message was: {msg}"); + + // Unlock: rebase succeeds. + let unlock_out = Command::new(&binary) + .env("GITKIT_NO_UPDATE_CHECK", "1") + .env("HOME", dir.path()) + .args(["unlock"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run gitkit unlock"); + assert!(unlock_out.status.success()); + + let (ok, _) = git_rebase(dir.path(), "master"); + assert!(ok, "rebase should succeed after unlock"); +} + +// ═══════════════════════════════════════════════════════════════════════════ +// Lock / reference-transaction integration tests +// ═══════════════════════════════════════════════════════════════════════════ + +#[test] +fn lock_fixture_reference_transaction_rejects_head_update() { + let dir = TempDir::new().unwrap(); + init_git_repo(dir.path()); + let binary = gitkit_binary(); + + let (ok, _) = git_commit_allow_empty(dir.path(), "initial commit"); + assert!(ok); + let (ok, _) = git_commit_allow_empty(dir.path(), "second commit"); + assert!(ok); + + // Install the reference-transaction hook via --refs. + let lock_out = Command::new(&binary) + .env("GITKIT_NO_UPDATE_CHECK", "1") + .env("HOME", dir.path()) + .args(["lock", "--refs", "--reason", "Agent session active"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run gitkit lock --refs"); + assert!(lock_out.status.success()); + + let hooks_dir = dir.path().join(".git").join("hooks"); + assert!( + hooks_dir.join("reference-transaction").exists(), + "reference-transaction hook should be installed" + ); + + // Attempt to update HEAD to the previous commit (simulates a ref update). + let output = Command::new("git") + .args(["update-ref", "HEAD", "HEAD~1"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run git update-ref"); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + !output.status.success(), + "HEAD update should be rejected by reference-transaction hook" + ); + assert!(stderr.contains("gitkit unlock"), "message was: {stderr}"); +} + +#[test] +fn lock_fixture_reference_transaction_permits_refs_remotes() { + let dir = TempDir::new().unwrap(); + init_git_repo(dir.path()); + let binary = gitkit_binary(); + + let (ok, _) = git_commit_allow_empty(dir.path(), "initial commit"); + assert!(ok); + + // Install the reference-transaction hook via --refs. + let lock_out = Command::new(&binary) + .env("GITKIT_NO_UPDATE_CHECK", "1") + .env("HOME", dir.path()) + .args(["lock", "--refs", "--reason", "Agent session active"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run gitkit lock --refs"); + assert!(lock_out.status.success()); + + // Updating a refs/remotes/* ref should succeed. + let output = Command::new("git") + .args(["update-ref", "refs/remotes/origin/main", "HEAD"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run git update-ref"); + assert!( + output.status.success(), + "refs/remotes update should be permitted: {}", + String::from_utf8_lossy(&output.stderr) + ); +} + +#[test] +fn lock_fixture_refs_not_in_default_lock() { + let dir = TempDir::new().unwrap(); + init_git_repo(dir.path()); + let binary = gitkit_binary(); + + let lock_out = Command::new(&binary) + .env("GITKIT_NO_UPDATE_CHECK", "1") + .env("HOME", dir.path()) + .args(["lock"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run gitkit lock"); + assert!(lock_out.status.success()); + + let hooks_dir = dir.path().join(".git").join("hooks"); + assert!( + !hooks_dir.join("reference-transaction").exists(), + "reference-transaction hook should NOT be installed by default" + ); + + let lock_path = dir.path().join(".git").join("gitkit.lock"); + let content = std::fs::read_to_string(&lock_path).unwrap(); + assert!( + !content.contains("\"refs\""), + "refs should not be in default lock operations: {content}" + ); +} + +#[test] +fn lock_fixture_status_reports_axes() { + let dir = TempDir::new().unwrap(); + init_git_repo(dir.path()); + let binary = gitkit_binary(); + + let lock_out = Command::new(&binary) + .env("GITKIT_NO_UPDATE_CHECK", "1") + .env("HOME", dir.path()) + .args(["lock", "--refs", "--reason", "Agent session active"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run gitkit lock --refs"); + assert!(lock_out.status.success()); + + let status_out = Command::new(&binary) + .env("GITKIT_NO_UPDATE_CHECK", "1") + .env("HOME", dir.path()) + .args(["lock", "status"]) + .current_dir(dir.path()) + .output() + .expect("Failed to run gitkit lock status"); + assert!(status_out.status.success()); + + let stdout = String::from_utf8_lossy(&status_out.stdout); + assert!(stdout.contains("Commit:"), "status was: {stdout}"); + assert!(stdout.contains("Push:"), "status was: {stdout}"); + assert!(stdout.contains("Rebase:"), "status was: {stdout}"); + assert!(stdout.contains("Refs:"), "status was: {stdout}"); +} From e832135d6ec744b5f893e27d599ceeec85f3f406 Mon Sep 17 00:00:00 2001 From: Jheison Martinez Bolivar Date: Tue, 25 Aug 2026 19:35:12 -0500 Subject: [PATCH 5/8] feat(uninstall): add gitkit uninstall to remove hooks from every touched repo --- docs/cli-reference.md | 14 ++ docs/installation.md | 20 +- src/main.rs | 4 + src/uninstall/mod.rs | 511 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 548 insertions(+), 1 deletion(-) create mode 100644 src/uninstall/mod.rs diff --git a/docs/cli-reference.md b/docs/cli-reference.md index d38962d..6751660 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -53,6 +53,20 @@ Running `gitkit` with no command starts the interactive wizard. `git commit --no-verify` and `git push --no-verify` bypass the lock — see [Lock](lock.md) for why that is accepted rather than defended against. +## Uninstall + +| Command | Description | +|---|---| +| `gitkit uninstall` | Remove gitkit hooks from every repository it has touched | +| `gitkit uninstall --data` | Also remove local state under `~/.gitkit` (builds, registry) | +| `gitkit uninstall --yes` | Skip the confirmation prompt | +| `gitkit uninstall --dry-run` | Print what would be done without changing anything | + +By default, `gitkit uninstall` lists every repository in the registry, shows what hooks are +installed, and asks for confirmation before removing anything. It restores any hand-written hook +that gitkit had absorbed when it first installed its dispatcher. The gitkit binary itself is never +removed — see [Installation](installation.md#uninstall) for how to remove it. + ## Ignore | Command | Description | diff --git a/docs/installation.md b/docs/installation.md index b591027..fedef89 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -65,11 +65,23 @@ the update to maintain consistency. ## Uninstall +First, remove gitkit's hooks from every repository it has touched: + +```bash +gitkit uninstall +``` + +This lists every repository in the registry, shows what hooks are installed, and asks for +confirmation before removing anything. It restores any hand-written hook that gitkit had absorbed +when it first installed its dispatcher. Add `--data` to also remove local state under `~/.gitkit` +(builds, registry). + +Then remove the binary itself: + **Linux / macOS:** ```bash rm -f ~/.local/bin/gitkit -rm -rf ~/.gitkit/ # saved builds (optional) ``` **Windows (PowerShell):** @@ -77,3 +89,9 @@ rm -rf ~/.gitkit/ # saved builds (optional) ```powershell Remove-Item "$env:LOCALAPPDATA\gitkit\gitkit.exe" -Force ``` + +If gitkit was installed via `cargo install gitkit`, remove it with: + +```bash +cargo uninstall gitkit +``` diff --git a/src/main.rs b/src/main.rs index 6c7536f..ec13afb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ mod init; mod lock; mod registry; mod status; +mod uninstall; mod utils; #[derive(Parser)] @@ -63,6 +64,8 @@ enum Command { Lock(lock::LockArgs), /// Remove an active commit/push lock Unlock, + /// Remove gitkit hooks from every repository it has touched + Uninstall(uninstall::UninstallArgs), } fn main() -> Result<()> { @@ -79,5 +82,6 @@ fn main() -> Result<()> { Some(Command::Build { action }) => builds::run(action), Some(Command::Lock(args)) => lock::run(args), Some(Command::Unlock) => lock::unlock(), + Some(Command::Uninstall(args)) => uninstall::run(args), } } diff --git a/src/uninstall/mod.rs b/src/uninstall/mod.rs new file mode 100644 index 0000000..3364992 --- /dev/null +++ b/src/uninstall/mod.rs @@ -0,0 +1,511 @@ +use anyhow::{Context, Result}; +use clap::Args; +use std::fs; +use std::path::{Path, PathBuf}; + +use crate::hooks; +use crate::registry; + +#[derive(Args)] +pub struct UninstallArgs { + /// Also remove local state under ~/.gitkit (builds, registry) + #[arg(long)] + pub data: bool, + + /// Skip the confirmation prompt + #[arg(short, long)] + pub yes: bool, + + /// Print what would be done without changing anything + #[arg(long)] + pub dry_run: bool, +} + +pub fn run(args: UninstallArgs) -> Result<()> { + let plan = build_plan(args.data)?; + + print_plan(&plan); + + if plan.is_empty() { + println!("\nNothing to uninstall."); + print_binary_note(); + return Ok(()); + } + + if args.dry_run { + println!("\n[dry-run] No changes made."); + return Ok(()); + } + + if !args.yes && !crate::utils::confirm("\nProceed with uninstall?", false) { + println!("Aborted."); + return Ok(()); + } + + execute_plan(&plan)?; + + if plan.remove_local_data { + remove_local_data()?; + } + + println!("\nUninstall complete."); + print_binary_note(); + Ok(()) +} + +fn print_binary_note() { + println!("\nThe gitkit binary was not removed."); + if let Some(method) = detect_install_method() { + println!("It was installed via {method} — remove it with that tool's uninstall command."); + } else { + println!("Remove it manually from wherever it was installed."); + } +} + +fn detect_install_method() -> Option<&'static str> { + let exe = std::env::current_exe().ok()?; + let exe_str = exe.to_string_lossy(); + if exe_str.contains(".cargo/bin") { + Some("cargo") + } else if exe_str.contains(".local/bin") || exe_str.contains("/usr/local/bin") { + Some("the install script") + } else if exe_str.contains("Homebrew") || exe_str.contains("homebrew") { + Some("Homebrew") + } else { + None + } +} + +// ── Plan ───────────────────────────────────────────────────────────────────── + +struct UninstallPlan { + repos: Vec, + remove_local_data: bool, +} + +impl UninstallPlan { + fn is_empty(&self) -> bool { + self.repos.iter().all(|r| !r.exists || r.hooks.is_empty()) && !self.remove_local_data + } +} + +struct RepoPlan { + path: String, + exists: bool, + hooks: Vec, +} + +struct HookPlan { + hook_name: String, + has_dispatcher: bool, + parts: Vec, + has_preexisting: bool, +} + +fn build_plan(include_data: bool) -> Result { + let reg = registry::load(); + let mut repos = Vec::new(); + + for (key, entry) in ®.repos { + let repo_path = PathBuf::from(&entry.path); + let exists = repo_path.exists(); + + let mut hook_plans = Vec::new(); + + if exists { + let git_dir = repo_path.join(".git"); + if git_dir.exists() { + let hooks_dir = git_dir.join("hooks"); + if hooks_dir.exists() { + for hook_name in hooks::valid_hook_names() { + let dispatcher_path = hooks_dir.join(hook_name); + if !dispatcher_path.exists() { + continue; + } + let content = fs::read_to_string(&dispatcher_path).unwrap_or_default(); + if !hooks::is_dispatcher(&content, hook_name) { + continue; + } + + let parts = hooks::list_parts(&hooks_dir, hook_name); + let has_preexisting = parts.iter().any(|p| p == hooks::PRESERVED_PART_NAME); + + hook_plans.push(HookPlan { + hook_name: hook_name.to_string(), + has_dispatcher: true, + parts, + has_preexisting, + }); + } + } + } + } + + repos.push(RepoPlan { + path: key.clone(), + exists, + hooks: hook_plans, + }); + } + + Ok(UninstallPlan { + repos, + remove_local_data: include_data, + }) +} + +fn print_plan(plan: &UninstallPlan) { + println!("gitkit uninstall will:"); + + let mut any_repo = false; + for repo in &plan.repos { + if !repo.exists { + println!("\n {} — repository no longer exists, skipping", repo.path); + continue; + } + if repo.hooks.is_empty() { + println!("\n {} — no gitkit hooks found, skipping", repo.path); + continue; + } + + any_repo = true; + println!("\n {}", repo.path); + for hook in &repo.hooks { + if hook.has_preexisting { + println!( + " restore .git/hooks/{} from absorbed hand-written hook", + hook.hook_name + ); + } + if hook.has_dispatcher { + println!( + " remove .git/hooks/{} (gitkit dispatcher)", + hook.hook_name + ); + } + if !hook.parts.is_empty() { + println!( + " remove .git/hooks/gitkit.d/{}/ ({} part{})", + hook.hook_name, + hook.parts.len(), + if hook.parts.len() == 1 { "" } else { "s" } + ); + } + } + } + + if !any_repo && plan.repos.is_empty() { + println!(" (no repositories in registry)"); + } + + if plan.remove_local_data { + println!("\n remove ~/.gitkit/ (local state: builds, registry)"); + } else { + println!("\n keep ~/.gitkit/ (use --data to also remove local state)"); + } +} + +// ── Execute ────────────────────────────────────────────────────────────────── + +fn execute_plan(plan: &UninstallPlan) -> Result<()> { + for repo in &plan.repos { + if !repo.exists { + continue; + } + if repo.hooks.is_empty() { + continue; + } + + let repo_path = PathBuf::from(&repo.path); + if let Err(e) = execute_repo_plan(&repo_path, &repo.hooks) { + eprintln!("Warning: failed to clean {}: {e}", repo.path); + } + } + + remove_registry_entries(plan)?; + + Ok(()) +} + +fn execute_repo_plan(repo_path: &Path, hooks: &[HookPlan]) -> Result<()> { + let hooks_dir = repo_path.join(".git").join("hooks"); + + for hook in hooks { + if let Err(e) = execute_hook_plan(&hooks_dir, hook) { + eprintln!( + "Warning: failed to clean hook {} in {}: {e}", + hook.hook_name, + repo_path.display() + ); + } + } + + Ok(()) +} + +fn execute_hook_plan(hooks_dir: &Path, hook: &HookPlan) -> Result<()> { + let dispatcher_path = hooks_dir.join(&hook.hook_name); + let parts_dir = hooks::parts_dir(hooks_dir, &hook.hook_name); + + if hook.has_preexisting { + let preexisting_path = parts_dir.join(hooks::PRESERVED_PART_NAME); + if preexisting_path.exists() { + let content = fs::read(&preexisting_path) + .with_context(|| format!("Failed to read preserved hook for {}", hook.hook_name))?; + fs::write(&dispatcher_path, &content) + .with_context(|| format!("Failed to restore original {} hook", hook.hook_name))?; + hooks::set_executable(&dispatcher_path)?; + } + } + + if parts_dir.exists() { + let _ = fs::remove_dir_all(&parts_dir); + } + + if hook.has_dispatcher && dispatcher_path.exists() { + let content = fs::read_to_string(&dispatcher_path).unwrap_or_default(); + if hooks::is_dispatcher(&content, &hook.hook_name) { + fs::remove_file(&dispatcher_path) + .with_context(|| format!("Failed to remove dispatcher for {}", hook.hook_name))?; + } + } + + Ok(()) +} + +fn remove_registry_entries(plan: &UninstallPlan) -> Result<()> { + let mut reg = registry::load(); + for repo in &plan.repos { + reg.repos.remove(&repo.path); + } + registry::save(®) +} + +fn remove_local_data() -> Result<()> { + let home = std::env::var("HOME") + .or_else(|_| std::env::var("USERPROFILE")) + .context("Neither HOME nor USERPROFILE environment variable is set")?; + let gitkit_dir = PathBuf::from(home).join(".gitkit"); + if gitkit_dir.exists() { + fs::remove_dir_all(&gitkit_dir).context("Failed to remove ~/.gitkit")?; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use serial_test::serial; + + fn with_temp_home(f: F) { + let dir = tempfile::TempDir::new().unwrap(); + let original = std::env::var("HOME").ok(); + unsafe { + std::env::set_var("HOME", dir.path()); + } + f(dir.path()); + unsafe { + match &original { + Some(h) => std::env::set_var("HOME", h), + None => std::env::remove_var("HOME"), + } + } + } + + fn init_repo(path: &Path) { + fs::create_dir_all(path.join(".git").join("hooks")).unwrap(); + } + + fn install_dispatcher(hooks_dir: &Path, hook_name: &str) { + let script = hooks::dispatcher_script(hook_name); + let hook_path = hooks_dir.join(hook_name); + fs::write(&hook_path, &script).unwrap(); + hooks::set_executable(&hook_path).unwrap(); + } + + fn install_part(hooks_dir: &Path, hook_name: &str, part_name: &str, content: &str) { + let parts_dir = hooks::parts_dir(hooks_dir, hook_name); + fs::create_dir_all(&parts_dir).unwrap(); + let part_path = parts_dir.join(part_name); + fs::write(&part_path, content).unwrap(); + hooks::set_executable(&part_path).unwrap(); + } + + #[serial] + #[test] + fn uninstall_removes_dispatcher_and_parts() { + with_temp_home(|_home| { + let repo = tempfile::TempDir::new().unwrap(); + init_repo(repo.path()); + let hooks_dir = repo.path().join(".git").join("hooks"); + install_dispatcher(&hooks_dir, "pre-commit"); + let builtin = hooks::builtins::get("no-secrets").unwrap(); + install_part(&hooks_dir, "pre-commit", "no-secrets", builtin.script); + + registry::record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); + + let plan = build_plan(false).unwrap(); + assert_eq!(plan.repos.len(), 1); + assert_eq!(plan.repos[0].hooks.len(), 1); + assert!(plan.repos[0].hooks[0].has_dispatcher); + + execute_plan(&plan).unwrap(); + + assert!(!hooks_dir.join("pre-commit").exists()); + assert!(!hooks::parts_dir(&hooks_dir, "pre-commit").exists()); + }); + } + + #[serial] + #[test] + fn uninstall_restores_preexisting_hook() { + with_temp_home(|_home| { + let repo = tempfile::TempDir::new().unwrap(); + init_repo(repo.path()); + let hooks_dir = repo.path().join(".git").join("hooks"); + + let original_hook = "#!/bin/sh\necho my custom hook\n"; + install_dispatcher(&hooks_dir, "pre-commit"); + install_part( + &hooks_dir, + "pre-commit", + hooks::PRESERVED_PART_NAME, + original_hook, + ); + let builtin = hooks::builtins::get("no-secrets").unwrap(); + install_part(&hooks_dir, "pre-commit", "no-secrets", builtin.script); + + registry::record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); + + let plan = build_plan(false).unwrap(); + assert!(plan.repos[0].hooks[0].has_preexisting); + + execute_plan(&plan).unwrap(); + + let restored = hooks_dir.join("pre-commit"); + assert!(restored.exists()); + let content = fs::read_to_string(&restored).unwrap(); + assert_eq!(content, original_hook); + + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let perms = fs::metadata(&restored).unwrap().permissions(); + assert!( + perms.mode() & 0o111 != 0, + "restored hook should be executable" + ); + } + + assert!(!hooks::parts_dir(&hooks_dir, "pre-commit").exists()); + }); + } + + #[serial] + #[test] + fn uninstall_skips_missing_repo() { + with_temp_home(|_home| { + let fake_path = "/tmp/nonexistent-repo-gitkit-test-12345"; + let mut reg = registry::load(); + reg.repos.insert( + fake_path.to_string(), + registry::RegistryEntry { + path: fake_path.to_string(), + applied_at: "2026-01-01T00:00:00Z".to_string(), + applied: vec!["hook:no-secrets".to_string()], + }, + ); + registry::save(®).unwrap(); + + let plan = build_plan(false).unwrap(); + assert_eq!(plan.repos.len(), 1); + assert!(!plan.repos[0].exists); + + execute_plan(&plan).unwrap(); + + let reg_after = registry::load(); + assert!(!reg_after.repos.contains_key(fake_path)); + }); + } + + #[serial] + #[test] + fn dry_run_does_not_change_disk() { + with_temp_home(|_home| { + let repo = tempfile::TempDir::new().unwrap(); + init_repo(repo.path()); + let hooks_dir = repo.path().join(".git").join("hooks"); + install_dispatcher(&hooks_dir, "pre-commit"); + let builtin = hooks::builtins::get("no-secrets").unwrap(); + install_part(&hooks_dir, "pre-commit", "no-secrets", builtin.script); + + registry::record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); + + let args = UninstallArgs { + data: false, + yes: false, + dry_run: true, + }; + run(args).unwrap(); + + assert!(hooks_dir.join("pre-commit").exists()); + assert!(hooks::parts_dir(&hooks_dir, "pre-commit").exists()); + }); + } + + #[serial] + #[test] + fn without_data_flag_gitkit_dir_survives() { + with_temp_home(|home| { + let gitkit_dir = home.join(".gitkit"); + fs::create_dir_all(&gitkit_dir).unwrap(); + fs::write(gitkit_dir.join("registry.toml"), "").unwrap(); + + let repo = tempfile::TempDir::new().unwrap(); + init_repo(repo.path()); + let hooks_dir = repo.path().join(".git").join("hooks"); + install_dispatcher(&hooks_dir, "pre-commit"); + let builtin = hooks::builtins::get("no-secrets").unwrap(); + install_part(&hooks_dir, "pre-commit", "no-secrets", builtin.script); + + registry::record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); + + let args = UninstallArgs { + data: false, + yes: true, + dry_run: false, + }; + run(args).unwrap(); + + assert!(gitkit_dir.exists()); + }); + } + + #[serial] + #[test] + fn with_data_flag_removes_gitkit_dir() { + with_temp_home(|home| { + let gitkit_dir = home.join(".gitkit"); + fs::create_dir_all(&gitkit_dir).unwrap(); + fs::write(gitkit_dir.join("registry.toml"), "").unwrap(); + + let repo = tempfile::TempDir::new().unwrap(); + init_repo(repo.path()); + let hooks_dir = repo.path().join(".git").join("hooks"); + install_dispatcher(&hooks_dir, "pre-commit"); + let builtin = hooks::builtins::get("no-secrets").unwrap(); + install_part(&hooks_dir, "pre-commit", "no-secrets", builtin.script); + + registry::record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); + + let args = UninstallArgs { + data: true, + yes: true, + dry_run: false, + }; + run(args).unwrap(); + + assert!(!gitkit_dir.exists()); + }); + } +} From 7d53e80938d686c087c0e317eb451d4b4ead0745 Mon Sep 17 00:00:00 2001 From: Jheison Martinez Bolivar Date: Tue, 25 Aug 2026 20:25:47 -0500 Subject: [PATCH 6/8] chore: bump version to 0.6.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0951658..234ea27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -344,7 +344,7 @@ dependencies = [ [[package]] name = "gitkit" -version = "0.5.0" +version = "0.6.0" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index 82d7c92..405d2bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gitkit" -version = "0.5.0" +version = "0.6.0" edition = "2021" description = "Standalone CLI for configuring git repos — hooks, .gitignore, and .gitattributes" license = "MIT" From 190493f546cc486e471b0c361743981babf02619 Mon Sep 17 00:00:00 2001 From: Jheison Martinez Bolivar Date: Wed, 26 Aug 2026 13:28:06 -0500 Subject: [PATCH 7/8] fix(registry): isolate the test registry from the real one and summarize gone entries in status --global --- src/attributes/mod.rs | 7 + src/config/mod.rs | 45 +++- src/hooks/mod.rs | 487 ++++++++++++++++++++++-------------------- src/ignore/mod.rs | 33 +++ src/registry/mod.rs | 188 ++++++++++++---- src/status/mod.rs | 105 +++++++-- src/uninstall/mod.rs | 6 + tests/integration.rs | 43 ++++ 8 files changed, 631 insertions(+), 283 deletions(-) diff --git a/src/attributes/mod.rs b/src/attributes/mod.rs index e68dba6..e783ff1 100644 --- a/src/attributes/mod.rs +++ b/src/attributes/mod.rs @@ -105,6 +105,7 @@ pub(crate) fn apply_presets(labels: &[&str]) -> Result<()> { #[cfg(test)] mod tests { use super::*; + use serial_test::serial; use tempfile::TempDir; fn make_git_repo() -> TempDir { @@ -135,6 +136,7 @@ mod tests { assert!(PRESET_BINARY.contains("*.png binary")); } + #[serial] #[test] fn apply_presets_line_endings_writes_content() { let dir = make_git_repo(); @@ -146,6 +148,7 @@ mod tests { assert!(content.contains("eol=lf")); } + #[serial] #[test] fn apply_presets_binary_files_writes_content() { let dir = make_git_repo(); @@ -157,6 +160,7 @@ mod tests { assert!(content.contains("*.png binary")); } + #[serial] #[test] fn apply_presets_both_presets() { let dir = make_git_repo(); @@ -169,6 +173,7 @@ mod tests { assert!(content.contains("*.png binary")); } + #[serial] #[test] fn apply_presets_skips_unknown_labels() { let dir = make_git_repo(); @@ -180,6 +185,7 @@ mod tests { assert!(content.is_empty()); } + #[serial] #[test] fn apply_presets_does_not_duplicate() { let dir = make_git_repo(); @@ -191,6 +197,7 @@ mod tests { assert_eq!(content.matches("eol=lf").count(), 1); } + #[serial] #[test] fn apply_presets_appends_to_existing_content() { let dir = make_git_repo(); diff --git a/src/config/mod.rs b/src/config/mod.rs index 393f15f..ba99051 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -709,6 +709,11 @@ mod tests { #[serial] #[test] fn apply_configs_non_dry_run_in_temp_repo() { + let gitkit_home = tempfile::TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", gitkit_home.path()); + } let dir = tempfile::TempDir::new().unwrap(); std::process::Command::new("git") .args(["init"]) @@ -719,16 +724,26 @@ mod tests { let _ = std::env::set_current_dir(dir.path()); let single: &[(&str, &str)] = &[("push.autoSetupRemote", "true")]; let result = apply_configs(single, false, ConfigScope::Local); - // May fail if CWD race — just verify no panic let _ = result; if let Some(orig) = original { let _ = std::env::set_current_dir(orig); } + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } #[serial] #[test] fn apply_configs_non_dry_run_already_set() { + let gitkit_home = tempfile::TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", gitkit_home.path()); + } let dir = tempfile::TempDir::new().unwrap(); std::process::Command::new("git") .args(["init"]) @@ -745,11 +760,22 @@ mod tests { if let Some(orig) = original { let _ = std::env::set_current_dir(orig); } + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } #[serial] #[test] fn apply_configs_non_dry_run_multiple_configs() { + let gitkit_home = tempfile::TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", gitkit_home.path()); + } let dir = tempfile::TempDir::new().unwrap(); std::process::Command::new("git") .args(["init"]) @@ -769,6 +795,12 @@ mod tests { if let Some(orig) = original { let _ = std::env::set_current_dir(orig); } + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } // ── git_config_set ──────────────────────────────────────────────────── @@ -920,6 +952,11 @@ mod tests { #[serial] #[test] fn apply_config_keys_multiple_valid_non_dry_run() { + let gitkit_home = tempfile::TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", gitkit_home.path()); + } let dir = tempfile::TempDir::new().unwrap(); std::process::Command::new("git") .args(["init"]) @@ -938,6 +975,12 @@ mod tests { if let Some(orig) = original { let _ = std::env::set_current_dir(orig); } + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } // ── show_config ─────────────────────────────────────────────────────── diff --git a/src/hooks/mod.rs b/src/hooks/mod.rs index d0da50b..e5a03f6 100644 --- a/src/hooks/mod.rs +++ b/src/hooks/mod.rs @@ -689,6 +689,25 @@ mod tests { use super::*; use serial_test::serial; + /// Sets `GITKIT_HOME` to a fresh temp dir for the duration of `f`, + /// restoring the original value afterward. This isolates the registry + /// from the test suite: any `record_best_effort` call during the test + /// writes to the temp dir, not the user's real `~/.gitkit`. + fn with_isolated_registry(f: F) { + let dir = tempfile::TempDir::new().unwrap(); + let original = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", dir.path()); + } + f(); + unsafe { + match &original { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } + } + #[test] fn resolve_hook_returns_builtin_script() { let (hook, script) = resolve_hook("conventional-commits", None).unwrap(); @@ -1172,45 +1191,49 @@ mod tests { #[serial] #[test] fn install_builtin_writes_hook_file() { - let dir = tempfile::TempDir::new().unwrap(); - std::fs::create_dir(dir.path().join(".git")).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); - let result = install_builtin("no-secrets", true); - assert!(result.is_ok()); - let hook_path = dir.path().join(".git").join("hooks").join("pre-commit"); - assert!(hook_path.exists()); - let part_path = dir - .path() - .join(".git") - .join("hooks") - .join("gitkit.d") - .join("pre-commit") - .join("no-secrets"); - assert!(part_path.exists()); - let content = std::fs::read_to_string(&part_path).unwrap(); - assert!(content.contains("secret")); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + let result = install_builtin("no-secrets", true); + assert!(result.is_ok()); + let hook_path = dir.path().join(".git").join("hooks").join("pre-commit"); + assert!(hook_path.exists()); + let part_path = dir + .path() + .join(".git") + .join("hooks") + .join("gitkit.d") + .join("pre-commit") + .join("no-secrets"); + assert!(part_path.exists()); + let content = std::fs::read_to_string(&part_path).unwrap(); + assert!(content.contains("secret")); + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[serial] #[test] fn install_custom_writes_hook_file() { - let dir = tempfile::TempDir::new().unwrap(); - std::fs::create_dir(dir.path().join(".git")).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); - let result = install_custom("pre-commit", "cargo fmt --check", true); - assert!(result.is_ok()); - let hook_path = dir.path().join(".git").join("hooks").join("pre-commit"); - assert!(hook_path.exists()); - let content = std::fs::read_to_string(&hook_path).unwrap(); - assert!(content.contains("cargo fmt --check")); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + let result = install_custom("pre-commit", "cargo fmt --check", true); + assert!(result.is_ok()); + let hook_path = dir.path().join(".git").join("hooks").join("pre-commit"); + assert!(hook_path.exists()); + let content = std::fs::read_to_string(&hook_path).unwrap(); + assert!(content.contains("cargo fmt --check")); + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } // ── list() paths ────────────────────────────────────────────────────── @@ -1664,219 +1687,229 @@ mod tests { #[serial] #[test] fn installing_two_builtins_for_one_hook_leaves_both_as_parts_and_a_dispatcher() { - let dir = tempfile::TempDir::new().unwrap(); - std::fs::create_dir(dir.path().join(".git")).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); - - install_builtin("conventional-commits", true).unwrap(); - install_builtin("no-body", true).unwrap(); - - let hooks_dir = dir.path().join(".git").join("hooks"); - let parts = hooks_dir.join("gitkit.d").join("commit-msg"); - let cc_part = parts.join("conventional-commits"); - let nb_part = parts.join("no-body"); - assert!(cc_part.exists()); - assert!(nb_part.exists()); - assert!(is_executable(&cc_part).unwrap()); - assert!(is_executable(&nb_part).unwrap()); - - let dispatcher_path = hooks_dir.join("commit-msg"); - assert!(dispatcher_path.exists()); - assert!(is_executable(&dispatcher_path).unwrap()); - let dispatcher_content = std::fs::read_to_string(&dispatcher_path).unwrap(); - assert!(is_dispatcher(&dispatcher_content, "commit-msg")); - - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + install_builtin("conventional-commits", true).unwrap(); + install_builtin("no-body", true).unwrap(); + + let hooks_dir = dir.path().join(".git").join("hooks"); + let parts = hooks_dir.join("gitkit.d").join("commit-msg"); + let cc_part = parts.join("conventional-commits"); + let nb_part = parts.join("no-body"); + assert!(cc_part.exists()); + assert!(nb_part.exists()); + assert!(is_executable(&cc_part).unwrap()); + assert!(is_executable(&nb_part).unwrap()); + + let dispatcher_path = hooks_dir.join("commit-msg"); + assert!(dispatcher_path.exists()); + assert!(is_executable(&dispatcher_path).unwrap()); + let dispatcher_content = std::fs::read_to_string(&dispatcher_path).unwrap(); + assert!(is_dispatcher(&dispatcher_content, "commit-msg")); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[serial] #[test] fn dispatcher_rejects_message_that_violates_only_conventional_commits() { - let dir = tempfile::TempDir::new().unwrap(); - std::fs::create_dir(dir.path().join(".git")).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); - - install_builtin("conventional-commits", true).unwrap(); - install_builtin("no-body", true).unwrap(); - let hooks_dir = dir.path().join(".git").join("hooks"); - - // Non-conventional single-line subject: fails conventional-commits, - // would pass no-body on its own. - let (accepted, output) = run_dispatcher(&hooks_dir, "commit-msg", "just a message\n"); - assert!(!accepted, "expected rejection: {output}"); - assert!( - output.contains("Conventional Commits"), - "must name the conventional-commits failure: {output}" - ); + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + install_builtin("conventional-commits", true).unwrap(); + install_builtin("no-body", true).unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + + let (accepted, output) = run_dispatcher(&hooks_dir, "commit-msg", "just a message\n"); + assert!(!accepted, "expected rejection: {output}"); + assert!( + output.contains("Conventional Commits"), + "must name the conventional-commits failure: {output}" + ); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[serial] #[test] fn dispatcher_rejects_message_that_violates_only_no_body() { - let dir = tempfile::TempDir::new().unwrap(); - std::fs::create_dir(dir.path().join(".git")).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); - - install_builtin("conventional-commits", true).unwrap(); - install_builtin("no-body", true).unwrap(); - let hooks_dir = dir.path().join(".git").join("hooks"); - - // Conventional subject followed by a bulleted body: passes - // conventional-commits, fails no-body. - let (accepted, output) = run_dispatcher( - &hooks_dir, - "commit-msg", - "feat(x): add thing\n\n- bullet one\n- bullet two\n", - ); - assert!(!accepted, "expected rejection: {output}"); + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + install_builtin("conventional-commits", true).unwrap(); + install_builtin("no-body", true).unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + + let (accepted, output) = run_dispatcher( + &hooks_dir, + "commit-msg", + "feat(x): add thing\n\n- bullet one\n- bullet two\n", + ); + assert!(!accepted, "expected rejection: {output}"); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[serial] #[test] fn dispatcher_accepts_message_that_passes_both_builtins() { - let dir = tempfile::TempDir::new().unwrap(); - std::fs::create_dir(dir.path().join(".git")).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); - - install_builtin("conventional-commits", true).unwrap(); - install_builtin("no-body", true).unwrap(); - let hooks_dir = dir.path().join(".git").join("hooks"); - - let (accepted, output) = run_dispatcher(&hooks_dir, "commit-msg", "feat(x): add thing\n"); - assert!(accepted, "expected acceptance: {output}"); - - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + install_builtin("conventional-commits", true).unwrap(); + install_builtin("no-body", true).unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + + let (accepted, output) = + run_dispatcher(&hooks_dir, "commit-msg", "feat(x): add thing\n"); + assert!(accepted, "expected acceptance: {output}"); + + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[serial] #[test] fn installing_same_builtin_twice_leaves_exactly_one_part() { - let dir = tempfile::TempDir::new().unwrap(); - std::fs::create_dir(dir.path().join(".git")).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); - install_builtin("conventional-commits", true).unwrap(); - install_builtin("conventional-commits", true).unwrap(); + install_builtin("conventional-commits", true).unwrap(); + install_builtin("conventional-commits", true).unwrap(); - let hooks_dir = dir.path().join(".git").join("hooks"); - let parts = list_parts(&hooks_dir, "commit-msg"); - assert_eq!(parts, vec!["conventional-commits".to_string()]); + let hooks_dir = dir.path().join(".git").join("hooks"); + let parts = list_parts(&hooks_dir, "commit-msg"); + assert_eq!(parts, vec!["conventional-commits".to_string()]); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[serial] #[test] fn hand_written_hook_is_preserved_runs_and_is_restored_when_last_builtin_removed() { - let dir = tempfile::TempDir::new().unwrap(); - let hooks_dir = dir.path().join(".git").join("hooks"); - std::fs::create_dir_all(&hooks_dir).unwrap(); - std::fs::write( - hooks_dir.join("commit-msg"), - "#!/bin/sh\necho hand-written ran >&2\n", - ) - .unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + std::fs::create_dir_all(&hooks_dir).unwrap(); + std::fs::write( + hooks_dir.join("commit-msg"), + "#!/bin/sh\necho hand-written ran >&2\n", + ) + .unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); - install_builtin("conventional-commits", true).unwrap(); + install_builtin("conventional-commits", true).unwrap(); - let preserved_part = hooks_dir - .join("gitkit.d") - .join("commit-msg") - .join(PRESERVED_PART_NAME); - assert!(preserved_part.exists()); + let preserved_part = hooks_dir + .join("gitkit.d") + .join("commit-msg") + .join(PRESERVED_PART_NAME); + assert!(preserved_part.exists()); - let (_, output) = run_dispatcher(&hooks_dir, "commit-msg", "feat(x): add thing\n"); - assert!( - output.contains("hand-written ran"), - "hand-written hook must still run: {output}" - ); + let (_, output) = run_dispatcher(&hooks_dir, "commit-msg", "feat(x): add thing\n"); + assert!( + output.contains("hand-written ran"), + "hand-written hook must still run: {output}" + ); - remove_hook("conventional-commits", true).unwrap(); + remove_hook("conventional-commits", true).unwrap(); - assert!(!preserved_part.exists()); - assert!(!hooks_dir.join("gitkit.d").join("commit-msg").exists()); - let restored = std::fs::read_to_string(hooks_dir.join("commit-msg")).unwrap(); - assert!(restored.contains("hand-written ran")); + assert!(!preserved_part.exists()); + assert!(!hooks_dir.join("gitkit.d").join("commit-msg").exists()); + let restored = std::fs::read_to_string(hooks_dir.join("commit-msg")).unwrap(); + assert!(restored.contains("hand-written ran")); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[serial] #[test] fn removing_one_of_two_builtins_leaves_the_other_running() { - let dir = tempfile::TempDir::new().unwrap(); - std::fs::create_dir(dir.path().join(".git")).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + std::fs::create_dir(dir.path().join(".git")).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); - install_builtin("conventional-commits", true).unwrap(); - install_builtin("no-body", true).unwrap(); - let hooks_dir = dir.path().join(".git").join("hooks"); + install_builtin("conventional-commits", true).unwrap(); + install_builtin("no-body", true).unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); - remove_hook("no-body", true).unwrap(); + remove_hook("no-body", true).unwrap(); - let parts = list_parts(&hooks_dir, "commit-msg"); - assert_eq!(parts, vec!["conventional-commits".to_string()]); - assert!(hooks_dir.join("commit-msg").exists()); + let parts = list_parts(&hooks_dir, "commit-msg"); + assert_eq!(parts, vec!["conventional-commits".to_string()]); + assert!(hooks_dir.join("commit-msg").exists()); - // conventional-commits still rejects a non-conventional subject. - let (accepted, _) = run_dispatcher(&hooks_dir, "commit-msg", "not conventional\n"); - assert!(!accepted, "surviving builtin must still run"); + let (accepted, _) = run_dispatcher(&hooks_dir, "commit-msg", "not conventional\n"); + assert!(!accepted, "surviving builtin must still run"); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[serial] #[test] fn migration_absorbs_a_bare_builtin_script_when_a_new_builtin_is_added() { - let dir = tempfile::TempDir::new().unwrap(); - let hooks_dir = dir.path().join(".git").join("hooks"); - std::fs::create_dir_all(&hooks_dir).unwrap(); - // The pre-composition damaged shape: a bare builtin script sitting - // directly at .git/hooks/commit-msg. - let no_body = builtins::get("no-body").unwrap(); - std::fs::write(hooks_dir.join("commit-msg"), no_body.script).unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); - - install_builtin("conventional-commits", true).unwrap(); - - let parts = list_parts(&hooks_dir, "commit-msg"); - assert_eq!( - parts, - vec!["conventional-commits".to_string(), "no-body".to_string()] - ); - let dispatcher_content = std::fs::read_to_string(hooks_dir.join("commit-msg")).unwrap(); - assert!(is_dispatcher(&dispatcher_content, "commit-msg")); + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + std::fs::create_dir_all(&hooks_dir).unwrap(); + let no_body = builtins::get("no-body").unwrap(); + std::fs::write(hooks_dir.join("commit-msg"), no_body.script).unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + + install_builtin("conventional-commits", true).unwrap(); + + let parts = list_parts(&hooks_dir, "commit-msg"); + assert_eq!( + parts, + vec!["conventional-commits".to_string(), "no-body".to_string()] + ); + let dispatcher_content = std::fs::read_to_string(hooks_dir.join("commit-msg")).unwrap(); + assert!(is_dispatcher(&dispatcher_content, "commit-msg")); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } // ── GK-E: outdated builtin recognition ───────────────────────────────── @@ -1895,40 +1928,42 @@ mod tests { #[serial] #[test] fn installing_over_outdated_builtin_replaces_it_without_preserving() { - let dir = tempfile::TempDir::new().unwrap(); - let hooks_dir = dir.path().join(".git").join("hooks"); - std::fs::create_dir_all(&hooks_dir).unwrap(); - std::fs::write( - hooks_dir.join("commit-msg"), - "#!/bin/sh\n# gitkit-builtin: no-trailers\necho old-version\n", - ) - .unwrap(); - let original = std::env::current_dir().ok(); - let _ = std::env::set_current_dir(dir.path()); + with_isolated_registry(|| { + let dir = tempfile::TempDir::new().unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + std::fs::create_dir_all(&hooks_dir).unwrap(); + std::fs::write( + hooks_dir.join("commit-msg"), + "#!/bin/sh\n# gitkit-builtin: no-trailers\necho old-version\n", + ) + .unwrap(); + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); - install_builtin("conventional-commits", true).unwrap(); + install_builtin("conventional-commits", true).unwrap(); - let parts = list_parts(&hooks_dir, "commit-msg"); - assert!( - !parts.contains(&PRESERVED_PART_NAME.to_string()), - "outdated builtin must not be preserved as 00-preexisting: {parts:?}" - ); - assert!(parts.contains(&"no-trailers".to_string())); - assert!(parts.contains(&"conventional-commits".to_string())); - - let nt_content = std::fs::read_to_string( - hooks_dir - .join("gitkit.d") - .join("commit-msg") - .join("no-trailers"), - ) - .unwrap(); - let current_nt = builtins::get("no-trailers").unwrap(); - assert_eq!(nt_content, current_nt.script); + let parts = list_parts(&hooks_dir, "commit-msg"); + assert!( + !parts.contains(&PRESERVED_PART_NAME.to_string()), + "outdated builtin must not be preserved as 00-preexisting: {parts:?}" + ); + assert!(parts.contains(&"no-trailers".to_string())); + assert!(parts.contains(&"conventional-commits".to_string())); + + let nt_content = std::fs::read_to_string( + hooks_dir + .join("gitkit.d") + .join("commit-msg") + .join("no-trailers"), + ) + .unwrap(); + let current_nt = builtins::get("no-trailers").unwrap(); + assert_eq!(nt_content, current_nt.script); - if let Some(orig) = original { - let _ = std::env::set_current_dir(orig); - } + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + }); } #[test] diff --git a/src/ignore/mod.rs b/src/ignore/mod.rs index b9d84d2..008af98 100644 --- a/src/ignore/mod.rs +++ b/src/ignore/mod.rs @@ -536,6 +536,11 @@ skills-lock.json\n"; #[serial] #[test] fn add_templates_force_writes_gitignore() { + let gitkit_home = tempfile::TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", gitkit_home.path()); + } let dir = tempfile::TempDir::new().unwrap(); std::fs::create_dir(dir.path().join(".git")).unwrap(); let original = std::env::current_dir().ok(); @@ -547,11 +552,22 @@ skills-lock.json\n"; if let Some(orig) = original { let _ = std::env::set_current_dir(orig); } + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } #[serial] #[test] fn add_templates_merge_with_existing_gitignore() { + let gitkit_home = tempfile::TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", gitkit_home.path()); + } let dir = tempfile::TempDir::new().unwrap(); std::fs::create_dir(dir.path().join(".git")).unwrap(); std::fs::write(dir.path().join(".gitignore"), "target/\n").unwrap(); @@ -565,11 +581,22 @@ skills-lock.json\n"; if let Some(orig) = original { let _ = std::env::set_current_dir(orig); } + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } #[serial] #[test] fn add_templates_no_existing_gitignore() { + let gitkit_home = tempfile::TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", gitkit_home.path()); + } let dir = tempfile::TempDir::new().unwrap(); std::fs::create_dir(dir.path().join(".git")).unwrap(); let original = std::env::current_dir().ok(); @@ -581,6 +608,12 @@ skills-lock.json\n"; if let Some(orig) = original { let _ = std::env::set_current_dir(orig); } + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } // ── resolve_templates with builtins only ────────────────────────────── diff --git a/src/registry/mod.rs b/src/registry/mod.rs index a04b5a3..dad33fe 100644 --- a/src/registry/mod.rs +++ b/src/registry/mod.rs @@ -24,11 +24,34 @@ pub(crate) struct RegistryEntry { pub applied: Vec, } +#[cfg(test)] +static TEST_REGISTRY_DIR: std::sync::OnceLock = std::sync::OnceLock::new(); + +#[cfg(test)] +fn ensure_test_registry_dir() -> PathBuf { + TEST_REGISTRY_DIR + .get_or_init(|| { + let dir = tempfile::TempDir::new().unwrap(); + dir.keep() + }) + .clone() +} + pub(crate) fn registry_path() -> Result { - let home = std::env::var("HOME") - .or_else(|_| std::env::var("USERPROFILE")) - .context("Neither HOME nor USERPROFILE environment variable is set")?; - Ok(PathBuf::from(home).join(".gitkit").join("registry.toml")) + if let Ok(gitkit_home) = std::env::var("GITKIT_HOME") { + return Ok(PathBuf::from(gitkit_home).join("registry.toml")); + } + #[cfg(test)] + { + Ok(ensure_test_registry_dir().join("registry.toml")) + } + #[cfg(not(test))] + { + let home = std::env::var("HOME") + .or_else(|_| std::env::var("USERPROFILE")) + .context("Neither HOME nor USERPROFILE environment variable is set")?; + Ok(PathBuf::from(home).join(".gitkit").join("registry.toml")) + } } /// Loads the ledger. A missing, empty, or unparseable file yields an empty @@ -47,7 +70,7 @@ pub(crate) fn load() -> Registry { pub(crate) fn save(registry: &Registry) -> Result<()> { let path = registry_path()?; if let Some(parent) = path.parent() { - fs::create_dir_all(parent).context("Failed to create ~/.gitkit directory")?; + fs::create_dir_all(parent).context("Failed to create gitkit registry directory")?; } let content = toml::to_string_pretty(registry).context("Failed to serialize registry")?; fs::write(&path, content).context("Failed to write registry")?; @@ -211,37 +234,69 @@ mod tests { use super::*; use serial_test::serial; - /// Points HOME at a fresh temp dir for the duration of `f`, restoring - /// the original value afterward. Never touches the real ~/.gitkit. - fn with_temp_home(f: F) { + /// Provides a clean, isolated registry for tests that need an empty starting state. + /// Sets GITKIT_HOME to a unique temp dir, ensuring no interference from other tests. + fn with_clean_registry(f: F) { let dir = tempfile::TempDir::new().unwrap(); - let original = std::env::var("HOME").ok(); + let orig = std::env::var("GITKIT_HOME").ok(); unsafe { - std::env::set_var("HOME", dir.path()); + std::env::set_var("GITKIT_HOME", dir.path()); } - f(dir.path()); + f(); unsafe { - match &original { - Some(h) => std::env::set_var("HOME", h), - None => std::env::remove_var("HOME"), + match &orig { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), } } } + #[test] + fn registry_path_returns_registry_toml_filename() { + let path = registry_path().unwrap(); + assert_eq!(path.file_name().unwrap(), "registry.toml"); + } + + #[test] + fn registry_path_resolves_under_test_dir_not_real_home() { + let path = registry_path().unwrap(); + let real_home = std::env::var("HOME").unwrap_or_default(); + let real_gitkit = PathBuf::from(&real_home) + .join(".gitkit") + .join("registry.toml"); + assert_ne!( + path, real_gitkit, + "registry_path() in tests must NOT resolve to the real ~/.gitkit/registry.toml" + ); + } + #[serial] #[test] - fn registry_path_lives_under_gitkit() { - with_temp_home(|_| { - let path = registry_path().unwrap(); - assert!(path.to_string_lossy().contains(".gitkit")); - assert_eq!(path.file_name().unwrap(), "registry.toml"); - }); + fn registry_path_honors_gitkit_home_over_test_default() { + let gitkit_home = tempfile::TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", gitkit_home.path()); + } + let path = registry_path().unwrap(); + assert!( + path.starts_with(gitkit_home.path()), + "GITKIT_HOME must take precedence: got {}", + path.display() + ); + assert_eq!(path.file_name().unwrap(), "registry.toml"); + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } #[serial] #[test] fn load_missing_registry_returns_default() { - with_temp_home(|_| { + with_clean_registry(|| { let reg = load(); assert!(reg.repos.is_empty()); }); @@ -250,9 +305,8 @@ mod tests { #[serial] #[test] fn load_corrupt_registry_returns_default_not_panic() { - with_temp_home(|home| { - let dir = home.join(".gitkit"); - fs::create_dir_all(&dir).unwrap(); + with_clean_registry(|| { + let dir = ensure_test_registry_dir(); fs::write(dir.join("registry.toml"), "not valid toml {{{").unwrap(); let reg = load(); assert!(reg.repos.is_empty()); @@ -262,9 +316,8 @@ mod tests { #[serial] #[test] fn load_empty_registry_returns_default() { - with_temp_home(|home| { - let dir = home.join(".gitkit"); - fs::create_dir_all(&dir).unwrap(); + with_clean_registry(|| { + let dir = ensure_test_registry_dir(); fs::write(dir.join("registry.toml"), "").unwrap(); let reg = load(); assert!(reg.repos.is_empty()); @@ -274,7 +327,7 @@ mod tests { #[serial] #[test] fn record_writes_entry_with_absolute_path() { - with_temp_home(|_| { + with_clean_registry(|| { let repo = tempfile::TempDir::new().unwrap(); record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); let reg = load(); @@ -289,7 +342,7 @@ mod tests { #[serial] #[test] fn record_twice_updates_single_entry_not_duplicate() { - with_temp_home(|_| { + with_clean_registry(|| { let repo = tempfile::TempDir::new().unwrap(); record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); record(repo.path(), &["hook:conventional-commits".to_string()]).unwrap(); @@ -307,7 +360,7 @@ mod tests { #[serial] #[test] fn record_same_item_twice_does_not_duplicate_in_list() { - with_temp_home(|_| { + with_clean_registry(|| { let repo = tempfile::TempDir::new().unwrap(); record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); record(repo.path(), &["hook:no-secrets".to_string()]).unwrap(); @@ -328,7 +381,7 @@ mod tests { #[serial] #[test] fn record_empty_items_is_noop() { - with_temp_home(|_| { + with_clean_registry(|| { let repo = tempfile::TempDir::new().unwrap(); record(repo.path(), &[]).unwrap(); let reg = load(); @@ -339,22 +392,36 @@ mod tests { #[serial] #[test] fn record_best_effort_swallows_write_failure_without_panic() { - with_temp_home(|home| { - // Put a plain file where the ~/.gitkit directory would go, so - // `fs::create_dir_all` inside `save` fails. `record_best_effort` - // must warn and return, never panic or propagate — the actual - // caller (a hook install) must not be failed by this. - fs::write(home.join(".gitkit"), "not a directory").unwrap(); - let repo = tempfile::TempDir::new().unwrap(); - record_best_effort(repo.path(), &["hook:no-secrets".to_string()]); - assert!(record(repo.path(), &["hook:no-secrets".to_string()]).is_err()); - }); + let blocker = tempfile::TempDir::new().unwrap(); + let blocker_file = blocker.path().join("blocker"); + fs::write(&blocker_file, "not a directory").unwrap(); + + let orig = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", &blocker_file); + } + + let repo = tempfile::TempDir::new().unwrap(); + let result = record(repo.path(), &["hook:no-secrets".to_string()]); + assert!( + result.is_err(), + "record must fail when GITKIT_HOME is a file" + ); + + record_best_effort(repo.path(), &["hook:no-secrets".to_string()]); + + unsafe { + match &orig { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } #[serial] #[test] fn save_and_load_roundtrip() { - with_temp_home(|_| { + with_clean_registry(|| { let mut reg = Registry::default(); reg.repos.insert( "/tmp/example".to_string(), @@ -370,6 +437,43 @@ mod tests { }); } + #[serial] + #[test] + fn test_suite_does_not_write_to_real_registry() { + let real_home = match std::env::var("HOME") { + Ok(h) => h, + Err(_) => return, + }; + let real_registry = PathBuf::from(&real_home) + .join(".gitkit") + .join("registry.toml"); + let real_existed = real_registry.exists(); + let real_mtime_before = fs::metadata(&real_registry) + .ok() + .and_then(|m| m.modified().ok()); + + let repo = tempfile::TempDir::new().unwrap(); + crate::registry::record_best_effort( + repo.path(), + &["hook:test-isolation-check".to_string()], + ); + + if real_existed { + let real_mtime_after = fs::metadata(&real_registry) + .ok() + .and_then(|m| m.modified().ok()); + assert_eq!( + real_mtime_before, real_mtime_after, + "the real ~/.gitkit/registry.toml must not be modified by tests" + ); + } else { + assert!( + !real_registry.exists(), + "the real ~/.gitkit/registry.toml must not be created by tests" + ); + } + } + // ── civil_from_days / now_timestamp ───────────────────────────────────── #[test] diff --git a/src/status/mod.rs b/src/status/mod.rs index a34e342..c8178c6 100644 --- a/src/status/mod.rs +++ b/src/status/mod.rs @@ -103,14 +103,8 @@ fn run_global(prune: bool) -> Result<()> { for (path_str, entry) in ®istry.repos { let path = Path::new(path_str); - if !path.exists() { + if let Ok(false) = path.try_exists() { gone.push(path_str.clone()); - println!("{path_str}"); - println!( - " ✗ gone — repository no longer exists (last applied {})", - entry.applied_at - ); - println!(); continue; } @@ -175,7 +169,7 @@ fn run_global(prune: bool) -> Result<()> { println!("Pruned {} repositories that no longer exist.", gone.len()); } else if !gone.is_empty() { println!( - "{} repositories are gone. Re-run with `gitkit status --global --prune` to remove them from the registry.", + "{} repositories are gone (path no longer exists). Re-run with `gitkit status --global --prune` to remove them from the registry.", gone.len() ); } @@ -696,9 +690,12 @@ mod tests { #[serial] #[test] fn repair_sets_executable_bit_on_dormant_part_and_on_dispatcher() { - // GK-A: two builtins composed on one git hook via the gitkit.d - // dispatcher; both the dispatcher and one of its parts lose their - // executable bit, and `--repair` must fix both. + let home = TempDir::new().unwrap(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); + unsafe { + std::env::set_var("GITKIT_HOME", home.path().join(".gitkit")); + } + let dir = TempDir::new().unwrap(); std::fs::create_dir(dir.path().join(".git")).unwrap(); let original = std::env::current_dir().ok(); @@ -737,6 +734,12 @@ mod tests { if let Some(orig) = original { let _ = std::env::set_current_dir(orig); } + unsafe { + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } + } } #[serial] @@ -928,9 +931,11 @@ mod tests { fs::create_dir_all(repo.path().join(".git").join("hooks")).unwrap(); let orig_home = std::env::var("HOME").ok(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); let orig_cwd = std::env::current_dir().ok(); unsafe { std::env::set_var("HOME", home.path()); + std::env::set_var("GITKIT_HOME", home.path().join(".gitkit")); } let _ = std::env::set_current_dir(repo.path()); @@ -944,6 +949,10 @@ mod tests { Some(h) => std::env::set_var("HOME", h), None => std::env::remove_var("HOME"), } + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } } } @@ -1147,9 +1156,6 @@ mod tests { #[test] fn ledger_write_failure_does_not_fail_hook_installation() { with_temp_home_and_repo(|home, repo| { - // Block ~/.gitkit from being created, so the registry write - // inside install_builtin fails. The hook install itself must - // still succeed. fs::write(home.join(".gitkit"), "not a directory").unwrap(); let result = crate::hooks::install_builtin("no-secrets", true); assert!(result.is_ok()); @@ -1157,4 +1163,75 @@ mod tests { assert!(hook_path.exists()); }); } + + #[serial] + #[test] + fn prune_removes_only_gone_entries_and_reports_count() { + with_temp_home_and_repo(|_home, repo| { + crate::hooks::install_builtin("no-secrets", true).unwrap(); + let live_key = repo.to_string_lossy().to_string(); + + let mut reg = crate::registry::load(); + let gone_paths: Vec = (0..3).map(|i| format!("/tmp/gone-repo-{i}")).collect(); + for fake_path in &gone_paths { + reg.repos.insert( + fake_path.clone(), + crate::registry::RegistryEntry { + path: fake_path.clone(), + applied_at: "2026-01-01T00:00:00Z".to_string(), + applied: vec!["hook:no-secrets".to_string()], + }, + ); + } + crate::registry::save(®).unwrap(); + + let _ = std::env::set_current_dir(std::env::temp_dir()); + fs::remove_dir_all(repo).unwrap(); + + run_global(true).unwrap(); + let reg_after = crate::registry::load(); + assert!( + !reg_after.repos.contains_key(&live_key), + "the gone live-key repo must be pruned" + ); + for g in &gone_paths { + assert!( + !reg_after.repos.contains_key(g), + "gone entry {g} must be pruned" + ); + } + }); + } + + #[serial] + #[test] + fn prune_does_not_remove_existing_path_that_is_not_a_repo() { + with_temp_home_and_repo(|_home, repo| { + crate::hooks::install_builtin("no-secrets", true).unwrap(); + + let existing_non_repo = tempfile::TempDir::new().unwrap(); + let non_repo_key = existing_non_repo.path().to_string_lossy().to_string(); + let mut reg = crate::registry::load(); + reg.repos.insert( + non_repo_key.clone(), + crate::registry::RegistryEntry { + path: non_repo_key.clone(), + applied_at: "2026-01-01T00:00:00Z".to_string(), + applied: vec!["hook:no-secrets".to_string()], + }, + ); + crate::registry::save(®).unwrap(); + + let repo_buf = repo.to_path_buf(); + let _ = std::env::set_current_dir(std::env::temp_dir()); + fs::remove_dir_all(&repo_buf).unwrap(); + + run_global(true).unwrap(); + let reg_after = crate::registry::load(); + assert!( + reg_after.repos.contains_key(&non_repo_key), + "a path that still exists on disk must survive prune even if it is not a repo" + ); + }); + } } diff --git a/src/uninstall/mod.rs b/src/uninstall/mod.rs index 3364992..1aee4c4 100644 --- a/src/uninstall/mod.rs +++ b/src/uninstall/mod.rs @@ -300,8 +300,10 @@ mod tests { fn with_temp_home(f: F) { let dir = tempfile::TempDir::new().unwrap(); let original = std::env::var("HOME").ok(); + let orig_gitkit_home = std::env::var("GITKIT_HOME").ok(); unsafe { std::env::set_var("HOME", dir.path()); + std::env::set_var("GITKIT_HOME", dir.path().join(".gitkit")); } f(dir.path()); unsafe { @@ -309,6 +311,10 @@ mod tests { Some(h) => std::env::set_var("HOME", h), None => std::env::remove_var("HOME"), } + match &orig_gitkit_home { + Some(h) => std::env::set_var("GITKIT_HOME", h), + None => std::env::remove_var("GITKIT_HOME"), + } } } diff --git a/tests/integration.rs b/tests/integration.rs index 180343f..d8dbd3c 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1615,3 +1615,46 @@ fn lock_fixture_status_reports_axes() { assert!(stdout.contains("Rebase:"), "status was: {stdout}"); assert!(stdout.contains("Refs:"), "status was: {stdout}"); } + +// ═══════════════════════════════════════════════════════════════════════════ +// GK-I: `status --global` summarises gone entries instead of listing each +// ═══════════════════════════════════════════════════════════════════════════ + +#[test] +fn status_global_summarizes_gone_entries_in_one_line() { + let home = TempDir::new().unwrap(); + let gitkit_dir = home.path().join(".gitkit"); + std::fs::create_dir_all(&gitkit_dir).unwrap(); + + let mut registry_content = String::from("[repos]\n"); + for i in 0..5 { + let fake_path = format!("/tmp/gone-repo-{i}"); + registry_content.push_str(&format!( + "[repos.\"{fake_path}\"]\npath = \"{fake_path}\"\napplied_at = \"2026-01-01T00:00:00Z\"\napplied = [\"hook:no-secrets\"]\n" + )); + } + std::fs::write(gitkit_dir.join("registry.toml"), ®istry_content).unwrap(); + + let binary = gitkit_binary(); + let out = Command::new(&binary) + .env("GITKIT_NO_UPDATE_CHECK", "1") + .env("HOME", home.path()) + .args(["status", "--global"]) + .current_dir(home.path()) + .output() + .expect("Failed to run gitkit status --global"); + assert!(out.status.success()); + + let stdout = String::from_utf8_lossy(&out.stdout); + assert!( + stdout.contains("5 repositories are gone"), + "expected a single summary line for 5 gone entries, stdout was:\n{stdout}" + ); + for i in 0..5 { + let fake_path = format!("/tmp/gone-repo-{i}"); + assert!( + !stdout.contains(&fake_path), + "stdout must NOT list individual gone entry {fake_path}, stdout was:\n{stdout}" + ); + } +} From de9c22175d00a7f7f8b2f94f6f537ae8dd714bc2 Mon Sep 17 00:00:00 2001 From: Jheison Martinez Bolivar Date: Wed, 26 Aug 2026 13:35:49 -0500 Subject: [PATCH 8/8] fix(status): report a modified hook that is also non-executable as dormant --- src/hooks/mod.rs | 48 +++++++++++-------- src/status/mod.rs | 119 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 143 insertions(+), 24 deletions(-) diff --git a/src/hooks/mod.rs b/src/hooks/mod.rs index e5a03f6..9c66027 100644 --- a/src/hooks/mod.rs +++ b/src/hooks/mod.rs @@ -324,8 +324,11 @@ fn remove_part(dir: &Path, hook_name: &str, part_name: &str) -> Result<()> { /// Health of one installed part within `gitkit.d//`, mirroring /// [`classify_hook`]'s categories but also accounting for the dispatcher's -/// own executable bit — a part stays `Dormant` if the dispatcher that would -/// run it is itself not executable, since git never even reaches it then. +/// own executable bit — a part stays `Dormant`/`ModifiedDormant` if the +/// dispatcher that would run it is itself not executable, since git never +/// even reaches it then. The execute bit is orthogonal to content: a +/// non-executable part is dormant regardless of whether its content is +/// recognized. pub(crate) fn classify_part(dir: &Path, hook_name: &str, part_name: &str) -> Result { let part_path = parts_dir(dir, hook_name).join(part_name); if !part_path.exists() { @@ -347,14 +350,13 @@ pub(crate) fn classify_part(dir: &Path, hook_name: &str, part_name: &str) -> Res Err(_) => false, }; - if !recognized { - return Ok(HookHealth::Modified); - } + let executable = dispatcher_ok && is_executable(&part_path)?; - if dispatcher_ok && is_executable(&part_path)? { - Ok(HookHealth::Active) - } else { - Ok(HookHealth::Dormant) + match (recognized, executable) { + (true, true) => Ok(HookHealth::Active), + (true, false) => Ok(HookHealth::Dormant), + (false, true) => Ok(HookHealth::Modified), + (false, false) => Ok(HookHealth::ModifiedDormant), } } @@ -647,17 +649,22 @@ pub(crate) enum HookHealth { /// Present but its content matches no builtin. Not an error: the user /// may have edited it deliberately, or it's a custom (non-builtin) hook. Modified, + /// Content matches no builtin AND the file is not executable — git silently + /// ignores it. Both facts are reported: the user must learn it does not run. + ModifiedDormant, /// No file at this hook's path. Absent, } /// Classifies an installed hook file's health for `gitkit status`, by /// comparing its content against the builtin catalogue via exact-content -/// match. A hook with a marker but hand-edited content is `Modified`, not -/// `Active` — health reporting cares about byte-identical content, not -/// identity. Reads the file itself rather than trusting a caller-supplied -/// string, so non-UTF-8 content is classified `Modified` instead of -/// erroring — git runs a hook regardless of its encoding, so an +/// match and checking the execute bit. The execute bit is orthogonal to +/// content: a non-executable hook is dormant regardless of whether its +/// content matches a builtin, so a hand-edited hook that lost its execute +/// bit is `ModifiedDormant` — both facts reported, not one. +/// Reads the file itself rather than trusting a caller-supplied string, +/// so non-UTF-8 content is classified `Modified`/`ModifiedDormant` instead +/// of erroring — git runs a hook regardless of its encoding, so an /// unreadable-as-text file is not a failure, just content gitkit can't /// match against a builtin. pub(crate) fn classify_hook(hook_name: &str, path: &Path) -> Result { @@ -673,14 +680,13 @@ pub(crate) fn classify_hook(hook_name: &str, path: &Path) -> Result Err(_) => false, }; - if !is_builtin { - return Ok(HookHealth::Modified); - } + let executable = is_executable(path)?; - if is_executable(path)? { - Ok(HookHealth::Active) - } else { - Ok(HookHealth::Dormant) + match (is_builtin, executable) { + (true, true) => Ok(HookHealth::Active), + (true, false) => Ok(HookHealth::Dormant), + (false, true) => Ok(HookHealth::Modified), + (false, false) => Ok(HookHealth::ModifiedDormant), } } diff --git a/src/status/mod.rs b/src/status/mod.rs index c8178c6..698401b 100644 --- a/src/status/mod.rs +++ b/src/status/mod.rs @@ -132,7 +132,7 @@ fn run_global(prune: bool) -> Result<()> { }; match health { - HookHealth::Dormant => { + HookHealth::Dormant | HookHealth::ModifiedDormant => { any_dormant = true; problems.push(format!( " ✗ {name} ({hook_file}) — dormant: not executable, git ignores it" @@ -263,7 +263,7 @@ fn print_hooks(repair: bool) -> Result { let health = crate::hooks::classify_hook(&hook_name, &path)?; - if repair && health == HookHealth::Dormant { + if repair && matches!(health, HookHealth::Dormant | HookHealth::ModifiedDormant) { crate::hooks::set_executable(&path)?; let label = builtin_label(&hook_name, &path); println!(" ✓ {label} ({hook_name}) — repaired: set executable, git will now run it"); @@ -282,6 +282,18 @@ fn print_hooks(repair: bool) -> Result { " ✗ {label} ({hook_name}) — dormant: not executable, so git ignores it and never runs it (fix with `gitkit status --repair`)" ); } + HookHealth::ModifiedDormant => { + dormant_found = true; + let content = fs::read_to_string(&path).unwrap_or_default(); + let first_cmd = content + .lines() + .find(|l| !l.starts_with('#') && !l.starts_with("set ") && !l.trim().is_empty()) + .unwrap_or("(custom)") + .trim(); + println!( + " ✗ {hook_name} — dormant: not executable, so git ignores it and never runs it; also modified: {first_cmd:?} (fix with `gitkit status --repair`)" + ); + } HookHealth::Modified => { let content = fs::read_to_string(&path).unwrap_or_default(); let first_cmd = content @@ -318,7 +330,7 @@ fn print_dispatcher_parts(hooks_dir: &Path, hook_name: &str, repair: bool) -> Re let part_path = crate::hooks::parts_dir(hooks_dir, hook_name).join(&part_name); let health = crate::hooks::classify_part(hooks_dir, hook_name, &part_name)?; - if repair && health == HookHealth::Dormant { + if repair && matches!(health, HookHealth::Dormant | HookHealth::ModifiedDormant) { crate::hooks::set_executable(&part_path)?; println!( " ✓ {part_name} ({hook_name}) — repaired: set executable, git will now run it" @@ -334,6 +346,12 @@ fn print_dispatcher_parts(hooks_dir: &Path, hook_name: &str, repair: bool) -> Re " ✗ {part_name} ({hook_name}) — dormant: not executable, so git ignores it and never runs it (fix with `gitkit status --repair`)" ); } + HookHealth::ModifiedDormant => { + dormant_found = true; + println!( + " ✗ {part_name} ({hook_name}) — dormant: not executable, so git ignores it and never runs it; also modified since install (fix with `gitkit status --repair`)" + ); + } HookHealth::Modified => { println!(" ~ {part_name} ({hook_name}) — modified since install"); } @@ -1234,4 +1252,99 @@ mod tests { ); }); } + + // ── GK-J: dormant check for non-executable hooks ──────────────────────── + + #[serial] + #[test] + fn non_executable_modified_hook_is_reported_as_dormant() { + let dir = TempDir::new().unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + std::fs::create_dir_all(&hooks_dir).unwrap(); + let path = hooks_dir.join("pre-push"); + std::fs::write(&path, "#!/bin/sh\ncargo test\n").unwrap(); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = std::fs::metadata(&path).unwrap().permissions(); + perms.set_mode(0o644); + std::fs::set_permissions(&path, perms).unwrap(); + } + + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + let dormant_found = print_hooks(false).unwrap(); + #[cfg(unix)] + assert!( + dormant_found, + "a non-executable modified hook must be reported dormant" + ); + #[cfg(not(unix))] + assert!( + !dormant_found, + "the executable bit does not apply on non-Unix targets" + ); + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[serial] + #[test] + fn repair_sets_executable_bit_on_non_executable_modified_hook() { + let dir = TempDir::new().unwrap(); + let hooks_dir = dir.path().join(".git").join("hooks"); + std::fs::create_dir_all(&hooks_dir).unwrap(); + let path = hooks_dir.join("pre-push"); + std::fs::write(&path, "#!/bin/sh\ncargo test\n").unwrap(); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = std::fs::metadata(&path).unwrap().permissions(); + perms.set_mode(0o644); + std::fs::set_permissions(&path, perms).unwrap(); + } + + let original = std::env::current_dir().ok(); + let _ = std::env::set_current_dir(dir.path()); + let dormant_found = print_hooks(true).unwrap(); + assert!(!dormant_found, "repair should leave nothing dormant"); + #[cfg(unix)] + assert!( + crate::hooks::is_executable(&path).unwrap(), + "repair must set the executable bit on a modified hook" + ); + if let Some(orig) = original { + let _ = std::env::set_current_dir(orig); + } + } + + #[test] + fn classify_hook_returns_modified_dormant_for_non_executable_non_builtin() { + let dir = tempfile::TempDir::new().unwrap(); + let path = dir.path().join("pre-push"); + std::fs::write(&path, "#!/bin/sh\ncargo test\n").unwrap(); + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = std::fs::metadata(&path).unwrap().permissions(); + perms.set_mode(0o644); + std::fs::set_permissions(&path, perms).unwrap(); + } + let health = crate::hooks::classify_hook("pre-push", &path).unwrap(); + #[cfg(unix)] + assert_eq!(health, HookHealth::ModifiedDormant); + #[cfg(not(unix))] + assert_eq!(health, HookHealth::Modified); + } + + #[test] + fn classify_hook_returns_modified_for_executable_non_builtin() { + let dir = tempfile::TempDir::new().unwrap(); + let path = dir.path().join("pre-push"); + std::fs::write(&path, "#!/bin/sh\ncargo test\n").unwrap(); + crate::hooks::set_executable(&path).unwrap(); + let health = crate::hooks::classify_hook("pre-push", &path).unwrap(); + assert_eq!(health, HookHealth::Modified); + } }