From c8a4d202c99c772822a2b9b09fa6da2c90b2ae81 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 26 Sep 2017 09:51:24 +0200 Subject: [PATCH] favicon uploader generating ci status favicons --- Gemfile | 1 + Gemfile.lock | 2 + .../overlays/favicon_status_canceled.png | Bin 0 -> 864 bytes .../overlays/favicon_status_created.png | Bin 0 -> 889 bytes .../overlays/favicon_status_failed.png | Bin 0 -> 1015 bytes .../overlays/favicon_status_manual.png | Bin 0 -> 1067 bytes .../overlays/favicon_status_not_found.png | Bin 0 -> 945 bytes .../overlays/favicon_status_pending.png | Bin 0 -> 919 bytes .../overlays/favicon_status_running.png | Bin 0 -> 1077 bytes .../overlays/favicon_status_skipped.png | Bin 0 -> 923 bytes .../overlays/favicon_status_success.png | Bin 0 -> 1044 bytes .../overlays/favicon_status_warning.png | Bin 0 -> 830 bytes app/uploaders/favicon_uploader.rb | 44 ++++++++++++++++++ spec/uploaders/favicon_uploader_spec.rb | 38 +++++++++++++++ 14 files changed, 85 insertions(+) create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_canceled.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_created.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_failed.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_manual.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_not_found.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_pending.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_running.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_skipped.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_success.png create mode 100644 app/assets/images/ci_favicons/overlays/favicon_status_warning.png create mode 100644 app/uploaders/favicon_uploader.rb create mode 100644 spec/uploaders/favicon_uploader_spec.rb diff --git a/Gemfile b/Gemfile index 90fa659fe78..b508fb17742 100644 --- a/Gemfile +++ b/Gemfile @@ -104,6 +104,7 @@ gem 'hamlit', '~> 2.6.1' # Files attachments gem 'carrierwave', '~> 1.2' +gem 'mini_magick' # Drag and Drop UI gem 'dropzonejs-rails', '~> 0.7.1' diff --git a/Gemfile.lock b/Gemfile.lock index 2daaa3b516e..7437b6e7898 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -494,6 +494,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mimemagic (0.3.0) + mini_magick (4.8.0) mini_mime (1.0.0) mini_portile2 (2.3.0) minitest (5.7.0) @@ -1078,6 +1079,7 @@ DEPENDENCIES loofah (~> 2.2) mail_room (~> 0.9.1) method_source (~> 0.8) + mini_magick minitest (~> 5.7.0) mousetrap-rails (~> 1.4.6) mysql2 (~> 0.4.10) diff --git a/app/assets/images/ci_favicons/overlays/favicon_status_canceled.png b/app/assets/images/ci_favicons/overlays/favicon_status_canceled.png new file mode 100644 index 0000000000000000000000000000000000000000..8adaa9c600bb4ee553c874000c3a448d44109521 GIT binary patch literal 864 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 literal 0 HcmV?d00001 diff --git a/app/assets/images/ci_favicons/overlays/favicon_status_not_found.png b/app/assets/images/ci_favicons/overlays/favicon_status_not_found.png new file mode 100644 index 0000000000000000000000000000000000000000..df3049315a9be0e0271f4926450cc211348e40b6 GIT binary patch literal 945 zcmV;i15W&jP)Px&Ye_^wR9Fe^R!d78Q4~It@tM>h2BO4;#3#Xp76wd{AJC1(Z8u%?C)jRVD7Y)7 zYuD{g?5_3~_^5?0iim;+u_TxXh6GWg$(VlMG$ZqH?4)+r9Jo&IJ@=mP-0z%wjv_5- zG0hSY2I>sj8Z+*XuEiP#_SDZ_NwmUJd|A+1S{4itjuC zG|rts054%}3C=AflgX@0?_BUZ-`w1c*J`yTfNEV`U3xScReO7TrL(hB047&gS8{fC zCdFb=PEJm)Ayu&QDwRsTvtqbBwko}TudS^;f^G!{!|`}r?eFjR+G?y6g?u zxNuNLMnQlNdRjuEkYK+Y9Ua*m0R1vFG^9e8KrTIQvuW>`@SQ`gA=_PH3x~r7-30CF=`pNu zjgFBWr$izVI?IV3ASy)NYf3fq@(FQmG_`Lc!P;3

5r6I_cFH#c04D>t zX15iAamTwimY9gKm~qUy#rVy70U7k|05(713C7t=`20+8hGSx4LfYHgZ{1EixKz-0 z2#`ERHZj@!$mr;(SYL|s4DG;Xp&17Ujxo?iF|QOfHur{WUoG$+rVMjKo=B zS7T!_jak2DMcm%rmh z@ty!cMOS1qdBMiQ+RpN7z5wePx&QAtEWR9Fe^R!vA$Q4~J+-5F={2V2y}FsNCWLbOP*ABu{iMWG-BrHg*(msYh_ zDB48@fn#H3V35R+1R6#J*&@jFDA^}`CpcED;d-!tCuuF_{@5D+U_u}`qF zIT%eBX*F zg-S*mi4CE6P%RTpZq%FeZewsCcO1-WX#8^u-nLrDu@7mY+P6e+0}=>zUAFpl^sHR6 zgg@^U{qszNn{Y(WDFcLl&9j$+W>f>ZKktBY)XsMVfR!I{1lndK6CmzX2#kOKT*Yu%k;$m)K`rVSfH7E9WTID_Xh~vYOqD5JBxa$SYf_u~RW&03#pje_p&RVk z=F{D5`GU2G3TN;xm!TvM|s_V z2E{(-2Q8NJ$#KBJHl4e;&+#iDA2d>Fs>x?(lg(~%?C3H2f`Y5_7+@!+!WjXedCrhE z%5M*u>}zxsZ;nws45GVM5rsC)3%%#&>}B#mBbBBa4HgtL=9^8wj`X2^t3+4xWC8>3 zb!NPbGGHF!%W4j*`z!L@&E#PD)D9q~&F#5s>?6=S7ady>rp6+i<7Rd;(Qg`MRD|Xs zbET1r5-!qUA#Nvn1;ubcB%}JAS`A}ET(zhACd2@xogIvin&)X<6aaESUpF+>Xs{5s t6TK3{5y?=Wt8c002ovPDHLkV1oKtr9c1x literal 0 HcmV?d00001 diff --git a/app/assets/images/ci_favicons/overlays/favicon_status_running.png b/app/assets/images/ci_favicons/overlays/favicon_status_running.png new file mode 100644 index 0000000000000000000000000000000000000000..ff4167c4b20a2a95106a92921c78fbd94308874f GIT binary patch literal 1077 zcmV-51j_q~P)Px&?@2^KR9Fe^Rb6ZpRTw>YW_P-EyIV_zlD47*DS;5wu!$mQfEM+E1QVl@7-Rf- z5G5rFzVQGt;h_NySs#q?!6+uAU^FIBg91v7@h8z}5Mc|3r7g?0Wm~#!8MiZYxu@G5 zCR;mBi*NROn9R(*-~G=0e$D}AZ8ih58JNw$|2+fZze>P{S$fuT@GZDL-~fO zz8_7VU1%3XyCY?yp~kRVmd5qOT~XA247-2pB+S{Axp`U$#BfF7;^vV7Ig3So5Hk%9_}5 zs0%};%D=LZiumH{T3uaaX@6JhvA_U0=Nz>Ss@we0N4kR`O z20)VGoUc@)HWT~iTpsT>pCwMW&<_^ z1^@?D^d`yp+3B9^NPC*jyVo2m_5uGz!a^M>ZVP-Jp&=ucKkHdlF?swr;~#$CkApwu z)aZF;&x2roJnViAjM$1lWHvYeB`owNy_Sz4$868h49@r7OtBkj;$==Wgk|-W?(fcC z({`lj^v|ce9iXaFSjg>O>o|Q4uN+AG2Iu~5Ep;wkcjXG`9w_J#I1(5DC6%g1VIjAd ztf?-7N>xukd*c2YJbcf13yp6(_;Zf*ZRvXG)4%}eNlB%uQCLa=7tO7}2hT6W+9ffR z69m(~ds72i*Uu|$$C-?YFaH=){^Gr_w=KHl58ZXU`Lgcq)SGaewr3xx1-ad81EV&` ze0kFb8;&*il2%qx^p*o@d&smiFrxPz-`aR}+5i}E{oZpQNyz6YEaZ05>%SRqzVq`Q z``UHOln|>=ZeQ{neWoqPbV|IO{DP9IZoBHMKl65VrLHyB7?VoCy==JmPxUEb>Xijs zURJ?dO2N54qYTiIR+LoPMqwehlU~ViBpJ>*M~&UihGWe|MRXU_Ui2{m)>sxe;<|w6wSpi00000NkvXXu0mjf8`chd literal 0 HcmV?d00001 diff --git a/app/assets/images/ci_favicons/overlays/favicon_status_skipped.png b/app/assets/images/ci_favicons/overlays/favicon_status_skipped.png new file mode 100644 index 0000000000000000000000000000000000000000..a9c36464b69a28c1af0634b03f4ce6dbc70b0c6a GIT binary patch literal 923 zcmV;M17!S(P)Px&RY^oaR9Fe^R!d78Q4~It@ez|MK|#d`8oNr{R7%<3k7$j zbZxioPP(=*E!#J&;9PX5oua8 z1I-LHGw{D>K>1e*SX^8jP*pWisZ<8=g#&>=K~a>Qcs%|Mzj{5K2N3{}va+)B48PL= z(Aaka0sI(a^B^~yNF;K1=G_Bc`{{H#rtA7VK($~nX!Q2>s*y-U+S}U&U~+SFBNrDJ za&&Yg#bWUmRz_A{CzHwdPK-N@os;$2OG`^nFt>n!U9nh9?d$8Sx6~Xjl}fU^yITPn zBt-cP5-;#;aMCvcYvxE4f@w0RADBO1^l2Q+xH3Hz^Seer_?WZpS)_eYjuNof~zea(sudnm$^R2C|Z|U#r278j%66;x*%AGQ)?3wVldmg>xGPm(SfPx&&PhZ;R9Fe^R#`|?VH7_9{cnzr<5H=WgL^&XWVSC8jR|21L808qo$ zIXlimEz{80m_@6!R=3#3J3U80Vs4xwj-W4{|JE5CM_3;P#Pra zLJ!Q#rPlZ~9=dN+pL$ziU(I=T*HK0It&3)WT)WjSBM|C|M$0=!4n(Nnk%nGRKR{PT zrHttuZH5H|!-m)ugz*|xw$-NcIvAYx+PnBoz#pxGHOI7Lyp3Wy=Bjm*tguT*7jFe?{HjrIjDO@}GFZy;AFJU!fi-?>fy{e*;CcI7&tq6?Tmm{8 zATx!n*9>5gWPsqPX%TcTJt%@#T@A3K>eO#4I$;u+Ba<-@vt|G)!*Me>=iYLzt{lqv zyt~Eiyt%Iv!UGI&a#^1H)6f&`5JHUN(8>5O2E2kK<0(iqh1F+46eyfnx*g_(C#aFT zotLETRnI(i@Lewk@@Zgt%>bA{nn7VI!x;=gL-tlg&4Kw-WF(S z1NBZv1}+wJlxZ{^KF@G6tQGs^@A7~H#Go8!$;&>!0H9^Q#U6)BrX<{I9Rod(Ha!*i zYWC^W{Q)CK=WYEx{UDOnO<9*3@tfZOP-(4Xx`ivXrmKGWjSmmyh`=x*A!G)(JJK9B z+@aUSP*8n_4MvX6OJ1TK6u+8qP-Xa6U8#&6#>Il%j`TYCA5ow>=QwKE?VRykSaTu< z6*XmD=oq%}mjKX^WRoavHC!yn?MSc4a7Z#Z=e$+!aPGW{4d?0D{r(I7Xomj>W@SqN O0000P)Px%_(?=TR9Fe^R!wLVQ4s##ZnbFq7cWLzq$*7hdg-C2p!A>>5qj{VplC&J(&AB6 z6!c>8C-Dbbico@h2t5?U9@K*utDp#?)IcnvsIh2lK}E&g9cSLUVz=44oAzdg>`vZ$ z^JeDFo0)Hc3RNOdi9jU+|9b?~Oa*{0VL2=`K`{qn%-=H~!8$xpExZyy({g}_&7`oC z--lU$BV_C+WsHNIEKHnI9e6Wo**_6>%qLz2TV+Aih(&ca>UW!{-2%+70cOR3uN;7n zPdEkxK)&B$Cw@ZFG1ZB)VQmD;(FJUvwDF0q#4LK&OXOHIC5`8a2DUl8kNC-u#G_o2 zlWXHwS6WmYp3?5bMTh9#5pjShjdNw$mpiAFdZQ9AL#p14<>sJK%OWx6XqU zN12y?p;SDI1M{?gX)-fGqK9a1RRmoHEh`$4vc7x z(q4l~Pz1JK*JA&CeRynhd(MZy0!B3mut;y8iXNQ-ZtVkv2hms#7<(b5baOI#1#RMa zZlgUg%mdh)Gq7-VX~{I7iCZRz7wB|K%iP`%4EI^wSL?z@KvXfLYE--1$rkumiqvnF z9{0->?u&8R-_6MQI+6n}p3`x>98?%O>R0WKTQfk@2|&1?KEDEPwAmb;x2VEN|8nTD zhEzc{0T%m5Dae^T_il)&XPL!d_JuBDy=N>^1iVd%qn%;wJf8LfeQRyxt^xM9Kg$#T zNW#gTXPXJ%iv<|e%#q|$aw$?0dYe2>8d6o41{Ue<(q8}mB9c;*Y*&iE38`Dct`4E- z?H4{R2SkDXx?xlkU|~Z^e&W*Mn2$=GbFL0@wE89CMBY!o0ECXKRt<{9 literal 0 HcmV?d00001 diff --git a/app/uploaders/favicon_uploader.rb b/app/uploaders/favicon_uploader.rb new file mode 100644 index 00000000000..dc30e838337 --- /dev/null +++ b/app/uploaders/favicon_uploader.rb @@ -0,0 +1,44 @@ +class FaviconUploader < AttachmentUploader + include CarrierWave::MiniMagick + + STATUS_ICON_NAMES = [ + :status_not_found, + :status_canceled, + :status_success, + :status_skipped, + :status_created, + :status_failed, + :status_warning, + :status_pending, + :status_manual, + :status_running + ].freeze + + version :default_without_format_conversion do + process resize_to_fill: [32, 32] + end + + # this intermediate version generates an image in the ico format but with the + # original file suffix. + version :_default, from_version: :default_without_format_conversion do + process convert: 'ico' + end + + version :default, from_version: :_default + + STATUS_ICON_NAMES.each do |status_name| + version status_name, from_version: :default do + process status_favicon: status_name + end + end + + def status_favicon(status_name) + manipulate! do |img| + overlay_path = Rails.root.join("app/assets/images/ci_favicons/overlays/favicon_#{status_name}.png") + overlay = MiniMagick::Image.open(overlay_path) + img.composite(overlay) do |c| + c.compose 'over' + end + end + end +end diff --git a/spec/uploaders/favicon_uploader_spec.rb b/spec/uploaders/favicon_uploader_spec.rb new file mode 100644 index 00000000000..5989d294112 --- /dev/null +++ b/spec/uploaders/favicon_uploader_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +RSpec.describe FaviconUploader do + include CarrierWave::Test::Matchers + + let(:uploader) { described_class.new(build_stubbed(:user)) } + + after do + uploader.remove! + end + + def upload_fixture(filename) + fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) + end + + context 'versions' do + before do + uploader.store!(upload_fixture('dk.png')) + end + + it 'has the correct format' do + expect(uploader.default).to be_format('ico') + end + + it 'has the correct dimensions' do + expect(uploader.default).to have_dimensions(32, 32) + end + + it 'generates all the status icons' do + # make sure that the following each statement actually loops + expect(FaviconUploader::STATUS_ICON_NAMES.count).to eq 10 + + FaviconUploader::STATUS_ICON_NAMES.each do |status_name| + expect(File.exist?(uploader.status_not_found.file.file)).to be true + end + end + end +end