V_*(A0DKAD4i*6y-1ep8
zY3x(XojJ?$20xRQ**R$nODh32X%33cd%P0KT|fgx*K7|1$6fuokFdB|l9@N&}ox
zKQSA;9t=ZFB*oo7sNV%(cd!x|sdla^Yv%#@p}s=%NoRrwKoYNp?YzeQ8t-cirFpXD
z>^xVc9%c`~2aU5eud4Z=Eb~gk6faNW1NE5)f|Z83-K)BF_WK@e$(?vjZvyNnM$vLJ)$l3eC#mL0KT|0N_zGD^YdW6fh9#{xaMfJ&O+;$ehx;7
zzeUycA^fWTSp9OvxB>Bi+6rs}E(V&rEQ&9qTF$Nb_+_A)7cO~>&_*kQW5B~;RQcME
zdTU->&l)w?RdSY$rg^l>HsD8K3Frq$sxrg1#fRYk>7&WQ^3|HQ(D++@#-Oi_8m9QV
zg!b3~l#ehYVv&3g#=*5<5V)m&P3wIh2U;iiNCeFXDYh4bL8wPs8}+WsD?l|aDL5wa
zxng5Kpm&ARwwLd8PhpFmIo}8tfDeH;fjxoVm(u;;I9MO74YYn%SQqHNUC-a12X+Hm
z8+jZ!9cZ56r{K?E(AK}mC#u6L1yf{Xi^JD?xAbG6pVwRQ^md>)I2ybJi1#yq);T(9
zAL)spHDX#1voX+|^|9bWARE*tEiE~IfPM3vIHgjO=mC7J>+Y3(;DR`K3-~117wEd*
z_h-o1pl3X50>#XS!8PD-pp0`A_hFa%#=iS4kzfNXz^~haUxOm9mExD~l{9Cmdz}qI
z>F=YlQGM6yU;>;3eh4()DZ*!I%6JT0js(^GmZMn2m%7Jz8F&b!X@jh36cc(6LVd)G
z!9c$=g#GfH?#t$a!@w1w46&m7;#0v2jwmv+YVe`1herU7^Rn{3SH1_){aLUBSP=}R
zzp0n*#Wa5TAh-wg@{3Qou0>x1)wn$)+wh&PeKqiJ;JU4(^A>O@7`Zm0&NIP*K=)rh
z{F}DDuA=-o87VTd+3?v4;7pL#&uP=bTtngpMyuihD42l~;U{DgAXby}$*RECe#?|&1d
z<$RiSdbYL)sN$jrXYi5wlfA(&KpNk=Orv&MyN8J*E5yt;QM~-uavQMzw296`P6k5_$BCd
z?MRYq{r0Y)D3hyl5`8AEfLI?A6H=J2KNd$%1LhYUeQ
zXb+7eUkL64E@B}`$Jfz6w9m4roBXJ?xLL>JcaV3}A)wSyR)MzJ0_c6lB!1^Tud&YC
zz_9vnE9$l|qyK(JzV(OFF+)-*@fK_VZUT8@At}GUYxb-maapq()Jf0B_3SRG-rdeC
zHmdcVO>dTahqluDzV(c4-HiuE_P^+!S#B?+w~o5#x}s-2rhYbCjmxUpO7X7K2yHcsc
zDj>_4O>^E`xwE9w)DI8PhU)^YTTjy`*rvGxy#xD>8@B7d>f{W*(OS_L_oF?lGTnQC
zw$!usyE5>gSG;H*^wsVyE=D7^ZwK_8yH`Eqa(&z45KxSfo=Z99@?FN_@LXJJ)zh9^
z0w3>^DDGA-ZN(D|!{+Hg^9*tBr`gwg8w0-{jhI*w>;T>aJ_$Yw=7XKUT43bX#n7%V
z1zJy)h6grj-jB`%CYJLw_P!~DA2gO5=y^MMul`~jd<#4UmbT$v9RC@78@vk4C}#`0
zw@MraS~HjR`EXLqJc!PLd3POK*8sMCsm9}T-M30{8sWNPV-s*YXpf6d$4f|e3wRMI
z&d@%VL>n&;T)ih6kC#*WSgq7WQ+Hh>P6KhoQ8;hhXDo;4#oECgSolNI%eH4!AuXd>p7x=oSk}GUYoJ4D5WR
z&1H-B-Wk}=-NZT5Y5!yBv@xU5w6YDH4?5YNbne%rAGrC4xMSh8?yL3yPk5_vNayw5LutPcgl(F`v$-Z{E_b&i9}dcS_&f*v5~PWN
zUTGGgN3k|2)z54vZLep?S=Zzx#mRA*4f2?gdaCcZ03_Mn>Ac2i9O=kGf!CZrW2RUx!<9ybl(QTCawLq`F^X`DG&U5b$C1vJODcJ
zJkPn$qO<=5_G|$h(0$ga!0_9}_CU{OTdSvj=ULXVl>MMh#o@2|jx#;PhT`f;u%(SX
zgPIoJtPXx-$)9dFzZ
zi9fQ4k3W!hSo)5C78Dy__x%=}ipN9yeqWy-P>1JO*5iYPIoeY}
z@Kk-rIl#reQ(7I5Q{K3zDwRqtd{Q6sZcARZ$Avk506nYrtAdoRcQuSHy|#J=RQmN}
zy?hBzHv>NBtde5piQj6u_Ra^6
zYgJBlaLaaHG%058L094Lpi!pHI^9M;Y;@i7aPvcbj19$y`jAojj(OH^rp04L?-p(E
znhV|ZiR<7mAZ|yu{Zc%u=~ky+GI+TfxDWWehf1USYuGR<&qFqcV>au-lQ?*Mul98*
z$L5y+jeU~riJw=x9bJ~+4_$Eb$P&bc;z#S>3%wrp!`~_s-st(kl__}^=Un^#jp!)s
znnGEpS=g-g#smF3i|}yOk}t-dU47QMEV|*@Y+y4_n#9LK-owMz4S~&C-Mz}<
z>nwJ_!{xz^pciM0mfws`1KlsDX%D!j`>X{ZiT7#GpOmJ&ylJrWH5Rt2Ut2A2nf=TU
z2X_IwUKh>(H08aapS~%oY&fK632Dc>N%3+$I=q`q8E1kd8`{rbQ-n>vDoso*2d*q>
zY$$$y4+i?%7HQfJ4(UDhy!TlDK!?}oAn4cF;}@Vk4w8-sdc76g+Y#t{hiR_m{Yvv;
z>`OzlflUM7bdU9Q3*II1aT}jbz&?E!(Pr%N5})??)D7p|{Ju|)CFzDs8vs2EPwE@eocH>i
z8r$AuVc)H!O{#9G&%-r+3-LP8&cm`E>-(h7FSS#18V8s3os%rTvlNe;t9)`2-Fn|7
zUS7BT1vy>Px9o6jZ=i1(mNgza*>wZung1A6toht1ghl`ef#
zgf3!2?{^#m%Ji(h-~HL#hn?u1XKCBOeU}DqX^pNp
zX2Z#{r9B?|eNdq9I^mz@PxJo%)XqLCf?a!B#E0gt=J>F~r%rfv?10CHVpZ>NZRFEW
z{n8Dmrh~k{8*+dT`?2c?khUNDBWVX}Z4jJV6Z{2~tv|?O&zGsk(9QS4DUE@@Yr(@#
ze0`Uv_^|n{hTEvaz_brs(zxTKA&Cvelim^8&Ib?rtrK3IkuyF{^icmESaeXfKu}9DL
z^}XLt@!08{mp;rzUE(_6j{1&Ic;=|#^4nFO`HRZd?@k%HkFB2L9A(NJhAkY_H>~rl
z!@A71AFyXdVDp=_A9Zbm4}EZFE_lQga;v4Mx9%&*s
zk!h{)#lT$eeQfnzxn~vWUteXxL4A8I&%1;^`j2(7$>uvcth(Yy$oPe8h&)skyU(U*8K4wGQx4AnDrN>%5QghrU_zl!Z-R-$Uuew_b91qThbf
zHPvv($5!j(Uk-Yiqx(GJXyC&Rqf=w`*Yz}}0
zw!xJ?IHJDetDde?BTFI(Vq~_$_GXecI#mUDpd+
z^lqa~d|cq#23Pvv$F{)t?*{&sGJ4)uwbzL}dM2_E_=pXov+H=M-KMe~!$ZZ#??Bpk
zXiw+--UeH2#~+uHr);j(J&gK}3qA8sWBy%%b^VnG90LrOeQb4Y7})P2!z;yyey6XU
z_i2w$ux^+h8L&m)c(j?n(r*%`zPIR6yfZPp*aG+*cjz8p&-^mioxCf8>wu5gFgkyP
zey`txa@J^Vir|&T=YIxiJKI#|KExJ%pUdW%%-y6f)m#aD(6w2=b7?r@WBXn7
zub9{2=-3?ip3id5lf3m#lOJBq1o~aUcHXBwcK-ecwkT#7TG;e3X;(>8-=fmMH?6bs
zx!&n6^gH`~MRXkwe7@(aan7bi`QKGJ@M<-nZy~0QhxT;NzsZIzT7P9bCYtNYCwcY2
z1N9xJ0Uv#abZU)?(|daK>HBnF2fl2U-YY?=`uSdM4G-4?Huw7R_|W_3&VR!ZoqDeS
z6A&+}*ZxGWx)vpe1A4#XA>e~+dd~3{;JiBMTnp$KqYt~KQ~lE$og3~^AspP=l814g
zYK@ey@0VO{Y1iQ%-IQ82?eDwq(0thPsSUDBi0<8hzW?ScM)XechL&daEjb+2ZyM=>uL1vW?@d|q?EHV__3#Y$Tzx2
zd`)Hp3(N=yPq5@+JU-6!Whyq=#;xYyyxn)CsV8mz0w5myh>t>_LsN$>!K0q)BLC<<
z%h~)}n)b0x1D`Ywz7WJYZ?pdn+cMLp$EIB~*yVh#Ag#T$wbqUQ0QiUvz0))+tu3z7
zQKsere9rlP3;m_N&w_uNN41?NipP()IV0>^KSO-t?GVo9_qIYs<`!W{Y%LCi@w)(P8k@lSdehGZU$C>Eu
z+clQ5^_=sMp6VulJqYIc;!z&G@b4KQ-XGZP|AxGo*ZuUe8{NA1yUEhN-;=)ZF$nE@
z5b$vyayNSWx;~upHDA3C@cB-zo*Ne4ZYel;kR|`(@#Fnkjcs4Bv~Mx#3w^JXc3lD7
z0$leUy7$<(R~r@~#}3WQX@0bm+J51eVBvvl9c!KP;epWi3a7_RVnI>Wd477l3*dDeAT`d+&C
z_575f`GW_6iODout&3kTURPiHw58UCyIza&FLdgD-H?m
zn-R|F-s)Ol%QvN81PcExM#?-YqrES*^-r4gwAaoKIdKEJR!&oH8Pj0cs3Vgo!3=d6=iC(9Ln4bJPmAP`fEPyrM>n8?bo_2$M>OUUbCVDxP$$=*Zhbh
zer4r)?craiCwvt3-<
z)(?HuVm?gI3Cy$6LWD}XyP@J#XX2w1%z{#TileN0BXKTbZUX46hv0F9};
zwP!b()}svM_n?v-Nqsg0nuF_B@4Pb2877&K`#e0!^Gt9-ZUb^Cz;@ejx|=@lA@VwX
zXPY+CGqQVfaN!K{4%ByU(li})dOgT<-RKoRTBEg78e44B=o$*L%mW#oIseX;O&xOD
zf0FXM{G**t2EE#|ll)Tht>n^{vgo2-%YiRt^h+mSbvmc(()zCJ3_qR+^iGrEyUq4C
z@~z<7CR=^ja6m@;_58$jAF>|pq`8$&ZJ2cKYSOQ2TkkN~!bkz0zRQrs(Jht^cypRpdFAfIuGlPzs@B+ytQsU73zFDKo=&g0rRjCyK(
z_E1W{#C>G5um0P{ti-hN;#ol7I<)CCOj><=)cUt25{=0rzz)UvX&LLGxvb4|6u(SX
z+DG>jdT*#(j7auXFcPt0oJ4*11zL-2!+D#u(w+O;&k?7-nvqkAk^ltAuupx+4>HzIez+CPH2SKoUk|`t#mIX>`}o1-@$KkOb?;2uYaFX@xTTGW
zc)D*Yzh95#*N%<51KkJ4ZMWIiGm+BQGrySj*3#HXP`9Q4?
z!d~4+UI1+C8c(meuxc#QjZh9{a93lI{ejQ5zIyL>PLkQQ_qZizwEkkdBza91&M5{O^-UGM)l`a6F2nzmjE=-r3-buwvR@2(y=NdAr6
zitTz1n&-Vp`98+2Y^
z{|xX`kaP`5b6(${cscOMib{3d18{dua2qh3cD>d2Uv)1RFE-exowaWF5s<_U-IE*$
zmWi)rlnuZM>hXLajwjVO&3XA`#{sDB(3l8!p9y?EU)OuT%Y09rc2*y+5J0sVke<H!JJ+TjKGdeSI53&r?Twj8{|}!e2c<
zyv1XT`~uy5{f+see3?`ZT-F-K<3XNxMdEQHJ!gVdlFF>kyYm42T^IO##(o|8M|$2D
zF6&*9FMv4D^X}h-KD|fajtrHijvj!&8-w2h*Y{XP-vV?G-8YdtIy2!UJk}bmi$LDE
zi09YZ1g+7j?za;B?&>uB-5fML#>lDY9_g_qJl6B|D?yy&dH406=GmYWzisb|k7d&X
zceN&dJMbVd*L{~;y^r!1P`0WUYL9pf>L71iwCDdVI(GvjeGT&6nDBQ8;OnGkdjfsq*znrr_D=MU{51~#YCNLvRvTWs+-e?JeUyHC#jf$I
z)IB`_e>EO?CD1*Q%h)iwu0gM}-x=vyp^_$myPDVfGH~^Lq&>!T&vhP{2TJON@|iXB
zlKb>*SI@4dX}{AS{8fx-UA(VvGoFs_ksnXe26{g70U$27^V`+2-sSu>*a&oL?&=&K
zkZ-`opa!l3dY3P8eP|RThqLwZ?uh2J-k>r@{f{=#wd&Qt)q1U@xRQST&d-Km)ZN~!
zzkC7oy!9;bIEedCaguni6UE38o?=Ab(<=4%cAHN0yh9tPjr4xiZ$P|#eC$6=8J_{V
zR(h^kdDT;QU6-~8-vCM94_Jt7y>7LD!+O8!D4=V;8AG_*-iywz<#)4f*krWD8sJjk
zYfKW4w|`R3`9K^Qi8T(?Q`e!j!JEO4KrcV*-n8d@5*${Hyc_t4k^e#O%EQL>to5Ni
zRshEUeUmuOXJ7kTW2|q|zX_}ZhH6}>`T&i+<^#>Ex8Fl`^Xtz^pX%BX#faV!^bsQ$
zqPLo}kAjLe(RFSIa2x2>ey(M@_tLoZwO~y!kgDrP+zt!DDCfkVwP4?6<=>A
zZ@3r5$eY=^eugN0hg30QJl)#TZsN`}!6hK?{X-W1bju^YDt5&&arjd3C7@?69|rFS
z?*w{J_^r|Yd)XcjP6QtZdftCIP=BEQO8R`nL3=&)Z0JKE)$gRWTBQ4)I1F9~Tz{kS
zNp!we`m4WXJwQ8Z{JA^01+=$yb)4QOdhYRgumM=s(GJdt!$51-U9XLQ0-djPVB*lK
zpiOlT@a*w_9@B$vs2A2SrG4d$-cF$wiDCHFgz{cPMpx^Vt{frM?BhCk!kM3(+#Q6u8
zR{$pim*2!zjJ!BrPPO0L1Mougtvi6vfd&}%`!C%?=|1yV&~xonZx8xO0hcvye?1Vd
zUG*jUecq9OM>lJW!52MO+ZmhzG!Hv0v7&xLbHbV{*7K5q`R);X*0}v{hcWVdbd6`_
zNR_YoF3?PPq<*CaZUT>ie%=e&mi<@k)mpK`z+5meG11OJ_`D&|I$c-&$j#`gzO&ix
z=nTj3O3xhiy9{fAJ;6u7_2BQoma{(7--kVlhhxC@Ky!8(YFy4N@OfqMRfjQh7P?9^
z<|?PxvsoqH0o{vj0}ckC0N(+(f(OBqKyyMa<6#N<^jzXm@GEd7&@=VdfO#O*I`eEb
zE=Ml-yd3xla4~Mzn%}+4QM1vo0*-24O!sB#YjmH#3wRYc8k_)51zJ<`4e(uXHMj;`
z8{vCwuK*VTJ-0p)ybbINbg#D|P`@y+_ey!00H^h?)!Tud{pG#ix(gjM^4e78_u~P0
zu6}3={FF3YTH&koPy*e}ax`98!^LC_MnTw*b0N
z%6hN$6nQruO6OFSsyu)P;P?9Ah8!`nZ{^6!1HsjKiKx?-;J#*LZNN+Nz^{eczJmA6u#K3g$9B@21ADjc`gV`?h
zS2`*WR34~2P@Eo;V`H<-iI{9*Bx_m|lhq?xvl=m(5jB;z
zWQ&`!=~00#nJKPyrnOgRH~O0lGji0@U}WQMGE+OrXSB&ehlM#KV>k#C#Y{1$nzDMB
zCH#LfNZ*vz;x1ur*(G@+qJ7MQ7GY7&M`VPrBhNFCN?N_h=r$`)k|
zc1^z8*jQBKprR8>Wn^r}b-Z+G;Jk6|MKYb3)G>cG_5;pDGOEy|NrQ8NS&n|9GT4g$j>S@4Ew4z{2rF-7CI%#up*jv_3tJwO46n&Cp{&u2
zD~XnhJTck0&Y3@Xl>PAk`jjdJXD5xU)@;}?Yb~g6n6EaadV#kmOunhr3o1As$(BU2
zB_?~=)Pc?=Q41|LCQ(5g8psw$RbOO?F+~=(Uei5P9%=>o7DaApnAWHAEg4qv*D&@X
z!`VT;g^>+)Bja>SHW}orHJiAmR6)K*E4+dF7MegVzu6QRy#Gb}4x5~WtYP=ibk
z^BI}qt|c1}bjD?Y;IK$`-TLUxR#MO?$~^1v*W>I{6IKYS^cvMa`y7memlo8fj|2
z&a%nCPGvInMw^Pc2!HRL$3Hh>o(z*$ZiJQesPxPfaw2
z3BjL{HR7_UA=+eWzVL!X&W^IEk=kU9AYarFiy~X1@;b{xJ@qi(WMF4AUvF7$Y)roy
zIWZ+)JJZLtFXA10#Zpp>u-#ji$~}#{Yq1v~9ps
z6}?b=#dw{Q)3i0Rp!;h?4NwmqT95J>*(B-7FgAnD6dCCyl1%liW6>C=g09%eBB#}+
z$_)7e-_`JOET18Cpu8pHbUiR3blRj^Gt3v<7Suy71nn5eBp>6DqKr&uCUicOEtRYh
zx+OR>uG~h(P9tzJHLJ-nfhy??6qt)P%8@OWsz4@#ql;+dw8e5xB%4^eD6D$WAk&wM
z)-Bl*d02lqZ5lETgM4y&^KX$(1$Q!$EV}Y5LBJ-_CCt}|d=lgh*c6wU!X!o2M36er
zsf%;#k5l7;mpaI5foviwZ|ZGp9mfP74Dw-iOXboAY-%X90vTqrYyQNTh7t!d%$_ik
z&@q8`JIE+u+Cq6Zkn#U`E1w**NEHrcwRXpxASW7GyJMs#l+~AUOiR`f1)6`gsQ55n
zV@l=gIHr}4>P|MZ1&(RSsM2^#7KKt|3ss7>yei+yhb&eJRlX&|p|REtSb=a#5>q56
zCt9-F6hk?R$?8)KjgH2`VjEKojgBIjsZv-XN3Ax3|8b9UB(tM@s?ubbY3b6ZIBK&Vbz;#TEIri`4{r9cIQCpcG^OcxLRPYLE4qI@zY`U})iBMv1A
zIw>QY2rgEkh(EDZj}k#P|Af9&he
z$h1%CVSlRw{u-e$B&sUNaVQBdavY8a$2GhYlZBQ>tym{dTo$xNm`w#tk?BNOT2P6}
zcs^6Gw&+NdQHhD9d=!=}t96mpyT}?{WDH^wZDIVJC|irn(YvGOR(=r_WxM$
B_Dlc(
literal 0
HcmV?d00001
diff --git a/docs/src/images/format-review.png b/docs/docs/images/format-review.png
similarity index 100%
rename from docs/src/images/format-review.png
rename to docs/docs/images/format-review.png
diff --git a/docs/src/images/format-suggestion.png b/docs/docs/images/format-suggestion.png
similarity index 100%
rename from docs/src/images/format-suggestion.png
rename to docs/docs/images/format-suggestion.png
diff --git a/docs/theme/favicon.png b/docs/docs/images/logo.png
similarity index 100%
rename from docs/theme/favicon.png
rename to docs/docs/images/logo.png
diff --git a/docs/src/images/step-summary.png b/docs/docs/images/step-summary.png
similarity index 100%
rename from docs/src/images/step-summary.png
rename to docs/docs/images/step-summary.png
diff --git a/docs/src/images/tidy-review.png b/docs/docs/images/tidy-review.png
similarity index 100%
rename from docs/src/images/tidy-review.png
rename to docs/docs/images/tidy-review.png
diff --git a/docs/src/index.md b/docs/docs/index.md
similarity index 59%
rename from docs/src/index.md
rename to docs/docs/index.md
index 9a774e8..627e8a7 100644
--- a/docs/src/index.md
+++ b/docs/docs/index.md
@@ -1,10 +1,10 @@
-[file-annotations]: cli.md#-a---file-annotations
-[thread-comments]: cli.md#-g---thread-comments
-[step-summary]: cli.md#-w---step-summary
-[tidy-review]: cli.md#-d---tidy-review
-[format-review]: cli.md#-m---format-review
+[file-annotations]: cli.md#-a-file-annotations
+[thread-comments]: cli.md#-g-thread-comments
+[step-summary]: cli.md#-w-step-summary
+[tidy-review]: cli.md#-d-tidy-review
+[format-review]: cli.md#-m-format-review
[format-annotations-preview]: images/annotations-clang-format.png
[tidy-annotations-preview]: images/annotations-clang-tidy.png
@@ -14,4 +14,9 @@
[format-review-preview]: images/format-review.png
[format-suggestion-preview]: images/format-suggestion.png
-{{#include ../../README.md:16:}}
+[cli-doc]: cli.md
+
+{%
+ include "../../README.md"
+ start=""
+%}
diff --git a/docs/docs/node.md b/docs/docs/node.md
new file mode 100644
index 0000000..19b522d
--- /dev/null
+++ b/docs/docs/node.md
@@ -0,0 +1,6 @@
+# Node.js Binding
+
+{%
+ include "../../node-binding/README.md"
+ start=""
+%}
diff --git a/docs/src/permissions.md b/docs/docs/permissions.md
similarity index 81%
rename from docs/src/permissions.md
rename to docs/docs/permissions.md
index 2fab227..299a5cb 100644
--- a/docs/src/permissions.md
+++ b/docs/docs/permissions.md
@@ -4,7 +4,7 @@
This is an exhaustive list of required permissions organized by features.
-> [!important]
+> [!IMPORTANT]
> The `GITHUB_TOKEN` environment variable should be supplied when running on a private repository.
> Otherwise the runner does not not have the privileges needed for the features mentioned here.
>
@@ -15,8 +15,8 @@ This is an exhaustive list of required permissions organized by features.
## File Changes
-When using [`--files-changed-only`](cli.md#-f---files-changed-only) or
-[`--lines-changed-only`](cli.md#-l---lines-changed-only) to get the list
+When using [`--files-changed-only`](cli.md#-f-files-changed-only) or
+[`--lines-changed-only`](cli.md#-l-lines-changed-only) to get the list
of file changes for a CI event, the following permissions are needed:
### Push
@@ -51,7 +51,7 @@ the repository is not checked out before running cpp-linter.
## Thread Comments
-The [`--thread-comments`](cli.md#-g---thread-comments) feature requires the following permissions:
+The [`--thread-comments`](cli.md#-g-thread-comments) feature requires the following permissions:
### Push
@@ -78,7 +78,7 @@ For [`pull_request` events][pr-events].
## Pull Request Reviews
-The [`tidy-review`](cli.md#-d---tidy-review), [`format-review`](cli.md#-m---format-review), and [`passive-reviews`](cli.md#-r---passive-reviews) features require the following permissions:
+The [`tidy-review`](cli.md#-d-tidy-review), [`format-review`](cli.md#-m-format-review), and [`passive-reviews`](cli.md#-r-passive-reviews) features require the following permissions:
```yaml
permissions:
diff --git a/docs/src/pr-review-caveats.md b/docs/docs/pr-review-caveats.md
similarity index 95%
rename from docs/src/pr-review-caveats.md
rename to docs/docs/pr-review-caveats.md
index 26d0f98..955bf33 100644
--- a/docs/src/pr-review-caveats.md
+++ b/docs/docs/pr-review-caveats.md
@@ -5,12 +5,12 @@
[hiding a comment]: https://docs.github.com/en/communities/moderating-comments-and-conversations/managing-disruptive-comments#hiding-a-comment
[resolve a conversation]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/commenting-on-a-pull-request#resolving-conversations
-[tidy-review]: cli.md#-d---tidy-review
-[format-review]: cli.md#-m---format-review
-[lines-changed-only]: cli.md#-l---lines-changed-only
-[style]: cli.md#-s---style
+[tidy-review]: cli.md#-d-tidy-review
+[format-review]: cli.md#-m-format-review
+[lines-changed-only]: cli.md#-l-lines-changed-only
+[style]: cli.md#-s-style
-> [!note]
+> [!NOTE]
> This information is specific to GitHub Pull Requests (often abbreviated as "PR").
While the Pull Request review feature has been diligently tested, there are still some caveats to
@@ -23,7 +23,7 @@ By default, the bot cannot approve Pull Request changes, only request more chang
This will show as a warning in the workflow logs if the given token (set to the
environment variable `GITHUB_TOKEN`) isn't configured with the proper permissions.
-> [!important]
+> [!IMPORTANT]
> Refer to the GitHub documentation for [repository settings][] or [organization settings][]
> about adjusting the required permissions for GitHub Actions's `secrets.GITHUB_TOKEN`.
>
@@ -50,7 +50,7 @@ Clang-tidy and clang-format suggestions are shown in 1 Pull Request review.
Also, the outdated review's summary comment is not automatically hidden.
To reduce the Pull Request's thread noise, users interaction is required.
-> [!important]
+> [!IMPORTANT]
> Refer to GitHub's documentation about [hiding a comment][].
> Hiding a Pull Request review's summary comment will not resolve the suggestions in the diff.
> Please also refer to [resolve a conversation][] to collapse outdated or duplicate suggestions
@@ -58,7 +58,7 @@ Clang-tidy and clang-format suggestions are shown in 1 Pull Request review.
GitHub REST API does not provide a way to hide comments or mark review suggestions as resolved.
-> [!tip]
+> [!TIP]
> We do support an environment variable named `CPP_LINTER_PR_REVIEW_SUMMARY_ONLY`.
> If the variable is set to `true`, then the review only contains a summary comment
> with no suggestions posted in the diff.
diff --git a/docs/docs/python.md b/docs/docs/python.md
new file mode 100644
index 0000000..87b2a73
--- /dev/null
+++ b/docs/docs/python.md
@@ -0,0 +1,6 @@
+# Python Binding
+
+{%
+ include "../../py-binding/README.md"
+ start=""
+%}
diff --git a/docs/docs/stylesheets/extra.css b/docs/docs/stylesheets/extra.css
new file mode 100644
index 0000000..abd602f
--- /dev/null
+++ b/docs/docs/stylesheets/extra.css
@@ -0,0 +1,241 @@
+th {
+ background-color: var(--md-default-fg-color--lightest);
+}
+
+.md-header {
+ background-color: #4051b5;
+}
+
+.md-typeset .admonition.important, .md-typeset details.important {
+ border-color: #00b8d4;
+}
+
+.md-typeset .important > .admonition-title::before, .md-typeset .important > summary::before {
+ background-color: #00b8d4;
+ -webkit-mask-image: var(--md-admonition-icon--info);
+ mask-image: var(--md-admonition-icon--info);
+}
+
+.md-typeset .important > .admonition-title, .md-typeset .important > summary {
+ background-color: #00b8d41a;
+}
+
+@keyframes heart {
+
+ 0%,
+ 40%,
+ 80%,
+ to {
+ transform: scale(1)
+ }
+
+ 20%,
+ 60% {
+ transform: scale(1.15)
+ }
+}
+
+.md-typeset .mdx-heart {
+ animation: heart 1s infinite
+}
+
+.md-typeset .mdx-badge {
+ font-size: .85em
+}
+
+.md-typeset .mdx-badge--heart {
+ color: #ff4281;
+}
+
+.md-typeset .mdx-badge--heart.twemoji {
+ animation: heart 1s infinite
+}
+
+.md-typeset .mdx-badge--right {
+ float: right;
+ margin-left: .35em
+}
+
+[dir=ltr] .md-typeset .mdx-badge__icon {
+ border-top-left-radius: .1rem
+}
+
+[dir=rtl] .md-typeset .mdx-badge__icon {
+ border-top-right-radius: .1rem
+}
+
+[dir=ltr] .md-typeset .mdx-badge__icon {
+ border-bottom-left-radius: .1rem
+}
+
+[dir=rtl] .md-typeset .mdx-badge__icon {
+ border-bottom-right-radius: .1rem
+}
+
+.md-typeset .mdx-badge__icon {
+ background: var(--md-accent-fg-color--transparent);
+ padding: .2rem
+}
+
+.md-typeset .mdx-badge__icon:last-child {
+ border-radius: .1rem
+}
+
+[dir=ltr] .md-typeset .mdx-badge__text {
+ border-top-right-radius: .1rem
+}
+
+[dir=rtl] .md-typeset .mdx-badge__text {
+ border-top-left-radius: .1rem
+}
+
+[dir=ltr] .md-typeset .mdx-badge__text {
+ border-bottom-right-radius: .1rem
+}
+
+[dir=rtl] .md-typeset .mdx-badge__text {
+ border-bottom-left-radius: .1rem
+}
+
+.md-typeset .mdx-badge__text {
+ box-shadow: 0 0 0 1px inset var(--md-accent-fg-color--transparent);
+ padding: .2rem .3rem
+}
+
+.md-typeset .mdx-social {
+ height: min(27rem, 80vw);
+ position: relative
+}
+
+.md-typeset .mdx-social:hover .mdx-social__image {
+ background-color: #e4e4e40d
+}
+
+.md-typeset .mdx-social__layer {
+ margin-top: 4rem;
+ position: absolute;
+ transform-style: preserve-3d;
+ transition: .25s cubic-bezier(.7, 0, .3, 1)
+}
+
+.md-typeset .mdx-social__layer:hover .mdx-social__label {
+ opacity: 1
+}
+
+.md-typeset .mdx-social__layer:hover .mdx-social__image {
+ background-color: #7f7f7ffc
+}
+
+.md-typeset .mdx-social__layer:hover~.mdx-social__layer {
+ opacity: 0
+}
+
+.md-typeset .mdx-social__image {
+ box-shadow: -.25rem .25rem .5rem #0000000d;
+ transform: rotate(-40deg) skew(15deg, 15deg) scale(.7);
+ transition: all .25s
+}
+
+.md-typeset .mdx-social__image img {
+ display: block
+}
+
+.md-typeset .mdx-social__label {
+ background-color: var(--md-default-fg-color--light);
+ color: var(--md-default-bg-color);
+ display: block;
+ opacity: 0;
+ padding: .2rem .4rem;
+ position: absolute;
+ transition: all .25s
+}
+
+.md-typeset .mdx-social:hover .mdx-social__layer:nth-child(6) {
+ transform: translateY(-30px)
+}
+
+.md-typeset .mdx-social:hover .mdx-social__layer:nth-child(5) {
+ transform: translateY(-20px)
+}
+
+.md-typeset .mdx-social:hover .mdx-social__layer:nth-child(4) {
+ transform: translateY(-10px)
+}
+
+.md-typeset .mdx-social:hover .mdx-social__layer:nth-child(3) {
+ transform: translateY(0)
+}
+
+.md-typeset .mdx-social:hover .mdx-social__layer:nth-child(2) {
+ transform: translateY(10px)
+}
+
+.md-typeset .mdx-social:hover .mdx-social__layer:first-child {
+ transform: translateY(20px)
+}
+
+.md-typeset .mdx-social:hover .mdx-social__layer:nth-child(0) {
+ transform: translateY(30px)
+}
+
+.md-banner {
+ color: var(--md-footer-fg-color--lighter)
+}
+
+.md-banner strong {
+ white-space: nowrap
+}
+
+.md-banner a,
+.md-banner strong {
+ color: var(--md-footer-fg-color)
+}
+
+.md-banner a:focus,
+.md-banner a:hover {
+ color: currentcolor
+}
+
+.md-banner a:focus .twemoji,
+.md-banner a:hover .twemoji {
+ background-color: var(--md-footer-fg-color);
+ box-shadow: none
+}
+
+.md-banner .twemoji {
+ border-radius: 100%;
+ box-shadow: inset 0 0 0 .05rem currentcolor;
+ display: inline-block;
+ height: 1.2rem;
+ padding: .25rem;
+ transition: all .25s;
+ vertical-align: bottom;
+ width: 1.2rem
+}
+
+.md-banner .twemoji svg {
+ display: block;
+ max-height: none
+}
+
+/* annotation buttons' pulse animation */
+a.md-annotation__index {
+ border-radius: 2.2ch;
+}
+
+@keyframes pulse {
+ 0% {
+ box-shadow: 0 0 0 0 var(--md-accent-fg-color);
+ transform: scale(.95)
+ }
+
+ 75% {
+ box-shadow: 0 0 0 .625em transparent;
+ transform: scale(1)
+ }
+
+ to {
+ box-shadow: 0 0 0 0 transparent;
+ transform: scale(.95)
+ }
+}
diff --git a/docs/gen_cli_doc.py b/docs/gen_cli_doc.py
new file mode 100644
index 0000000..3378cf5
--- /dev/null
+++ b/docs/gen_cli_doc.py
@@ -0,0 +1,36 @@
+from pathlib import Path
+from typing import Dict, Any
+import yaml
+import mkdocs_gen_files
+from cli_gen import generate_cli_doc
+
+FILENAME = "cli.md"
+
+VERSION_DISCLAIMER = """
+!!! quote "v1.x vs v2.x"
+
+ - v1.x was written in pure python
+ - v2.x was written in rust (with python and node.js bindings)
+
+ Version 2.x is intended to be backwards compatible, but a complete
+ rewrite in rust prompted a major version bump.
+
+ The minimum versions (badges) specified here hyperlink to different repositories.
+ Anything established in v2.x will correspond to the rust project.
+ Anything established in v1.4.6 or later (before v2.0.0) will correspond to the pure
+ python project. Anything established before v1.4.6 will correspond to pure python
+ sources in the cpp-linter-action project.
+
+"""
+
+with mkdocs_gen_files.open(FILENAME, "w") as io_doc:
+ options_versions = Path(__file__).parent / "cli.yml"
+ versions: Dict[str, Any] = yaml.safe_load(options_versions.read_bytes())
+
+ print("# Command Line Interface\n", file=io_doc)
+ print(VERSION_DISCLAIMER, file=io_doc)
+ doc = generate_cli_doc(versions["inputs"])
+ # print(doc)
+ print(doc, file=io_doc)
+
+mkdocs_gen_files.set_edit_path(FILENAME, "gen_cli_doc.py")
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
new file mode 100644
index 0000000..a968d56
--- /dev/null
+++ b/docs/mkdocs.yml
@@ -0,0 +1,104 @@
+site_name: Cpp-Linter
+site_description: "Documentation for the cpp-linter package."
+site_url: "https://cpp-linter.github.io/cpp-linter-rs"
+repo_url: "https://github.com/cpp-linter/cpp-linter-rs"
+repo_name: "cpp-linter/cpp-linter-rs"
+edit_uri: "edit/main/docs/docs/"
+nav:
+ - index.md
+ - cli.md
+ - pr-review-caveats.md
+ - permissions.md
+ - python.md
+ - node.md
+ - changelog.md
+
+theme:
+ name: material
+ features:
+ - navigation.top
+ - content.tabs.link
+ - content.tooltips
+ - content.code.annotate
+ - content.code.copy
+ - content.action.view
+ - content.action.edit
+ - navigation.footer
+ - search.suggest
+ - search.share
+ - navigation.tracking
+ - toc.follow
+ logo: images/logo.png
+ favicon: images/favicon.ico
+ icon:
+ repo: fontawesome/brands/github
+ palette:
+ # Palette toggle for automatic mode
+ - media: "(prefers-color-scheme)"
+ primary: blue
+ accent: cyan
+ toggle:
+ icon: material/brightness-auto
+ name: Switch to light mode
+
+ # Palette toggle for light mode
+ - media: "(prefers-color-scheme: light)"
+ scheme: default
+ primary: blue
+ accent: cyan
+ toggle:
+ icon: material/lightbulb-outline
+ name: Switch to dark mode
+
+ # Palette toggle for dark mode
+ - media: "(prefers-color-scheme: dark)"
+ scheme: slate
+ primary: blue
+ accent: cyan
+ toggle:
+ icon: material/lightbulb
+ name: Switch to system preference
+extra:
+ social:
+ - icon: fontawesome/brands/github
+ link: https://github.com/cpp-linter/cpp-linter
+ - icon: fontawesome/brands/python
+ link: https://pypi.org/project/cpp-linter/
+ - icon: fontawesome/brands/npm
+ link: https://www.npmjs.com/package/@cpp-linter/cpp-linter
+ - icon: simple/rust
+ link: https://crates.io/crates/cpp-linter
+
+extra_css:
+ - stylesheets/extra.css
+
+plugins:
+ - search
+ - include-markdown
+ - gen-files:
+ scripts:
+ - gen_cli_doc.py
+
+markdown_extensions:
+ - pymdownx.superfences
+ - pymdownx.tabbed:
+ alternate_style: true
+ - pymdownx.emoji:
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
+ - toc:
+ permalink: true
+ - pymdownx.highlight:
+ linenums_style: pymdownx-inline
+ - pymdownx.inlinehilite
+ - pymdownx.snippets:
+ check_paths: true
+ - pymdownx.tasklist:
+ custom_checkbox: true
+ - attr_list
+ - admonition
+ - markdown_gfm_admonition
+
+# Hooks
+hooks:
+ - badge_hook.py
diff --git a/docs/pyproject.toml b/docs/pyproject.toml
new file mode 100644
index 0000000..d2a7da3
--- /dev/null
+++ b/docs/pyproject.toml
@@ -0,0 +1,17 @@
+[build-system]
+requires = ["maturin>=1.4,<2.0"]
+build-backend = "maturin"
+
+[project]
+name = "cli-gen"
+description = "Generate cpp-linter CLI doc from rust src."
+version = "0.0.0"
+readme = "README.md"
+license = {text = "MIT License"}
+requires-python = ">=3.7"
+authors = [
+ { name = "Brendan Doherty", email = "2bndy5@gmail.com" },
+]
+
+[tool.maturin]
+features = ["pyo3/extension-module"]
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..9024916
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,6 @@
+markdown-gfm-admonition==0.1.1
+mkdocs==1.6.1
+mkdocs-gen-files==0.5.0
+mkdocs-include-markdown-plugin==6.2.2
+mkdocs-material==9.5.39
+pyyaml==6.0.2
diff --git a/docs/src/CHANGELOG.md b/docs/src/CHANGELOG.md
deleted file mode 100644
index ce53563..0000000
--- a/docs/src/CHANGELOG.md
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-{{#include ../../CHANGELOG.md}}
diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md
deleted file mode 100644
index c240a27..0000000
--- a/docs/src/SUMMARY.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Summary
-
-
-
-- [Introduction](./index.md)
-- [Command Line Interface](./cli.md)
-- [Token Permissions](./permissions.md)
-- [Pull Request Review Caveats](./pr-review-caveats.md)
-- [Python Binding](./python.md)
-- [Node.js Binding](./node.md)
-- [Change Log](./CHANGELOG.md)
diff --git a/docs/src/lib.rs b/docs/src/lib.rs
new file mode 100644
index 0000000..20e0cce
--- /dev/null
+++ b/docs/src/lib.rs
@@ -0,0 +1,125 @@
+//! This exposes a function in Python, so an mkdocs plugin can use it to generate the CLI document.
+//! For actual library/binary source code look in cpp-linter folder.
+use std::collections::HashMap;
+
+use cpp_linter::cli;
+use pyo3::{exceptions::PyValueError, prelude::*};
+
+const GROUPS_ORDER: [&str; 5] = [
+ "General options",
+ "Source options",
+ "Clang-format options",
+ "Clang-tidy options",
+ "Feedback options",
+];
+
+#[pyfunction]
+fn generate_cli_doc(metadata: HashMap>>) -> PyResult {
+ let mut out = String::new();
+ let mut command = cli::get_arg_parser();
+ out.push_str(
+ format!(
+ "```text title=\"Usage\"\n{}\n```\n",
+ command
+ .render_usage()
+ .to_string()
+ .trim_start_matches("Usage: ")
+ )
+ .as_str(),
+ );
+
+ out.push_str("\n## Commands\n");
+ for cmd in command.get_subcommands() {
+ out.push_str(format!("\n### `{}`\n\n", cmd.get_name()).as_str());
+ out.push_str(
+ format!(
+ "{}\n",
+ &cmd.get_about()
+ .ok_or(PyValueError::new_err(format!(
+ "{} command has no help message",
+ cmd.get_name()
+ )))?
+ .to_string()
+ .trim()
+ )
+ .as_str(),
+ );
+ }
+
+ out.push_str("## Arguments\n");
+ for arg in command.get_positionals() {
+ out.push_str(format!("\n### `{}`\n\n", arg.get_id().as_str()).as_str());
+ if let Some(help) = arg.get_help() {
+ out.push_str(format!("{}\n", help.to_string().trim()).as_str());
+ }
+ }
+
+ // reorganize groups according to GROUPS_ORDER
+ let mut ordered = Vec::with_capacity(command.get_groups().count());
+ for group in GROUPS_ORDER {
+ let group_obj = command
+ .get_groups()
+ .find(|arg_group| arg_group.get_id().as_str() == group)
+ .ok_or(PyValueError::new_err(format!(
+ "{} not found in command's groups",
+ group
+ )))?;
+ ordered.push(group_obj.to_owned());
+ }
+
+ for group in ordered {
+ out.push_str(format!("\n## {}\n", group.get_id()).as_str());
+ for arg_id in group.get_args() {
+ let arg = command
+ .get_arguments()
+ .find(|a| *a.get_id() == *arg_id)
+ .ok_or(PyValueError::new_err(format!(
+ "arg {} in group {} not found in command",
+ arg_id.as_str(),
+ group.get_id().as_str()
+ )))?;
+ let long_name = arg.get_long().ok_or(PyValueError::new_err(format!(
+ "Failed to get long name of argument with id {}",
+ arg_id.as_str()
+ )))?;
+ out.push_str(
+ format!(
+ "\n### `-{}, --{}`\n\n",
+ arg.get_short().ok_or(PyValueError::new_err(format!(
+ "Failed to get short name for argument with id {}",
+ arg_id.as_str()
+ )))?,
+ long_name
+ )
+ .as_str(),
+ );
+ if let Some(map) = metadata.get(long_name) {
+ if let Some(val) = map.get("minimum-version") {
+ out.push_str(format!("\n", val).as_str());
+ }
+ if let Some(val) = map.get("required-permission") {
+ out.push_str(format!("\n", val).as_str());
+ }
+ if map.contains_key("experimental") {
+ out.push_str("\n");
+ }
+ }
+ let default = arg.get_default_values();
+ if let Some(default_value) = default.first() {
+ out.push_str(format!("\n\n", default_value).as_str());
+ } else {
+ out.push('\n');
+ }
+ if let Some(help) = &arg.get_help() {
+ out.push_str(format!("{}\n", help.to_string().trim()).as_str());
+ }
+ }
+ }
+ Ok(out)
+}
+
+#[pymodule]
+pub fn cli_gen(m: &Bound<'_, PyModule>) -> PyResult<()> {
+ m.add_function(wrap_pyfunction!(generate_cli_doc, m)?)?;
+ Ok(())
+}
diff --git a/docs/src/main.rs b/docs/src/main.rs
deleted file mode 100644
index fcd99af..0000000
--- a/docs/src/main.rs
+++ /dev/null
@@ -1,203 +0,0 @@
-//! This is a preprocessor for mdbook that generates the CLI document.
-//! For actual library/binary source code look in cpp-linter folder.
-
-extern crate clap;
-use clap::{Arg, ArgMatches, Command};
-extern crate mdbook;
-use mdbook::errors::Error;
-use mdbook::preprocess::{CmdPreprocessor, Preprocessor};
-extern crate semver;
-extern crate serde_json;
-use semver::{Version, VersionReq};
-use std::io;
-use std::process;
-
-extern crate cpp_linter;
-
-use cli_gen_lib::CliGen;
-
-pub fn make_app() -> Command {
- Command::new("cli-gen")
- .about("A mdbook preprocessor which generates a doc of CLI options")
- .subcommand(
- Command::new("supports")
- .arg(Arg::new("renderer").required(true))
- .about("Check whether a renderer is supported by this preprocessor"),
- )
-}
-
-fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> {
- let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?;
-
- let book_version = Version::parse(&ctx.mdbook_version)?;
- let version_req = VersionReq::parse(mdbook::MDBOOK_VERSION)?;
-
- if !version_req.matches(&book_version) {
- eprintln!(
- "Warning: The {} plugin was built against version {} of mdbook, \
- but we're being called from version {}",
- pre.name(),
- mdbook::MDBOOK_VERSION,
- ctx.mdbook_version
- );
- }
-
- let processed_book = pre.run(&ctx, book)?;
- serde_json::to_writer(io::stdout(), &processed_book)?;
-
- Ok(())
-}
-
-fn handle_supports(pre: &dyn Preprocessor, sub_args: &ArgMatches) -> ! {
- let renderer = sub_args
- .get_one::("renderer")
- .expect("Required argument");
- let supported = pre.supports_renderer(renderer);
-
- // Signal whether the renderer is supported by exiting with 1 or 0.
- if supported {
- process::exit(0);
- } else {
- process::exit(1);
- }
-}
-
-fn main() {
- let matches = make_app().get_matches();
-
- // Users will want to construct their own preprocessor here
- let preprocessor = CliGen {};
-
- if let Some(sub_args) = matches.subcommand_matches("supports") {
- handle_supports(&preprocessor, sub_args);
- } else if let Err(e) = handle_preprocessing(&preprocessor) {
- eprintln!("{}", e);
- process::exit(1);
- }
-}
-
-mod cli_gen_lib {
- use std::path::PathBuf;
-
- use mdbook::book::Book;
- use mdbook::preprocess::{Preprocessor, PreprocessorContext};
-
- use cpp_linter::cli;
-
- pub struct CliGen;
-
- impl CliGen {
- fn generate_cli(groups_order: &Option>) -> String {
- let mut out = String::new();
- let command = cli::get_arg_parser();
- out.push_str(format!("\n{}\n\n", "# Command Line Interface").as_str());
- out.push_str("\n");
- out.push_str("\n## Commands\n");
- for cmd in command.get_subcommands() {
- out.push_str(format!("\n### `{}`\n\n", cmd.get_name()).as_str());
- out.push_str(
- format!("{}\n", &cmd.get_about().unwrap().to_string().trim()).as_str(),
- );
- }
- out.push_str("## Arguments\n");
- for arg in command.get_positionals() {
- out.push_str(format!("\n### `{}`\n\n", arg.get_id().as_str()).as_str());
- if let Some(help) = arg.get_help() {
- out.push_str(format!("{}\n", help.to_string().trim()).as_str());
- }
- }
- let arg_groups = if let Some(groups) = groups_order {
- eprintln!("ordering groups into {:?}", groups);
- let mut ordered = Vec::with_capacity(command.get_groups().count());
- for group in groups {
- let mut group_obj = None;
- for arg_group in command.get_groups() {
- if arg_group.get_id().as_str() == group.as_str() {
- group_obj = Some(arg_group.clone());
- }
- }
- ordered.push(
- group_obj
- .unwrap_or_else(|| panic!("{} not found in command's groups", group)),
- );
- }
- ordered
- } else {
- command.get_groups().map(|g| g.to_owned()).collect()
- };
- for group in arg_groups {
- out.push_str(format!("\n## {}\n", group.get_id()).as_str());
- for arg_id in group.get_args() {
- let mut arg_match = command.get_arguments().filter(|a| *a.get_id() == *arg_id);
- let arg = arg_match.next().unwrap_or_else(|| {
- panic!(
- "arg {} expected in group {}",
- arg_id.as_str(),
- group.get_id().as_str()
- )
- });
- out.push_str(
- format!(
- "\n### `-{}, --{}`\n\n",
- &arg.get_short().unwrap(),
- &arg.get_long().unwrap()
- )
- .as_str(),
- );
- let default = arg.get_default_values();
- if !default.is_empty() {
- out.push_str("Default");
- assert_eq!(default.len(), 1);
- out.push_str(
- format!("{:?}
\n\n", default.first().unwrap())
- .as_str(),
- );
- }
- if let Some(help) = &arg.get_help() {
- out.push_str(format!("{}\n", help.to_string().trim()).as_str());
- }
- }
- }
- out
- }
- }
-
- impl Preprocessor for CliGen {
- fn name(&self) -> &str {
- "cli-gen"
- }
-
- fn run(&self, ctx: &PreprocessorContext, book: Book) -> mdbook::errors::Result {
- let mut altered = book.clone();
- let groups_order = match ctx
- .config
- .get_preprocessor("cli-gen")
- .unwrap()
- .get("groups-order")
- {
- Some(val) => val.clone().as_array_mut().map(|v| {
- v.iter_mut()
- .map(|o| o.to_string().trim_matches('"').to_string())
- .collect()
- }),
- None => None,
- };
- altered.for_each_mut(|item| {
- if let mdbook::BookItem::Chapter(chap) = item {
- if chap
- .path
- .clone()
- .is_some_and(|p| p == PathBuf::from("cli.md"))
- {
- chap.content = CliGen::generate_cli(&groups_order);
- }
- }
- });
- Ok(altered)
- }
-
- fn supports_renderer(&self, renderer: &str) -> bool {
- matches!(renderer, "html" | "markdown")
- }
- }
-}
diff --git a/docs/src/node.md b/docs/src/node.md
deleted file mode 100644
index 2423e30..0000000
--- a/docs/src/node.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Node.js Binding
-
-{{#include ../../node-binding/README.md:2:}}
diff --git a/docs/src/python.md b/docs/src/python.md
deleted file mode 100644
index 870ca3e..0000000
--- a/docs/src/python.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Python Binding
-
-{{#include ../../py-binding/README.md:2:}}
diff --git a/docs/theme/pagetoc.css b/docs/theme/pagetoc.css
deleted file mode 100644
index eff428b..0000000
--- a/docs/theme/pagetoc.css
+++ /dev/null
@@ -1,63 +0,0 @@
-@media only screen {
- main {
- position: relative;
- }
-
- .sidetoc {
- margin-left: auto;
- margin-right: auto;
- }
-
- .pagetoc {
- width: auto;
- word-wrap: normal;
- }
-
- .pagetoc a {
- color: var(--sidebar-fg) !important;
- display: block;
- padding-left: 10px;
- text-align: left;
- text-decoration: none;
- margin-block-start: 0.6em;
- }
-
- .pagetoc a:hover,
- .pagetoc a.active {
- color: var(--sidebar-active) !important;
- }
-
- .pagetoc .active {
- color: var(--sidebar-active);
- }
-
- .pagetoc .pagetoc-H2 {
- padding-left: 20px;
- }
-
- .pagetoc .pagetoc-H3 {
- padding-left: 40px;
- }
-
- .pagetoc .pagetoc-H4 {
- padding-left: 60px;
- }
-
- .pagetoc .pagetoc-H5 {
- display: none;
- }
-
- .pagetoc .pagetoc-H6 {
- display: none;
- }
-
- ol.chapter a {
- color: var(--sidebar-fg);
- text-decoration: none;
- }
-
- ol.chapter a.active {
- color: var(--sidebar-active);
- text-decoration: none;
- }
-}
diff --git a/docs/theme/pagetoc.js b/docs/theme/pagetoc.js
deleted file mode 100644
index a9d7a91..0000000
--- a/docs/theme/pagetoc.js
+++ /dev/null
@@ -1,99 +0,0 @@
-let scrollTimeout;
-
-const listenActive = () => {
- const elems = document.querySelector(".pagetoc").children;
- [...elems].forEach((el) => {
- el.addEventListener("click", () => {
- clearTimeout(scrollTimeout);
- [...elems].forEach((el) => el.classList.remove("active"));
- el.classList.add("active");
- // Prevent scroll updates for a short period
- // eslint-disable-next-line no-async-operation
- scrollTimeout = setTimeout(() => {
- scrollTimeout = null;
- }, 100); // Adjust timing as needed
- });
- });
-};
-
-const getPagetoc = () => {
- return document.querySelector(".pagetoc") || autoCreatePagetoc();
-};
-
-const autoCreatePagetoc = () => {
- const chapter = document.querySelector(
- "body nav#sidebar.sidebar li.chapter-item.expanded a.active"
- );
- const content = Object.assign(document.createElement("div"), {
- className: "content-wrap",
- });
- content.appendChild(chapter.cloneNode(true));
- const divAddedToc = Object.assign(document.createElement("div"), {
- className: "sidetoc",
- });
- const navAddedToc = Object.assign(document.createElement("nav"), {
- className: "pagetoc",
- });
- divAddedToc.appendChild(navAddedToc);
- content.appendChild(divAddedToc);
- chapter.replaceWith(content);
- return document.querySelector(".pagetoc");
-};
-
-const updateFunction = () => {
- if (scrollTimeout) return; // Skip updates if within the cooldown period from a click
- const headers = [...document.getElementsByClassName("header")];
- const scrolledY = window.scrollY;
-
- // Find the last header that is above the current scroll position
- let headerOffsets = headers.filter((el) => scrolledY >= el.offsetTop);
- const lastHeader = headerOffsets.reverse().shift();
-
- const pagetocLinks = [...document.querySelector(".pagetoc").children];
- pagetocLinks.forEach((link) => link.classList.remove("active"));
-
- if (lastHeader) {
- const activeLink = pagetocLinks.find(
- (link) => lastHeader.href === link.href
- );
- if (activeLink) activeLink.classList.add("active");
- }
-};
-function getHeaderText(header) {
- let text = header.textContent;
- if (text === "") {
- let sibling = header.nextSibling;
- let maxIterations = 100;
- while (sibling != null && maxIterations > 0) {
- text += sibling.textContent;
- sibling = sibling.nextSibling;
- maxIterations--;
- }
- if (maxIterations === 0) {
- console.warn(
- "Possible circular reference in DOM when extracting header text"
- );
- }
- }
- return text;
-}
-
-const onLoad = () => {
- const pagetoc = getPagetoc();
- var headers = [...document.getElementsByClassName("header")];
- headers.shift();
- headers.forEach((header) => {
- const text = getHeaderText(header);
- const link = Object.assign(document.createElement("a"), {
- textContent: text,
- href: header.href,
- className: `pagetoc-${header.parentElement.tagName}`,
- });
- pagetoc.appendChild(link);
- });
- updateFunction();
- listenActive();
- window.addEventListener("scroll", updateFunction);
-};
-
-window.addEventListener("load", onLoad);
diff --git a/justfile b/justfile
index 000d796..1601b35 100644
--- a/justfile
+++ b/justfile
@@ -34,12 +34,12 @@ lcov:
# serve docs
[group("docs")]
docs open='':
- mdbook serve docs {{ open }}
+ mkdocs serve --config-file docs/mkdocs.yml {{ open }}
# build docs
[group("docs")]
-docs-build open='':
- mdbook build docs {{ open }}
+docs-build:
+ mkdocs build --config-file docs/mkdocs.yml
# rust docs
[group("docs")]
diff --git a/node-binding/README.md b/node-binding/README.md
index a71f6bd..2452c35 100644
--- a/node-binding/README.md
+++ b/node-binding/README.md
@@ -1,5 +1,5 @@
# cpp-linter
-
+
The node.js binding for the [cpp-linter-rs][this] rust project
(built using [napi-rs](https://napi.rs) and [yarn](https://yarnpkg.com)).
diff --git a/py-binding/README.md b/py-binding/README.md
index 2eacd73..45fcb59 100644
--- a/py-binding/README.md
+++ b/py-binding/README.md
@@ -1,5 +1,5 @@
# cpp-linter
-
+
The python binding for the [cpp-linter-rs][this] rust project
(built using [pyo3](https://pyo3.rs) and [maturin]).
From 0857121826e2ae8ebdd896ba6033eb495b614613 Mon Sep 17 00:00:00 2001
From: Brendan <2bndy5@gmail.com>
Date: Mon, 30 Sep 2024 23:19:31 -0700
Subject: [PATCH 03/60] fix: let public forks' PRs run git cliff in CI
---
.github/workflows/bump-n-release.yml | 2 --
1 file changed, 2 deletions(-)
diff --git a/.github/workflows/bump-n-release.yml b/.github/workflows/bump-n-release.yml
index a8adc2d..dfbcbf8 100644
--- a/.github/workflows/bump-n-release.yml
+++ b/.github/workflows/bump-n-release.yml
@@ -53,7 +53,6 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
- token: ${{ secrets.BUMP_N_RELEASE }}
fetch-depth: 0
- name: Generate a changelog
uses: orhun/git-cliff-action@v4
@@ -64,5 +63,4 @@ jobs:
env:
OUTPUT: ${{ runner.temp }}/changes.md
GITHUB_REPO: ${{ github.repository }}
- GITHUB_TOKEN: ${{ secrets.BUMP_N_RELEASE }}
- run: cat "${{ runner.temp }}/changes.md" >> "$GITHUB_STEP_SUMMARY"
From a11cf528cac9a2fd1ed920b2d4f08fda08b585e9 Mon Sep 17 00:00:00 2001
From: Brendan <2bndy5@gmail.com>
Date: Wed, 2 Oct 2024 01:19:48 -0700
Subject: [PATCH 04/60] feat: add optional colored log output (#52)
---
Cargo.lock | 1 +
README.md | 2 +
cpp-linter/Cargo.toml | 3 +-
cpp-linter/src/clang_tools/mod.rs | 8 +--
cpp-linter/src/logger.rs | 81 +++++++++++++++++----------
cpp-linter/src/rest_api/github/mod.rs | 10 ++++
cpp-linter/src/rest_api/mod.rs | 18 +++++-
cpp-linter/src/run.rs | 18 ++++--
8 files changed, 98 insertions(+), 43 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index bbcf761..7edf5cc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -277,6 +277,7 @@ dependencies = [
"anyhow",
"chrono",
"clap",
+ "colored",
"fast-glob",
"futures",
"git2",
diff --git a/README.md b/README.md
index 024b4ac..91840d4 100644
--- a/README.md
+++ b/README.md
@@ -210,6 +210,7 @@ license agreements:
Dual-licensed under [Apache 2.0][Apache2] or [MIT].
- [chrono](https://crates.io/crates/chrono):
Dual-licensed under [Apache 2.0][Apache2] or [MIT].
+- [colored](https://crates.io/crates/colored): Licensed under [MPL-2.0]
The python binding uses
@@ -223,3 +224,4 @@ The node binding uses
[MIT]: https://choosealicense.com/licenses/mit
[Apache2]: https://choosealicense.com/licenses/apache-2.0/
+[MPL-2.0]: https://choosealicense.com/licenses/mpl-2.0
diff --git a/cpp-linter/Cargo.toml b/cpp-linter/Cargo.toml
index 947eff8..176bddd 100644
--- a/cpp-linter/Cargo.toml
+++ b/cpp-linter/Cargo.toml
@@ -17,11 +17,12 @@ license.workspace = true
anyhow = "1.0.89"
chrono = "0.4.38"
clap = "4.5.17"
+colored = "2.1.0"
fast-glob = "0.4.0"
futures = "0.3.30"
git2 = "0.19.0"
lenient_semver = "0.4.2"
-log = "0.4.22"
+log = { version = "0.4.22", features = ["std"] }
openssl = { version = "0.10", features = ["vendored"], optional = true }
openssl-probe = { version = "0.1", optional = true }
regex = "1.10.6"
diff --git a/cpp-linter/src/clang_tools/mod.rs b/cpp-linter/src/clang_tools/mod.rs
index 68063ae..1b1bdd6 100644
--- a/cpp-linter/src/clang_tools/mod.rs
+++ b/cpp-linter/src/clang_tools/mod.rs
@@ -21,8 +21,7 @@ use which::{which, which_in};
use super::common_fs::FileObj;
use crate::{
cli::ClangParams,
- logger::{end_log_group, start_log_group},
- rest_api::{COMMENT_MARKER, USER_OUTREACH},
+ rest_api::{RestApiClient, COMMENT_MARKER, USER_OUTREACH},
};
pub mod clang_format;
use clang_format::run_clang_format;
@@ -144,6 +143,7 @@ pub async fn capture_clang_tools_output(
files: &mut Vec>>,
version: &str,
clang_params: &mut ClangParams,
+ rest_api_client: &impl RestApiClient,
) -> Result<()> {
// find the executable paths for clang-tidy and/or clang-format and show version
// info as debugging output.
@@ -192,11 +192,11 @@ pub async fn capture_clang_tools_output(
while let Some(output) = executors.join_next().await {
if let Ok(out) = output? {
let (file_name, logs) = out;
- start_log_group(format!("Analyzing {}", file_name.to_string_lossy()));
+ rest_api_client.start_log_group(format!("Analyzing {}", file_name.to_string_lossy()));
for (level, msg) in logs {
log::log!(level, "{}", msg);
}
- end_log_group();
+ rest_api_client.end_log_group();
}
}
Ok(())
diff --git a/cpp-linter/src/logger.rs b/cpp-linter/src/logger.rs
index 8426c27..f7fc004 100644
--- a/cpp-linter/src/logger.rs
+++ b/cpp-linter/src/logger.rs
@@ -1,58 +1,77 @@
//! A module to initialize and customize the logger object used in (most) stdout.
-// non-std crates
-use log::{Level, LevelFilter, Metadata, Record, SetLoggerError};
+use std::env;
+use anyhow::{Error, Result};
+use colored::{control::set_override, Colorize};
+use log::{Level, LevelFilter, Metadata, Record};
+
+#[derive(Default)]
struct SimpleLogger;
+impl SimpleLogger {
+ fn level_color(level: &Level) -> String {
+ let name = format!("{:>5}", level.as_str().to_uppercase());
+ match level {
+ Level::Error => name.red().bold().to_string(),
+ Level::Warn => name.yellow().bold().to_string(),
+ Level::Info => name.green().bold().to_string(),
+ Level::Debug => name.blue().bold().to_string(),
+ Level::Trace => name.magenta().bold().to_string(),
+ }
+ }
+}
+
impl log::Log for SimpleLogger {
fn enabled(&self, metadata: &Metadata) -> bool {
- metadata.level() <= Level::Debug
+ metadata.level() <= log::max_level()
}
fn log(&self, record: &Record) {
- if self.enabled(record.metadata()) {
- println!("{}: {}", record.level(), record.args());
+ if record.target() == "CI_LOG_GROUPING" {
+ // this log is meant to manipulate a CI workflow's log grouping
+ println!("{}", record.args());
+ } else if self.enabled(record.metadata()) {
+ println!(
+ "[{}]: {}",
+ Self::level_color(&record.level()),
+ record.args()
+ );
}
}
fn flush(&self) {}
}
-/// A private constant to manage the application's logger object.
-static LOGGER: SimpleLogger = SimpleLogger;
-
/// A function to initialize the private `LOGGER`.
///
/// The logging level defaults to [`LevelFilter::Info`].
/// Returns a [`SetLoggerError`] if the `LOGGER` is already initialized.
-pub fn init() -> Result<(), SetLoggerError> {
- log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Info))
-}
-
-/// This prints a line to indicate the beginning of a related group of log statements.
-///
-/// This function may or may not get moved to [crate::rest_api::RestApiClient] trait
-/// if/when platforms other than GitHub are supported.
-pub fn start_log_group(name: String) {
- println!("::group::{}", name);
-}
-
-/// This prints a line to indicate the ending of a related group of log statements.
-///
-/// This function may or may not get moved to [crate::rest_api::RestApiClient] trait
-/// if/when platforms other than GitHub are supported.
-pub fn end_log_group() {
- println!("::endgroup::");
+pub fn init() -> Result<()> {
+ let logger: SimpleLogger = SimpleLogger;
+ if matches!(
+ env::var("CPP_LINTER_COLOR").as_deref(),
+ Ok("on" | "1" | "true")
+ ) {
+ set_override(true);
+ }
+ log::set_boxed_logger(Box::new(logger))
+ .map(|()| log::set_max_level(LevelFilter::Info))
+ .map_err(Error::from)
}
#[cfg(test)]
-mod tests {
- use super::{end_log_group, start_log_group};
+mod test {
+ use std::env;
+
+ use super::{init, SimpleLogger};
#[test]
- fn issue_log_grouping_stdout() {
- start_log_group(String::from("a dumb test"));
- end_log_group();
+ fn trace_log() {
+ env::set_var("CPP_LINTER_COLOR", "true");
+ init().unwrap_or(());
+ assert!(SimpleLogger::level_color(&log::Level::Trace).contains("TRACE"));
+ log::set_max_level(log::LevelFilter::Trace);
+ log::trace!("A dummy log statement for code coverage");
}
}
diff --git a/cpp-linter/src/rest_api/github/mod.rs b/cpp-linter/src/rest_api/github/mod.rs
index 0fa66c3..1d7c067 100644
--- a/cpp-linter/src/rest_api/github/mod.rs
+++ b/cpp-linter/src/rest_api/github/mod.rs
@@ -95,6 +95,16 @@ impl RestApiClient for GithubApiClient {
checks_failed
}
+ /// This prints a line to indicate the beginning of a related group of log statements.
+ fn start_log_group(&self, name: String) {
+ log::info!(target: "CI_LOG_GROUPING", "::group::{}", name);
+ }
+
+ /// This prints a line to indicate the ending of a related group of log statements.
+ fn end_log_group(&self) {
+ log::info!(target: "CI_LOG_GROUPING", "::endgroup::");
+ }
+
fn make_headers() -> Result> {
let mut headers = HeaderMap::new();
headers.insert(
diff --git a/cpp-linter/src/rest_api/mod.rs b/cpp-linter/src/rest_api/mod.rs
index 4c9da48..589b52c 100644
--- a/cpp-linter/src/rest_api/mod.rs
+++ b/cpp-linter/src/rest_api/mod.rs
@@ -49,6 +49,12 @@ pub trait RestApiClient {
tidy_checks_failed: Option,
) -> u64;
+ /// This prints a line to indicate the beginning of a related group of log statements.
+ fn start_log_group(&self, name: String);
+
+ /// This prints a line to indicate the ending of a related group of log statements.
+ fn end_log_group(&self);
+
/// A convenience method to create the headers attached to all REST API calls.
///
/// If an authentication token is provided (via environment variable),
@@ -453,12 +459,21 @@ mod test {
) -> Result {
Err(anyhow!("Not implemented"))
}
+
+ fn start_log_group(&self, name: String) {
+ log::info!(target: "CI_LOG_GROUPING", "start_log_group: {name}");
+ }
+
+ fn end_log_group(&self) {
+ log::info!(target: "CI_LOG_GROUPING", "end_log_group");
+ }
}
#[tokio::test]
async fn dummy_coverage() {
assert!(TestClient::make_headers().is_err());
let dummy = TestClient::default();
+ dummy.start_log_group("Dummy test".to_string());
assert_eq!(dummy.set_exit_code(1, None, None), 0);
assert!(dummy
.get_list_of_changed_files(&FileFilter::new(&[], vec![]))
@@ -474,7 +489,8 @@ mod test {
assert!(dummy
.post_feedback(&[], FeedbackInput::default())
.await
- .is_err())
+ .is_err());
+ dummy.end_log_group();
}
// ************************************************* try_next_page() tests
diff --git a/cpp-linter/src/run.rs b/cpp-linter/src/run.rs
index 42cc050..a59b2af 100644
--- a/cpp-linter/src/run.rs
+++ b/cpp-linter/src/run.rs
@@ -17,7 +17,7 @@ use openssl_probe;
use crate::clang_tools::capture_clang_tools_output;
use crate::cli::{get_arg_parser, ClangParams, Cli, FeedbackInput, LinesChangedOnly};
use crate::common_fs::FileFilter;
-use crate::logger::{self, end_log_group, start_log_group};
+use crate::logger;
use crate::rest_api::{github::GithubApiClient, RestApiClient};
const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -93,7 +93,7 @@ pub async fn run_main(args: Vec) -> Result<()> {
}
}
- start_log_group(String::from("Get list of specified source files"));
+ rest_api_client.start_log_group(String::from("Get list of specified source files"));
let files = if cli.lines_changed_only != LinesChangedOnly::Off || cli.files_changed_only {
// parse_diff(github_rest_api_payload)
rest_api_client
@@ -124,16 +124,22 @@ pub async fn run_main(args: Vec) -> Result<()> {
log::info!(" ./{}", file.name.to_string_lossy().replace('\\', "/"));
arc_files.push(Arc::new(Mutex::new(file)));
}
- end_log_group();
+ rest_api_client.end_log_group();
let mut clang_params = ClangParams::from(&cli);
let user_inputs = FeedbackInput::from(&cli);
- capture_clang_tools_output(&mut arc_files, cli.version.as_str(), &mut clang_params).await?;
- start_log_group(String::from("Posting feedback"));
+ capture_clang_tools_output(
+ &mut arc_files,
+ cli.version.as_str(),
+ &mut clang_params,
+ &rest_api_client,
+ )
+ .await?;
+ rest_api_client.start_log_group(String::from("Posting feedback"));
let checks_failed = rest_api_client
.post_feedback(&arc_files, user_inputs)
.await?;
- end_log_group();
+ rest_api_client.end_log_group();
if env::var("PRE_COMMIT").is_ok_and(|v| v == "1") {
if checks_failed > 1 {
return Err(anyhow!("Some checks did not pass"));
From 43f986302fdac7f5b1b0c526bd9c10415f11c2af Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 2 Oct 2024 03:27:09 -0700
Subject: [PATCH 05/60] Bump reqwest from 0.12.7 to 0.12.8 in the cargo group
(#51)
Bumps the cargo group with 1 update: [reqwest](https://github.com/seanmonstar/reqwest).
Updates `reqwest` from 0.12.7 to 0.12.8
- [Release notes](https://github.com/seanmonstar/reqwest/releases)
- [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.7...v0.12.8)
---
updated-dependencies:
- dependency-name: reqwest
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: cargo
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
Cargo.lock | 4 ++--
cpp-linter/Cargo.toml | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 7edf5cc..24c63d5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1321,9 +1321,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "reqwest"
-version = "0.12.7"
+version = "0.12.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
+checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
dependencies = [
"base64",
"bytes",
diff --git a/cpp-linter/Cargo.toml b/cpp-linter/Cargo.toml
index 176bddd..5dc561a 100644
--- a/cpp-linter/Cargo.toml
+++ b/cpp-linter/Cargo.toml
@@ -26,7 +26,7 @@ log = { version = "0.4.22", features = ["std"] }
openssl = { version = "0.10", features = ["vendored"], optional = true }
openssl-probe = { version = "0.1", optional = true }
regex = "1.10.6"
-reqwest = "0.12.7"
+reqwest = "0.12.8"
semver = "1.0.23"
serde = { version = "1.0.210", features = ["derive"] }
serde-xml-rs = "0.6.0"
From 6239f7ef85395000a905b456b440e80ecdb18c29 Mon Sep 17 00:00:00 2001
From: Brendan <2bndy5@gmail.com>
Date: Wed, 2 Oct 2024 04:16:17 -0700
Subject: [PATCH 06/60] adjust color in docs' drawer
---
docs/docs/stylesheets/extra.css | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/docs/docs/stylesheets/extra.css b/docs/docs/stylesheets/extra.css
index abd602f..357df12 100644
--- a/docs/docs/stylesheets/extra.css
+++ b/docs/docs/stylesheets/extra.css
@@ -6,18 +6,27 @@ th {
background-color: #4051b5;
}
-.md-typeset .admonition.important, .md-typeset details.important {
- border-color: #00b8d4;
+@media screen and (max-width: 76.2344em) {
+ .md-nav--primary .md-nav__title[for="__drawer"] {
+ background-color: #4051b5;
+ }
+}
+
+.md-typeset .admonition.important,
+.md-typeset details.important {
+ border-color: #00b8d4;
}
-.md-typeset .important > .admonition-title::before, .md-typeset .important > summary::before {
- background-color: #00b8d4;
- -webkit-mask-image: var(--md-admonition-icon--info);
- mask-image: var(--md-admonition-icon--info);
+.md-typeset .important>.admonition-title::before,
+.md-typeset .important>summary::before {
+ background-color: #00b8d4;
+ -webkit-mask-image: var(--md-admonition-icon--info);
+ mask-image: var(--md-admonition-icon--info);
}
-.md-typeset .important > .admonition-title, .md-typeset .important > summary {
- background-color: #00b8d41a;
+.md-typeset .important>.admonition-title,
+.md-typeset .important>summary {
+ background-color: #00b8d41a;
}
@keyframes heart {
From 023c1705a078b9a7542022deefa228a567d68b67 Mon Sep 17 00:00:00 2001
From: Brendan <2bndy5@gmail.com>
Date: Thu, 3 Oct 2024 03:43:20 -0700
Subject: [PATCH 07/60] fix: regenerate TS type definitions
---
node-binding/index.d.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/node-binding/index.d.ts b/node-binding/index.d.ts
index 3f7d44f..9a04e02 100644
--- a/node-binding/index.d.ts
+++ b/node-binding/index.d.ts
@@ -3,4 +3,4 @@
/* auto-generated by NAPI-RS */
-export declare function main(args: Array): Promise
+export declare function main(args: Array): Promise
From 1ea0ea6faf9565b3056ece9dc0a11093daad2a51 Mon Sep 17 00:00:00 2001
From: Brendan <2bndy5@gmail.com>
Date: Thu, 3 Oct 2024 22:05:59 -0700
Subject: [PATCH 08/60] add CI to detect performance regressions (#53)
Compares two release builds of cpp-linter binary and pure-python package:
1. the previous commit (for push events) or the base branch of a PR
2. the newest commit on the branch
3. the latest v1.x release of the pure-python cpp-linter package
Caching is enabled to reduce CI runtime.
Results are output to the CI workflow's job summary.
This CI does not (currently) fail when a regression is detected.
---
.github/workflows/perf-test.yml | 146 +++++++++++++++++++++++++++++
.github/workflows/perf_annotate.py | 68 ++++++++++++++
2 files changed, 214 insertions(+)
create mode 100644 .github/workflows/perf-test.yml
create mode 100644 .github/workflows/perf_annotate.py
diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml
new file mode 100644
index 0000000..f6ac7ad
--- /dev/null
+++ b/.github/workflows/perf-test.yml
@@ -0,0 +1,146 @@
+name: Performance Regression
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - cpp-linter/src/**
+ - cpp-linter/Cargo.toml
+ - Cargo.toml
+ - Cargo.lock
+ - .github/workflows/perf-test.yml
+ - .github/workflows/bench.py
+ tags-ignore: ['*']
+ pull_request:
+ branches: [main]
+ paths:
+ - cpp-linter/src/**
+ - cpp-linter/Cargo.toml
+ - Cargo.toml
+ - Cargo.lock
+ - .github/workflows/perf*
+jobs:
+ build:
+ name: Build ${{ matrix.name }}
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ include:
+ - commit: ${{ github.sha }}
+ name: current
+ - commit: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
+ name: previous
+ outputs:
+ cached-previous: ${{ steps.is-cached-previous.outputs.is-cached == 'true' && steps.validate.outputs.cache-valid != 'false' }}
+ cached-current: ${{ steps.is-cached-current.outputs.is-cached == 'true' && steps.validate.outputs.cache-valid != 'false' }}
+ env:
+ BIN: target/release/cpp-linter
+ steps:
+ - name: Checkout ${{ matrix.name }}
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ matrix.commit }}
+ - name: Cache base ref build
+ uses: actions/cache@v4
+ id: cache
+ with:
+ key: bin-cache-${{ hashFiles('cpp-linter/src/**', 'Cargo.toml', 'Cargo.lock', 'cpp-linter/Cargo.toml') }}
+ path: ${{ env.BIN }}
+ - name: Is previous cached?
+ if: matrix.name == 'previous'
+ id: is-cached-previous
+ run: echo "is-cached=${{ steps.cache.outputs.cache-hit }}" >> "$GITHUB_OUTPUT"
+ - name: Is current cached?
+ if: matrix.name == 'current'
+ id: is-cached-current
+ run: echo "is-cached=${{ steps.cache.outputs.cache-hit }}" >> "$GITHUB_OUTPUT"
+ - name: Validate cached binary
+ if: steps.cache.outputs.cache-hit == 'true'
+ id: validate
+ run: |
+ chmod +x ${{ env.BIN }}
+ if ! ${{ env.BIN }} version; then
+ echo "Cached binary is invalid, rebuilding..."
+ echo "cache-valid=false" >> "$GITHUB_OUTPUT"
+ fi
+ - run: rustup update --no-self-update
+ if: steps.cache.outputs.cache-hit != 'true' || steps.validate.outputs.cache-valid == 'false'
+ - run: cargo build --bin cpp-linter --release
+ if: steps.cache.outputs.cache-hit != 'true' || steps.validate.outputs.cache-valid == 'false'
+ - name: Upload build artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ matrix.name }}
+ path: ${{ env.BIN }}
+
+ benchmark:
+ name: Measure Performance Difference
+ needs: [build]
+ if: ${{ !needs.build.outputs.cached-current || !needs.build.outputs.cached-previous }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Checkout libgit2
+ uses: actions/checkout@v4
+ with:
+ repository: libgit2/libgit2
+ ref: v1.8.1
+ path: libgit2
+ - name: Download built binaries
+ uses: actions/download-artifact@v4
+ - name: Make binaries executable
+ run: chmod +x ./*/cpp-linter
+ - name: Generate compilation database
+ working-directory: libgit2
+ run: |
+ mkdir build && cd build
+ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
+ - name: Install cargo-binstall
+ uses: cargo-bins/cargo-binstall@main
+ - name: Install hyperfine
+ run: cargo binstall -y hyperfine
+ - uses: actions/setup-python@v5
+ with:
+ python-version: 3.x
+ - run: pip install 'cpp-linter < 2.0'
+ - name: Warmup and list files
+ env:
+ CPP_LINTER_COLOR: true
+ working-directory: libgit2
+ # Use previous build for stability. This will
+ # - create the .cpp-linter_cache folder
+ # - list the files concerning the benchmark test
+ # NOTE: This does not actually invoke clang tools.
+ run: ../previous/cpp-linter -l 0 -p build -i='|!src/libgit2' -s="" -c="-*" -e c
+ - name: Run hyperfine tool
+ # using the generated compilation database,
+ # we will use cpp-linter (both builds) to scan libgit2 src/libgit2/**.c files.
+ working-directory: libgit2
+ run: >-
+ hyperfine
+ --runs 2
+ --style color
+ --export-markdown '${{ runner.temp }}/benchmark.md'
+ --export-json '${{ runner.temp }}/benchmark.json'
+ --command-name=previous-build
+ "../previous/cpp-linter -l 0 -p build -i='|!src/libgit2' -e c"
+ --command-name=current-build
+ "../current/cpp-linter -l 0 -p build -i='|!src/libgit2' -e c"
+ --command-name=pure-python
+ "cpp-linter -l false -j 0 -p build -i='|!src/libgit2' -e c"
+ - name: Append report to job summary
+ run: cat ${{ runner.temp }}/benchmark.md >> "$GITHUB_STEP_SUMMARY"
+ - name: Upload JSON results
+ uses: actions/upload-artifact@v4
+ with:
+ name: benchmark-json
+ path: ${{ runner.temp }}/benchmark.json
+ - name: Annotate summary
+ run: python .github/workflows/perf_annotate.py "${{ runner.temp }}/benchmark.json"
+
+ report-no-src-changes:
+ runs-on: ubuntu-latest
+ needs: [build]
+ if: needs.build.outputs.cached-current && needs.build.outputs.cached-previous
+ steps:
+ - run: echo "::notice title=No benchmark performed::No changes to cpp-linter source code detected."
diff --git a/.github/workflows/perf_annotate.py b/.github/workflows/perf_annotate.py
new file mode 100644
index 0000000..072c9b0
--- /dev/null
+++ b/.github/workflows/perf_annotate.py
@@ -0,0 +1,68 @@
+import argparse
+import json
+from os import environ
+from pathlib import Path
+from typing import List, Any, Dict, cast
+
+
+class Args(argparse.Namespace):
+ json_file: Path
+
+
+def main():
+ arg_parser = argparse.ArgumentParser()
+ arg_parser.add_argument("json_file", type=Path)
+ arg_parser.parse_args(namespace=Args)
+
+ bench_json = Args.json_file.read_text(encoding="utf-8")
+ bench: List[Dict[str, Any]] = json.loads(bench_json)["results"]
+
+ assert len(bench) == 3
+ old_mean, new_mean = (None, None)
+ for result in bench:
+ mean = cast(float, result["mean"])
+ if result["command"] == "previous-build":
+ old_mean = mean
+ elif result["command"] == "current-build":
+ new_mean = mean
+
+ assert old_mean is not None, "benchmark report has no result for previous-build"
+ assert new_mean is not None, "benchmark report has no result for current-build"
+
+ diff = round(new_mean - old_mean, 2)
+ scalar = int((new_mean - old_mean) / old_mean * 100)
+
+ output = []
+ if diff > 2:
+ output.extend(
+ [
+ "> [!CAUTION]",
+ "> Detected a performance regression in new changes:",
+ ]
+ )
+ elif diff < -2:
+ output.extend(
+ [
+ "> [!TIP]",
+ "> Detected a performance improvement in new changes:",
+ ]
+ )
+ else:
+ output.extend(
+ [
+ "> [!NOTE]",
+ "> Determined a negligible difference in performance with new changes:",
+ ]
+ )
+ output[-1] += f" {diff}s ({scalar} %)"
+ annotation = "\n".join(output)
+
+ if "GITHUB_STEP_SUMMARY" in environ:
+ with open(environ["GITHUB_STEP_SUMMARY"], "a") as summary:
+ summary.write(f"\n{annotation}\n")
+ else:
+ print(annotation)
+
+
+if __name__ == "__main__":
+ main()
From 6ab773ddcafc253a586b8711b728eea16e4bd5a4 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 14 Oct 2024 19:28:56 -0700
Subject: [PATCH 09/60] Bump the cargo group across 1 directory with 4 updates
(#58)
Bumps the cargo group with 4 updates in the / directory: [clap](https://github.com/clap-rs/clap), [futures](https://github.com/rust-lang/futures-rs), [pyo3](https://github.com/pyo3/pyo3) and [napi](https://github.com/napi-rs/napi-rs).
Updates `clap` from 4.5.18 to 4.5.20
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.18...clap_complete-v4.5.20)
Updates `futures` from 0.3.30 to 0.3.31
- [Release notes](https://github.com/rust-lang/futures-rs/releases)
- [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.30...0.3.31)
Updates `pyo3` from 0.22.3 to 0.22.4
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.22.3...v0.22.4)
Updates `napi` from 2.16.11 to 2.16.12
- [Release notes](https://github.com/napi-rs/napi-rs/releases)
- [Commits](https://github.com/napi-rs/napi-rs/compare/napi@2.16.11...napi@2.16.12)
---
updated-dependencies:
- dependency-name: clap
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: cargo
- dependency-name: futures
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: cargo
- dependency-name: pyo3
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: cargo
- dependency-name: napi
dependency-type: direct:production
update-type: version-update:semver-patch
dependency-group: cargo
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
Cargo.lock | 68 ++++++++++++++++++++---------------------
cpp-linter/Cargo.toml | 4 +--
docs/Cargo.toml | 2 +-
node-binding/Cargo.toml | 2 +-
py-binding/Cargo.toml | 2 +-
5 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 24c63d5..796120d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -196,18 +196,18 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.18"
+version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
+checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.5.18"
+version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
+checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [
"anstream",
"anstyle",
@@ -404,9 +404,9 @@ dependencies = [
[[package]]
name = "futures"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
dependencies = [
"futures-channel",
"futures-core",
@@ -419,9 +419,9 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
"futures-sink",
@@ -429,15 +429,15 @@ dependencies = [
[[package]]
name = "futures-core"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
@@ -446,15 +446,15 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
@@ -463,21 +463,21 @@ dependencies = [
[[package]]
name = "futures-sink"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
[[package]]
name = "futures-task"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-channel",
"futures-core",
@@ -954,9 +954,9 @@ dependencies = [
[[package]]
name = "napi"
-version = "2.16.11"
+version = "2.16.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53575dfa17f208dd1ce3a2da2da4659aae393b256a472f2738a8586a6c4107fd"
+checksum = "3a84fdaf64da2b2d86b1be5db1b81963353bf00f7bef4b9e2668bbe6f72e8eb3"
dependencies = [
"bitflags",
"ctor",
@@ -1181,9 +1181,9 @@ dependencies = [
[[package]]
name = "pyo3"
-version = "0.22.3"
+version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225"
+checksum = "00e89ce2565d6044ca31a3eb79a334c3a79a841120a98f64eea9f579564cb691"
dependencies = [
"cfg-if",
"indoc",
@@ -1199,9 +1199,9 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
-version = "0.22.3"
+version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3"
+checksum = "d8afbaf3abd7325e08f35ffb8deb5892046fcb2608b703db6a583a5ba4cea01e"
dependencies = [
"once_cell",
"target-lexicon",
@@ -1209,9 +1209,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
-version = "0.22.3"
+version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c"
+checksum = "ec15a5ba277339d04763f4c23d85987a5b08cbb494860be141e6a10a8eb88022"
dependencies = [
"libc",
"pyo3-build-config",
@@ -1219,9 +1219,9 @@ dependencies = [
[[package]]
name = "pyo3-macros"
-version = "0.22.3"
+version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28"
+checksum = "15e0f01b5364bcfbb686a52fc4181d412b708a68ed20c330db9fc8d2c2bf5a43"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
@@ -1231,9 +1231,9 @@ dependencies = [
[[package]]
name = "pyo3-macros-backend"
-version = "0.22.3"
+version = "0.22.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1"
+checksum = "a09b550200e1e5ed9176976d0060cbc2ea82dc8515da07885e7b8153a85caacb"
dependencies = [
"heck",
"proc-macro2",
diff --git a/cpp-linter/Cargo.toml b/cpp-linter/Cargo.toml
index 5dc561a..90f6ff6 100644
--- a/cpp-linter/Cargo.toml
+++ b/cpp-linter/Cargo.toml
@@ -16,10 +16,10 @@ license.workspace = true
[dependencies]
anyhow = "1.0.89"
chrono = "0.4.38"
-clap = "4.5.17"
+clap = "4.5.20"
colored = "2.1.0"
fast-glob = "0.4.0"
-futures = "0.3.30"
+futures = "0.3.31"
git2 = "0.19.0"
lenient_semver = "0.4.2"
log = { version = "0.4.22", features = ["std"] }
diff --git a/docs/Cargo.toml b/docs/Cargo.toml
index bbc84e3..19d7e24 100644
--- a/docs/Cargo.toml
+++ b/docs/Cargo.toml
@@ -11,7 +11,7 @@ license.workspace = true
[dependencies]
cpp-linter = { path = "../cpp-linter" }
-pyo3 = "0.22.3"
+pyo3 = "0.22.4"
[lib]
name = "cli_gen"
diff --git a/node-binding/Cargo.toml b/node-binding/Cargo.toml
index f980ac4..ac34173 100644
--- a/node-binding/Cargo.toml
+++ b/node-binding/Cargo.toml
@@ -16,7 +16,7 @@ crate-type = ["cdylib"]
[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
-napi = { version = "2.12.2", default-features = false, features = ["napi4", "async"] }
+napi = { version = "2.16.12", default-features = false, features = ["napi4", "async"] }
napi-derive = "2.12.2"
cpp-linter = { path = "../cpp-linter" }
anyhow = "1.0.89"
diff --git a/py-binding/Cargo.toml b/py-binding/Cargo.toml
index 77a454b..73d5527 100644
--- a/py-binding/Cargo.toml
+++ b/py-binding/Cargo.toml
@@ -16,7 +16,7 @@ name = "cpp_linter"
crate-type = ["cdylib"]
[dependencies]
-pyo3 = { version = "0.22.3", features = ["extension-module"] }
+pyo3 = { version = "0.22.4", features = ["extension-module"] }
cpp-linter = { path = "../cpp-linter" }
tokio = "1.40.0"
From 7a4519276833656ee19bd9b014c8cc7d7b1cf2e9 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 15 Nov 2024 19:04:06 -0800
Subject: [PATCH 10/60] Bump @eslint/plugin-kit from 0.2.0 to 0.2.3 (#69)
Bumps [@eslint/plugin-kit](https://github.com/eslint/rewrite) from 0.2.0 to 0.2.3.
- [Release notes](https://github.com/eslint/rewrite/releases)
- [Changelog](https://github.com/eslint/rewrite/blob/main/release-please-config.json)
- [Commits](https://github.com/eslint/rewrite/compare/core-v0.2.0...plugin-kit-v0.2.3)
---
updated-dependencies:
- dependency-name: "@eslint/plugin-kit"
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
yarn.lock | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 70449b2..8dc4edf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -54,9 +54,9 @@
integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==
"@eslint/plugin-kit@^0.2.0":
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d"
- integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz#812980a6a41ecf3a8341719f92a6d1e784a2e0e8"
+ integrity sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==
dependencies:
levn "^0.4.1"
From d33a656616c87a3e9006e95ece34c938b76edd92 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 15 Nov 2024 19:14:18 -0800
Subject: [PATCH 11/60] Bump cross-spawn from 7.0.3 to 7.0.5 (#70)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.5.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.5)
---
updated-dependencies:
- dependency-name: cross-spawn
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
yarn.lock | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/yarn.lock b/yarn.lock
index 8dc4edf..cfdebb4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -467,9 +467,9 @@ convert-to-spaces@^2.0.1:
integrity sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==
cross-spawn@^7.0.2:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
- integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ version "7.0.5"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.5.tgz#910aac880ff5243da96b728bc6521a5f6c2f2f82"
+ integrity sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
From 668f4d97e3608ba3f95aa93c095c4136c90165df Mon Sep 17 00:00:00 2001
From: Brendan <2bndy5@gmail.com>
Date: Sat, 23 Nov 2024 06:16:50 -0800
Subject: [PATCH 12/60] feat: capture and output clang tool's version number
(#54)
This affects thread-comments, step-summary, and PR review summary.
I also added tests to ensure PR review summary only shows relevant information about the tools that were actually used.
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---
cpp-linter/src/clang_tools/clang_tidy.rs | 19 ++--
cpp-linter/src/clang_tools/mod.rs | 95 +++++++++++++------
cpp-linter/src/common_fs/mod.rs | 17 ++--
cpp-linter/src/rest_api/github/mod.rs | 22 ++++-
.../src/rest_api/github/specific_api.rs | 8 +-
cpp-linter/src/rest_api/mod.rs | 20 +++-
cpp-linter/src/run.rs | 4 +-
cpp-linter/tests/reviews.rs | 68 +++++++++----
cspell.config.yml | 1 +
9 files changed, 181 insertions(+), 73 deletions(-)
diff --git a/cpp-linter/src/clang_tools/clang_tidy.rs b/cpp-linter/src/clang_tools/clang_tidy.rs
index 52d5640..cd82709 100644
--- a/cpp-linter/src/clang_tools/clang_tidy.rs
+++ b/cpp-linter/src/clang_tools/clang_tidy.rs
@@ -133,7 +133,7 @@ impl MakeSuggestions for TidyAdvice {
fn parse_tidy_output(
tidy_stdout: &[u8],
database_json: &Option>,
-) -> Result