From 8379a1c754d9a54cf63f78502dc690f0a09c0eea Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Thu, 17 Sep 2015 12:14:28 +0200 Subject: [PATCH 01/14] Add Gmail actions button for GitLab doc. --- .../gmail_action_buttons_for_gitlab.md | 22 ++++++++++++++++++ doc/integration/gmail_actions_button.png | Bin 0 -> 17321 bytes 2 files changed, 22 insertions(+) create mode 100644 doc/integration/gmail_action_buttons_for_gitlab.md create mode 100644 doc/integration/gmail_actions_button.png diff --git a/doc/integration/gmail_action_buttons_for_gitlab.md b/doc/integration/gmail_action_buttons_for_gitlab.md new file mode 100644 index 00000000000..21f34db6ed5 --- /dev/null +++ b/doc/integration/gmail_action_buttons_for_gitlab.md @@ -0,0 +1,22 @@ +# Gmail actions buttons for GitLab + +GitLab supports [Google actions in email](https://developers.google.com/gmail/markup/actions/actions-overview). + +If correctly setup, emails that require an action will be marked in Gmail. + +![gmail_actions_button.png](gmail_actions_button.png.png) + +To get this functioning, you need to be registered with Google. +[See how to register with Google in this document.](https://developers.google.com/gmail/markup/registering-with-google) + +*This process has a lot of steps so make sure that you fulfill all requirements set by Google.* +*Your application will be rejected by Google if you fail to do so.* + +Pay close attention to: + +* Email account used by GitLab to send notification emails needs to have "Consistent history of sending a high volume of mail from your domain (order of hundred emails a day minimum to Gmail) for a few weeks at least". +* "A very very low rate of spam complaints from users." +* Emails must be authenticated via DKIM or SPF +* Before sending the final form("Gmail Schema Whitelist Request"), you must send a real email from your production server. This means that you will have to find a way to send this email from the email address you are registering. You can do this by, for example, forwarding the real email from the email address you are registering or going into the rails console on the GitLab server and triggering the email sending from there. + +You can check how it looks going through all the steps laid out in the "Registering with Google" doc in [this GitLab.com issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/1517). diff --git a/doc/integration/gmail_actions_button.png b/doc/integration/gmail_actions_button.png new file mode 100644 index 0000000000000000000000000000000000000000..b08f54d137bd9ab1bde8471211f95016a9ee6aa0 GIT binary patch literal 17321 zcmb{4bzED`qA&bDErn9tDee?69=sHa6N;Ch#hnIsTHGma0a`3L#T`ls?gZBo+>1+) zH+}X#=k9awe$VIL`@Z=jnYCsXGi1#Q%$FZ4;vG;P=Q+jmM~@!iC@RQmJbLul8dbh| z_89e?(aIU{=#k7vMOkSr&-sHaLp28d`=d*{9pP2VSIf?;IJ%aN8kM-ZLBh9YZ&-85 zuGD_O!mMdy{d^-cYGEvS5`-B*ub&I1y^xh}(nJEYFUuYVrK+9JfP#M=2O4YD9FRxnuY+oy*Y{ z-J}vf1y&^a<89&HH%QvbJABrwend3-ll6e(Gq=jaCZ=TUr$OI(_yh#_B&o&P@C~wu0`$_ev#ZR#y*F~XQf+g37~Q**erm!oY<@^f%_m#TZlujlPB;39etPAD*i+)evFM z63meqjmVD;uhR)r@5$sA^oAFW-S^r_!RC@JMffg82p=q$yRQ$1k3BA;Ap_KHo}woe z!URB1&C&bRaOKZ#N|6A@{=d)!vfixo!sZ4-hNeI?zCZ-$8PAB$ha3=JZKH9KP_Ud} z9nlo7V{2OfjUxlF7*2e(;(vFZL)dYDy7Ex9>$`V-TH_K?b9zg1w>LL;t?lR5GQ~%n7T30e1Z42rQth&naXGjsMvEW(u z)G@}xy+=Q}SoTSWZ3ni zAK$Hif0}(stNF7l_>%Y_waOKr(SfpQiebTh0Wr03BH(7fepW8w9|Sl8Esa{2P8mZNZ0gqGi%L^;BQ3GM zb0bd*e04QSmUzwqec6*XY%4j2i-K$%i!H?i$w`BND0s2mUboYY3O*)y4DO?_N^jhU6+1%8)k6iW5)9RhA!; zQBbEMqW7(oc5vzgejr<0}#Lu}|V&*wmb%WMJ#!MA$-|czE3jnj&iLm24I1h6k zh7l&Q)5|56Lb)IA7Bjk&{Bh%blivZ12umWmzuyCiv{Ri42O|JtOfRBY`5`d?pN106 zCB105pXRwb6TWvU;%7>zS$y)VjZ|aAPpB23)|I>3Ph7coNH%iC+JLi=?HF|T`LgrV zJ^A_AY0oWFI{Bmq#9gKF5yEvQ?_*0Q2i!kEoa2nxN{p8F1qD5<{WqvdwIjpgU_mPX zjVN)(elp=mFElhXw8s+n>SX8aWg;~VMa;glL)*}u2ETlvP?J4hPhq%x591PLn?#IS z4I83rNA><^aw~bi*kuoO1{p_4Ou=~3iuiAzEAQ_L{Fl7_^wOZ}S{7&qBn3lO-b2JuScqS6gH>f1*1qn88~dEVjni%M zZEZ%32yQ~GlWks}L+|nAx8roS(wSZaVwA+{6``8N^N=C1)@h8WmYg=(yc3(@8M*{l z{D?MXj5B?k5*HEB)gX$We5pUVaxHruK!RrP7S{Qpo$R zCa2^j{38ZJpJ_YYJR{&HL`Ln(_w!GYOLaaMuf2#*$- z+f3ha9cDo>8m#$m_uLAzY-{Z7h~}S4LMZvFy_iGxj<2>ZcK0s><4z^x=z&>ME%`U= zQ}(r1t1i1i+`i`yR@dJ5uRVq+0o5WNssV>OJvRm$?PqEUQu;#BEY{RfbP|s@kW2F4 zWv91qFO*d-2FAX8aQ@QwmiT<=9r!sfgH&d}G~>PJ(%Y1)r52mzw`!` z{uOd^u$+sEM!t6|`A6QZqRwt@qKcICO2Pu!Nv07=kOj$%CBq%8b5sgZoAfd#VCkUsu&*cq&0CW z&Q>3h4GKr`kP43=1X6_`fp^>bZE9>quCzQe;?`TRF z_p`s z>`W_n+eBZ8GM_(%o{OCAynv!e8Fe@M{zalPy{F-q z?X%yvLBP!Ae#J`eGl+O1gQmYCtCSiYamE=r@g{Ri()Vv>oWmRh(ACAuqowT9fCRh< zz})2w5aOuOjt`YY7k>p6)a!hYqfs%I%irSqMf0{A0qun*k_tYXbZ6vu^C-_l2yD15 zfTt3{UZ$@|w!UzuOo7BGh{|Ih#K9$^0yYt6leq?7 zVG~)t$ZVW!#0x)i1ycj(>HgL@OD`TSi_zI7agQE`NYgj(O)KN9beH(V#VACpVDUxq z@i`tmGfBH_hrBnL08YhZU0kcVYk6l_6D&LPsPKa!#Eul|6%D7au8oo;0OKaM$NFC7hNc$C1Ff09dvk9QA-?`Ezezso|x%8C+7pGu5 znD+hs_J(3Dfk#Tb8}I-g`r>&^zllt$^hs75>h`m-)OP>7d44rJeCQGxZaADiZSfp$ zu1pIY*4z$%134@3Fgt`IG{DZ5c%{mww=EWJ0Nt|g7pvK+fMGi-!*ESR^A873&^hde zUP2$-!(XpHpBGW1sY6_6EjSa(&R#}j1xsUaV+9H#YRQka!=#cgE~nU+ly|w`NEG6# zr-o%$0+xmh+M3wfXC4=rh@L9yQxGWIZS67wr!j=CVw+zZS?pB4rTcb>4;V* z9OZ3x(w)W_-UbT_RD+}a31U%P+W?HpB_x`1dgB*v<~AF-S}w4@uB zi(l_V`yk}W4E8V8SD85Oo!%PO#U?ojM6mSY!YpGBwl-#G*0R#{C0`0U&8m0JJEIa+zK+#Otovr~oO6-(pR?GO!ikDOhG8GUN`&Q__b;$4 z7E3m3R-Sz3d?GQsWEfHY@myaYOu;y!p8<6f;VOaxcxtuEf6?{LFafJwZsY_gaOI*I zeGAMdKa`D_XHk!D4+o2iY^P;W5ermQS|6lktpgz*Grg|zy71F>u~-lgw>bw;y!3?f zMW>~SMsZW6&W;h$z>ZeNZ3j~;%$UR_xkOOTe!oOj)%R4_KFKUPF|r0E>Ds2T#=%!$ zz>>(J?U|jL>Y5-eV+IkqrXL*HbmOg`Su{-bFvb+zZAQC#p_y zALGTZG-PkhD>vxE=J*F(!v%+dZl@cVi1o>WB&7tn5-Tni)y~dZCYihXS9M5(*Hq@3 zpF{dLiaJ{^V0~g0LKHvy{ATs}=$G+KrbuBH7RN z9okFE8QOZw=4l@rUR7mGyw%OE_iENSc+$-_QIIaZL`ZNNa$}o}dON5?TF5v@GVjOG zIR!V$tX$t>6R=XY;UIC9Z6zcv6bpD7xz(hY*C3&@t`VFcKU@r`;}&{_T}<)W-F!LM zjPPvITf{Y?teSZGeNlT?`dEBej77wGF$LgBxZfDeX)q%3G z9U2GTjj`Hgh(+_ISWBvr{_?}SrIuK!v}(z${nw=xLcHwhxF2JCZZhgCx#Y)|oD zoTNSPrA#^SSYb~Iy!rHoGDMhhBy*_w1LOOn4;ww|kbPLrVQcR7HC+u&H<4(5@g%dM z(ez4Ikxzkcoj_tAfn{I?*Tkm0(urPx;t?#^pA}6?*XMon`NHdNJ!NFf_`Tw2!;pz8 zpKf0@HUm(1(a0M4I9i4I)VGCe!??GuI}K!@km?XU^s(@_`uxTnojz&*j^4!?n+y|& za~0BIr()rew5@F$*R-1O91i{!ZKV!m{s>&sKh?6Ed$*tPPW-@si|%x8XD`-cH>T@H7ITF!%RCX3N>5*WQsZzb^zm~iSqa1L6 zrDyKp)2S@>$`ucJwzII;r&KMLN%1+O#Ng!zgS&XgAUov%-hH~N8G#OY!!)1Tk>2Ge z;hNR`-Gz6ffjADEZ);56ABWF1-W|G|8LOD(fS5zm#rz`Ri|-yBTTn{y;%_k;!F9Ft_t2C6cIfKOvsoMW6PTG3@V znPdu0MozvG3s?~nbXnGS{_d%Ad|Y-=2D*8z1DD{>_b|1wQun~A(c!*3rwy2j zi=#M{C|PVNb-}UI>O+4vL2Z-+Oe35WZzw=&ysCn=_#71p9t@m$uh0Wo_RFjo*BA?N zPW$|~8yq1X`dgMN&^TauQhDgBJ!8v5D>hLPYYUgRm1FVgs$DEcZI)9#W!=|j9q2cM zk9HgF;*EDXQw!$OaHLy%0hH-mdMsP1{X1N&NCl~9?1n|-Yg>bpwDRz~v($~w!$pdO z+XJEdW_rn8x(`sX9PMWKUbfRIylyw7(3Vy5$+TGZ zLYwEfjaxy;Yt(JWu$Go)!oMYcQKPCw(>Ed@P&mdx3RVn{{IO-hJrL-*@UU|p<*P@R zY<}AM>PpqPPOnY_KJVMqa!qUO)Uj@Lk0t5;OC%ibx86x(1&+O?F)B2s|8^HQ;~#$d zboD#cQv{j`YMl)yxa0^5b3MFszxfA%1q0}TkHGit9kH{qVG5@2;z{QpJP*Q9d;d^f zheWHHU$mBa2SOT|Q+S8Jg%zmje`~i+j6nOvt5JtX@F{b z>CTEt_f_qeT>5(6V>?uL{{o@^S^V$#^&cqv-|_3;DEq(gYbzD_4?REni1Rnho-qQ^ zmi}z_{8M33#s2`=e<{ZOY4UIO|I6P0t0tXySNC^51seSu&K-aKwxpx=JgH)(^*{SV z%6|Gp187cqIUiX+0i*-I@GRvc8yg$((WI&HSK9p&AMzjQ+h2~|H;nn8d}gKfIay_W zKpVqDLGsyWDo0WMQxR7fp3Rf_xC{OI&%XPp6L5$64y0-OFiW9F<~c4}!51A_7lSzg zXHWighH_u`>Y&}%!l_*ch+q}B^UHrlV+}8@8r0wrRI+| z0kC3cpJV1jT1u}O3u|k0Ur~2&`bP2ehiX0v3A6sQvw^qz+*6V<^81l&A<#m+$qD?e zAAPW(zo@@KVuZzF48&EQqt!jmdh=e=3i>I4Ii(mRJnJTRm*SzR)-m%2Iezb7`4sG4 zpcfn6Rs-uu_W=9*xZGw*FhWfmlK$zmp8yzx=Oyez+dcja=_)ia_|a0VJNKb-dl-20l;o{tce)> zYxD7aHf>fvMEKXg{#4h7EEZvbd#V{=BJV&-edNy$8oZOa4meVVq#<~*07V{`vt|A= z!rA+V;wOalPtML)L--{HkF@U*=^YfV#1l{M`^3u3u5)k-gYMTl&MLh(HPooyO6277w3R#DrnEpFFPqK=` zg}J2~6$!y&-L-W-I3rnu#Eq`sLsqkV7&81IfbfHO=EY3h!)3s@FyepTV3iD{UHMtO zIoK_naI~KV?upW9LpIiJUy(;2ZdG7miqgG^JTw*)&C?#Xm+ji$ws_T=#x9_BnnWt| z?IR$+P2rvpo4L#q-EBbeL_?vi-W6oc%etrzmLm+=d&4&rn-a=^Sz$}RI~iN?p02Sm zk<_41&HEYs1j19Xh=tVcl0;9nb%=L_fyl*MYR|&cO#td;Eq(HZ1-NqZfGrxh^A{s9 zZXVspkGF%GN+{e#@*GAmYj&D2KbnuRO}SclN5uUawu4?Zbl_N_g1kE}8`Fdw`1+b# z2je4u+HDBk*{0MvJ$!k-^Uk_jR|!CyLxFl^iu@Xc!t+$zJ*@?*2kXxHE|rI=(&yK! z`^hsIXkNs*I-OkzNDdc<_ZA9YFXXU}O!xy#q-)J-D@hWf{-R_MgSZ-TkX3uTLC30< zwhz;kdt4Yupwy-N_6sdN?G8KE6*HF%nPFdl^L6*5#WU$6c?Vk=_MaAMNi2AIJ<}@k zAQ&=gX&&-uYAunf2Na+ys%EONZ8EW0sPTZOd7_psNO-tFl{|V$QB}QYMj|aUOA_lM zla={V1}EqK9A&4eZ*?0s+nL+A*^5Rs*}F2kck+yTH)C&_1z^`j|NrPI5fliBw+@Ec zcY5~t|I#=$cvT(Grd_)6##Ea~?X2-;4cM0tH?R%c=DKAw zl%dKhuwo;Q>;dBE>1#!#nsQn#D+Odb<0j($+Le{c_Wi#?f7u3Wm(#}&knr`#Y)6qo zf3S%7Dc=s`hxo{Z==_rjHl1k_60Qgp3O{g%Zl3|%j^H)?XTN$JF z?M+SD9FDUyzF;k?L4zb!RmqY$J+vg@0$JtLI z6vE;;&88K()E|yA?h;mg$(B-PX71`!eFEMI7>v-n_#ZVAA@)}?Awrq;dq2Njg-Dl? z84jG++c?H&2vJi`*|@rP7gnxAr=0nr73jh*z_Bdpt+sapZ?w}o1S4HIdwBbe9F|mq z`-R}(X{a&wsdDw=hpei!k_$=2Us_HT8Sc#1%s+3EI0cQRYHWuG)fLcYzxS7wG~nwv zbxs!TnH6-#uf<}4l~$`AAL%$hM1=#mm^1GBV4{2JhsT>nU)xo;Ebhuhk{4 z5=7s|g2N7quU%EPln%}-a$+l*g-ctoxD-HxUjXlCkQmDyc-v9lX06}uG{P;9sW@{w z+P&s8e+b6l2@$8g(o(PmWSA8k9%BSaCISk2cy;6B`aIh5BTn;uzF!(HzM2c{|8;va zJssvXz0?WugL!qC9C!D*E&?I;UM-^ZKtF6x6Ci4NUPX~_@a?UY`wkuS%A#8>PK}kz z7Qg5~&T{tGhrX0H{>j>a~EI%Q9ocJ7TLnf_}!mN929QY$cT|j zy`wW1A}$_yOqm2wh4MR)7Kk5|F!bX0PZVlm@3_9fVU|JWVu2}W-!$Ox2qBn0tXfsl z2bbj7fxFkkn!R2pg=CJXcZhV ziULTu&{}`lS3bV22jvA^o6L=d0?zS3qeq%SJIW4PGY?gcgwTMUBJST-7(QFN_Eh3j ziz5T0uR1QXV*oLu9}a6Ms(HSTcJd;$DtxupuMu<0TV$D8`2mVu0E(u*RS%;5D)KV$b`y?ISag|ib(fXb{IwD>e$tR1{j06fc)5;_elE|J~+wJc^X@@8JWNGSZw^h=^U9J`MKZ!Q9$;)I5a?3mAQ@+(M zGLiU<*QDX`Shcth4XzQKA6NTWk1OLttk0$rC|GN}N8C^fW3L|?J<&JBNg-ZEQjztg zIX{%FiEAmyVqKsLHhx*;-#%nJftr05%|)(c%~6{;^o?4R@(iOJU9Re6Px-vuG@A6j zq{N%n%(?RSM1-Gy_F6D}_%f_S;!(6G#syO}_7>jsXXhqiwYvD;%+%ANKON=L4T2CH zHic_03+cGY<^M9BGlQ0eyBs&}(vAFn-Th*j=k8-PfS)o_B&c3tt&AJ?f>&;dhZRw~ zcJewZ_wnA&C5=l51?w=j>LdT{` zK^> z*5H6eJ87|t6RnTdh#an5hQ5kg9&dj}-YkY|Mi|%iB_NN7x^3(@p<3leF`+!nBFyoW z@!G;K!5I}6MBq@q%dAX$Bz|@SV9E8pta4&X)(4Z8{%0zwC2dV2#us89b=h-_nf+qf zv&+p*7%b!E4oO3@5Z(%%d8`bk#>LiRu5(u45kaNe6uVi9Go>dNKI>^r9d2_yFwDkK z5<}2%=T#4zGB8ws*YE>Bv^&sTleMP@b$vwW$&^e}sSTpm9ApQUK|GhH(wQ$b%>k`D zEQnglwOalHdc?kn&U0`i8I);UbR(zgT~E2KBvJyuk8dn!X(@U3xo$@t36vMnTHpmr zg$H^^p1x6@dX5|D8;e-45W9=i%OqbOcQ03E>ChnDZwwIK&Y~#8J=?M>95_<%D7eofnn+8WLOrfJqn#0Xcj<;}v5tf6t3)-34JHCNJjqD)f! zSyiSag&^M_eMh#WLNbhHYeo&%G^a~cx0o%p81;E_a?P)FT4rTi8@<{I((Mz+_fkqV z*qYiB=?Z7bY-O%0zIk0I{5BS_v=~AaKC`ELZ7-B4X^0&#c~?V;x!?UyTixr^(tQzgDl%89au1M4hFia zcoZPLOUJG4Fh!O};~OtaZ}b{-DWYw)my{t*z!e0sv#X5_?E7x;2<3Cm!XqO?*p8)& z!Y-`Nix$+XXnFcwJrD>nf5%=^s8}f`QbhS1HfcfK?grc`jI;C$eNk#o*dPDlTOW+@ zh|W_7!sO?h$R7+Dv@(B;TS>-hCrO*`Hd(G@NG~%_X0R1gHG_!^pWQF$r5z;j(Bi{N zq**Ehm2S~>dkwiF_5YzEFa?|-kx~G4q#?FX(I+f z-fxiJUh#M#toBru(E}?3?-CGWp|RT&Ml+Ig%ghapskKTVr<7 zaF1M<($eQ}-W-3CNM0K{yJ+h3eeM#>kh3V;$(BRE@dVZ(Nd~ku{6=)Mb%!+9E)eRv;6tfaC!KxVDbco5 z4tL5qk8tvj#vBgbbnn11G@8o4vVklZflbhggOGiSZ8eTdE6FI{S@j`Hn3@;vNrF2g+Max2rA8(AGZ8Ev#;Tbc~Mdq&Mz$no79^pCh50 zb9>baE=%Q^L$JQ&sa!X(ujOVUlbJ>=Hjr%jf95?gWUTv8ZS~R{(&8>5(kD<_?}Nny zf&|=OvtFOx7~7$uh^`j3T$d~05C62SoadZK=eofB`5VPlA{XS7gRoLctH|OI#%i~w;m;HjC zt@jeK`gw^#EYr1?Ek3x-K8WonIdq8I8Z19CPLAlqdl}u(t<5<;nuq!2j8SotB0YnN zgP|?V@*Jx2r)jGnEMbaqdP-TS-K>bT#EDU{N}!MHsVyxBP%t?;9z7! z`7K|>`sGRhPYS!Ss>Py#$2$vq!g1f#%K!`K{E(27bKTVQfIGh#sa3pTo^mHg8fTJo zPc9|h;#ULlYQ;vx_ve)>E=>ljxrIF9jr1CSDAh)J8bzmo5+ zc>Xt`x>6A`8WR?Ni}`C#{k_^RqSQf)iM`YLt0iNGfB^S{860$7qqEbF%PkCquQY&D z{xhIc4IhehI@|}R#*}Bhc^&p_#E| zDaT83;Zr43mag+ioU)?)VGP z{ayUPs7*lPL+^@vs_E(K$6$PY(1L_G*HpFxvh+bTnXbc4|Ne$OJK*7ucH=`%){GgU zD7KVD_$u_Ckr%i6i#gWP{;A{t4+-CjQk#;@f8tCe(I|4sixTg=JNG{!Sky4LTn?#_ zsw>~_tUEGMWBG%oGNhyNv1@xXl~1C@X&5uSa8U+ntcUFH&Gx~?hnr78UBNVh?4!+teRpT}0)PAE7_Nlvn8W27~FJ z1p?^W{g5mViVrfr>aB$riT^l=#YsT&0Cm<(9`&sj)(GYVDbP%W3NQPgYz|1X{zpx5 zD>N1661!_;jNI^ek>ief>t4MAOR6biE16jToqT>o!;G3ftjkADoOs1sR$0jEzyDt1 zVzO8VL;oD@R43|bM?WI1h~PyVbD9jfVARG!{i-TfVEqao8$CB-Vi3G}?k_-WGRsqE zKlr>r<(u>a=uZavAXK>G=(m@r_TQ#G_MfJGFdzeAZy+;9+*ieW7>0(*^+3&_WPyW; z*E}3>IDd+YTBSj)gBs@%P;rJbCIX+8apXu$?gi z+O|vVQndQhLfpI2gGYXTo~zMn!#>F!o|~129GS>u`k6wmbg^b{rd0_eB(2OW{#Km3 zPK=PedwRaD(4j7FoKt<49ln~yQ`~FeZrTP1#)i#zi3^Zvi~^_kklfi_`jHmkW#Z!Q z8Tn%-O&4PC(V?B`xf;3h%@ng?59X#$6obbpmoj%DnZ>}%ZlItJV>?k(k1YSv87-DN zMTDlRw|A#zsX;7wdQ{5V6krB3!X75mf zbu%+mz+O*{9hWjgY1g>vcc~7McbdmrZUE^~)(puh#yx?H(4{1z)j?VR{WH@ARXue! zAG@MA_y#k_3W%g6f@mr-v>E^-GF`(vh*}(*=a4v942!zJ{b#du&o2aU{@r(o0S7|QD1|Tm)POyo>l801JHA!FU(4#{~G6AIgUV__ri?F##IEM>#p)L+!k0 zBOnJ4Md2mWIHu_fO9tr|$ThuhP{6|VRo~b%`iqd60SES{W^>E;s|;G1GVu7F_8!3L zaq+ir->TA|wEK!m448+7$uYJV=<~RAOb*2tt8!;X$5hAC`~$-)qP+iM;mjl484OzB zd3^B-zP4jSvz2;Rf!O?3W z7p-e)Hy)(&oIO^GV#^YvO!r&hU|!ear(T?r=&|Kf!b(YBE0C4-lLXRU>DWBrgeQXO z`==|c9336|IuCPx8huils!6tUj}zWAM05G=?Up{e)sOozRrfrT+g8Hy8}xnl9v#rx z#@TRZx0`TfGOKiIuFR11)VXSqndL*K?KnY)X-7u8Pp=RdXVTajHwP^%rnNNqj9!!#~|S-K^aFqs%Ky z*{RaE1soV_FT@-U?Ub+`sjNz7rrwBlhFev6v%WP?cg;{f7^}vNRdz`UO7_^mPMucb zF6=kv-w-qF3OtrAdB;w5BwGj2AKbeDci;x~D$OZ~C-+-SC@uxH!EclVj%K5sBE_{8KODpXT*V0WMAP2FG2&$`3 zR#{s-)yAgPx}l-ii9xd5xkXl?k(%KIPV*|b6vw@)C&bsy3Z;9Rkp0D#_+;~Xqpglt zpVua((<3!?CutR(4V*0oissX=*gPn5#s@0ab3|>BgLu3$R@32y_Y$q0OT6jrjU`zC zR#!YKc%Y4;L1BmmD%iy|q5uTi)!T<*Jmm&rSB|kPwr|sQyM&NV*rmu|yG!`0O-Gc%)M( z_go8TEs@=pJ60~$S(d6iGW04VSGJi2 z0k#t3em((Fp%VD^cBDx_6Ef08pnqL^4@yw-^R`?aV#XV*cwxI|$)HkyEs%@$74^?K z&fxp)mtd-_gp%{tDAdd&jKfj0xp3okb11vIdB1bT*h}4(gN>=Um(*OcJ>}XZ@F?{e znmxs$i;hF@2OX|!p|S5HWpatse)V(1ccPJS^3!o4rj5yxlu1Jr7-7WR75wzDV19;k z&_|2VkI+oCXY)NYmp?v|^+dwpMt2qYOG8 zjFuNC>b(5RQZ$|l`h08B;Bz@uQ}dUHqK27*<*4j~R+E$%HiS8U|ME2+Z9{_;T3XM` z#Na3&8ZN@D)aS$e(=@o7EeHckSidINR`n$7caM-lh3|uZLWKFj=8dRSfGp%mp8r1x z{G+jd2x-<_K@bFyN+Km8nYE6=F#=xW%y&09H#f*8SFxkX*yPeLU2*}A7D2`7jC*2B8LWqsSOUq*bYb`|t(c79r2t{KmgAj-;p zFPJR9gk7FDXOuQ0&cRQ#Sivm!Hi2b?ywWH&2B4_{(?fps9K*(%|5=-Sn^n zZ(E72+bhJRns;?keFxI5(fcE>+ty1USG9*MH>Wv5<=!Ak9;_%?pE36?Ose0n__NK~ zEZFxH2qfre4~L`cU}m>XsAlO2yjbJ_4KeLLFU&1)k)YMM&J{2&MA109YLL%$MUiE( ze)USQgUsP1ziw0UP|4PnDQn8lv9}P7lKLi+S26nNfrAS99rYL5rhwwdDXN>Tdh}& zz;*N6`qAB=t^{Z1y*q@gwE;FB^%VfPpjF}t z0971*orRSJW4QICL5MB z2dwuN$k&oy`aS1$v4e-z2%u#p)g%>$Ybx1Pix};JN3IhO1u}_a22ybGf_gOCQ3>W8 zZiNHE(t5F;{v56a!x=IVk2)K0HaX)et@+kcWlAZ&mJm##QRh3b<=e3P&RT8tyw-9w zoX8B)wz`wz8IQb@rM#zFgRv4q`J@#74k+tFNX0OAH0rcWzC}lE&5WW;*c#Ynm5@vo zSC#CdGXgcc>=}W&mwP9>BLr5~jBB~eI)VQ1)%BPBX$iNp@7#aK975fbIK&!SHB;^= ze5s2;r}>0Y3PtXw2dO_&e#j~htlf)$S9HK(5&Mx5Jqyhx}9oLgJ}NFTDyc;E8^!;T`hrJwXQ1O-@%wZLmD z&LnUq^lIcVI?IouuCttVhztMJXDTs7!Q6(z|iP=#=b|LhyOLSgD zXn8QbOMvKzg5UpAP@`RG{T}rggKNZt-xxc}V0-=RH$yMLMRIte`GqT7o>FYynYh@B z)LCpOm%y;il?F$VV)>j4=&%^OPJ7-3K?RjRR6SaY@1C2vlT?66q1_b4Xx38LH1D6L zaYuZ>t;Pbv7DF8ug3Y$BhjMSb>4-;LUBSy|PXhRyVukrt4PVH>=7y{jgM4ekY$YOB z#c5VVq0!_CV4zH6JxtK)icyBHF{vJBE*eo*aF@XlH>siOz-#T1LPSJlw`#&)b2u*c zzNK;%v*0~{*M2e6Xo7#Ba)BH0CNi*i^Wz8eAXrBIF;8^nKdex z{#KV0c7tN1B|bC97@E`2m6R!m&zwoOufY@*%wrobW%%9XrQ5~9N{1?&Fra*qrH;%d z4!*3z-e1m=x(vvQ$e9AP8Zh<2B63l=jlgP}q44>X4s_~ejl(m$QuZ4H=zR4%UsQN` z76;!us-_a@mj+NoYsoXT;Z?W&qKwHLo1Q~#G1K-k_W;+AZ_gG+#h=5L<_G{{Ymj+g zystdjg(+$gyy^)E3uQnDCx{fB(kwYAU0;9gZI!Fxki2`J_h67w;zI&Y*UU74>qG2s z<;6+U3|Hne@c3rZ-ZKUj6m;piV>`P$_}MvRs~%Q>1(zVphYrD(GTy_31gv6%#Vu4J ziwD7B=`_CEo4k}|id)ZL47`R^G`5XhJS9(8+PrqxALxj+i{kCwVJB*~H#3(b8Fety zrx00}>Pva+?42UvS7I;r?B){=etzNfg6W-W;?kqf568LPY@i6ZxP!njFp9)k9hqxi zJ9#u}CO?-bjr@B^aEI+q%EH}Xm+O!fw5?Ik*E~EmmYzfnruz4DeJ{A{!s~Zx+ zrQg(q+5ec_TP?~2${L+j!p=BGq#kY)Z?7A^>(UZWV_Uojr?fy(E^XA(B&=+6akePB zX7S)XY+|ZWkmos647w{(GMn(Ie2Fob%$(CDgqgGcW_U3L+FM3z@zRsW+@s~*b@%`- z)SGc~`cQ*)SGwT?OZg07&NQ%}f8d-QvosRG3MGk4i&;2w6uu~M?0CY-2>fOY&Y;{~ zakwO0KP6?&!Y#Qt8oxUO8+3Gey5=!u+8KhvoJ**_CEXfSex|D9de4r(Pa^ zbY=7?Kbk)(an7Cm-XH7sUR!~0%|C$?m7sM;VDCNA^SIn&8u7~mRBDzEq!RkQdr7RJ z4tH!F$B815$l9$cpu<8EtdYKP@1jv6BILQ5nc9c#EK1L$O>(5qY6@g!7JgWRX(VUs zD~9m!*@E5}6p*jO2l(XvK<^`sde}~RJ)d+Z0O=@fKo^z7{mo8B| zn)40nJo+V@>@YP72xoE^j2ZT{3tEhEk!+WC^gh>IU#!KK@uK>j&g#az#tr-ZP|4pQ z9+G~l7jLSxY$RW!UpBhd=&)^?N0KZbB8HU|IV?1bbl8@KGW3p}QlU~ETTmvChw#JN-a+c^P(Wud zZY#?=_tfIIg@{Or5rm`z;5}Qj4J!)B+UclL@=#_cE(UJi2}dS(%B)XT){goA$!Gjg z;9rWGb?#X$)Ohi*uMAwZw8fym_l|d8iI1wU0Xy0cS8I4RVgb+9*r0!swe<=ArOhW4Mh;4|dUk(l zNNXLxs(lhp^yzbx=1mCC_GvPEVr$cPmVciT{(rfN#J}8H0wt3uLjCUo&Hsed|Gb~X zk3j Date: Thu, 17 Sep 2015 13:19:38 +0200 Subject: [PATCH 02/14] Remove double png. --- doc/integration/gmail_action_buttons_for_gitlab.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/integration/gmail_action_buttons_for_gitlab.md b/doc/integration/gmail_action_buttons_for_gitlab.md index 21f34db6ed5..de45f25ad62 100644 --- a/doc/integration/gmail_action_buttons_for_gitlab.md +++ b/doc/integration/gmail_action_buttons_for_gitlab.md @@ -4,7 +4,7 @@ GitLab supports [Google actions in email](https://developers.google.com/gmail/ma If correctly setup, emails that require an action will be marked in Gmail. -![gmail_actions_button.png](gmail_actions_button.png.png) +![gmail_actions_button.png](gmail_actions_button.png) To get this functioning, you need to be registered with Google. [See how to register with Google in this document.](https://developers.google.com/gmail/markup/registering-with-google) From 4e33b47a50b6fa2585ece0a3b199556623978e24 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Thu, 17 Sep 2015 17:08:10 +0200 Subject: [PATCH 03/14] Update the link in integration readme. --- doc/integration/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/integration/README.md b/doc/integration/README.md index 6d856951d4e..eff39a626ae 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -10,7 +10,7 @@ See the documentation below for details on how to configure these services. - [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider - [Slack](slack.md) Integrate with the Slack chat service - [OAuth2 provider](oauth_provider.md) OAuth2 application creation -- [Gmail](gitlab_buttons_in_gmail.md) Adds GitLab actions to messages +- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html) and [advanced Jenkins support](http://doc.gitlab.com/ee/integration/jenkins.html). From a19a0b431c05d7e17aca61f2e04abfe6fb5ac5b2 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 17 Sep 2015 23:54:52 +0200 Subject: [PATCH 04/14] Fix 500 when showing project page and there's no CI project present --- app/models/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 6e2f9645661..1a5c1c978c9 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -428,7 +428,7 @@ class Project < ActiveRecord::Base end def gitlab_ci? - gitlab_ci_service && gitlab_ci_service.active + gitlab_ci_service && gitlab_ci_service.active && gitlab_ci_project.present? end def ci_services From 3377808193e8571b028fd05f009a7d1089dcc916 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Sun, 20 Sep 2015 18:18:39 +0200 Subject: [PATCH 05/14] Fix reply by email for comments on a specific line in a diff/commit. --- app/mailers/emails/notes.rb | 6 +++--- app/models/sent_notification.rb | 14 ++++++++++++-- ...920161119_add_line_code_to_sent_notification.rb | 5 +++++ db/schema.rb | 3 ++- lib/gitlab/email/receiver.rb | 3 ++- 5 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20150920161119_add_line_code_to_sent_notification.rb diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb index 63d4aca61af..87ba94a583d 100644 --- a/app/mailers/emails/notes.rb +++ b/app/mailers/emails/notes.rb @@ -12,7 +12,7 @@ module Emails to: recipient(recipient_id), subject: subject("#{@commit.title} (#{@commit.short_id})")) - SentNotification.record(@commit, recipient_id, reply_key) + SentNotification.record_note(@note, recipient_id, reply_key) end def note_issue_email(recipient_id, note_id) @@ -27,7 +27,7 @@ module Emails to: recipient(recipient_id), subject: subject("#{@issue.title} (##{@issue.iid})")) - SentNotification.record(@issue, recipient_id, reply_key) + SentNotification.record_note(@note, recipient_id, reply_key) end def note_merge_request_email(recipient_id, note_id) @@ -43,7 +43,7 @@ module Emails to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - SentNotification.record(@merge_request, recipient_id, reply_key) + SentNotification.record_note(@note, recipient_id, reply_key) end end end diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb index 33b113a2a27..03425389dd3 100644 --- a/app/models/sent_notification.rb +++ b/app/models/sent_notification.rb @@ -8,6 +8,7 @@ # noteable_type :string(255) # recipient_id :integer # commit_id :string(255) +# line_code :string(255) # reply_key :string(255) not null # @@ -21,13 +22,14 @@ class SentNotification < ActiveRecord::Base validates :noteable_id, presence: true, unless: :for_commit? validates :commit_id, presence: true, if: :for_commit? + validates :line_code, format: { with: /\A[a-z0-9]+_\d+_\d+\Z/ }, allow_blank: true class << self def for(reply_key) find_by(reply_key: reply_key) end - def record(noteable, recipient_id, reply_key) + def record(noteable, recipient_id, reply_key, params = {}) return unless reply_key noteable_id = nil @@ -38,7 +40,7 @@ class SentNotification < ActiveRecord::Base noteable_id = noteable.id end - create( + params.reverse_merge!( project: noteable.project, noteable_type: noteable.class.name, noteable_id: noteable_id, @@ -46,6 +48,14 @@ class SentNotification < ActiveRecord::Base recipient_id: recipient_id, reply_key: reply_key ) + + create(params) + end + + def record_note(note, recipient_id, reply_key, params = {}) + params[:line_code] = note.line_code + + record(note.noteable, recipient_id, reply_key, params) end end diff --git a/db/migrate/20150920161119_add_line_code_to_sent_notification.rb b/db/migrate/20150920161119_add_line_code_to_sent_notification.rb new file mode 100644 index 00000000000..d9af4e71751 --- /dev/null +++ b/db/migrate/20150920161119_add_line_code_to_sent_notification.rb @@ -0,0 +1,5 @@ +class AddLineCodeToSentNotification < ActiveRecord::Migration + def change + add_column :sent_notifications, :line_code, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index b8eb9d26779..01ccda7a75e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150920010715) do +ActiveRecord::Schema.define(version: 20150920161119) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -623,6 +623,7 @@ ActiveRecord::Schema.define(version: 20150920010715) do t.integer "recipient_id" t.string "commit_id" t.string "reply_key", null: false + t.string "line_code" end add_index "sent_notifications", ["reply_key"], name: "index_sent_notifications_on_reply_key", unique: true, using: :btree diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb index 355fbd27898..341b557858f 100644 --- a/lib/gitlab/email/receiver.rb +++ b/lib/gitlab/email/receiver.rb @@ -98,7 +98,8 @@ module Gitlab note: reply, noteable_type: sent_notification.noteable_type, noteable_id: sent_notification.noteable_id, - commit_id: sent_notification.commit_id + commit_id: sent_notification.commit_id, + line_code: sent_notification.line_code ).execute end end From 3b39b648d2f0545f9d3dbd1680f8e9e977893792 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 18 Sep 2015 11:05:27 -0700 Subject: [PATCH 06/14] Fix Markdown links not showing up in dashboard activity feed Closes #2586 --- CHANGELOG | 1 + app/helpers/gitlab_markdown_helper.rb | 4 ++-- spec/helpers/gitlab_markdown_helper_spec.rb | 11 +++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a1b17e58156..cb3794f7cb6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.0.0 (unreleased) + - Fix Markdown links not showing up in dashboard activity feed (Stan Hu) - Fix HTML link that was improperly escaped in new user e-mail (Stan Hu) - Fix broken sort in merge request API (Stan Hu) - Bump rouge to 1.10.1 to remove warning noise and fix other syntax highlighting bugs (Stan Hu) diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 1ebfd92f119..78bf25f55e7 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -45,7 +45,7 @@ module GitlabMarkdownHelper end def markdown(text, context = {}) - context.merge!( + context.reverse_merge!( current_user: current_user, path: @path, project: @project, @@ -59,7 +59,7 @@ module GitlabMarkdownHelper # TODO (rspeicher): Remove all usages of this helper and just call `markdown` # with a custom pipeline depending on the content being rendered def gfm(text, options = {}) - options.merge!( + options.reverse_merge!( current_user: current_user, path: @path, project: @project, diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 5639b3db913..b8101ae77ec 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -38,6 +38,17 @@ describe GitlabMarkdownHelper do expect(markdown(actual)).to match(expected) end end + + describe "override default project" do + let(:actual) { issue.to_reference } + let(:second_project) { create(:project) } + let(:second_issue) { create(:issue, project: second_project) } + + it 'should link to the issue' do + expected = namespace_project_issue_path(second_project.namespace, second_project, second_issue) + expect(markdown(actual, project: second_project)).to match(expected) + end + end end describe '#link_to_gfm' do From 71a5d5a036a34a9b2cd257e6e6a105095ec89241 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 18 Sep 2015 17:28:09 +0200 Subject: [PATCH 07/14] Fail builds if no .gitlab-ci.yml is found --- CHANGELOG | 1 + app/models/ci/commit.rb | 2 +- spec/services/ci/create_commit_service_spec.rb | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index a1b17e58156..4733b28e50d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -42,6 +42,7 @@ v 8.0.0 (unreleased) - Retrieving oauth token with LDAP credentials - Load Application settings from running database unless env var USE_DB=false - Added Drone CI integration (Kirill Zaitsev) + - Fail builds if no .gitlab-ci.yml is found - Refactored service API and added automatically service docs generator (Kirill Zaitsev) - Added web_url key project hook_attrs (Kirill Zaitsev) - Add ability to get user information by ID of an SSH key via the API diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index 23cd47dfe37..f102d0a7679 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -236,7 +236,7 @@ module Ci end def config_processor - @config_processor ||= Ci::GitlabCiYamlProcessor.new(push_data[:ci_yaml_file] || project.generated_yaml_config) + @config_processor ||= Ci::GitlabCiYamlProcessor.new(push_data[:ci_yaml_file]) rescue Ci::GitlabCiYamlProcessor::ValidationError => e save_yaml_error(e.message) nil diff --git a/spec/services/ci/create_commit_service_spec.rb b/spec/services/ci/create_commit_service_spec.rb index 38d9943765a..981caaa51e1 100644 --- a/spec/services/ci/create_commit_service_spec.rb +++ b/spec/services/ci/create_commit_service_spec.rb @@ -50,6 +50,19 @@ module Ci end end + it 'fails commits without .gitlab-ci.yml' do + result = service.execute(project, + ref: 'refs/heads/0_1', + before: '00000000', + after: '31das312', + ci_yaml_file: config, + commits: [ { message: 'Message'} ] + ) + expect(result).to be_persisted + expect(result.builds.any?).to be_falsey + expect(result.status).to eq('failed') + end + describe :ci_skip? do it "skips builds creation if there is [ci skip] tag in commit message" do commits = [{ message: "some message[ci skip]" }] From 8671343b65810b983d2c8ea37b3123abd620c093 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 18 Sep 2015 17:51:56 +0200 Subject: [PATCH 08/14] Rubocop fix --- spec/services/ci/create_commit_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/ci/create_commit_service_spec.rb b/spec/services/ci/create_commit_service_spec.rb index 981caaa51e1..84ab0a615dd 100644 --- a/spec/services/ci/create_commit_service_spec.rb +++ b/spec/services/ci/create_commit_service_spec.rb @@ -56,7 +56,7 @@ module Ci before: '00000000', after: '31das312', ci_yaml_file: config, - commits: [ { message: 'Message'} ] + commits: [ { message: 'Message' } ] ) expect(result).to be_persisted expect(result.builds.any?).to be_falsey From 45a105b127eb5ee4f9ebc99f3cf46d582de3601c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 20 Sep 2015 22:12:45 +0200 Subject: [PATCH 09/14] Use pure SQL queries to migrate CI tags --- lib/ci/migrate/tags.rb | 58 ++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/lib/ci/migrate/tags.rb b/lib/ci/migrate/tags.rb index 125a535e9a9..2bbd253f8de 100644 --- a/lib/ci/migrate/tags.rb +++ b/lib/ci/migrate/tags.rb @@ -4,45 +4,37 @@ module Ci module Migrate class Tags def restore - puts 'Migrating tags for Runners... ' - list_objects('Runner').each do |id| - putc '.' - runner = Ci::Runner.find_by_id(id) - if runner - tags = list_tags('Runner', id) - runner.update_attributes(tag_list: tags) - end - end - puts '' + ActiveRecord::Base.transaction do + puts 'Inserting tags...' + connection.execute( + 'INSERT INTO tags (name) ' + + 'SELECT ci_tags.name FROM ci_tags ' + + 'WHERE (SELECT COUNT(*) FROM tags WHERE tags.name = ci_tags.name)=0' + ) - puts 'Migrating tags for Builds... ' - list_objects('Build').each do |id| - putc '.' - build = Ci::Build.find_by_id(id) - if build - tags = list_tags('Build', id) - build.update_attributes(tag_list: tags) - end + puts 'Deleting old records' + connection.execute "DELETE FROM taggings WHERE context = 'tags' AND taggable_type LIKE 'Ci::%'" + + puts 'Inserting tags...' + connection.execute( + 'INSERT INTO taggings (taggable_type, taggable_id, tag_id, context) ' + + "SELECT CONCAT('Ci::', ci_taggings.taggable_type), ci_taggings.taggable_id, tags.id, 'tags' FROM ci_taggings " + + 'JOIN ci_tags ON ci_tags.id = ci_taggings.tag_id ' + + 'JOIN tags ON tags.name = ci_tags.name ' + ) + + puts 'Resetting counters... ' + connection.execute( + 'UPDATE tags SET ' + + 'taggings_count = (SELECT COUNT(*) FROM taggings WHERE tags.id = taggings.tag_id)' + ) end - puts '' end protected - def list_objects(type) - ids = ActiveRecord::Base.connection.select_all( - "select distinct taggable_id from ci_taggings where taggable_type = #{ActiveRecord::Base::sanitize(type)}" - ) - ids.map { |id| id['taggable_id'] } - end - - def list_tags(type, id) - tags = ActiveRecord::Base.connection.select_all( - 'select ci_tags.name from ci_tags ' + - 'join ci_taggings on ci_tags.id = ci_taggings.tag_id ' + - "where taggable_type = #{ActiveRecord::Base::sanitize(type)} and taggable_id = #{ActiveRecord::Base::sanitize(id)} and context = 'tags'" - ) - tags.map { |tag| tag['name'] } + def connection + ActiveRecord::Base.connection end end end From 265ad515c697b9d50c4fd3e4bb360689a369a190 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 20 Sep 2015 23:20:51 +0200 Subject: [PATCH 10/14] Create CI migration task on GitLab side --- lib/ci/migrate/builds.rb | 29 +++++++++++++++ lib/ci/migrate/database.rb | 42 +++++++++++----------- lib/ci/migrate/manager.rb | 72 ++++++++++++++++++++++++++++++++++++++ lib/tasks/ci/migrate.rake | 49 ++++++++++++++++---------- 4 files changed, 152 insertions(+), 40 deletions(-) create mode 100644 lib/ci/migrate/builds.rb create mode 100644 lib/ci/migrate/manager.rb diff --git a/lib/ci/migrate/builds.rb b/lib/ci/migrate/builds.rb new file mode 100644 index 00000000000..fdc143cfad5 --- /dev/null +++ b/lib/ci/migrate/builds.rb @@ -0,0 +1,29 @@ +module Ci + module Migrate + class Builds + attr_reader :app_builds_dir, :backup_builds_tarball, :backup_dir + + def initialize + @app_builds_dir = Settings.gitlab_ci.builds_path + @backup_dir = Gitlab.config.backup.path + @backup_builds_tarball = File.join(backup_dir, 'builds/builds.tar.gz') + end + + def restore + backup_existing_builds_dir + + FileUtils.mkdir_p(app_builds_dir, mode: 0700) + unless system('tar', '-C', app_builds_dir, '-zxvf', backup_builds_tarball) + abort 'Restore failed'.red + end + end + + def backup_existing_builds_dir + timestamped_builds_path = File.join(app_builds_dir, '..', "builds.#{Time.now.to_i}") + if File.exists?(app_builds_dir) + FileUtils.mv(app_builds_dir, File.expand_path(timestamped_builds_path)) + end + end + end + end +end diff --git a/lib/ci/migrate/database.rb b/lib/ci/migrate/database.rb index 74f592dcaea..bf9b80f1f62 100644 --- a/lib/ci/migrate/database.rb +++ b/lib/ci/migrate/database.rb @@ -9,32 +9,32 @@ module Ci @config = YAML.load_file(File.join(Rails.root, 'config', 'database.yml'))[Rails.env] end - def restore(ci_dump) - puts 'Deleting all CI related data ... ' - truncate_ci_tables + def restore + decompress_rd, decompress_wr = IO.pipe + decompress_pid = spawn(*%W(gzip -cd), out: decompress_wr, in: db_file_name) + decompress_wr.close - puts 'Restoring CI data ... ' - case config["adapter"] - when /^mysql/ then - print "Restoring MySQL database #{config['database']} ... " - # Workaround warnings from MySQL 5.6 about passwords on cmd line - ENV['MYSQL_PWD'] = config["password"].to_s if config["password"] - system('mysql', *mysql_args, config['database'], in: ci_dump) - when "postgresql" then - puts "Restoring PostgreSQL database #{config['database']} ... " - pg_env - system('psql', config['database'], '-f', ci_dump) - end + restore_pid = case config["adapter"] + when /^mysql/ then + $progress.print "Restoring MySQL database #{config['database']} ... " + # Workaround warnings from MySQL 5.6 about passwords on cmd line + ENV['MYSQL_PWD'] = config["password"].to_s if config["password"] + spawn('mysql', *mysql_args, config['database'], in: decompress_rd) + when "postgresql" then + $progress.print "Restoring PostgreSQL database #{config['database']} ... " + pg_env + spawn('psql', config['database'], in: decompress_rd) + end + decompress_rd.close + + success = [decompress_pid, restore_pid].all? { |pid| Process.waitpid(pid); $?.success? } + abort 'Restore failed' unless success end protected - def truncate_ci_tables - c = ActiveRecord::Base.connection - c.tables.select { |t| t.start_with?('ci_') }.each do |table| - puts "Deleting data from #{table}..." - c.execute("DELETE FROM #{table}") - end + def db_file_name + File.join(Gitlab.config.backup.path, 'db', 'database.sql.gz') end def mysql_args diff --git a/lib/ci/migrate/manager.rb b/lib/ci/migrate/manager.rb new file mode 100644 index 00000000000..9405397031c --- /dev/null +++ b/lib/ci/migrate/manager.rb @@ -0,0 +1,72 @@ +module Ci + module Migrate + class Manager + VERSION = '8.0.0.pre' + + def cleanup + $progress.print "Deleting tmp directories ... " + + backup_contents.each do |dir| + next unless File.exist?(File.join(Gitlab.config.backup.path, dir)) + + if FileUtils.rm_rf(File.join(Gitlab.config.backup.path, dir)) + $progress.puts "done".green + else + puts "deleting tmp directory '#{dir}' failed".red + abort 'Backup failed' + end + end + end + + def unpack + Dir.chdir(Gitlab.config.backup.path) + + # check for existing backups in the backup dir + file_list = Dir.glob("*_gitlab_ci_backup.tar").each.map { |f| f.split(/_/).first.to_i } + puts "no backups found" if file_list.count == 0 + + if file_list.count > 1 && ENV["BACKUP"].nil? + puts "Found more than one backup, please specify which one you want to restore:" + puts "rake gitlab:backup:restore BACKUP=timestamp_of_backup" + exit 1 + end + + tar_file = ENV["BACKUP"].nil? ? File.join("#{file_list.first}_gitlab_ci_backup.tar") : File.join(ENV["BACKUP"] + "_gitlab_ci_backup.tar") + + unless File.exists?(tar_file) + puts "The specified CI backup doesn't exist!" + exit 1 + end + + $progress.print "Unpacking backup ... " + + unless Kernel.system(*%W(tar -xf #{tar_file})) + puts "unpacking backup failed".red + exit 1 + else + $progress.puts "done".green + end + + ENV["VERSION"] = "#{settings[:db_version]}" if settings[:db_version].to_i > 0 + + # restoring mismatching backups can lead to unexpected problems + if settings[:gitlab_version] != VERSION + puts "GitLab CI version mismatch:".red + puts " Your current GitLab CI version (#{VERSION}) differs from the GitLab CI (#{settings[:gitlab_version]}) version in the backup!".red + exit 1 + end + end + + private + + def backup_contents + ["db", "builds", "backup_information.yml"] + end + + def settings + @settings ||= YAML.load_file("backup_information.yml") + end + end + end +end + diff --git a/lib/tasks/ci/migrate.rake b/lib/tasks/ci/migrate.rake index e7d41874a11..3507871fcb0 100644 --- a/lib/tasks/ci/migrate.rake +++ b/lib/tasks/ci/migrate.rake @@ -1,40 +1,49 @@ namespace :ci do desc 'GitLab | Import and migrate CI database' task migrate: :environment do + warn_user_is_not_gitlab + configure_cron_mode + unless ENV['force'] == 'yes' - puts "This will truncate all CI tables and restore it from provided backup." - puts "You will lose any previous CI data stored in the database." + puts 'This will remove all CI related data and restore it from the provided backup.' ask_to_continue - puts "" + puts '' end - Rake::Task["ci:migrate:db"].invoke - Rake::Task["ci:migrate:autoincrements"].invoke - Rake::Task["ci:migrate:tags"].invoke - Rake::Task["ci:migrate:services"].invoke + migrate = Ci::Migrate::Manager.new + migrate.unpack + + Rake::Task['ci:migrate:db'].invoke + Rake::Task['ci:migrate:builds'].invoke + Rake::Task['ci:migrate:tags'].invoke + Rake::Task['ci:migrate:services'].invoke + + migrate.cleanup end namespace :migrate do desc 'GitLab | Import CI database' task db: :environment do - if ENV["CI_DUMP"].nil? - puts "No CI SQL dump specified:" - puts "rake gitlab:backup:restore CI_DUMP=ci_dump.sql" - exit 1 - end + configure_cron_mode + $progress.puts 'Restoring database ... '.blue + Ci::Migrate::Database.new.restore + $progress.puts 'done'.green + end - ci_dump = ENV["CI_DUMP"] - unless File.exists?(ci_dump) - puts "The specified sql dump doesn't exist!" - exit 1 - end - - ::Ci::Migrate::Database.new.restore(ci_dump) + desc 'GitLab | Import CI builds' + task builds: :environment do + configure_cron_mode + $progress.puts 'Restoring builds ... '.blue + Ci::Migrate::Builds.new.restore + $progress.puts 'done'.green end desc 'GitLab | Migrate CI tags' task tags: :environment do + configure_cron_mode + $progress.puts 'Migrating tags ... '.blue ::Ci::Migrate::Tags.new.restore + $progress.puts 'done'.green end desc 'GitLab | Migrate CI auto-increments' @@ -56,8 +65,10 @@ namespace :ci do desc 'GitLab | Migrate CI services' task services: :environment do + $progress.puts 'Migrating services ... '.blue c = ActiveRecord::Base.connection c.execute("UPDATE ci_services SET type=CONCAT('Ci::', type) WHERE type NOT LIKE 'Ci::%'") + $progress.puts 'done'.green end end end From 500e277a8326b345854a5fc3114c1163826c1b4a Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 21 Sep 2015 00:13:58 +0200 Subject: [PATCH 11/14] Change notices during migrating --- lib/ci/migrate/tags.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ci/migrate/tags.rb b/lib/ci/migrate/tags.rb index 2bbd253f8de..2e4872f0716 100644 --- a/lib/ci/migrate/tags.rb +++ b/lib/ci/migrate/tags.rb @@ -12,10 +12,10 @@ module Ci 'WHERE (SELECT COUNT(*) FROM tags WHERE tags.name = ci_tags.name)=0' ) - puts 'Deleting old records' + puts 'Deleting old taggings...' connection.execute "DELETE FROM taggings WHERE context = 'tags' AND taggable_type LIKE 'Ci::%'" - puts 'Inserting tags...' + puts 'Inserting taggings...' connection.execute( 'INSERT INTO taggings (taggable_type, taggable_id, tag_id, context) ' + "SELECT CONCAT('Ci::', ci_taggings.taggable_type), ci_taggings.taggable_id, tags.id, 'tags' FROM ci_taggings " + From 098c1982713f3a4075efd6f27ab6326c75fc20ea Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 21 Sep 2015 00:14:07 +0200 Subject: [PATCH 12/14] Disable CI for time of migration --- lib/tasks/ci/migrate.rake | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/tasks/ci/migrate.rake b/lib/tasks/ci/migrate.rake index 3507871fcb0..1de664c85e1 100644 --- a/lib/tasks/ci/migrate.rake +++ b/lib/tasks/ci/migrate.rake @@ -10,6 +10,10 @@ namespace :ci do puts '' end + # disable CI for time of migration + enable_ci(false) + + # unpack archives migrate = Ci::Migrate::Manager.new migrate.unpack @@ -18,6 +22,9 @@ namespace :ci do Rake::Task['ci:migrate:tags'].invoke Rake::Task['ci:migrate:services'].invoke + # enable CI for time of migration + enable_ci(true) + migrate.cleanup end @@ -71,4 +78,10 @@ namespace :ci do $progress.puts 'done'.green end end + + def enable_ci(enabled) + settings = ApplicationSetting.current || ApplicationSetting.create_from_defaults + settings.ci_enabled = enabled + settings.save! + end end From b2a90216858160840fdfbe7a221c317a6c073f22 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 21 Sep 2015 00:16:51 +0200 Subject: [PATCH 13/14] Change wording --- app/views/admin/application_settings/_form.html.haml | 2 +- app/views/ci/projects/disabled.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 1476e29524c..143cd10c543 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -131,7 +131,7 @@ .checkbox = f.label :ci_enabled do = f.check_box :ci_enabled - Enable Continuous Integration + Disable to prevent CI usage until rake ci:migrate is run (8.0 only) .form-actions = f.submit 'Save', class: 'btn btn-primary' diff --git a/app/views/ci/projects/disabled.html.haml b/app/views/ci/projects/disabled.html.haml index 95276d894ed..83b0d8329e1 100644 --- a/app/views/ci/projects/disabled.html.haml +++ b/app/views/ci/projects/disabled.html.haml @@ -1 +1 @@ -Continuous Integration has been disabled. Please ask your administrator to enable it. +Continuous Integration has been disabled for time of the migration. From a37e591e7414f51ca9076e966c724030225528db Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 21 Sep 2015 10:07:53 +0200 Subject: [PATCH 14/14] Use INSERT INTO to insert tags --- lib/ci/migrate/tags.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/ci/migrate/tags.rb b/lib/ci/migrate/tags.rb index 2e4872f0716..97e043ece27 100644 --- a/lib/ci/migrate/tags.rb +++ b/lib/ci/migrate/tags.rb @@ -4,14 +4,15 @@ module Ci module Migrate class Tags def restore - ActiveRecord::Base.transaction do - puts 'Inserting tags...' - connection.execute( - 'INSERT INTO tags (name) ' + - 'SELECT ci_tags.name FROM ci_tags ' + - 'WHERE (SELECT COUNT(*) FROM tags WHERE tags.name = ci_tags.name)=0' - ) + puts 'Inserting tags...' + connection.select_all('SELECT ci_tags.name FROM ci_tags').each do |tag| + begin + connection.execute("INSERT INTO tags (name) VALUES(#{ActiveRecord::Base::sanitize(tag['name'])})") + rescue ActiveRecord::RecordNotUnique + end + end + ActiveRecord::Base.transaction do puts 'Deleting old taggings...' connection.execute "DELETE FROM taggings WHERE context = 'tags' AND taggable_type LIKE 'Ci::%'"