From 0cde7bf2c72d0e157fd3c6288e71b3944a0641ca Mon Sep 17 00:00:00 2001 From: Fernando Rodrigues da Silva Date: Fri, 3 Nov 2023 18:01:32 -0300 Subject: [PATCH] add the new plugin should i deploy Signed-off-by: Fernando Rodrigues da Silva --- microsite/data/plugins/should-i-deploy.yaml | 10 + microsite/static/img/should-i-deploy-logo.png | Bin 0 -> 3903 bytes plugins/should-i-deploy/.eslintrc.js | 1 + plugins/should-i-deploy/CHANGELOG.md | 1 + plugins/should-i-deploy/README.md | 54 ++ plugins/should-i-deploy/catalog-info.yaml | 9 + plugins/should-i-deploy/dev/index.tsx | 47 ++ .../docs/should-i-deploy-card-with-title.png | Bin 0 -> 16635 bytes .../should-i-deploy-card-without-title.png | Bin 0 -> 12250 bytes plugins/should-i-deploy/package.json | 63 ++ .../src/@types/api/apiResponse.ts | 21 + .../src/api/ShouldIDeployCIApi.ts | 25 + .../src/api/ShouldIDeployCIClient.test.ts | 85 +++ .../src/api/ShouldIDeployCIClient.ts | 49 ++ plugins/should-i-deploy/src/api/index.ts | 17 + .../ShouldIDeployCard/CardStyles.ts | 53 ++ .../ShouldIDeployCard/Content.test.tsx | 79 +++ .../components/ShouldIDeployCard/Content.tsx | 21 + .../ShouldIDeployCard.test.tsx | 62 ++ .../ShouldIDeployCard/ShouldIDeployCard.tsx | 76 +++ .../src/components/ShouldIDeployCard/index.ts | 17 + .../src/helpers/getBackgroundColor.test.ts | 58 ++ .../src/helpers/getBackgroundColor.ts | 39 ++ .../should-i-deploy/src/helpers/timezones.ts | 609 ++++++++++++++++++ plugins/should-i-deploy/src/index.ts | 20 + plugins/should-i-deploy/src/plugin.test.tsx | 107 +++ plugins/should-i-deploy/src/plugin.ts | 77 +++ plugins/should-i-deploy/src/routes.ts | 20 + plugins/should-i-deploy/src/setupTests.ts | 16 + yarn.lock | 146 ++++- 30 files changed, 1774 insertions(+), 8 deletions(-) create mode 100644 microsite/data/plugins/should-i-deploy.yaml create mode 100644 microsite/static/img/should-i-deploy-logo.png create mode 100644 plugins/should-i-deploy/.eslintrc.js create mode 100644 plugins/should-i-deploy/CHANGELOG.md create mode 100644 plugins/should-i-deploy/README.md create mode 100644 plugins/should-i-deploy/catalog-info.yaml create mode 100644 plugins/should-i-deploy/dev/index.tsx create mode 100644 plugins/should-i-deploy/docs/should-i-deploy-card-with-title.png create mode 100644 plugins/should-i-deploy/docs/should-i-deploy-card-without-title.png create mode 100644 plugins/should-i-deploy/package.json create mode 100644 plugins/should-i-deploy/src/@types/api/apiResponse.ts create mode 100644 plugins/should-i-deploy/src/api/ShouldIDeployCIApi.ts create mode 100644 plugins/should-i-deploy/src/api/ShouldIDeployCIClient.test.ts create mode 100644 plugins/should-i-deploy/src/api/ShouldIDeployCIClient.ts create mode 100644 plugins/should-i-deploy/src/api/index.ts create mode 100644 plugins/should-i-deploy/src/components/ShouldIDeployCard/CardStyles.ts create mode 100644 plugins/should-i-deploy/src/components/ShouldIDeployCard/Content.test.tsx create mode 100644 plugins/should-i-deploy/src/components/ShouldIDeployCard/Content.tsx create mode 100644 plugins/should-i-deploy/src/components/ShouldIDeployCard/ShouldIDeployCard.test.tsx create mode 100644 plugins/should-i-deploy/src/components/ShouldIDeployCard/ShouldIDeployCard.tsx create mode 100644 plugins/should-i-deploy/src/components/ShouldIDeployCard/index.ts create mode 100644 plugins/should-i-deploy/src/helpers/getBackgroundColor.test.ts create mode 100644 plugins/should-i-deploy/src/helpers/getBackgroundColor.ts create mode 100644 plugins/should-i-deploy/src/helpers/timezones.ts create mode 100644 plugins/should-i-deploy/src/index.ts create mode 100644 plugins/should-i-deploy/src/plugin.test.tsx create mode 100644 plugins/should-i-deploy/src/plugin.ts create mode 100644 plugins/should-i-deploy/src/routes.ts create mode 100644 plugins/should-i-deploy/src/setupTests.ts diff --git a/microsite/data/plugins/should-i-deploy.yaml b/microsite/data/plugins/should-i-deploy.yaml new file mode 100644 index 0000000000..828ea50715 --- /dev/null +++ b/microsite/data/plugins/should-i-deploy.yaml @@ -0,0 +1,10 @@ +--- +title: Should I Deploy Today? +author: NandoRFS +authorUrl: https://github.com/NandoRFS +category: Humor +description: Can I deploy this plugin if it's Friday? Oh, hell no!!! +documentation: https://github.com/backstage/backstage/blob/master/plugins/should-i-deploy/README.md +iconUrl: /img/should-i-deploy-logo.png +npmPackageName: '@backstage/plugin-should-i-deploy' +addedDate: '2023-11-03' diff --git a/microsite/static/img/should-i-deploy-logo.png b/microsite/static/img/should-i-deploy-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..311544cf531e434c1e80ba0c8b8c99b1c1e1c072 GIT binary patch literal 3903 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 literal 0 HcmV?d00001 diff --git a/plugins/should-i-deploy/.eslintrc.js b/plugins/should-i-deploy/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/should-i-deploy/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/should-i-deploy/CHANGELOG.md b/plugins/should-i-deploy/CHANGELOG.md new file mode 100644 index 0000000000..4e00f59bcc --- /dev/null +++ b/plugins/should-i-deploy/CHANGELOG.md @@ -0,0 +1 @@ +# @backstage/plugin-should-i-deploy diff --git a/plugins/should-i-deploy/README.md b/plugins/should-i-deploy/README.md new file mode 100644 index 0000000000..231a01318e --- /dev/null +++ b/plugins/should-i-deploy/README.md @@ -0,0 +1,54 @@ +# @backstage/plugin-should-i-deploy + +--- + +Welcome to the @backstage/plugin-should-i-deploy plugin! + +## Overview + +--- + +Tired of looking at the calendar to see if today is a good day to deploy? Your problems are solved! This plugin creates the perfect card containing this information for your home! The phrases and background color change according to the day, based on UTC or the time zone. + +### Simple Card + +![Simple card](./docs/should-i-deploy-card-without-title.png) + +### Card with title + +![Simple card](./docs/should-i-deploy-card-with-title.png) + +## Getting started + +--- + +### Install the package + +```bash +# From your Backstage root directory +yarn add --cwd packages/app @backstage/plugin-should-i-deploy +``` + +### Import the card + +Add a **Should I deploy card** to the home page on the `packages/app/src/components/home/HomePage.tsx` add: + +```diff ++ import { ShouldIDeployCard } from '@backstage/plugin-should-i-deploy'; + + +
+ + + + ++ ++ ++ + + {/* ...other items */} +``` + +**_Note_**: Title and time zone are optional. If you don't specify a title, it will not be rendered. If you don't specify a time zone, the API will use UTC. + +This project uses the API available at [shouldideploy](https://github.com/baires/shouldideploy) :heart: diff --git a/plugins/should-i-deploy/catalog-info.yaml b/plugins/should-i-deploy/catalog-info.yaml new file mode 100644 index 0000000000..90be14ce2a --- /dev/null +++ b/plugins/should-i-deploy/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-plugin-should-i-deploy + title: '@backstage/plugin-should-i-deploy' +spec: + lifecycle: experimental + type: backstage-frontend-plugin + owner: maintainers diff --git a/plugins/should-i-deploy/dev/index.tsx b/plugins/should-i-deploy/dev/index.tsx new file mode 100644 index 0000000000..97c5112ba2 --- /dev/null +++ b/plugins/should-i-deploy/dev/index.tsx @@ -0,0 +1,47 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { createDevApp } from '@backstage/dev-utils'; +import { configApiRef } from '@backstage/core-plugin-api'; +import { shouldIDeployPlugin, ShouldIDeployCard } from '../src/plugin'; +import { ShouldIDeployCIApiRef, ShouldIDeployCIClient } from '../src/api'; + +createDevApp() + .registerPlugin(shouldIDeployPlugin) + .registerApi({ + api: ShouldIDeployCIApiRef, + deps: { configApi: configApiRef }, + factory: () => { + const cli = new ShouldIDeployCIClient({ + fetchApi: { + fetch: window.fetch.bind(window), + }, + }); + + return cli; + }, + }) + .addPage({ + element: ( + + ), + title: 'Should I Deploy Today?', + path: '/plugin-should-i-deploy', + }) + .render(); diff --git a/plugins/should-i-deploy/docs/should-i-deploy-card-with-title.png b/plugins/should-i-deploy/docs/should-i-deploy-card-with-title.png new file mode 100644 index 0000000000000000000000000000000000000000..4c006c0ed5301eb34e49777a040dd274cc4f6cf6 GIT binary patch literal 16635 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�cYIH4^#&~TNeAaOLgtEd#YSh;Jv z-;Ip;tZq0W;i@XLvw_ogY`8Yx1w*A}s(FcvB{kUWH}7vq3@2^s&6~eEPKEr)v?Ti? zLov-^(#$SZIS3uN5`;Z#+U*aapr-b(ume^c~P%l=J?qzOO zi6ah7XMah{sii?{t6P_{j%C0VK^^9znJPsio{R%bd?KKmp7;`{?VIx*TRq^r0KN+ugj#k$`_? zmG|K6s6)WRgJOS8FEX%Za;xya$;84458C0z$O#I568~418OtXCCPEeIObU<7lPVX8 z3>ilA>Sgv{j~!2;5aviw3W${#6bNC^s#D(H-hzq@m;Ng=B_#%l@>S+znnKA-6e`Zk z6X1Ed5KQH^VC|=rr@FxXn@W!a>4RGOAS<8}_^-+AW_(KVKfSbk)26;;IDOo8FR1qPS@DmB2F;1Br*FSei?gf0r z6k6jsL1r`|92m+oNl@4Y|2qW@jR=~LemKKUh9clUD$bSZPfz{v4zYX}(4?Apm|VF3 gIbqF53-iK@;acmVAcS1@aavwnSVpK)K-d3&0UX-a!2kdN literal 0 HcmV?d00001 diff --git a/plugins/should-i-deploy/docs/should-i-deploy-card-without-title.png b/plugins/should-i-deploy/docs/should-i-deploy-card-without-title.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e658c0bc3ebc4e7ff5dde33da3e90ed0ae8634 GIT binary patch literal 12250 zcmeIYWl&r}^Dm4A4Z%Wi3GPnt#Vxp7a1ZV-K?4N$APd25ad(%XSs*yU-F>mUB+v8Z z{q}yib?>eESMAxFbIwdp%S?Blo?nErqBJ@xAu0?E47#k0genXSED+khMn;7Gqu58* zKp$vZi;FAEii?vgJ3Cld+nU3`(8asOwafJyVGaQOW%}J69bJbg=+x;ef_K#!XHCMC znf(KeAPt3~RDKy!>W*i^m`KlXZXTbdc|?~&P$@tlvG-9ao(_418iKsXgS{?;%dp+X z$u2^#yV&d)f%-`w8XF3R7=IwY4|*kETHXzgq)2?V>c*D&0qzGtK1#=f8)abM{Az2n z+;6Tq`~HCJYrJZ6cd@@R4Su67IVP><8(Ws!G|$l=1z(k3*^n9{vv@DX@mEi}mnACG~ z;WE5`iH6k*2}wkh!{_ zu-aJN_UoL83X`jZHJZ%gJO}5EpTEcUcy{{|ee3A!T91Hh9J%KD7ducVu7X1xZs23uz*zrKt#`R6RN3x7e}CVX=255Xkx0YO2&dN>U;t zQBgw0=-;3B8f~2$sc3nU1Gu@l2}mI3J!~(1$-j(?!gyEPFY`4OJZH~3=luHs2E~jr zPBzdP8)!>#%KM*3b)hi*Ma*^hsedg&&Wb<>@amSK{ij*G_abN3Xv_oDf9DuNgN;-& zVEcvgcc_RSva;`jSd^3OUkjd#1+FLJeRCE2YqiODP+K)jntb}lbsJ{R?dB`WtQWSR za{hm(bbc~*z8hk;zZwfCg1m?ci%rM&B~D*!l9>0Lp3Z>(pNyxJB4=lL|J7&^cFyhF zx2#$Jq`k$;xxG~}#{b8fD2lQ#YGms8Kh_?gj6M{zefuk6P7YMUSN(E3|0MK>-ubKJ z|67*I%22L@)(c$zat$jCU6jHM|4}_19aMPHvtN9FX9y&Njf^G34U7LP(Ay-a4s$&B zGXKud6${fp7>nBbZ)Kx?3|v=JZgW-qtCv60f$JO6p~n9ve?<*l>Hi}h49fp?*86CQ zLDbYNV=lQ!e|bWSy-q*l?)d#j%g21J33qBcj~@#0mUf2mr6cZm=_tYCfkKjw3(k2q zCi+gfA=`cwxssezbrv1kJcdWNbu5BEA?vo zR?U1%j2p)RkAo{ql1{qX`x+J@R#QUa(KJgPosrZ7u(9(B0R^|dUQBM=MNx#?Ml!|L zmST3wfYW*mpH(kMNUzDVUt+I7ok>c_imySw16e%F47M&Lx%cN4NvtEa6}ixF?PqR zQiNOE54rJcQ09c>h&*Krg=M5#8o9MeXXm^sWIx~&YBG$|Dux>y24u{2j;wf%6bog& z`PH#yUp?`hH@Cs+46>?lk}eo7iSG6Q(4DRMe0}UGGdXH(2Z}vn;~baPV2i7Ry{OT z!cAvaE8j@Yifnm|MZ$)LsGTTV0r~Qc7|eTNR)H)psZLBX0>UO=i3e3+q zONyW;U`%)57_o6RnYZB7xD`$sV@lIkz9*S8)Pl!K+J1l%t9>2GR_lEo9+{B%itMM=Z~f`pskGobaX%L_ zq$C@(7GybxERIXt%*9Fghdv1_WWNLLK6{(*Q|q_Zu|!0M)my5%YCcUu(k6Ipeu`2= zrAC(P91y$R?j>ay*_rvZ&+$AhV`WcX#PZ@HfpTt}M)>GVvkURa5XXz9H|B1h)XbK> zvAzW*q!2!Sx{|I|##Ghbq-g-Epjt-W1B25sAYrNuEO>5=`xI?&VssW~GAd)B=`!ziE};xHxX4 z7Aex2==b@_)}u=PDrXl?o!s{_F^-m#=EVPE&VA~V{=Vj(Z+NET5fI;kOVJx1`S`#{ zu`(`bg9yN?*_>wxO@-}4{1I#|M$+A6vYGGH?`+fVIOSG=UWmjld7rO1;g^>;=u}h^ zG+$A(o;ofWxDIY!5HPi~%W{swSZ01Nrrp|nMHnBMqVI6MMl0L)lf2rYwWxn$L?dEC zzm;Y+k@5>JVK&G`7H?(Utyc+@#;o75RxK8KyJ_9YFT1XfRAdmt)^x{eK#>+x^X!@2 z=YdauzJhcde|dsWvKJPb)J$1|%ZMYoJ4xnEaYi7Pgz+<_C_Oy<3*(2`sMv_mC`?>Q z0ztOq9)ia|MEd|cDTbxHs;hSt4DvB_JX{Tc0f(#@Xy^oUdwoZ}*~{X^j7F6h@?YnR zx96s4QO+Db^g_c44`>U%u%})%UxAA^m(87H;NuS8qp~&8)=VAV3LC8A){@3$yFZvG zB4w43X%Tdj*!ZT%CgvnfKm2f{1i-mplI!o-w%FMRq?*kCsq=d7d&8seQY&Q(#Mhao z?nhFbt#J7?kMFeE?L2~W=Sd)9g@``sMz?(T)rHb)Z4EU+tCnObdNCA!pEh8GC&`j?YV1OPMJ`Ie8X!I zO_Y2oRkGFPpD||ViwX-7D~=klzMP=o^!sm+JR__qcM4Vq%c0u#8e2#iLz9ooON&WbH57sM9c(gY;`r?8M?7#1KhLp6&T|_yx1L zTXIGdk$JR)xDwS}wI*gx1^Pi=QJ~@R(QoX0qR1UQ!Ij3uynU7c~iS9^0Et zG%WWEp!t!<`1MEa<6?Bu-eX#CU(lcKDvi4v%gBmFAhq<_a2hSY(p4%)60`JKbqp_6 z@@usOOtO39ELEcBR_&tV+mot_ug4>`tPWV~DF}D>Npjg8ud7yq>&xlMXi#fE7QL<( zP}13I){_t+c5D z?5^lOBGaEK%-~1fnU)&~hkPlrKkPBSf+GA^TDAy*o^`)3pRf&sS6v5vaa?;u%9A&( z6=*HJGbko9(FVVY(srREi8>h1#=hi?ALF3A0D&k}lHw)D&%w#LMQ9Jz5&oM9i$Zf! zY}>c*B3?QMDF&|NT)wk-d`T{I5TI%9$0`+Vs+W$){Lln-QZMc5Rcd{&oC$PR^79ZNr4sCS{UP<41AXM{1Qrk#|AsI71fZ1yIAbAsmjG zV6PUbiggmut?7GU?*YW}eL15G#c=d#YPRJf{5~jrCo`Zkci{TCD**cFNw9q(&`%5G zirOucz0fV~jOO>dijJ}^tURaK?qt`gm|BJ0=pI|R)ubDk{dhQP9{-el8O&nhay5mc zMqAg0Nk`qltMp-iX%>eH(55p2A|W?NB4zk>wX^R;H}&;w z6n3XCNSm|Aq<_K1z0^im3c8fPc`gK;j<7TcYEC8i1B-|B4<3}(ZOZJtifgEkvk7lt zflUjYBLUMpoeXwfS^?3w$AtWUrXcrsZh6$E8tJ2%v-_#--g7^2(CAwWR}v_5jl!ZU ztGDbnzIp0t`~b$I{5k;%`S!`U==3G5auLE>16Y2;{fLSEJl`p4j2`SrT4By-=yx?v zL5{|C6s*x8m`nTzT=%qZnF+a52&N8>c5ZbtnB~Iz+}fmBK?b<%rb^}wit)%l=Qwh* zi_NOjH!^KqfHyJzeK#wrpd%D@S8vsX;?Ul`c=^e6=^DlA3|D)#5i4MpMk#?)y zvf-6kFwh;i_Zug9`zTTYR?TZMz4C1~_LJ)xsM621zrJR>Z_M@-=1^)eBf!w|uYK*0 zN8bs4?GMp7F8|dqMPD;<>Dw1Nk}_f%qG{rg^+rHrqakUbqWQVC!rIhlSAC%%Bg$>A znZLgwLuz_@>g38U!XHsEPJO4r0{fUk)h{H8L{MTqSC7j32o9yQ!ii2~gs#)VmHWoqyMC(qT~6duBk^)B-&ya?wBi<-E{q3N&SPSZ z=>W!jJw{JMq>@~2+>@JvL&}9vbU?^^<=RW0UECP`$ujfm;r*LBkb4>bci9xWB7wTv z^kVY>F##r5F8}Mg$iY|p(%d7z*|6IrAD4>YJj%p`M(G5wMJN@p=g?UYI*b+&o`#AImKPbX~e6*`ayB(qNg5Z#43#D z+#NDeeA?S-bL+|PeV1>?wAd7mvQ!!a`JTG!P5F+6PVpDS*CexySJ1F`$7b1}xGL-7 z;f+wIMlZ+rio3yv=m<9zLzEMbeAEexU)sXr@OCBTze33@1z%y)(e)MS5c+FVy3?`D zEZ@soZL(9~3DZQE;mK`rF)OD$aJ&mc;vvsb_{iu6w@dj3Y^ck>c9!zYeRLQ*eQU8A z6`yJi77{*AhY)dvA~~&sV z+3_lL|F{=2_zh!CSYrcFl%*lfWp$#!&m>M#Gmmd)<{_~?(5@r>t8i_RnY2JiGuhL# z=ICR@(V92NGjy;V4WKlAL4@~yo@s@ZCO3+)!1u&Y!uv9@hDce4+32n_SJu76w4voBjf0%g`dt`J)r@$Yivu?%5YyK45gR_2atdA_}SrNFbu zYxrkSFd%0*l?t4My~tWWYSD~Tf+}1}x%Rw&$vTb$X8U-9kRJZ3b>WB4F4Mv|JXf1) zitlx9+hwd)ew%HDZ9_f(8|cTxV|(QIkIe%CbUh~cFdMyMt9IXsfUN`B#C&VJ+7J(7 z^6IJY11{{d4C4OQoY2^t5s%9Q%fAsWM1naBPjj$DT$rM$xz?<|x;kYX)eHz$T`5yj zKDOE}THwnAJE8X&fpF!gta&T_3bJ4e?>}9{_)2*pj79Hsbmoxs3FhHQ+^Q^?wiSf- z=uVaBx|atpSFlnNNwZZoY%OGY&ww;+&9#bm+w!x1-7R<-=7@bz5jM19k+Qa(egsV5 z1~AfQoT51z7PxgC7*{-N@#BS}p;RvC=i%EOe`^3TT*-*9VLfZ+t?&>5*LKa!w?Prf z*m~dQ6naDZMRgm2R?GJ4A81H&&WYZ)?j3==JIFrE)-Ed)cHV`yT@R`6EqBT`%-4oL zRQYxcLHJ5#`RA?0LoVBWBe*Ib#5DbRq{EI@#2Z%Yr2vo4Fm9i{cDL|pI!VZhlPAH>zIcyi3<0)vO$plWzpOP#@ zN!A^i4qi&G(5vWt)b#e@8>l@k?9GWoHpe>e2f#P3aDKvTC)L;Sl^&2om}sAD_Z)-X z89^!2LZQ4X2Yu8Ft36+-#xS&qC?UAWE4D^-j^uYHwhL&ibqnt-9DK>Q10fxf~Xq zkUZ9ztOOvVyjjId>^D3p9@Nc^N&T6?hqgH;`)J;skhpnqXKJu3xPv@|IoAx)#Ag~J!kp*-bu#ojygoA`=A!dsZ}V4LLLHrHSa zs+6C(q}}_$^;*rLuyfD*P(mn-o*-$0dpG&MH9%?O+f+0PJ~j0+?-b%^fcTh~08jN< z%oQoPiimZY1F>*?g?pcyYR?C>Z8MAXRHf2GXU~9UBq$cE@S#we?Fg~sIN6`UIl{lo zzMn|Q<^wqCi~ zY_em%gyQJ4&TQhb#~-RCddof6-h0cO3}`#oiGW2zCh>4P)`NqL&D#yypFV2uhQ@v$ z48WDi7Rr;n7kIcNoOh1uIKLZp*h~Bfk9OSS;C6`p*V+3i*neNBs(81@Ws z68BbZSxg7*XyS+Xz0N`{H?ure;%c~YYgX+wIO-amze)9jtY-;d|qg3@`$A|AbqZY=yVrlH^Ly`hjEFt<~1N&k9B@ zZGxsqx4mejnSXiPzB8Ovn5CfaU5`t=rPgAHcaKRln54bH6#I7~>%!aQNUKjhxb0?; zZ(irKI+h=S*~SEHMsbIi8^9rf6U7wI@+fu9l%L=Ug``RgKUNJ5<2_BV{`Hbgez`6r zmy2g#nPay2>^t?gi+#aQ;MzP&e!J&Tb`pD}XxAZA9PkD}M#6}0x* zxzOEtd&sg56{FB|X`b+5W#u>TG2O62hTSH(cPIS2wfEH3f#1z6*NZxKcoo0-&4@KLdUk7j-OblL1!se4ZO=8LwFbme-JPZIz(VA2&w4zcW)g( z6Hac^y&@gdKPePt;z;+1Stn5Sr^!@1$}J!jWA|Hadr+d&otkW~FI{=eOcF)-7bSgqP#7>lYaOqVN3Q{$w&g!Pcg{Sn%WI962kVfc6;TDY8{{C8 zf?B?$GrZfGJ`MWzpn#216yh{d{U-aqnsU5o6 z6g21R%z~z)O1835y}z9MWFX(ltJcvAQR1b+97nOY>O3?#;S_=z8#n|L23skSwcbg4 z^OJnTA0;AOz9Qr0lzatt0Hr%&rW`$y@+_;6e(5?cWo%1bCA_oC!tkYRmiwvD>f(I+ z1uN->ov$h4m+!mmjBOTuqnj1RAa2aY$_pRci9FKkpvplZs?n5?!u2_rh9<<$KuBxs48^Bqwv7l(;`}eOQ*C~Vgp3mjf&y7MF(7K^TVk(#Ey>z zKCIxx4^P<^g#wG;3AqQo{k~3|$L4E2B9z!Y#oFgiV_~>ghhFBR9F&O$FuQ>ZlzLr$ zH5vzLyPcG=Rm{|(2KWU_07^BnZ0;2Df2OWA zs^kG+!)typAXw;5{jAH*b8aCD~7jMLxkah1K_MxDEx> z8HD^1l+ar>C6*Ta1_9eq2FOn&FTNGzFF{L!XX$gUk9%VA-a}UuK3t*WUfd6sWR`QN znZ;o*tmM!iM6u~j4K>>uk+P%|1%9szv1R^LYk>{EYu`q+{$<@d;5Jrs+}d=RuFGN` z^ZB!+l^67kcNlG;hre4F%fD$m&*XG7P%mqIxqlns zTxARvrVzh68b6l68T}E4lxQQ% z!X+%Zz?QJ0%Fc|!3Ma^u&Yfr7ifm;3L&3De>#l_zjGi z@aTPolCuFC>zILjgHX#yj`r@$W){_2iD%?x#AY@lQ)K+2;ejUO1u^U{-Tn*6E&fSj zBzP;r`unq$?*z+?x~q%#7UX;eq=t1{>w{Zqi))vSxVOesy$&r-=NY#qF0 z2&9-xny}xXRw}Cv%(-0&cz0oCO@T)=+R`7Y+foTQD&kej!uqLJm{0?=! zymq~Ib+7yDe5+qoT570+)Ed%0_EDxUr7Lma9aBOgI-X)nWecO|Gl4sweO3#0&~7s; z?G~~dy2yeKI4eGl)H7?5>a#u~hMW5}iSNC8z$iH<&C#4{hjJcHtn7zz)G>BwyB1{;xZyOiUH zZ}~+1mU1VggZ5Wn-*{*pEigs%a~&+pJ!`5K02riy`6Cti+}XghFS&a4gpa>f0pS zTw1?sxgiTU;&M{}QSMCdj3b!i%p|YZMs#uNLF>>8a$R1pm3Fc;7VA#AJ>*ltFZJk` z+I2CsBrVxLHu~>gByhd=;y-U*iq(?R)3zl^qjmn8{x3Jz9RM1{;p$%XA~4cQjsK4(V9+|f+IyF_Bu5!dRh^oy8hUVKCX$e(zY9IDc48Ivj?NbdUdkM9m{P%v-8vsl%(WeV6gs# z1;cRDl>KstbHdF?l{#Soe#58Hr$ARV)SxZ`aH}9Pm*5aXKWv7I7BS+nR!38x+{%18 zJuj;sH!*Gi)IzhM8=+(L%ocFNFPpKJx~I0YyDWqt87Mn_n&w%~G^ewq!U=c5ke}2Z z!t@%^3N?j=a-T239y6ck?>A;@@(m#>7#xtFV;E89i+nr7U!j|o0t$M2mG!-AQ{N*g z&mij%8AHU?Pz%Tz80!Jw1dI9+Og?SjeBp%#(RSh53T3%V}ggNKFy((zMaF?m`cfP3BU0D>0qxp5JNbXxl@n9lc5^~ocN4u zr*UKNeA6VpCE}+FJDX@lH97xs0&M zNh}~$E!$h;cSu7@Wg}_Q2U3hU5oPFMTF^pGxt1b=|MjqZdfkp;UMV&0!fe_9_F}nf=gr(f?YkJ7piTS^U|lb5=|pEBd2?Uof%InZDP4oXWZ)?Djg) zNroI5p=pgAxnhXFE~AT1KehXM|6qV@=PPXA`ZO)=MEeZnzp{4h)0;D5rRlc z$Jk_z{OLMeZEJz(*ui7Fx+bn1w6`zcYdpea7?z<|zoIXOAhwZmEujT@jJ%Jg1ukDC-T?#oktiGgC|z$$t%TlSJL0lI_%Yqhob z`;q)$nVdW*$j@~;#k5%ui&q5r_VibW&rniUBgQ2%G9~FWmYZajHPxgFiesamv>jiH z4?J9x&fC8fIEw?U(ADhl&qO?5oD(cOVw^|^@>}mlqJCOKW=Y|f!#GTGxX^cGimk79 z&5Skv2BkbGPSG_f#f0xKw<0gxewNn^eF-@HsL&Fxv^9N7;>#VJ1auqc44C~tH4GWA zHizgw^(<0Hb6fH+98sAUj`;3v471Qb5M@5}Q$Q9ztoubdB52S2&OaB|E$F1j|v?z z^lokL*FQk22qAR8av9LY6Je~`m}a2%zDJ$Ve%KWEq8c15I%(i92)gR4$@p)~2nM~GzfA;ma5eWw>E z{Vz&5)4df7=Pytd24yo5Y8)WfUerHx(84{Fk-K?crDL;veF1~ZN-9c##EgRe7mi$n Aq5uE@ literal 0 HcmV?d00001 diff --git a/plugins/should-i-deploy/package.json b/plugins/should-i-deploy/package.json new file mode 100644 index 0000000000..d6c9bd6d6e --- /dev/null +++ b/plugins/should-i-deploy/package.json @@ -0,0 +1,63 @@ +{ + "name": "@backstage/plugin-should-i-deploy", + "version": "0.1.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "frontend-plugin" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/should-i-deploy" + }, + "sideEffects": false, + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-home-react": "workspace:^", + "@backstage/theme": "workspace:^", + "@material-ui/core": "^4.9.13", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.57", + "@testing-library/jest-dom": "^5.10.1", + "cross-fetch": "^3.1.5", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router": "6.0.0-beta.0 || ^6.3.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/react": "12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/jest": "*", + "@types/node": "*", + "msw": "^0.44.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/should-i-deploy/src/@types/api/apiResponse.ts b/plugins/should-i-deploy/src/@types/api/apiResponse.ts new file mode 100644 index 0000000000..834087d9f4 --- /dev/null +++ b/plugins/should-i-deploy/src/@types/api/apiResponse.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export type ApiResponse = { + timezone: string; + date: string; + shouldideploy: boolean; + message: string; +}; diff --git a/plugins/should-i-deploy/src/api/ShouldIDeployCIApi.ts b/plugins/should-i-deploy/src/api/ShouldIDeployCIApi.ts new file mode 100644 index 0000000000..188f650479 --- /dev/null +++ b/plugins/should-i-deploy/src/api/ShouldIDeployCIApi.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createApiRef } from '@backstage/core-plugin-api'; +import { ApiResponse } from '../@types/api/apiResponse'; + +export const ShouldIDeployCIApiRef = createApiRef({ + id: 'backstage.plugin.should.i.deploy', +}); + +export type ShouldIDeployCIApi = { + get(timeZone?: string): Promise; +}; diff --git a/plugins/should-i-deploy/src/api/ShouldIDeployCIClient.test.ts b/plugins/should-i-deploy/src/api/ShouldIDeployCIClient.test.ts new file mode 100644 index 0000000000..c7f052972e --- /dev/null +++ b/plugins/should-i-deploy/src/api/ShouldIDeployCIClient.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { FetchApi } from '@backstage/core-plugin-api'; +import { ShouldIDeployCIClient } from './ShouldIDeployCIClient'; +import { ShouldIDeployCIApi } from './ShouldIDeployCIApi'; + +interface ExtendedFetchApi extends FetchApi { + fetch: jest.Mock>; +} + +describe('ShouldIDeployCIClient', () => { + let fetchApi: ExtendedFetchApi; + let client: ShouldIDeployCIApi; + + beforeEach(() => { + fetchApi = { + fetch: jest.fn(), + }; + client = new ShouldIDeployCIClient({ fetchApi }); + }); + + it('should create an instance of ShouldIDeployCIClient', () => { + expect(client).toBeInstanceOf(ShouldIDeployCIClient); + }); + + it('should call the API and return the response', async () => { + const mockResponse = { some: 'data' }; + fetchApi.fetch.mockResolvedValue({ + ok: true, + json: () => mockResponse, + }); + + const response = await client.get(); + + expect(fetchApi.fetch).toHaveBeenCalledWith( + 'https://shouldideploy.today/api', + ); + expect(response).toEqual(mockResponse); + }); + + it('should build the correct URL with timeZone', async () => { + const mockResponse = { some: 'data' }; + fetchApi.fetch.mockResolvedValue({ + ok: true, + json: () => mockResponse, + }); + + const timeZone = 'America/Sao_Paulo'; + + await client.get(timeZone); + + expect(fetchApi.fetch).toHaveBeenCalledWith( + `https://shouldideploy.today/api?tz=${timeZone}`, + ); + }); + + it('should handle API error and throw an error', async () => { + let error; + fetchApi.fetch.mockResolvedValue({ + ok: false, + }); + + try { + await client.get(); + } catch (err) { + error = err; + } + + expect(error).toBeInstanceOf(Error); + expect(error.message).toBe('Error to load response.'); + }); +}); diff --git a/plugins/should-i-deploy/src/api/ShouldIDeployCIClient.ts b/plugins/should-i-deploy/src/api/ShouldIDeployCIClient.ts new file mode 100644 index 0000000000..c87d8dd192 --- /dev/null +++ b/plugins/should-i-deploy/src/api/ShouldIDeployCIClient.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { FetchApi } from '@backstage/core-plugin-api'; +import { ShouldIDeployCIApi } from './ShouldIDeployCIApi'; +import { ApiResponse } from '../@types/api/apiResponse'; + +export class ShouldIDeployCIClient implements ShouldIDeployCIApi { + fetchApi: FetchApi; + + constructor({ fetchApi }: { fetchApi: FetchApi }) { + this.fetchApi = fetchApi; + } + + protected async callApi(timeZone?: string): Promise { + const url = timeZone + ? `https://shouldideploy.today/api?tz=${timeZone}` + : 'https://shouldideploy.today/api'; + const response = await this.fetchApi.fetch(url); + + if (response.ok) { + return (await response.json()) as T; + } + + return Promise.reject(response); + } + + async get(timeZone?: string): Promise { + try { + const response = await this.callApi(timeZone); + + return response; + } catch (_error) { + throw new Error('Error to load response.'); + } + } +} diff --git a/plugins/should-i-deploy/src/api/index.ts b/plugins/should-i-deploy/src/api/index.ts new file mode 100644 index 0000000000..167860cbec --- /dev/null +++ b/plugins/should-i-deploy/src/api/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { ShouldIDeployCIApiRef } from './ShouldIDeployCIApi'; +export { ShouldIDeployCIClient } from './ShouldIDeployCIClient'; diff --git a/plugins/should-i-deploy/src/components/ShouldIDeployCard/CardStyles.ts b/plugins/should-i-deploy/src/components/ShouldIDeployCard/CardStyles.ts new file mode 100644 index 0000000000..257b88cc21 --- /dev/null +++ b/plugins/should-i-deploy/src/components/ShouldIDeployCard/CardStyles.ts @@ -0,0 +1,53 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { makeStyles } from '@material-ui/core'; + +export const cardStyles = makeStyles({ + card: { padding: '20px' }, + reason: { fontSize: '1.5em' }, + tagline: { + font: "800 0.75rem/0.75rem SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace", + marginBottom: '1em', + color: '#FFF', + textTransform: 'uppercase', + padding: '14px 0 13px 0', + }, + text: { + font: "800 1.5rem -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif", + color: '#111', + textTransform: 'uppercase', + hyphens: 'auto', + }, + reload: { + display: 'inline-block', + font: "350 0.75rem/0.75rem SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace", + background: 'transparent', + textDecoration: 'none', + color: 'gray', + marginTop: '1rem', + outline: 'none', + cursor: 'pointer', + width: '4rem', + padding: '0.25em 1em', + border: '1px solid', + borderRadius: '4px', + borderColor: 'gray', + }, + container: { + textAlign: 'center', + alignItems: 'center', + }, +}); diff --git a/plugins/should-i-deploy/src/components/ShouldIDeployCard/Content.test.tsx b/plugins/should-i-deploy/src/components/ShouldIDeployCard/Content.test.tsx new file mode 100644 index 0000000000..235dea660e --- /dev/null +++ b/plugins/should-i-deploy/src/components/ShouldIDeployCard/Content.test.tsx @@ -0,0 +1,79 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { Content } from './Content'; +import { ShouldIDeployCIApiRef } from '../../api'; +import { ShouldIDeployCIApi } from '../../api/ShouldIDeployCIApi'; +import { screen } from '@testing-library/react'; + +const mockSuccessApiRef = { + get: async () => + Promise.resolve({ + timezone: 'UTC', + date: '2023-10-30T11:10:26.000Z', + shouldideploy: true, + message: 'Make me proud', + }), +}; + +const mockErrorApiRef = { + get: async () => Promise.reject(new Error('Error to load infos')), +}; + +describe('ShouldIDeployCard', () => { + beforeEach(async () => { + await renderInTestApp( + + + , + ); + }); + + it('should render', async () => { + expect( + await screen.findByTestId('should-i-deploy-card'), + ).toBeInTheDocument(); + }); +}); + +describe('ShouldIDeployCard Error', () => { + beforeEach(async () => { + await renderInTestApp( + + + , + ); + }); + + it('should render error panel', async () => { + expect(screen.getByText('Error to load infos')).toBeInTheDocument(); + }); +}); diff --git a/plugins/should-i-deploy/src/components/ShouldIDeployCard/Content.tsx b/plugins/should-i-deploy/src/components/ShouldIDeployCard/Content.tsx new file mode 100644 index 0000000000..a25146a9c8 --- /dev/null +++ b/plugins/should-i-deploy/src/components/ShouldIDeployCard/Content.tsx @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { ShouldIDeployCard } from './ShouldIDeployCard'; + +export const Content = ({ timeZone }: { timeZone?: string }) => { + return ; +}; diff --git a/plugins/should-i-deploy/src/components/ShouldIDeployCard/ShouldIDeployCard.test.tsx b/plugins/should-i-deploy/src/components/ShouldIDeployCard/ShouldIDeployCard.test.tsx new file mode 100644 index 0000000000..9fd7785bee --- /dev/null +++ b/plugins/should-i-deploy/src/components/ShouldIDeployCard/ShouldIDeployCard.test.tsx @@ -0,0 +1,62 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { ShouldIDeployCard } from './ShouldIDeployCard'; +import { ShouldIDeployCIApiRef } from '../../api'; +import { ShouldIDeployCIApi } from '../../api/ShouldIDeployCIApi'; +import { screen, fireEvent } from '@testing-library/react'; + +const mockSuccessApiRef = { + get: jest.fn(() => + Promise.resolve({ + message: "It's a good day to deploy!", + date: new Date().toISOString(), + }), + ), +}; + +describe('ShouldIDeployCard', () => { + beforeEach(async () => { + await renderInTestApp( + + + , + ); + }); + + it('should render the card with data', async () => { + await screen.findByText("It's a good day to deploy!"); + expect(screen.getByText('Should I Deploy Today?')).toBeInTheDocument(); + expect(screen.getByText("It's a good day to deploy!")).toBeInTheDocument(); + expect(screen.getByText('Click')).toBeInTheDocument(); + }); + + it('should reload data on click', async () => { + await screen.findByText("It's a good day to deploy!"); + fireEvent.click(screen.getByText('Click')); + expect( + await screen.findByText("It's a good day to deploy!"), + ).toBeInTheDocument(); + }); +}); diff --git a/plugins/should-i-deploy/src/components/ShouldIDeployCard/ShouldIDeployCard.tsx b/plugins/should-i-deploy/src/components/ShouldIDeployCard/ShouldIDeployCard.tsx new file mode 100644 index 0000000000..9f46ea761f --- /dev/null +++ b/plugins/should-i-deploy/src/components/ShouldIDeployCard/ShouldIDeployCard.tsx @@ -0,0 +1,76 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Progress, ResponseErrorPanel } from '@backstage/core-components'; +import { useApi } from '@backstage/core-plugin-api'; +import useAsync from 'react-use/lib/useAsync'; +import { ShouldIDeployCIApiRef } from '../../api'; +import { getBackegroundColor } from '../../helpers/getBackgroundColor'; +import { cardStyles } from './CardStyles'; +import { Typography } from '@material-ui/core'; + +export const ShouldIDeployCard = ({ timeZone }: { timeZone?: string }) => { + const [reason, setReasons] = React.useState(); + const [backgroundColor, setBackgroundColor] = React.useState(); + const classes = cardStyles(); + + const ShouldIDeployCIApi = useApi(ShouldIDeployCIApiRef); + const { loading, error } = useAsync(async () => { + const res = await ShouldIDeployCIApi.get(timeZone); + const day = new Date(res.date).getDay(); + setBackgroundColor(getBackegroundColor(day)); + setReasons(res?.message); + + return res; + }, []); + + const onClick = async (event: { type: string }) => { + if (event.type === 'click') { + const response = await ShouldIDeployCIApi.get(timeZone); + setReasons(response.message); + } + }; + + if (loading) { + return ; + } + + if (error) { + return ; + } + + return ( +
+
+

Should I Deploy Today?

+

+ {reason} +

+ + Click + +
+
+ ); +}; diff --git a/plugins/should-i-deploy/src/components/ShouldIDeployCard/index.ts b/plugins/should-i-deploy/src/components/ShouldIDeployCard/index.ts new file mode 100644 index 0000000000..183cfbf637 --- /dev/null +++ b/plugins/should-i-deploy/src/components/ShouldIDeployCard/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { ShouldIDeployCard } from './ShouldIDeployCard'; +export { Content } from './Content'; diff --git a/plugins/should-i-deploy/src/helpers/getBackgroundColor.test.ts b/plugins/should-i-deploy/src/helpers/getBackgroundColor.test.ts new file mode 100644 index 0000000000..d42161eb94 --- /dev/null +++ b/plugins/should-i-deploy/src/helpers/getBackgroundColor.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { getBackegroundColor } from './getBackgroundColor'; + +describe('getBackegroundColor', () => { + it('should return green for Monday (day 1)', () => { + const result = getBackegroundColor(1); + expect(result).toBe('MediumSpringGreen'); + }); + + it('should return green for Tuesday (day 2)', () => { + const result = getBackegroundColor(2); + expect(result).toBe('MediumSpringGreen'); + }); + + it('should return green for Wednesday (day 3)', () => { + const result = getBackegroundColor(3); + expect(result).toBe('MediumSpringGreen'); + }); + + it('should return orange for Thursday (day 4)', () => { + const result = getBackegroundColor(4); + expect(result).toBe('LightSalmon'); + }); + + it('should return red for Friday (day 5)', () => { + const result = getBackegroundColor(5); + expect(result).toBe('Red'); + }); + + it('should return red for Saturday (day 6)', () => { + const result = getBackegroundColor(6); + expect(result).toBe('Red'); + }); + + it('should return red for Sunday (day 0)', () => { + const result = getBackegroundColor(0); + expect(result).toBe('Red'); + }); + + it('should return white for an invalid day (e.g., 7)', () => { + const result = getBackegroundColor(7); + expect(result).toBe('White'); + }); +}); diff --git a/plugins/should-i-deploy/src/helpers/getBackgroundColor.ts b/plugins/should-i-deploy/src/helpers/getBackgroundColor.ts new file mode 100644 index 0000000000..b3d42456a3 --- /dev/null +++ b/plugins/should-i-deploy/src/helpers/getBackgroundColor.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const getBackegroundColor = (day: number) => { + const red = 'Red'; + const green = 'MediumSpringGreen'; + const orange = 'LightSalmon'; + const white = 'White'; + switch (day) { + case 1: + return green; + case 2: + return green; + case 3: + return green; + case 4: + return orange; + case 5: + return red; + case 6: + return red; + case 0: + return red; + default: + return white; + } +}; diff --git a/plugins/should-i-deploy/src/helpers/timezones.ts b/plugins/should-i-deploy/src/helpers/timezones.ts new file mode 100644 index 0000000000..3191d113e0 --- /dev/null +++ b/plugins/should-i-deploy/src/helpers/timezones.ts @@ -0,0 +1,609 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const timeZones = [ + 'Africa/Abidjan', + 'Africa/Accra', + 'Africa/Addis_Ababa', + 'Africa/Algiers', + 'Africa/Asmara', + 'Africa/Asmera', + 'Africa/Bamako', + 'Africa/Bangui', + 'Africa/Banjul', + 'Africa/Bissau', + 'Africa/Blantyre', + 'Africa/Brazzaville', + 'Africa/Bujumbura', + 'Africa/Cairo', + 'Africa/Casablanca', + 'Africa/Ceuta', + 'Africa/Conakry', + 'Africa/Dakar', + 'Africa/Dar_es_Salaam', + 'Africa/Djibouti', + 'Africa/Douala', + 'Africa/El_Aaiun', + 'Africa/Freetown', + 'Africa/Gaborone', + 'Africa/Harare', + 'Africa/Johannesburg', + 'Africa/Juba', + 'Africa/Kampala', + 'Africa/Khartoum', + 'Africa/Kigali', + 'Africa/Kinshasa', + 'Africa/Lagos', + 'Africa/Libreville', + 'Africa/Lome', + 'Africa/Luanda', + 'Africa/Lubumbashi', + 'Africa/Lusaka', + 'Africa/Malabo', + 'Africa/Maputo', + 'Africa/Maseru', + 'Africa/Mbabane', + 'Africa/Mogadishu', + 'Africa/Monrovia', + 'Africa/Nairobi', + 'Africa/Ndjamena', + 'Africa/Niamey', + 'Africa/Nouakchott', + 'Africa/Ouagadougou', + 'Africa/Porto-Novo', + 'Africa/Sao_Tome', + 'Africa/Timbuktu', + 'Africa/Tripoli', + 'Africa/Tunis', + 'Africa/Windhoek', + 'America/Adak', + 'America/Anchorage', + 'America/Anguilla', + 'America/Antigua', + 'America/Araguaina', + 'America/Argentina/Buenos_Aires', + 'America/Argentina/Catamarca', + 'America/Argentina/ComodRivadavia', + 'America/Argentina/Cordoba', + 'America/Argentina/Jujuy', + 'America/Argentina/La_Rioja', + 'America/Argentina/Mendoza', + 'America/Argentina/Rio_Gallegos', + 'America/Argentina/Salta', + 'America/Argentina/San_Juan', + 'America/Argentina/San_Luis', + 'America/Argentina/Tucuman', + 'America/Argentina/Ushuaia', + 'America/Aruba', + 'America/Asuncion', + 'America/Atikokan', + 'America/Atka', + 'America/Bahia', + 'America/Bahia_Banderas', + 'America/Barbados', + 'America/Belem', + 'America/Belize', + 'America/Blanc-Sablon', + 'America/Boa_Vista', + 'America/Bogota', + 'America/Boise', + 'America/Buenos_Aires', + 'America/Cambridge_Bay', + 'America/Campo_Grande', + 'America/Cancun', + 'America/Caracas', + 'America/Catamarca', + 'America/Cayenne', + 'America/Cayman', + 'America/Chicago', + 'America/Chihuahua', + 'America/Coral_Harbour', + 'America/Cordoba', + 'America/Costa_Rica', + 'America/Creston', + 'America/Cuiaba', + 'America/Curacao', + 'America/Danmarkshavn', + 'America/Dawson', + 'America/Dawson_Creek', + 'America/Denver', + 'America/Detroit', + 'America/Dominica', + 'America/Edmonton', + 'America/Eirunepe', + 'America/El_Salvador', + 'America/Ensenada', + 'America/Fort_Nelson', + 'America/Fort_Wayne', + 'America/Fortaleza', + 'America/Glace_Bay', + 'America/Godthab', + 'America/Goose_Bay', + 'America/Grand_Turk', + 'America/Grenada', + 'America/Guadeloupe', + 'America/Guatemala', + 'America/Guayaquil', + 'America/Guyana', + 'America/Halifax', + 'America/Havana', + 'America/Hermosillo', + 'America/Indiana/Indianapolis', + 'America/Indiana/Knox', + 'America/Indiana/Marengo', + 'America/Indiana/Petersburg', + 'America/Indiana/Tell_City', + 'America/Indiana/Vevay', + 'America/Indiana/Vincennes', + 'America/Indiana/Winamac', + 'America/Indianapolis', + 'America/Inuvik', + 'America/Iqaluit', + 'America/Jamaica', + 'America/Jujuy', + 'America/Juneau', + 'America/Kentucky/Louisville', + 'America/Kentucky/Monticello', + 'America/Knox_IN', + 'America/Kralendijk', + 'America/La_Paz', + 'America/Lima', + 'America/Los_Angeles', + 'America/Louisville', + 'America/Lower_Princes', + 'America/Maceio', + 'America/Managua', + 'America/Manaus', + 'America/Marigot', + 'America/Martinique', + 'America/Matamoros', + 'America/Mazatlan', + 'America/Mendoza', + 'America/Menominee', + 'America/Merida', + 'America/Metlakatla', + 'America/Mexico_City', + 'America/Miquelon', + 'America/Moncton', + 'America/Monterrey', + 'America/Montevideo', + 'America/Montreal', + 'America/Montserrat', + 'America/Nassau', + 'America/New_York', + 'America/Nipigon', + 'America/Nome', + 'America/Noronha', + 'America/North_Dakota/Beulah', + 'America/North_Dakota/Center', + 'America/North_Dakota/New_Salem', + 'America/Ojinaga', + 'America/Panama', + 'America/Pangnirtung', + 'America/Paramaribo', + 'America/Phoenix', + 'America/Port-au-Prince', + 'America/Port_of_Spain', + 'America/Porto_Acre', + 'America/Porto_Velho', + 'America/Puerto_Rico', + 'America/Punta_Arenas', + 'America/Rainy_River', + 'America/Rankin_Inlet', + 'America/Recife', + 'America/Regina', + 'America/Resolute', + 'America/Rio_Branco', + 'America/Rosario', + 'America/Santa_Isabel', + 'America/Santarem', + 'America/Santiago', + 'America/Santo_Domingo', + 'America/Sao_Paulo', + 'America/Scoresbysund', + 'America/Shiprock', + 'America/Sitka', + 'America/St_Barthelemy', + 'America/St_Johns', + 'America/St_Kitts', + 'America/St_Lucia', + 'America/St_Thomas', + 'America/St_Vincent', + 'America/Swift_Current', + 'America/Tegucigalpa', + 'America/Thule', + 'America/Thunder_Bay', + 'America/Tijuana', + 'America/Toronto', + 'America/Tortola', + 'America/Vancouver', + 'America/Virgin', + 'America/Whitehorse', + 'America/Winnipeg', + 'America/Yakutat', + 'America/Yellowknife', + 'Antarctica/Casey', + 'Antarctica/Davis', + 'Antarctica/DumontDUrville', + 'Antarctica/Macquarie', + 'Antarctica/Mawson', + 'Antarctica/McMurdo', + 'Antarctica/Palmer', + 'Antarctica/Rothera', + 'Antarctica/South_Pole', + 'Antarctica/Syowa', + 'Antarctica/Troll', + 'Antarctica/Vostok', + 'Arctic/Longyearbyen', + 'Asia/Aden', + 'Asia/Almaty', + 'Asia/Amman', + 'Asia/Anadyr', + 'Asia/Aqtau', + 'Asia/Aqtobe', + 'Asia/Ashgabat', + 'Asia/Ashkhabad', + 'Asia/Atyrau', + 'Asia/Baghdad', + 'Asia/Bahrain', + 'Asia/Baku', + 'Asia/Bangkok', + 'Asia/Barnaul', + 'Asia/Beirut', + 'Asia/Bishkek', + 'Asia/Brunei', + 'Asia/Calcutta', + 'Asia/Chita', + 'Asia/Choibalsan', + 'Asia/Chongqing', + 'Asia/Chungking', + 'Asia/Colombo', + 'Asia/Dacca', + 'Asia/Damascus', + 'Asia/Dhaka', + 'Asia/Dili', + 'Asia/Dubai', + 'Asia/Dushanbe', + 'Asia/Famagusta', + 'Asia/Gaza', + 'Asia/Harbin', + 'Asia/Hebron', + 'Asia/Ho_Chi_Minh', + 'Asia/Hong_Kong', + 'Asia/Hovd', + 'Asia/Irkutsk', + 'Asia/Istanbul', + 'Asia/Jakarta', + 'Asia/Jayapura', + 'Asia/Jerusalem', + 'Asia/Kabul', + 'Asia/Kamchatka', + 'Asia/Karachi', + 'Asia/Kashgar', + 'Asia/Kathmandu', + 'Asia/Katmandu', + 'Asia/Khandyga', + 'Asia/Kolkata', + 'Asia/Krasnoyarsk', + 'Asia/Kuala_Lumpur', + 'Asia/Kuching', + 'Asia/Kuwait', + 'Asia/Macao', + 'Asia/Macau', + 'Asia/Magadan', + 'Asia/Makassar', + 'Asia/Manila', + 'Asia/Muscat', + 'Asia/Nicosia', + 'Asia/Novokuznetsk', + 'Asia/Novosibirsk', + 'Asia/Omsk', + 'Asia/Oral', + 'Asia/Phnom_Penh', + 'Asia/Pontianak', + 'Asia/Pyongyang', + 'Asia/Qatar', + 'Asia/Qyzylorda', + 'Asia/Rangoon', + 'Asia/Riyadh', + 'Asia/Saigon', + 'Asia/Sakhalin', + 'Asia/Samarkand', + 'Asia/Seoul', + 'Asia/Shanghai', + 'Asia/Singapore', + 'Asia/Srednekolymsk', + 'Asia/Taipei', + 'Asia/Tashkent', + 'Asia/Tbilisi', + 'Asia/Tehran', + 'Asia/Tel_Aviv', + 'Asia/Thimbu', + 'Asia/Thimphu', + 'Asia/Tokyo', + 'Asia/Tomsk', + 'Asia/Ujung_Pandang', + 'Asia/Ulaanbaatar', + 'Asia/Ulan_Bator', + 'Asia/Urumqi', + 'Asia/Ust-Nera', + 'Asia/Vientiane', + 'Asia/Vladivostok', + 'Asia/Yakutsk', + 'Asia/Yangon', + 'Asia/Yekaterinburg', + 'Asia/Yerevan', + 'Atlantic/Azores', + 'Atlantic/Bermuda', + 'Atlantic/Canary', + 'Atlantic/Cape_Verde', + 'Atlantic/Faeroe', + 'Atlantic/Faroe', + 'Atlantic/Jan_Mayen', + 'Atlantic/Madeira', + 'Atlantic/Reykjavik', + 'Atlantic/South_Georgia', + 'Atlantic/St_Helena', + 'Atlantic/Stanley', + 'Australia/ACT', + 'Australia/Adelaide', + 'Australia/Brisbane', + 'Australia/Broken_Hill', + 'Australia/Canberra', + 'Australia/Currie', + 'Australia/Darwin', + 'Australia/Eucla', + 'Australia/Hobart', + 'Australia/LHI', + 'Australia/Lindeman', + 'Australia/Lord_Howe', + 'Australia/Melbourne', + 'Australia/NSW', + 'Australia/North', + 'Australia/Perth', + 'Australia/Queensland', + 'Australia/South', + 'Australia/Sydney', + 'Australia/Tasmania', + 'Australia/Victoria', + 'Australia/West', + 'Australia/Yancowinna', + 'Brazil/Acre', + 'Brazil/DeNoronha', + 'Brazil/East', + 'Brazil/West', + 'CET', + 'CST6CDT', + 'Canada/Atlantic', + 'Canada/Central', + 'Canada/Eastern', + 'Canada/Mountain', + 'Canada/Newfoundland', + 'Canada/Pacific', + 'Canada/Saskatchewan', + 'Canada/Yukon', + 'Chile/Continental', + 'Chile/EasterIsland', + 'Cuba', + 'EET', + 'EST', + 'EST5EDT', + 'Egypt', + 'Eire', + 'Etc/GMT', + 'Etc/GMT+0', + 'Etc/GMT+1', + 'Etc/GMT+10', + 'Etc/GMT+11', + 'Etc/GMT+12', + 'Etc/GMT+2', + 'Etc/GMT+3', + 'Etc/GMT+4', + 'Etc/GMT+5', + 'Etc/GMT+6', + 'Etc/GMT+7', + 'Etc/GMT+8', + 'Etc/GMT+9', + 'Etc/GMT-0', + 'Etc/GMT-1', + 'Etc/GMT-10', + 'Etc/GMT-11', + 'Etc/GMT-12', + 'Etc/GMT-13', + 'Etc/GMT-14', + 'Etc/GMT-2', + 'Etc/GMT-3', + 'Etc/GMT-4', + 'Etc/GMT-5', + 'Etc/GMT-6', + 'Etc/GMT-7', + 'Etc/GMT-8', + 'Etc/GMT-9', + 'Etc/GMT0', + 'Etc/Greenwich', + 'Etc/UCT', + 'Etc/UTC', + 'Etc/Universal', + 'Etc/Zulu', + 'Europe/Amsterdam', + 'Europe/Andorra', + 'Europe/Astrakhan', + 'Europe/Athens', + 'Europe/Belfast', + 'Europe/Belgrade', + 'Europe/Berlin', + 'Europe/Bratislava', + 'Europe/Brussels', + 'Europe/Bucharest', + 'Europe/Budapest', + 'Europe/Busingen', + 'Europe/Chisinau', + 'Europe/Copenhagen', + 'Europe/Dublin', + 'Europe/Gibraltar', + 'Europe/Guernsey', + 'Europe/Helsinki', + 'Europe/Isle_of_Man', + 'Europe/Istanbul', + 'Europe/Jersey', + 'Europe/Kaliningrad', + 'Europe/Kiev', + 'Europe/Kirov', + 'Europe/Lisbon', + 'Europe/Ljubljana', + 'Europe/London', + 'Europe/Luxembourg', + 'Europe/Madrid', + 'Europe/Malta', + 'Europe/Mariehamn', + 'Europe/Minsk', + 'Europe/Monaco', + 'Europe/Moscow', + 'Europe/Nicosia', + 'Europe/Oslo', + 'Europe/Paris', + 'Europe/Podgorica', + 'Europe/Prague', + 'Europe/Riga', + 'Europe/Rome', + 'Europe/Samara', + 'Europe/San_Marino', + 'Europe/Sarajevo', + 'Europe/Saratov', + 'Europe/Simferopol', + 'Europe/Skopje', + 'Europe/Sofia', + 'Europe/Stockholm', + 'Europe/Tallinn', + 'Europe/Tirane', + 'Europe/Tiraspol', + 'Europe/Ulyanovsk', + 'Europe/Uzhgorod', + 'Europe/Vaduz', + 'Europe/Vatican', + 'Europe/Vienna', + 'Europe/Vilnius', + 'Europe/Volgograd', + 'Europe/Warsaw', + 'Europe/Zagreb', + 'Europe/Zaporozhye', + 'Europe/Zurich', + 'GB', + 'GB-Eire', + 'GMT', + 'GMT+0', + 'GMT-0', + 'GMT0', + 'Greenwich', + 'HST', + 'Hongkong', + 'Iceland', + 'Indian/Antananarivo', + 'Indian/Chagos', + 'Indian/Christmas', + 'Indian/Cocos', + 'Indian/Comoro', + 'Indian/Kerguelen', + 'Indian/Mahe', + 'Indian/Maldives', + 'Indian/Mauritius', + 'Indian/Mayotte', + 'Indian/Reunion', + 'Iran', + 'Israel', + 'Jamaica', + 'Japan', + 'Kwajalein', + 'Libya', + 'MET', + 'MST', + 'MST7MDT', + 'Mexico/BajaNorte', + 'Mexico/BajaSur', + 'Mexico/General', + 'NZ', + 'NZ-CHAT', + 'Navajo', + 'PRC', + 'PST8PDT', + 'Pacific/Apia', + 'Pacific/Auckland', + 'Pacific/Bougainville', + 'Pacific/Chatham', + 'Pacific/Chuuk', + 'Pacific/Easter', + 'Pacific/Efate', + 'Pacific/Enderbury', + 'Pacific/Fakaofo', + 'Pacific/Fiji', + 'Pacific/Funafuti', + 'Pacific/Galapagos', + 'Pacific/Gambier', + 'Pacific/Guadalcanal', + 'Pacific/Guam', + 'Pacific/Honolulu', + 'Pacific/Johnston', + 'Pacific/Kiritimati', + 'Pacific/Kosrae', + 'Pacific/Kwajalein', + 'Pacific/Majuro', + 'Pacific/Marquesas', + 'Pacific/Midway', + 'Pacific/Nauru', + 'Pacific/Niue', + 'Pacific/Norfolk', + 'Pacific/Noumea', + 'Pacific/Pago_Pago', + 'Pacific/Palau', + 'Pacific/Pitcairn', + 'Pacific/Pohnpei', + 'Pacific/Ponape', + 'Pacific/Port_Moresby', + 'Pacific/Rarotonga', + 'Pacific/Saipan', + 'Pacific/Samoa', + 'Pacific/Tahiti', + 'Pacific/Tarawa', + 'Pacific/Tongatapu', + 'Pacific/Truk', + 'Pacific/Wake', + 'Pacific/Wallis', + 'Pacific/Yap', + 'Poland', + 'Portugal', + 'ROC', + 'ROK', + 'Singapore', + 'Turkey', + 'UCT', + 'US/Alaska', + 'US/Aleutian', + 'US/Arizona', + 'US/Central', + 'US/East-Indiana', + 'US/Eastern', + 'US/Hawaii', + 'US/Indiana-Starke', + 'US/Michigan', + 'US/Mountain', + 'US/Pacific', + 'US/Pacific-New', + 'US/Samoa', + 'UTC', + 'Universal', + 'W-SU', + 'WET', + 'Zulu', +]; diff --git a/plugins/should-i-deploy/src/index.ts b/plugins/should-i-deploy/src/index.ts new file mode 100644 index 0000000000..ad6f751f61 --- /dev/null +++ b/plugins/should-i-deploy/src/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { + shouldIDeployPlugin, + ShouldIDeployCard, + ShouldIDeployPage, +} from './plugin'; diff --git a/plugins/should-i-deploy/src/plugin.test.tsx b/plugins/should-i-deploy/src/plugin.test.tsx new file mode 100644 index 0000000000..e57d456207 --- /dev/null +++ b/plugins/should-i-deploy/src/plugin.test.tsx @@ -0,0 +1,107 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Routes, Route } from 'react-router'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { + ShouldIDeployCard, + ShouldIDeployPage, + shouldIDeployPlugin, +} from './plugin'; +import { + ShouldIDeployCIApi, + ShouldIDeployCIApiRef, +} from './api/ShouldIDeployCIApi'; +import { screen } from '@testing-library/react'; + +const fetchPageApi = { + fetch: jest.fn().mockResolvedValue({ + ok: true, + json: () => + Promise.resolve({ + message: "It's a good day to deploy!", + date: new Date().toISOString(), + }), + }), +}; + +const mockSuccessApiRef = { + get: async () => + Promise.resolve({ + message: "It's a good day to deploy!", + date: new Date().toISOString(), + }), +}; + +describe('Plugin base', () => { + it('should export plugin', () => { + expect(shouldIDeployPlugin).toBeDefined(); + }); + + it('should create plugin api', () => { + const apiArray = Array.from(shouldIDeployPlugin.getApis()); + const api = apiArray[0]?.factory({ + fetchApi: fetchPageApi, + }) as ShouldIDeployCIApi[]; + expect(api).toBeDefined(); + }); +}); + +describe('Plugin page', () => { + beforeEach(async () => { + await renderInTestApp( + + + } /> + + , + ); + }, 35000); + + it('should export plugin page', () => { + expect(ShouldIDeployPage).toBeDefined(); + const { getByText } = screen; + const element = getByText(/Should i deploy today/i); + expect(element).toBeInTheDocument(); + }); +}); + +describe('Plugin card', () => { + beforeEach(async () => { + await renderInTestApp( + + + } /> + + , + ); + }, 35000); + + it('should export plugin card', async () => { + expect(ShouldIDeployCard).toBeDefined(); + expect( + await screen.findByTestId('should-i-deploy-card'), + ).toBeInTheDocument(); + }); +}); diff --git a/plugins/should-i-deploy/src/plugin.ts b/plugins/should-i-deploy/src/plugin.ts new file mode 100644 index 0000000000..41f0abf595 --- /dev/null +++ b/plugins/should-i-deploy/src/plugin.ts @@ -0,0 +1,77 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + createApiFactory, + createPlugin, + createRoutableExtension, + fetchApiRef, +} from '@backstage/core-plugin-api'; +import { createCardExtension } from '@backstage/plugin-home-react'; +import { rootRouteRef } from './routes'; +import { ShouldIDeployCIClient, ShouldIDeployCIApiRef } from './api'; +import { timeZones } from './helpers/timezones'; + +export const shouldIDeployPlugin = createPlugin({ + id: '@backstage/plugin-should-i-deploy', + routes: { + root: rootRouteRef, + }, + apis: [ + createApiFactory({ + api: ShouldIDeployCIApiRef, + deps: { + fetchApi: fetchApiRef, + }, + factory: ({ fetchApi }) => + new ShouldIDeployCIClient({ + fetchApi, + }), + }), + ], +}); + +export const ShouldIDeployPage = shouldIDeployPlugin.provide( + createRoutableExtension({ + name: 'ShouldIDeployPage', + component: () => + import('./components/ShouldIDeployCard').then(m => m.Content), + mountPoint: rootRouteRef, + }), +); + +export const ShouldIDeployCard = shouldIDeployPlugin.provide( + createCardExtension<{ timeZone?: string; title?: string }>({ + name: 'ShouldIDeployCard', + components: () => import('./components/ShouldIDeployCard'), + layout: { + height: { minRows: 4 }, + width: { minColumns: 3 }, + }, + settings: { + schema: { + title: 'Should I Deploy settings', + type: 'object', + properties: { + timeZone: { + title: 'config local timezone', + type: 'string', + enum: timeZones, + }, + }, + }, + }, + }), +); diff --git a/plugins/should-i-deploy/src/routes.ts b/plugins/should-i-deploy/src/routes.ts new file mode 100644 index 0000000000..4137af3c26 --- /dev/null +++ b/plugins/should-i-deploy/src/routes.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { createRouteRef } from '@backstage/core-plugin-api'; + +export const rootRouteRef = createRouteRef({ + id: 'should-i-deploy', +}); diff --git a/plugins/should-i-deploy/src/setupTests.ts b/plugins/should-i-deploy/src/setupTests.ts new file mode 100644 index 0000000000..865308e634 --- /dev/null +++ b/plugins/should-i-deploy/src/setupTests.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@testing-library/jest-dom'; diff --git a/yarn.lock b/yarn.lock index 0a8a00ef9f..c8e7629e86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,7 +12,7 @@ __metadata: languageName: node linkType: hard -"@adobe/css-tools@npm:^4.3.1": +"@adobe/css-tools@npm:^4.0.1, @adobe/css-tools@npm:^4.3.1": version: 4.3.1 resolution: "@adobe/css-tools@npm:4.3.1" checksum: ad43456379ff391132aff687ece190cb23ea69395e23c9b96690eeabe2468da89a4aaf266e4f8b6eaab53db3d1064107ce0f63c3a974e864f4a04affc768da3f @@ -9389,6 +9389,37 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-should-i-deploy@workspace:plugins/should-i-deploy": + version: 0.0.0-use.local + resolution: "@backstage/plugin-should-i-deploy@workspace:plugins/should-i-deploy" + dependencies: + "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/dev-utils": "workspace:^" + "@backstage/plugin-home-react": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@material-ui/core": ^4.9.13 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.57 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": 12.1.3 + "@testing-library/user-event": ^14.0.0 + "@types/jest": "*" + "@types/node": "*" + cross-fetch: ^3.1.5 + msw: ^0.44.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router: 6.0.0-beta.0 || ^6.3.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + languageName: unknown + linkType: soft + "@backstage/plugin-sonarqube-backend@workspace:^, @backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend": version: 0.0.0-use.local resolution: "@backstage/plugin-sonarqube-backend@workspace:plugins/sonarqube-backend" @@ -13861,7 +13892,7 @@ __metadata: languageName: node linkType: hard -"@mswjs/interceptors@npm:^0.17.10": +"@mswjs/interceptors@npm:^0.17.10, @mswjs/interceptors@npm:^0.17.2": version: 0.17.10 resolution: "@mswjs/interceptors@npm:0.17.10" dependencies: @@ -17892,6 +17923,22 @@ __metadata: languageName: unknown linkType: soft +"@testing-library/dom@npm:^8.0.0": + version: 8.20.1 + resolution: "@testing-library/dom@npm:8.20.1" + dependencies: + "@babel/code-frame": ^7.10.4 + "@babel/runtime": ^7.12.5 + "@types/aria-query": ^5.0.1 + aria-query: 5.1.3 + chalk: ^4.1.0 + dom-accessibility-api: ^0.5.9 + lz-string: ^1.5.0 + pretty-format: ^27.0.2 + checksum: 06fc8dc67849aadb726cbbad0e7546afdf8923bd39acb64c576d706249bd7d0d05f08e08a31913fb621162e3b9c2bd0dce15964437f030f9fa4476326fdd3007 + languageName: node + linkType: hard + "@testing-library/dom@npm:^9.0.0": version: 9.3.3 resolution: "@testing-library/dom@npm:9.3.3" @@ -17908,6 +17955,23 @@ __metadata: languageName: node linkType: hard +"@testing-library/jest-dom@npm:^5.10.1": + version: 5.17.0 + resolution: "@testing-library/jest-dom@npm:5.17.0" + dependencies: + "@adobe/css-tools": ^4.0.1 + "@babel/runtime": ^7.9.2 + "@types/testing-library__jest-dom": ^5.9.1 + aria-query: ^5.0.0 + chalk: ^3.0.0 + css.escape: ^1.5.1 + dom-accessibility-api: ^0.5.6 + lodash: ^4.17.15 + redent: ^3.0.0 + checksum: 9f28dbca8b50d7c306aae40c3aa8e06f0e115f740360004bd87d57f95acf7ab4b4f4122a7399a76dbf2bdaaafb15c99cc137fdcb0ae457a92e2de0f3fbf9b03b + languageName: node + linkType: hard + "@testing-library/jest-dom@npm:^6.0.0": version: 6.1.4 resolution: "@testing-library/jest-dom@npm:6.1.4" @@ -17960,6 +18024,20 @@ __metadata: languageName: node linkType: hard +"@testing-library/react@npm:12.1.3": + version: 12.1.3 + resolution: "@testing-library/react@npm:12.1.3" + dependencies: + "@babel/runtime": ^7.12.5 + "@testing-library/dom": ^8.0.0 + "@types/react-dom": "*" + peerDependencies: + react: "*" + react-dom: "*" + checksum: 2f059e93dc3f161c4d15910d1fa80cd4f5cfb6eff8a733939a72ac720c2499b74761e8980c02983a6e49153b776e82bd770a1c3e66e05c4429db0e01612f7d0a + languageName: node + linkType: hard + "@testing-library/react@npm:^14.0.0": version: 14.0.0 resolution: "@testing-library/react@npm:14.0.0" @@ -22949,6 +23027,16 @@ __metadata: languageName: node linkType: hard +"chalk@npm:4.1.1": + version: 4.1.1 + resolution: "chalk@npm:4.1.1" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: 036e973e665ba1a32c975e291d5f3d549bceeb7b1b983320d4598fb75d70fe20c5db5d62971ec0fe76cdbce83985a00ee42372416abfc3a5584465005a7855ed + languageName: node + linkType: hard + "chalk@npm:4.1.2, chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" @@ -29470,7 +29558,7 @@ __metadata: languageName: node linkType: hard -"graphql@npm:^16.0.0, graphql@npm:^16.8.1": +"graphql@npm:^16.0.0, graphql@npm:^16.3.0, graphql@npm:^16.8.1": version: 16.8.1 resolution: "graphql@npm:16.8.1" checksum: 8d304b7b6f708c8c5cc164b06e92467dfe36aff6d4f2cf31dd19c4c2905a0e7b89edac4b7e225871131fd24e21460836b369de0c06532644d15b461d55b1ccc0 @@ -29740,6 +29828,13 @@ __metadata: languageName: node linkType: hard +"headers-polyfill@npm:^3.0.4": + version: 3.3.0 + resolution: "headers-polyfill@npm:3.3.0" + checksum: 6dd010544b7c1a878aa612b49d9e27d273aa9e8a462e1ae05ca212fafa68e6b7cbdec4765f4e443b2fe70d2818f5d9814eab53fa2ba793bf1e5a6b6eff760474 + languageName: node + linkType: hard + "helmet@npm:^6.0.0": version: 6.0.1 resolution: "helmet@npm:6.0.1" @@ -30979,7 +31074,7 @@ __metadata: languageName: node linkType: hard -"is-node-process@npm:^1.2.0": +"is-node-process@npm:^1.0.1, is-node-process@npm:^1.2.0": version: 1.2.0 resolution: "is-node-process@npm:1.2.0" checksum: 930765cdc6d81ab8f1bbecbea4a8d35c7c6d88a3ff61f3630e0fc7f22d624d7661c1df05c58547d0eb6a639dfa9304682c8e342c4113a6ed51472b704cee2928 @@ -35598,6 +35693,41 @@ __metadata: languageName: node linkType: hard +"msw@npm:^0.44.0": + version: 0.44.2 + resolution: "msw@npm:0.44.2" + dependencies: + "@mswjs/cookies": ^0.2.2 + "@mswjs/interceptors": ^0.17.2 + "@open-draft/until": ^1.0.3 + "@types/cookie": ^0.4.1 + "@types/js-levenshtein": ^1.1.1 + chalk: 4.1.1 + chokidar: ^3.4.2 + cookie: ^0.4.2 + graphql: ^16.3.0 + headers-polyfill: ^3.0.4 + inquirer: ^8.2.0 + is-node-process: ^1.0.1 + js-levenshtein: ^1.1.6 + node-fetch: ^2.6.7 + outvariant: ^1.3.0 + path-to-regexp: ^6.2.0 + statuses: ^2.0.0 + strict-event-emitter: ^0.2.0 + type-fest: ^1.2.2 + yargs: ^17.3.1 + peerDependencies: + typescript: ">= 4.2.x <= 4.7.x" + peerDependenciesMeta: + typescript: + optional: true + bin: + msw: cli/index.js + checksum: 739d536ee09d1c0a2cbc9dbe917f167c42115a6548f99780850ce9a63a5e7c377cf9b5f1a3b497e85ce7304025ab22966e997fe73adbd8d2ab968b8685f15a24 + languageName: node + linkType: hard + "msw@npm:^1.0.0, msw@npm:^1.0.1, msw@npm:^1.2.1, msw@npm:^1.2.3, msw@npm:^1.3.0, msw@npm:^1.3.1": version: 1.3.2 resolution: "msw@npm:1.3.2" @@ -36850,7 +36980,7 @@ __metadata: languageName: node linkType: hard -"outvariant@npm:^1.2.1, outvariant@npm:^1.4.0": +"outvariant@npm:^1.2.1, outvariant@npm:^1.3.0, outvariant@npm:^1.4.0": version: 1.4.0 resolution: "outvariant@npm:1.4.0" checksum: ec32dfc315c464bb6e4906b2f450d259ce0b86caf70b70b249054359d9af21a7fccf53a8b6aa232f8d718449e31c1cfa594e6ebffaafe7bf908b502495256d7b @@ -42399,7 +42529,7 @@ __metadata: languageName: node linkType: hard -"statuses@npm:2.0.1": +"statuses@npm:2.0.1, statuses@npm:^2.0.0": version: 2.0.1 resolution: "statuses@npm:2.0.1" checksum: 18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb @@ -42520,7 +42650,7 @@ __metadata: languageName: node linkType: hard -"strict-event-emitter@npm:^0.2.4": +"strict-event-emitter@npm:^0.2.0, strict-event-emitter@npm:^0.2.4": version: 0.2.8 resolution: "strict-event-emitter@npm:0.2.8" dependencies: @@ -44054,7 +44184,7 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^1.0.2": +"type-fest@npm:^1.0.2, type-fest@npm:^1.2.2": version: 1.4.0 resolution: "type-fest@npm:1.4.0" checksum: b011c3388665b097ae6a109a437a04d6f61d81b7357f74cbcb02246f2f5bd72b888ae33631b99871388122ba0a87f4ff1c94078e7119ff22c70e52c0ff828201