From 2ff90f20add29644b4a66469ddc53669c76af2fc Mon Sep 17 00:00:00 2001 From: Itai Nathaniel Date: Sun, 9 Mar 2025 10:57:56 +0200 Subject: [PATCH 01/52] Add files via upload Signed-off-by: Itai Nathaniel --- microsite/static/img/amplication_logo.png | Bin 0 -> 7451 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 microsite/static/img/amplication_logo.png diff --git a/microsite/static/img/amplication_logo.png b/microsite/static/img/amplication_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..76cffe492b9b1605d711bce047265da12543a6b8 GIT binary patch literal 7451 zcmcgxcUTkKwogKo&?88Z-cgX=i}WHL=^#af&@{nx-zs~r^?ftnMC$3Nkr2`n0ssIK_1nt&xOwYh zKrZ9%vRl%uxC!i_psfG^yon<^vAKkMX12YpuMGhBa{>UU#{j@j91FDq0C)=k0BiRE z0IBBy05u}B?v4yjPyjPkx7XGNaN}qQ;4+XLfQO@ixDx=R1zcFeQ2=8g-Cwj7@cN%R zAe>MTfV%^zaKrwI69D|D{zKe+aoom@3;eHH&&dzw>Slv<_hi=dbY~Xk6XO#U0|4-{ zfq(nV2K{AYD;w```ob8i0$UPpB0$_W^8x^fC@uyNke*3{vk~cJXo@t|){?SycjL3M zbH5Mc^K(O7pa3#{QaI8LhO}Y!b904zN%`Gk{iPv=qc7O}tjxbukS@1aO||uymE1jH z%wl{3d;+Ypgv`v$GM;w!Qu@lOf5LH3w^$vKNQ4wWzpt+^pRX{VyQc%cproWEzkm?G zkPt6UgV*Z;9BJdn3-@CC!^pqvD8syLJ)ICpCwDmWg_^fPO8;A2G^YL?HER zL(P<(++c7oTt2cw!V)sSV*5AA-`V|!H2ts0-z5J;D!IG5dm12YY+(e(^_%uZ zvQqjmFLzh(i^VpAJ0WF-WcdFR`=2P&zhScC|HAyv{3pQdKLLJc{u7|<=>)^o$34{!aJ zOi5j7UGVp#p2C2V(levI)6w8HOKpfOGXV5|d(E%|*X$M|>fJ!mf^|*|tEPcBJynZX zeI6{HNu<5aK8~tYvOBQ*s64+JYk9hTbw4+YYX8UP&ndGPJWhf!FfPg**cH@l7i&hr z#Jj1nG^QzU)hvuOYicr6bntX^VuFQo`(qk-N59Ojf1G;cbZ+Ix!OKsF-^|}%?bLsh zs8=g9AnmJkezwEFw#8GHll1Z%yA&`!l`15WTZ4y2#zAvtlG<$f)SB_b%(~@<94%ds zhlN#>j~!n|Q?27e=^&vX`i4k4c;L9$gO=w`j}N~PX2q4Q1=vq5?ebZ2hblPR)87Eu zYXQPD1nYi)s`QtvYntqvr^Tx2)?(WV^i_}Z*g{6p{JXRVT&s`O+uZ}g$J5IS(jRzR z;a6>BvV_RRHD(#UQiaDP`H9n1_!ab$%bg}I!mTWYk=wD@PLIS`x1jh=l6;<}N`mN4 zc1La-A;Af|_w6yypP6s%n{GFroxju{4ir~$%Z$Fga*NpHx{jj8gI@ER_x>G?FLs=6 z>Zs6;l{OU1XdpZ@+F&l|-bd;1qByai5VJ2X+1u|s*m5sI_5(s z#NyW|P_y>YTgsdMGofR_MH0}!bn1S07z=k;HgfZ%CWI+}Mv#sF6S4RWQLgkMq+6x% z$-&f--MdOXBCe0>->JegI0d?ov5RGxC);%5qa*Q!5NSzRVo1?&sNO#IMD$kBbAQy2 zhhsMA&KtS1yWT-uLbH$7@tXK=Zz>)(dMyQ1((QSxb-KF> zoAZQ3qcu!=*d4?kcLrpYizt4)V}uch+esF$0nhx7Nugt0dOwjWsr<4%X04&(K=Sh^li@O0}Hbq&V^ljFLo~ev!OX6{|0mV)~IrDYHdZuPil9b z#I(A*+H?5rG{W!74o0P%-x^;osz0|olJO3*Z9UliDTINf&`jGZgjXGrT%typhuCVb z-lVa<<$0Qslm1g6V>F7ID^n(iXX^15ZDiGS@6FON@$Fi+)LmJSd02UpnC{hZ3h;&!+6RlnSjeF8W=!pKXZw$@VRYhvxN2nWc|+!)ED{ zj#-%e{O|dVxRY%}y3YmgerWnwsub5C>1T`Wc&+yUeuRhNad0E{PgHQZ)b~By#VspC zt`B`w?yahQQ#ELUmR)q>5FDi@7af<@b|1;Nea@IJ{+VX(4)Hnv_)A`5s<3l^bU}o8 z+nI&!>(ug=oFDD5A%(QpOQ+L}v$VB))Z)gx)(y`W9au5EHZo3VW8UL0%C6hrz29pw-iJ5+iu#e8P{U7pomjh~5x(?;M9keNz2`pi`bW{#_-1|%PFTI}b z;8pe<*EI@!YrFcOTC?Qy=aEm=F#YSp1fj{w(|JUt<3oDgQ_n>wOr3eNk2ss)eoM|6 zOTnf(#JYy9T3LeCHVF3K+$8r0CZms{w$a&@o5UD-g~LEavVxabcf!bPYG1cUsX;EF zAZlhvH_><5V+hu!_JaSYtS8uS=f|4DYWPT76Ay{+?B)oDdtdCV*Bo8(lr>YQP_*y*!huQ33w{^B< zORLbxiO(c0_vT2`HlLf1Ss2?aRVqDVYO2+$(f0dhZ;QOC$f&Dn`;8c+4bHvegUQT@ zPW9gW?(Bs2YB#o`ki_PF;4yCd)Y~7GSjrVpIOdn`SHFrS z3j%eq=}sE)Zhp`b@+{G|@!NTcc|o?pGH!`x)d;s@5oQ22WFQ>f8-9GvmgRDGv_XF! zI86=iKYHc8rXckbk!l^NCht8EYQ(bf6)S7@?h)l$ycG#?>R^?=ZKP9I5Zz1CHAPw& z`3&8z*ZB`~$HYBF&$OM0`0|F?zH63&A8Ok5mF-1Sa~di{mIGvtIOVi$C+9EA#c6FO z*yj^ra;3SCRo8lJ;Mbug%RpOvF43#STx>5hJ>M?mJ@xnPqOI5)Yh$BaFt}Po5f<*Q z>2>OHlRHhVE#$CkG-a6kc#Q%^;)^jb(j_-&GYKg&Y>1~a1D6rn4u!8Am+(C`{Dfel zHQ4KaD6r;Gm6V%r;ksUJ>2?CiBw9LU&$E*>>_e2}b+5+`PLEe`C__NyPzhtqOLKC= z%FeRPS@>y(Xwxty_y@?66PT(sc@`T{S zmaJ~3y0*iEs|{mID%UW)BvlRJw2yl6+=`~S0(|4us8R1ij;}7)30NMdD7r%ov54+7 zTEg8B8B1$2tl88Oh!^H(ugOv!=<0j7q^ymj6+oLeuR6zUj*>g;%{;yb+OwwX2w zkEN>^S*?^(v{KV7w;YkKDD^Q|0g@#z?o}2cRIBI1LYi!1$ZijI%Vc}m4PL?p79E@> zUAL=WSUp!XYd*f0>)lY>h7T5D)iY6>zDJtXzfm*`=OKxiQQEvE@+mD*-P_Pa$KIj_ zeRO0UXzx~f(wMmFStfAPvdeScWA{;Fn%V?&{0*S+RzO%5G%eBT&=n(Tk3OCf#oiAy zTw9wrfa&|<+fW;?)j95deedCtZ~HWiUeLnjO_=)1v$uCx0Fdj-&Fp83#%4aO>ajF% zvosGP;So8;R)R2QofwEfic2z#OW(DA7QS!_N*pYF(NVVKF;>CT`{3)d6Ny)vWjnNY zSv8|t_gh|j++Flu8Rv8Yyz{4+so6T)%c0xsdt4sw@}ZCe`>=ofg?cMKNQj{I{>Fp) z=`)AY*=GzRN&@aY)ewbRC9qV`PPj+%3y*PU^qcTQ3LpDEm`CRbWtMvjmlue{W;gRi z#^xebI6LXn!r}b|hNEC@&lX+?IKeYhU>0^69~5x7HOeS3HfFx(4OcLNcwVd9$kgEj*xY8Q2CJj6*m8TYO4Nr#_`fjB z<-d%--itU|nk%j%Cwb4DjTdsewITh$EB|CxLvTVom2pE^E4-kJG@r;RNn_^Js6Fq8 zS3V8=D2Ej94Y`{00~A6VvN5T`_bkEiMtH!2izmlVEurB{X?0g5(A7JH*PK%Bqea!e z`dy3MLu=ir+m$d_{aPuibz_@`+=_-Kt0_O)g7pQ26#yiGeB+y!>oSdCnLtdBQcT1k z7LwFEgc!AvcW{;VuaDob6?+A;J3kmYPpkF~6cf}FAqSlZl{gV1xyM~;cYuY)lvcP@pbfDh4e zW1$8QoFfK}9MXmm63`knV#DAIf=!V7Ekh-#PaYUt#Rgr^eLX9Njs1wI9^zN5Pm(8*WJR8+ zIT}cc7YggZyq!KO)mE{`FH<|aD26RA--}?=++#&+5-j*qNYAqlBh)yn#^KbCfCJ8*>VU#9soznP+SXb@9zm z0Y7?ATS&4K@S#w3lrKw|@iWCRvum4Q<$NnUh?S@y=n&MdD7>GAfqMc#`v3q;0MFel z*e~+*5RCjrJo>ap#4ZH21x|A3rf6CA3|ugpRNzSsq9@GD)cB+xzpD-75uSYd(B)I- z)ssi4ae{Bj>Wb}&j|nxKw*!36mRfIB;6AJ$AD%?vLeZ#uAm6T}M+HGOtAlP9D8y)L z7S-?{OeS_>86bX{sI~8Cf<5GlatgM-jpC_QZIRPxdo{oi`sB2_~T2=bAuDonZ)^XV+W9())?C+1#(t`dd;X%ym(qNlPgx)UBxhz~hL zx^Ul(K3u8V^BK5C`b{y3IU5Wt7?Obty$PXSZb&+zJ7AvS05uf8>IX&JwMCQph#z*R z$!YjtZbAIQ0Bq^K^PD^d0XgSe3)5(Pobws`Qim9q8%2%52fYoQdaIN$mMrFYX8AO1 zI32ORFjrixrrqVyVS;b)%d&OkGj*>X3WjzpXj-ENh2FF!5>9g_iPa+8-Ju9!V59VP z6T7nw@rnDi-;i%E6)WsbOVr&g)pqq6T((*t9|xMFvKJg0RR za?~VvCpYF%DffiWZC!FgLEabiP^#lr;DjBFxNc=-QpQVygY6pOmZcI(aOvfpMZ0p- zr$TjmdFLq`;Q>$t5peV~I_1$;aP2p?CMNu%`ux|dOk4!$TI{U^m9DU#9_fj)@7F&EK!5$j98uRz_M&=hR?s^sRd7rwQC!9e9$D6`?mPnnyY@6 z5&V`@K5&cP2wt4z5@dy>&N>9sD)QiMGwo(Mwrs9|)?d@mOlBM8V{V3c zEF<+?>e56i+e0dV({bhjm&Kt2Q2^Ut-IxgUT&ilRdGOvYf%t1Y0m$b{w$eu=M*BWY@A7}5cVtK3pmdy9W2c$3 zuL4Dqb&c9Ls6qWm-XAd-)JU=GOfE4nXI@<~Ofu4OX}4u@60{(tMJZW)sdbVHI5nbR z@SayfIEC^9#me%zSoAwyMTBn@fK6-rV7}|JZ~xpQ?Lx9$vW0FokNbJ9U*fZbfMtI- zwytG&x6rZ2lJffMm$a$Ez$R*n_i0yw-Yt4RJcjhc_u#o-c|b&j{y+KWrJu4oT?%)A zLRFie$ig{qZU@%h`#!+(hVkWed=`Ps<16w2Q8*T=`KU1LJ0Iyo@g}^qiohXBTSCYR z6qqxqpVLAQdS?7qAt+rH0UKtfdvj74 zl?MvaB@LuBnw()}ZJZy^iY13WBc~0%r!wdj`V?=n+$6BXx%ns6-8>6+APt---F7Qa zlU45JF2^h!$X-16eVfv{qcX{&j$<*J~Jr~G|GpwB@>0_RO0CP$u z={rMOZ+XZ-NDn;R@`F?y4#mAIcm!=W51uL0JZFF-}|XNWk+n7n53y?tl; zk=0puU{LL)z?rMfAD@bViadto#|`m%zim#f^5| z4(oYu(;dDtYFM)TaJUs7q_#gYZ6kzrx!;rUE`+!bgv;%c{99$yar`3~|9Rg8ja{|e z7jL8^JAD?Grz>M1sTMNJ_6$I5!rsei_E}#esQb9Z4(WtAF3;MQuywRma-|iYNobdr zQ1q81Cnrr9gQ8|NjE&U4wOo&zqc~$|bD0wycX7sNoS^uSAmC5tOO!2^QU<7LC88@v z&5jj)DMrjV;zGyCM`ZnnpfgIOYbu8#FM065#xQRaFW3RpZz8Xe}6?Rs^t zH01jeyI3#1Av;j+u*m3d+z~-m&~wf!8-U;l4q`l?!vpn#@1c9IXExnvbVG?MeyChM zZdZ=-+tjl5v(c3`OGA7#G61!tccm{ebzTNS0smju?a=0Ppu3T8h+^u~4;Mf5)Kzqp JD-`cN`X8;0;K%>~ literal 0 HcmV?d00001 From 090553e95bbefa2bb63988d2705150b669157582 Mon Sep 17 00:00:00 2001 From: Itai Nathaniel Date: Sun, 9 Mar 2025 11:02:12 +0200 Subject: [PATCH 02/52] Create amplication.yaml Signed-off-by: Itai Nathaniel --- microsite/data/plugins/amplication.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 microsite/data/plugins/amplication.yaml diff --git a/microsite/data/plugins/amplication.yaml b/microsite/data/plugins/amplication.yaml new file mode 100644 index 0000000000..a1b5f09c0e --- /dev/null +++ b/microsite/data/plugins/amplication.yaml @@ -0,0 +1,10 @@ +--- +title: Amplication Resources +author: Amplication +authorUrl: https://amplication.com +category: Development +description: A plugin that integrates Amplication services into Backstage, enabling seamless development and management of your applications. +documentation: https://docs.amplication.com/day-zero/integrate-with-backstage +iconUrl: /img/amplication_logo.png +npmPackageName: '@backstage-community/plugin-scaffolder-backend-module-amplication' +addedDate: '2025-03-07' From 02d8a845d6185fe83780167e9b2f66db3f5b9475 Mon Sep 17 00:00:00 2001 From: Paul Frybarger Date: Mon, 10 Mar 2025 19:14:54 +0000 Subject: [PATCH 03/52] add missing parameter from github catalog config definition Signed-off-by: Paul Frybarger --- plugins/catalog-backend-module-github/config.d.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/catalog-backend-module-github/config.d.ts b/plugins/catalog-backend-module-github/config.d.ts index cc197f3ec7..c94593b985 100644 --- a/plugins/catalog-backend-module-github/config.d.ts +++ b/plugins/catalog-backend-module-github/config.d.ts @@ -71,6 +71,11 @@ export interface Config { * Default: `/catalog-info.yaml`. */ catalogPath?: string; + /** + * (Optional) Whether to validate locations that exist before emitting them. + * Default: `false`. + */ + validateLocationsExist?: boolean; /** * (Optional) Filter configuration. */ From 16648ef7acbfc2470c8b6fefa232a15b6be93653 Mon Sep 17 00:00:00 2001 From: Paul Frybarger Date: Mon, 10 Mar 2025 19:49:00 +0000 Subject: [PATCH 04/52] add changeset Signed-off-by: Paul Frybarger --- .changeset/large-kings-protect.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/large-kings-protect.md diff --git a/.changeset/large-kings-protect.md b/.changeset/large-kings-protect.md new file mode 100644 index 0000000000..363e2b7759 --- /dev/null +++ b/.changeset/large-kings-protect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +Added `validateLocationsExist` to the config definition where it was missing. From 2c38b75c54dba5524334e474200ff77405fd742c Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Tue, 11 Mar 2025 23:27:45 -0400 Subject: [PATCH 05/52] module: move misc repo tasks into a maintenance module Signed-off-by: aramissennyeydd --- packages/cli/cli-report.md | 2 +- packages/cli/src/commands/index.ts | 46 +------- packages/cli/src/modules/maintenance/alpha.ts | 110 ++++++++++++++++++ .../maintenance/commands/package}/clean.ts | 2 +- .../maintenance/commands/package}/pack.ts | 8 +- .../maintenance}/commands/repo/clean.ts | 2 +- .../maintenance}/commands/repo/fix.ts | 4 +- .../commands/repo/list-deprecations.ts | 2 +- packages/cli/src/modules/maintenance/index.ts | 61 ++++++++++ .../migrate/commands/packageExports.ts | 2 +- 10 files changed, 188 insertions(+), 51 deletions(-) create mode 100644 packages/cli/src/modules/maintenance/alpha.ts rename packages/cli/src/{commands/clean => modules/maintenance/commands/package}/clean.ts (94%) rename packages/cli/src/{commands => modules/maintenance/commands/package}/pack.ts (80%) rename packages/cli/src/{ => modules/maintenance}/commands/repo/clean.ts (97%) rename packages/cli/src/{ => modules/maintenance}/commands/repo/fix.ts (99%) rename packages/cli/src/{ => modules/maintenance}/commands/repo/list-deprecations.ts (98%) create mode 100644 packages/cli/src/modules/maintenance/index.ts diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 32918caad2..00f3ce937d 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -200,10 +200,10 @@ Commands: start [options] build [options] test - lint [options] [directories...] clean prepack postpack + lint [options] [directories...] help [command] ``` diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 9a76711d08..2349a9fb22 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -35,6 +35,10 @@ import { registerPackageCommands as registerPackageLintCommands, registerRepoCommands as registerRepoLintCommands, } from '../modules/lint'; +import { + registerPackageCommands as registerMaintenancePackageCommands, + registerRepoCommands as registerMaintenanceRepoCommands, +} from '../modules/maintenance'; export function registerRepoCommand(program: Command) { const command = program @@ -44,30 +48,7 @@ export function registerRepoCommand(program: Command) { registerRepoBuildCommands(command); registerRepoTestCommands(command); registerRepoLintCommands(command); - - command - .command('fix') - .description('Automatically fix packages in the project') - .option( - '--publish', - 'Enable additional fixes that only apply when publishing packages', - ) - .option( - '--check', - 'Fail if any packages would have been changed by the command', - ) - .action(lazy(() => import('./repo/fix'), 'command')); - - command - .command('clean') - .description('Delete cache and output directories') - .action(lazy(() => import('./repo/clean'), 'command')); - - command - .command('list-deprecations') - .description('List deprecations') - .option('--json', 'Output as JSON') - .action(lazy(() => import('./repo/list-deprecations'), 'command')); + registerMaintenanceRepoCommands(command); } export function registerScriptCommand(program: Command) { @@ -92,22 +73,8 @@ export function registerScriptCommand(program: Command) { registerPackageBuildCommands(command); registerPackageTestCommands(command); - + registerMaintenancePackageCommands(command); registerPackageLintCommands(command); - command - .command('clean') - .description('Delete cache directories') - .action(lazy(() => import('./clean/clean'), 'default')); - - command - .command('prepack') - .description('Prepares a package for packaging before publishing') - .action(lazy(() => import('./pack'), 'pre')); - - command - .command('postpack') - .description('Restores the changes made by the prepack command') - .action(lazy(() => import('./pack'), 'post')); } export function registerCommands(program: Command) { @@ -153,7 +120,6 @@ export function registerCommands(program: Command) { registerMigrateCommand(program); registerBuildCommands(program); registerInfoCommands(program); - program .command('create-github-app ') .description('Create new GitHub App in your organization.') diff --git a/packages/cli/src/modules/maintenance/alpha.ts b/packages/cli/src/modules/maintenance/alpha.ts new file mode 100644 index 0000000000..41192afdc4 --- /dev/null +++ b/packages/cli/src/modules/maintenance/alpha.ts @@ -0,0 +1,110 @@ +/* + * Copyright 2025 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 { Command } from 'commander'; +import { createCliPlugin } from '../../wiring/factory'; +import { lazy } from '../../lib/lazy'; + +export default createCliPlugin({ + pluginId: 'maintenance', + init: async reg => { + reg.addCommand({ + path: ['package', 'clean'], + description: 'Delete cache directories', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/package/clean'), 'default'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['package', 'prepack'], + description: 'Prepares a package for packaging before publishing', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/package/pack'), 'pre'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['package', 'postpack'], + description: 'Restores the changes made by the prepack command', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/package/pack'), 'post'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'fix'], + description: 'Automatically fix packages in the project', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .option( + '--publish', + 'Enable additional fixes that only apply when publishing packages', + ) + .option( + '--check', + 'Fail if any packages would have been changed by the command', + ) + .action(lazy(() => import('./commands/repo/fix'), 'command')); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'clean'], + description: 'Delete cache and output directories', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command.action( + lazy(() => import('./commands/repo/clean'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + + reg.addCommand({ + path: ['repo', 'list-deprecations'], + description: 'List deprecations', + execute: async ({ args }) => { + const command = new Command(); + const defaultCommand = command + .option('--json', 'Output as JSON') + .action( + lazy(() => import('./commands/repo/list-deprecations'), 'command'), + ); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + }, +}); diff --git a/packages/cli/src/commands/clean/clean.ts b/packages/cli/src/modules/maintenance/commands/package/clean.ts similarity index 94% rename from packages/cli/src/commands/clean/clean.ts rename to packages/cli/src/modules/maintenance/commands/package/clean.ts index 74a1ea658b..5e2d0d65b3 100644 --- a/packages/cli/src/commands/clean/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/package/clean.ts @@ -15,7 +15,7 @@ */ import fs from 'fs-extra'; -import { paths } from '../../lib/paths'; +import { paths } from '../../../../lib/paths'; export default async function clean() { await fs.remove(paths.resolveTarget('dist')); diff --git a/packages/cli/src/commands/pack.ts b/packages/cli/src/modules/maintenance/commands/package/pack.ts similarity index 80% rename from packages/cli/src/commands/pack.ts rename to packages/cli/src/modules/maintenance/commands/package/pack.ts index 17162b9596..510401c6d1 100644 --- a/packages/cli/src/commands/pack.ts +++ b/packages/cli/src/modules/maintenance/commands/package/pack.ts @@ -17,11 +17,11 @@ import { productionPack, revertProductionPack, -} from '../modules/build/lib/packager/productionPack'; -import { paths } from '../lib/paths'; +} from '../../../../modules/build/lib/packager/productionPack'; +import { paths } from '../../../../lib/paths'; import fs from 'fs-extra'; -import { publishPreflightCheck } from '../lib/publishing'; -import { createTypeDistProject } from '../lib/typeDistProject'; +import { publishPreflightCheck } from '../../../../lib/publishing'; +import { createTypeDistProject } from '../../../../lib/typeDistProject'; export const pre = async () => { publishPreflightCheck({ diff --git a/packages/cli/src/commands/repo/clean.ts b/packages/cli/src/modules/maintenance/commands/repo/clean.ts similarity index 97% rename from packages/cli/src/commands/repo/clean.ts rename to packages/cli/src/modules/maintenance/commands/repo/clean.ts index 13ff061423..51c31129ea 100644 --- a/packages/cli/src/commands/repo/clean.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/clean.ts @@ -19,7 +19,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'path'; import { promisify } from 'util'; import { PackageGraph } from '@backstage/cli-node'; -import { paths } from '../../lib/paths'; +import { paths } from '../../../../lib/paths'; const execFile = promisify(execFileCb); diff --git a/packages/cli/src/commands/repo/fix.ts b/packages/cli/src/modules/maintenance/commands/repo/fix.ts similarity index 99% rename from packages/cli/src/commands/repo/fix.ts rename to packages/cli/src/modules/maintenance/commands/repo/fix.ts index a55440c53f..83f4da6114 100644 --- a/packages/cli/src/commands/repo/fix.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/fix.ts @@ -24,8 +24,8 @@ import { import { OptionValues } from 'commander'; import fs from 'fs-extra'; import { resolve as resolvePath, posix, relative as relativePath } from 'path'; -import { paths } from '../../lib/paths'; -import { publishPreflightCheck } from '../../lib/publishing'; +import { paths } from '../../../../lib/paths'; +import { publishPreflightCheck } from '../../../../lib/publishing'; /** * A mutable object representing a package.json file with potential fixes. diff --git a/packages/cli/src/commands/repo/list-deprecations.ts b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts similarity index 98% rename from packages/cli/src/commands/repo/list-deprecations.ts rename to packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts index 772038025a..de83f7a4ac 100644 --- a/packages/cli/src/commands/repo/list-deprecations.ts +++ b/packages/cli/src/modules/maintenance/commands/repo/list-deprecations.ts @@ -19,7 +19,7 @@ import { ESLint } from 'eslint'; import { OptionValues } from 'commander'; import { relative as relativePath } from 'path'; import { PackageGraph } from '@backstage/cli-node'; -import { paths } from '../../lib/paths'; +import { paths } from '../../../../lib/paths'; export async function command(opts: OptionValues) { const packages = await PackageGraph.listTargetPackages(); diff --git a/packages/cli/src/modules/maintenance/index.ts b/packages/cli/src/modules/maintenance/index.ts new file mode 100644 index 0000000000..48669e9c34 --- /dev/null +++ b/packages/cli/src/modules/maintenance/index.ts @@ -0,0 +1,61 @@ +/* + * Copyright 2025 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 { Command } from 'commander'; +import { lazy } from '../../lib/lazy'; + +export function registerPackageCommands(command: Command) { + command + .command('clean') + .description('Delete cache directories') + .action(lazy(() => import('./commands/package/clean'), 'default')); + + command + .command('prepack') + .description('Prepares a package for packaging before publishing') + .action(lazy(() => import('./commands/package/pack'), 'pre')); + + command + .command('postpack') + .description('Restores the changes made by the prepack command') + .action(lazy(() => import('./commands/package/pack'), 'post')); +} + +export function registerRepoCommands(command: Command) { + command + .command('fix') + .description('Automatically fix packages in the project') + .option( + '--publish', + 'Enable additional fixes that only apply when publishing packages', + ) + .option( + '--check', + 'Fail if any packages would have been changed by the command', + ) + .action(lazy(() => import('./commands/repo/fix'), 'command')); + + command + .command('clean') + .description('Delete cache and output directories') + .action(lazy(() => import('./commands/repo/clean'), 'command')); + + command + .command('list-deprecations') + .description('List deprecations') + .option('--json', 'Output as JSON') + .action(lazy(() => import('./commands/repo/list-deprecations'), 'command')); +} diff --git a/packages/cli/src/modules/migrate/commands/packageExports.ts b/packages/cli/src/modules/migrate/commands/packageExports.ts index c54422ceb9..4eb741ce4d 100644 --- a/packages/cli/src/modules/migrate/commands/packageExports.ts +++ b/packages/cli/src/modules/migrate/commands/packageExports.ts @@ -18,7 +18,7 @@ import { fixPackageExports, readFixablePackages, writeFixedPackages, -} from '../../../commands/repo/fix'; +} from '../../maintenance/commands/repo/fix'; export async function command() { console.log( From c7254aee80225ebfde11a024ce14ab0e6360678e Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Tue, 11 Mar 2025 23:28:28 -0400 Subject: [PATCH 06/52] add changeset Signed-off-by: aramissennyeydd --- .changeset/wet-penguins-beg.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/wet-penguins-beg.md diff --git a/.changeset/wet-penguins-beg.md b/.changeset/wet-penguins-beg.md new file mode 100644 index 0000000000..c4248f86f8 --- /dev/null +++ b/.changeset/wet-penguins-beg.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': minor +--- + +Internal update to move the `clean`, `pre/postpack` and `fix` commands into their own separate module. From dcda66ac65555088e24ba01478ace17d6b2136d2 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Fri, 14 Mar 2025 21:27:24 +0100 Subject: [PATCH 07/52] Made "sentry:project:create" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/funny-hotels-cut.md | 5 ++ .../src/actions/createProject.ts | 59 +++++++++++-------- 2 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 .changeset/funny-hotels-cut.md diff --git a/.changeset/funny-hotels-cut.md b/.changeset/funny-hotels-cut.md new file mode 100644 index 0000000000..7972b68bbb --- /dev/null +++ b/.changeset/funny-hotels-cut.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-sentry': patch +--- + +Made "sentry:project:create" action idempotent diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index 259b670f9e..de2564028d 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -88,32 +88,41 @@ export function createSentryCreateProjectAction(options: { config: Config }) { throw new InputError(`No valid sentry token given`); } - const response = await fetch( - `https://sentry.io/api/0/teams/${organizationSlug}/${teamSlug}/projects/`, - { - method: 'POST', - headers: { - Authorization: `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify(body), + const { contentType, result } = await ctx.checkpoint({ + key: `create.project.${organizationSlug}.${teamSlug}`, + // eslint-disable-next-line no-loop-func + fn: async () => { + const response = await fetch( + `https://sentry.io/api/0/teams/${organizationSlug}/${teamSlug}/projects/`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }, + ); + + if (contentType !== 'application/json') { + throw new InputError( + `Unexpected Sentry Response Type: ${await response.text()}`, + ); + } + + const res = await response.json(); + + if (response.status !== 201) { + throw new InputError(`Sentry Response was: ${await res.detail}`); + } + + return { + contentType: response.headers.get('content-type'), + code: response.status, + result: res as { id: string }, + }; }, - ); - - const contentType = response.headers.get('content-type'); - - if (contentType !== 'application/json') { - throw new InputError( - `Unexpected Sentry Response Type: ${await response.text()}`, - ); - } - - const code = response.status; - const result = await response.json(); - - if (code !== 201) { - throw new InputError(`Sentry Response was: ${await result.detail}`); - } + }); ctx.output('id', result.id); ctx.output('result', result); From e1ca7c249087a12a323c09d2edeeca8d3ab2bea6 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Fri, 14 Mar 2025 22:06:10 +0100 Subject: [PATCH 08/52] wip Signed-off-by: Bogdan Nechyporenko --- .../src/actions/createProject.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index de2564028d..b0a17f1947 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -88,7 +88,7 @@ export function createSentryCreateProjectAction(options: { config: Config }) { throw new InputError(`No valid sentry token given`); } - const { contentType, result } = await ctx.checkpoint({ + const { result } = await ctx.checkpoint({ key: `create.project.${organizationSlug}.${teamSlug}`, // eslint-disable-next-line no-loop-func fn: async () => { @@ -104,6 +104,8 @@ export function createSentryCreateProjectAction(options: { config: Config }) { }, ); + const contentType = response.headers.get('content-type'); + if (contentType !== 'application/json') { throw new InputError( `Unexpected Sentry Response Type: ${await response.text()}`, @@ -117,7 +119,6 @@ export function createSentryCreateProjectAction(options: { config: Config }) { } return { - contentType: response.headers.get('content-type'), code: response.status, result: res as { id: string }, }; From 5bd44b9aeb4de0283d79dea38f78bff188072daa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 08:41:36 +0000 Subject: [PATCH 09/52] chore(deps): bump @babel/runtime from 7.26.7 to 7.26.10 in /microsite Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.26.7 to 7.26.10. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime) --- updated-dependencies: - dependency-name: "@babel/runtime" dependency-type: indirect ... Signed-off-by: dependabot[bot] --- microsite/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/microsite/yarn.lock b/microsite/yarn.lock index fdcc32aad4..4d4d31d2d3 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -1637,11 +1637,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2": - version: 7.26.7 - resolution: "@babel/runtime@npm:7.26.7" + version: 7.26.10 + resolution: "@babel/runtime@npm:7.26.10" dependencies: regenerator-runtime: ^0.14.0 - checksum: a1664a08f3f4854b895b540cca2f5f5c6c1993b5fb788c9615d70fc201e16bb254df8e0550c83eaf2749a14d87775e11a7c9ded6161203e9da7a4a323d546925 + checksum: 22d2e0abb86e90de489ab16bb578db6fe2b63a88696db431198b24963749820c723f1982298cdbbea187f7b2b80fb4d98a514faf114ddb2fdc14a4b96277b955 languageName: node linkType: hard From d7c9229f9c4ae08b72c51fb5b4b41e580cc2e45c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 13:18:31 +0000 Subject: [PATCH 10/52] Update dependency lightningcss to v1.29.3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- canon-docs/yarn.lock | 98 ++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/canon-docs/yarn.lock b/canon-docs/yarn.lock index 858a1106e0..fb35ea5a89 100644 --- a/canon-docs/yarn.lock +++ b/canon-docs/yarn.lock @@ -1754,12 +1754,10 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^1.0.3": - version: 1.0.3 - resolution: "detect-libc@npm:1.0.3" - bin: - detect-libc: ./bin/detect-libc.js - checksum: daaaed925ffa7889bd91d56e9624e6c8033911bb60f3a50a74a87500680652969dbaab9526d1e200a4c94acf80fc862a22131841145a0a8482d60a99c24f4a3e +"detect-libc@npm:^2.0.3": + version: 2.0.3 + resolution: "detect-libc@npm:2.0.3" + checksum: 2ba6a939ae55f189aea996ac67afceb650413c7a34726ee92c40fb0deb2400d57ef94631a8a3f052055eea7efb0f99a9b5e6ce923415daa3e68221f963cfc27d languageName: node linkType: hard @@ -3424,91 +3422,91 @@ __metadata: languageName: node linkType: hard -"lightningcss-darwin-arm64@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-darwin-arm64@npm:1.29.1" +"lightningcss-darwin-arm64@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-darwin-arm64@npm:1.29.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"lightningcss-darwin-x64@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-darwin-x64@npm:1.29.1" +"lightningcss-darwin-x64@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-darwin-x64@npm:1.29.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"lightningcss-freebsd-x64@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-freebsd-x64@npm:1.29.1" +"lightningcss-freebsd-x64@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-freebsd-x64@npm:1.29.3" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"lightningcss-linux-arm-gnueabihf@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-linux-arm-gnueabihf@npm:1.29.1" +"lightningcss-linux-arm-gnueabihf@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.29.3" conditions: os=linux & cpu=arm languageName: node linkType: hard -"lightningcss-linux-arm64-gnu@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-linux-arm64-gnu@npm:1.29.1" +"lightningcss-linux-arm64-gnu@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-linux-arm64-gnu@npm:1.29.3" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"lightningcss-linux-arm64-musl@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-linux-arm64-musl@npm:1.29.1" +"lightningcss-linux-arm64-musl@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-linux-arm64-musl@npm:1.29.3" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"lightningcss-linux-x64-gnu@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-linux-x64-gnu@npm:1.29.1" +"lightningcss-linux-x64-gnu@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-linux-x64-gnu@npm:1.29.3" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"lightningcss-linux-x64-musl@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-linux-x64-musl@npm:1.29.1" +"lightningcss-linux-x64-musl@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-linux-x64-musl@npm:1.29.3" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"lightningcss-win32-arm64-msvc@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-win32-arm64-msvc@npm:1.29.1" +"lightningcss-win32-arm64-msvc@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-win32-arm64-msvc@npm:1.29.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"lightningcss-win32-x64-msvc@npm:1.29.1": - version: 1.29.1 - resolution: "lightningcss-win32-x64-msvc@npm:1.29.1" +"lightningcss-win32-x64-msvc@npm:1.29.3": + version: 1.29.3 + resolution: "lightningcss-win32-x64-msvc@npm:1.29.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "lightningcss@npm:^1.28.2": - version: 1.29.1 - resolution: "lightningcss@npm:1.29.1" + version: 1.29.3 + resolution: "lightningcss@npm:1.29.3" dependencies: - detect-libc: ^1.0.3 - lightningcss-darwin-arm64: 1.29.1 - lightningcss-darwin-x64: 1.29.1 - lightningcss-freebsd-x64: 1.29.1 - lightningcss-linux-arm-gnueabihf: 1.29.1 - lightningcss-linux-arm64-gnu: 1.29.1 - lightningcss-linux-arm64-musl: 1.29.1 - lightningcss-linux-x64-gnu: 1.29.1 - lightningcss-linux-x64-musl: 1.29.1 - lightningcss-win32-arm64-msvc: 1.29.1 - lightningcss-win32-x64-msvc: 1.29.1 + detect-libc: ^2.0.3 + lightningcss-darwin-arm64: 1.29.3 + lightningcss-darwin-x64: 1.29.3 + lightningcss-freebsd-x64: 1.29.3 + lightningcss-linux-arm-gnueabihf: 1.29.3 + lightningcss-linux-arm64-gnu: 1.29.3 + lightningcss-linux-arm64-musl: 1.29.3 + lightningcss-linux-x64-gnu: 1.29.3 + lightningcss-linux-x64-musl: 1.29.3 + lightningcss-win32-arm64-msvc: 1.29.3 + lightningcss-win32-x64-msvc: 1.29.3 dependenciesMeta: lightningcss-darwin-arm64: optional: true @@ -3530,7 +3528,7 @@ __metadata: optional: true lightningcss-win32-x64-msvc: optional: true - checksum: d1c4dba66dfe7f6a76532bdb84c35742bee61149550e5eb5b0e84e282f21aecd335f917ca9619bb7ca95fc1eb3092dc7e22f2c16b01e9a0ee472b76452343cce + checksum: 80cad5e1eb1c5eaae22ca6f17b127d65b5c93e859da124d57a90e256d7cb7802afa8dc7a6e1ec1e6aa208d0b23c8b9ec07078e69e61b10748bffdc8cadebed7e languageName: node linkType: hard From 5660c94c6c089d73fb6b44cb2d2c1a15dc9093f3 Mon Sep 17 00:00:00 2001 From: teemoo7 Date: Mon, 17 Mar 2025 17:06:06 +0100 Subject: [PATCH 11/52] Fix code example in proxy tutorial doc for better consistency Signed-off-by: teemoo7 --- .../using-backstage-proxy-within-plugin.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/tutorials/using-backstage-proxy-within-plugin.md b/docs/tutorials/using-backstage-proxy-within-plugin.md index d5ce554239..88052c5f39 100644 --- a/docs/tutorials/using-backstage-proxy-within-plugin.md +++ b/docs/tutorials/using-backstage-proxy-within-plugin.md @@ -131,7 +131,7 @@ export class MyAwesomeApiClient implements MyAwesomeApi { const proxyUri = `${await this.discoveryApi.getBaseUrl('proxy')}/`; const resp = await this.fetchApi.fetch(`${proxyUri}${input}`, init); - if (!resp.ok) throw new Error(resp); + if (!resp.ok) throw new Error(resp.statusText); return await resp.json(); } @@ -151,8 +151,9 @@ export class MyAwesomeApiClient implements MyAwesomeApi { } ``` -> For more information on the DiscoveryApi check out the -> [docs](../reference/core-plugin-api.discoveryapi.md) +> Check out the docs for more information on the +> [DiscoveryApi](../reference/core-plugin-api.discoveryapi.md) or the +> [FetchApi](../reference/core-plugin-api.fetchapi.md) ## Bundling your ApiRef with your plugin @@ -171,6 +172,7 @@ import { createRoutableExtension, createComponentExtension, discoveryApiRef, + fetchApiRef, } from '@backstage/core-plugin-api'; //... @@ -182,8 +184,12 @@ export const myCustomPlugin = createPlugin({ apis: [ createApiFactory({ api: myAwesomeApiRef, - deps: { discoveryApi: discoveryApiRef }, - factory: ({ discoveryApi }) => new MyAwesomeApiClient({ discoveryApi }), + deps: { + discoveryApi: discoveryApiRef, + fetchApi: fetchApiRef, + }, + factory: ({ discoveryApi, fetchApi }) => + new MyAwesomeApiClient({ discoveryApi, fetchApi }), }), ], }); From b9cb01d9b21e73d7e406dab63b2101e114a4bac3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Mar 2025 16:19:24 +0000 Subject: [PATCH 12/52] Update storybook monorepo to v8.6.7 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- canon-docs/yarn.lock | 80 +++++------ storybook/yarn.lock | 326 +++++++++++++++++++++---------------------- yarn.lock | 316 ++++++++++++++++++++--------------------- 3 files changed, 361 insertions(+), 361 deletions(-) diff --git a/canon-docs/yarn.lock b/canon-docs/yarn.lock index 858a1106e0..dc5532fc56 100644 --- a/canon-docs/yarn.lock +++ b/canon-docs/yarn.lock @@ -722,20 +722,20 @@ __metadata: languageName: node linkType: hard -"@storybook/components@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/components@npm:8.6.4" +"@storybook/components@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/components@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: b50923e759eea99320fdf8946056fb33614b9d993ca567207cd0d714e5fae83da485b64b0d74a18b84355396b33c28b5eea050484c40967873c540f83d314b9a + checksum: cb20f8baa76deef1af1739d6c1b1a9f57eb22d158fa046d9919a91840e7a00f1b48e96b7ffe7994365b60808f864c963a3476ee98b4c8b63968a3a877068da3a languageName: node linkType: hard -"@storybook/core@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/core@npm:8.6.4" +"@storybook/core@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/core@npm:8.6.7" dependencies: - "@storybook/theming": 8.6.4 + "@storybook/theming": 8.6.7 better-opn: ^3.0.2 browser-assert: ^1.2.1 esbuild: ^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 @@ -751,7 +751,7 @@ __metadata: peerDependenciesMeta: prettier: optional: true - checksum: 8352b0f65bd7c0462471409a7f086125f4e1a93e1777fa20268beb78109f9784cc1d75536a4f9136368db87ba3c5c11987c95835937ba4c2776f968365795d8f + checksum: b150b7472766fccbbc1dec74cba3c16e009a9f24c13f01198923f553d12e2a2070ee2a35f5514f9af350b79e34577946ea65a4a495fd1fa18a27655f897c013a languageName: node linkType: hard @@ -762,66 +762,66 @@ __metadata: languageName: node linkType: hard -"@storybook/manager-api@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/manager-api@npm:8.6.4" +"@storybook/manager-api@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/manager-api@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 50447d3961dfab2b2f36afa76aaeb779a9b51ca66a912bc763103f18f2f71514191388b101ec83093ac9dee6ab509b955da41325f15d88cfe1c480e7d7d1f9eb + checksum: 6bb0860c3795945189832613da5866e5159b2adb376478a2b596c113928c64f5962efc325f927a6bcb7a48d7257f42cf6489b0c44397876129626ac68c44aa28 languageName: node linkType: hard -"@storybook/preview-api@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/preview-api@npm:8.6.4" +"@storybook/preview-api@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/preview-api@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: d8f642de8053686192e28f7ec748944c99c9e4d0cef7f13d96e840fd159c8bea2e3139b88a84eb16009fbda3152a61d9e075777211c10773e4d01fd103bf0e28 + checksum: 0d24d62444b7b153bde89d3949ab6539a163e15bc80c5bfcc73b7d49bbb34fb02eb74a99434793b8a6446aeec491e07f006c0f4e404f98486c6d1d614d01defa languageName: node linkType: hard -"@storybook/react-dom-shim@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/react-dom-shim@npm:8.6.4" +"@storybook/react-dom-shim@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/react-dom-shim@npm:8.6.7" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 - checksum: 0062191f312c0bf32e622904b9da7176c961cec99258c6b230c3fb6758c1cca95ac4142d4701628dc8eb922601d74c350549b78e146b5af1747edf8cb3def756 + storybook: ^8.6.7 + checksum: 51c20259ac4485d9a996266341a4d9898c949049e2a9af9a08bec58c2ace3a40be1a534005c52fc2db2c81bb010dbd36030bb70581b36c05cf4b34d58f140d3a languageName: node linkType: hard "@storybook/react@npm:^8.4.7": - version: 8.6.4 - resolution: "@storybook/react@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/react@npm:8.6.7" dependencies: - "@storybook/components": 8.6.4 + "@storybook/components": 8.6.7 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 8.6.4 - "@storybook/preview-api": 8.6.4 - "@storybook/react-dom-shim": 8.6.4 - "@storybook/theming": 8.6.4 + "@storybook/manager-api": 8.6.7 + "@storybook/preview-api": 8.6.7 + "@storybook/react-dom-shim": 8.6.7 + "@storybook/theming": 8.6.7 peerDependencies: - "@storybook/test": 8.6.4 + "@storybook/test": 8.6.7 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 + storybook: ^8.6.7 typescript: ">= 4.2.x" peerDependenciesMeta: "@storybook/test": optional: true typescript: optional: true - checksum: 4e9860c8e177d0dd496e7d6c53927daa8429b82f9c02d5b004de61244573901160a936ba37ce69810fb13e3602391e18723237a901c57e1bd19cf9f58241c30c + checksum: c98438ddfd764300e1a805623fab976f9ef94a2d939984d6caf98ce92ed29d8a7307389b98e2df2d1302b302dc549c7c95050464731d9c588347cd154c360834 languageName: node linkType: hard -"@storybook/theming@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/theming@npm:8.6.4" +"@storybook/theming@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/theming@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: b7e13026c381e18e7ad2064e1528876eb01b7563ad16aababcac531ce76f5e59b985a72603f57d75465a611ea564bd46b9b1760634211faf4307f9265f06e044 + checksum: 747a2377df65d5f0962dc8606d06247ad89fb7ecabab0bd9611055d599b5bd0fa15769e4c76e948ae34ae232ba756bf6795ccb3467b1adf35ff961db7350f4de languageName: node linkType: hard @@ -5054,10 +5054,10 @@ __metadata: linkType: hard "storybook@npm:^8.4.7": - version: 8.6.4 - resolution: "storybook@npm:8.6.4" + version: 8.6.7 + resolution: "storybook@npm:8.6.7" dependencies: - "@storybook/core": 8.6.4 + "@storybook/core": 8.6.7 peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: @@ -5067,7 +5067,7 @@ __metadata: getstorybook: ./bin/index.cjs sb: ./bin/index.cjs storybook: ./bin/index.cjs - checksum: 96c59b5c6ac27dfb9fb85d110b0257a77264015454dd0ca7893ae9df04dbf31e523ff351ba45283f33a58ecb28fd985349aa9c1fb83ab51d0c781a4d5809fa15 + checksum: fe21ce4d9cd17069a5b409ed518603f97ec6ec421b7f41cff3e43b409820fcbc2c8dbcb3aed99dd7d0a99a0c6138c7576ddf72f78186b6f86085d503b3c8b32f languageName: node linkType: hard diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 4edee92e89..1a3e6f0a24 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -970,9 +970,9 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-actions@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-actions@npm:8.6.4" +"@storybook/addon-actions@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-actions@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 "@types/uuid": ^9.0.1 @@ -980,231 +980,231 @@ __metadata: polished: ^4.2.2 uuid: ^9.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: b08f73070ac90f2c0d404b63f3148ebe11d4683f0728fd04459df62b521422d8c17b3619f6c012a90571a2d5520ee34d35e02fd104c0298580177dd57e045312 + storybook: ^8.6.7 + checksum: 28add3c30e397894bb13d1d492b88e331cec2a24b47ad9e865002e54851a17a0916387dca02074b834c6d665748bd2a5ec88904ad08795645d1b8a9345fb1328 languageName: node linkType: hard -"@storybook/addon-backgrounds@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-backgrounds@npm:8.6.4" +"@storybook/addon-backgrounds@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-backgrounds@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 memoizerific: ^1.11.3 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 53a67d385d6241730d0d992552de58316cfa4c46f56fa5a81df8647c76356778164783b8a872e31b3624692f456186074e06407778cf4442ffc8596cdaded49e + storybook: ^8.6.7 + checksum: 574b634e49225f52800a7ed0ea7b120f15198ae91068c06842b16e2d197a076bf94c1b42dc05fc0daac328169317768f28294260a14451f928cb0641010bec0d languageName: node linkType: hard -"@storybook/addon-controls@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-controls@npm:8.6.4" +"@storybook/addon-controls@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-controls@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 dequal: ^2.0.2 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: a25c7f2ae7c3b4aee89ba865e5a305293d54bc4723f4e8e4f22d3c42a626d09b83a69521e728e2b3b35107a7709702801c1f5a4fe96e16871d77108282b8a8a2 + storybook: ^8.6.7 + checksum: 002184ac5444ea21bb76e2737f596920d1d06fbf2f7eab75d12d8f4b4f176439132e81e7433ad46f968e379bfb5224992a0a351b19f7673a96bbd74212d6d6c6 languageName: node linkType: hard -"@storybook/addon-docs@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-docs@npm:8.6.4" +"@storybook/addon-docs@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-docs@npm:8.6.7" dependencies: "@mdx-js/react": ^3.0.0 - "@storybook/blocks": 8.6.4 - "@storybook/csf-plugin": 8.6.4 - "@storybook/react-dom-shim": 8.6.4 + "@storybook/blocks": 8.6.7 + "@storybook/csf-plugin": 8.6.7 + "@storybook/react-dom-shim": 8.6.7 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 28705136eb3117fcc46b4038a6fb8bf24207fa39b2b5043ab3dd124a3a186d02d36afdb03a456638ec652e1944679de0721361bca27caa5920b234e92c4e9149 + storybook: ^8.6.7 + checksum: 764c3fddbbb92a2c4c7df4d96d943f9511a96a40e87f94b084dbaed789bec4de8d87a83e3877cb7648aafb1fa61940be8d52c2910c037ade89c6ef02beb3d745 languageName: node linkType: hard "@storybook/addon-essentials@npm:^8.3.5": - version: 8.6.4 - resolution: "@storybook/addon-essentials@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/addon-essentials@npm:8.6.7" dependencies: - "@storybook/addon-actions": 8.6.4 - "@storybook/addon-backgrounds": 8.6.4 - "@storybook/addon-controls": 8.6.4 - "@storybook/addon-docs": 8.6.4 - "@storybook/addon-highlight": 8.6.4 - "@storybook/addon-measure": 8.6.4 - "@storybook/addon-outline": 8.6.4 - "@storybook/addon-toolbars": 8.6.4 - "@storybook/addon-viewport": 8.6.4 + "@storybook/addon-actions": 8.6.7 + "@storybook/addon-backgrounds": 8.6.7 + "@storybook/addon-controls": 8.6.7 + "@storybook/addon-docs": 8.6.7 + "@storybook/addon-highlight": 8.6.7 + "@storybook/addon-measure": 8.6.7 + "@storybook/addon-outline": 8.6.7 + "@storybook/addon-toolbars": 8.6.7 + "@storybook/addon-viewport": 8.6.7 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 564cc7e6f4559572f12c7f015e40a3995c55c681704e4082ef80d9db0c7b06433a67473e810ea9d67a46121f3a4aca8d7851953bc7f109f54e96c069b05230e0 + storybook: ^8.6.7 + checksum: 774b50e98888ece9536ec2a7f491c8486055d3c7515ac9a7f0264916f684c6c4608e95da7db14bceb65dfdf05f3fc93011a0b74a690eec2d44b6c969511b9313 languageName: node linkType: hard -"@storybook/addon-highlight@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-highlight@npm:8.6.4" +"@storybook/addon-highlight@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-highlight@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: e080b543bd3fbe0e8d6e916f2abd562b7136371dff64e96d196532dca4958016b7890c6dcd48545f11c2ac31aa0d3a713b98d6fd2cde2a1f94b1ebaf7031095d + storybook: ^8.6.7 + checksum: 7baae25d40e717e5138d10b4ea7ef424b55500ab7496ef38738ea0fb99f910bdf3a56651efbfa85d3e4218382498b045894653b47cdd066c6b16ed0076537940 languageName: node linkType: hard "@storybook/addon-interactions@npm:^8.3.5": - version: 8.6.4 - resolution: "@storybook/addon-interactions@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/addon-interactions@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 - "@storybook/instrumenter": 8.6.4 - "@storybook/test": 8.6.4 + "@storybook/instrumenter": 8.6.7 + "@storybook/test": 8.6.7 polished: ^4.2.2 ts-dedent: ^2.2.0 peerDependencies: - storybook: ^8.6.4 - checksum: 6abfd78b17aef00708eb6221d3fdfc45fb738e1fd206a5c08c3909476abe6f042a507b6226ff99708538196294f37aea1d743ca7c33ea270ca0456c0f332ab55 + storybook: ^8.6.7 + checksum: f7a66307aa4e83b1a230d0103123eef15ce7d27aa25c47270624b9ddb6653293e9d0dfe9bb93d3c348604ec05c774716bd513f4d3987ae0b9818a0f865fa0d69 languageName: node linkType: hard "@storybook/addon-links@npm:^8.3.5": - version: 8.6.4 - resolution: "@storybook/addon-links@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/addon-links@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 ts-dedent: ^2.0.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 + storybook: ^8.6.7 peerDependenciesMeta: react: optional: true - checksum: 92ffa01adda87133dd97623e3beb69b1095929a8ec79c00191b816b4dcdf35d4dcad33b2dfa16791647f85357b8fa8f662cdc382772a6c9376953c8f49564dde + checksum: 3770196105742335eb862eea9e096a7be4cb056067b9bd72a1616ca8b1033d2549199494e017f252342959e51ebb4205b1562c0db17b800aceb4656c5bbe2fa3 languageName: node linkType: hard -"@storybook/addon-measure@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-measure@npm:8.6.4" +"@storybook/addon-measure@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-measure@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 tiny-invariant: ^1.3.1 peerDependencies: - storybook: ^8.6.4 - checksum: b020d052c87aab591b4b7e31dd60764af9f70140ad4d529d468cdf0c8eb45d02ad7ec2bc01a83d88a1547cf567da8db5e4ba0b4c7294e968df2bace3f07f4fd7 + storybook: ^8.6.7 + checksum: 38c51463366405216aa21f5e99a5c66acf8a626084427a439bbbdf76f41119cf66a5fd25e1b27f7859e180101b4a536ee058a3978b03cbe6a48f2e0807927c83 languageName: node linkType: hard -"@storybook/addon-outline@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-outline@npm:8.6.4" +"@storybook/addon-outline@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-outline@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: d705c2dda8fc4b9af2ecb8217a0463f0f8213f836150627f67e4702d449071e5982580617ff75ae8c48960ca27e957fe3700c17cd854e05d326ceeaf622202c2 + storybook: ^8.6.7 + checksum: 8919842d53079cb6ae8efcecc5673d1fcd3ec8f9cf2dbf2f44de0fa2648ef684bd626c9be187ef570e7ff2b21eb92bfe1759b8e72bd41f9f0cb82e2e57073cc7 languageName: node linkType: hard "@storybook/addon-storysource@npm:^8.3.6": - version: 8.6.4 - resolution: "@storybook/addon-storysource@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/addon-storysource@npm:8.6.7" dependencies: - "@storybook/source-loader": 8.6.4 + "@storybook/source-loader": 8.6.7 estraverse: ^5.2.0 tiny-invariant: ^1.3.1 peerDependencies: - storybook: ^8.6.4 - checksum: 6172f5ea802a5081a6e777597ca68c2e3bddb58be2bcc7b52f7646bdd2216902a2bb426b3fd8e2a6a8710741d9e72d569a279fb6e0aadadae47fbb881e72308f + storybook: ^8.6.7 + checksum: 3aecdc32867b7ecf0a38efffa80caae6f0249391b8e21ea7a7434ba6dd8f054cd918b4669e799b40fe2f654084c114ab20d411d233e540d46b8c208f9d6f5c2a languageName: node linkType: hard "@storybook/addon-themes@npm:^8.3.6": - version: 8.6.4 - resolution: "@storybook/addon-themes@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/addon-themes@npm:8.6.7" dependencies: ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 11ae08e570df4d94ed452c0be6b15773d51c0a8003c6a238156262fafbb8e094fb5c3d20c11bceaae68461ba12fe305732e4d3ea53bf16c8e115ec2ef6fd1f00 + storybook: ^8.6.7 + checksum: 209793b93774e3e1696e33fcf3a62dd63a4ca60920e45b465a86a2504545d00463ebc683f4ff65606b502175d575a969698efe96538daebc5254adfe9b767929 languageName: node linkType: hard -"@storybook/addon-toolbars@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-toolbars@npm:8.6.4" +"@storybook/addon-toolbars@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-toolbars@npm:8.6.7" peerDependencies: - storybook: ^8.6.4 - checksum: c15ef11c50ac067e5b226dba30db956405d94b5ff56d67279697bcdcc63367ef0ab523f091b8755f8b8ab5c1ac6e55c3ded9cef6f5b917261ea9a232bcf9a8dc + storybook: ^8.6.7 + checksum: 72de8200fcbd95714b79deae7194451725abfd75dac56862b76d9f19150aa844829d7e2c99597fc3be650c6cd952c3fe4789866512314fb26f5d112620ae8145 languageName: node linkType: hard -"@storybook/addon-viewport@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-viewport@npm:8.6.4" +"@storybook/addon-viewport@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-viewport@npm:8.6.7" dependencies: memoizerific: ^1.11.3 peerDependencies: - storybook: ^8.6.4 - checksum: 746cd771f371b825da4c5b974602a1c14287212c19ddff9f593e77e9867a3efe76ccc9ee3e503efdcf91949bf3a03979c8f37aa2fe62eb888a3eb11dd208def2 + storybook: ^8.6.7 + checksum: 2a83a8683ca8306e13578266aeffbc24968f9bf11b1b71c19a5aba0239e0365f19d335950ec261f11c4907577a9600ab6182ccc0ad8e60c13f9a9ea02b6b0adc languageName: node linkType: hard -"@storybook/blocks@npm:8.6.4, @storybook/blocks@npm:^8.3.5": - version: 8.6.4 - resolution: "@storybook/blocks@npm:8.6.4" +"@storybook/blocks@npm:8.6.7, @storybook/blocks@npm:^8.3.5": + version: 8.6.7 + resolution: "@storybook/blocks@npm:8.6.7" dependencies: "@storybook/icons": ^1.2.12 ts-dedent: ^2.0.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^8.6.4 + storybook: ^8.6.7 peerDependenciesMeta: react: optional: true react-dom: optional: true - checksum: fb891491f99fa63c02c90e00d166c9299cf93512d2d6036a932a1c243cd568f7ca45af961b89a19ba1c1c51c4ad76d0de8d687249f1dcb8b3411fbec2b7cf238 + checksum: 89b600680772712500318d82195d2a78885d84127a05ab3e2e6474170f871239ab5de72669d0bfdeede99186f8487c48e197ed33fc3e7fc17d0aea228f915bff languageName: node linkType: hard -"@storybook/builder-vite@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/builder-vite@npm:8.6.4" +"@storybook/builder-vite@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/builder-vite@npm:8.6.7" dependencies: - "@storybook/csf-plugin": 8.6.4 + "@storybook/csf-plugin": 8.6.7 browser-assert: ^1.2.1 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 + storybook: ^8.6.7 vite: ^4.0.0 || ^5.0.0 || ^6.0.0 - checksum: e3e6c1674af25a51b87c084476a2f6e07245a4206493ca7758f116588efc3986e1200b45a9e626406e31a37f001f9c8abf0c77e83f02a14a713c5ac407196775 + checksum: 8ffc8b2f60c4f1f88d99becd35f75cf34e6b7506b2a25ba6ec054a98758f3fada2a054a475c0f8fd74a7baba84fa1d799b9b843352df4cafab7e3d7a96d74348 languageName: node linkType: hard -"@storybook/components@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/components@npm:8.6.4" +"@storybook/components@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/components@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: b50923e759eea99320fdf8946056fb33614b9d993ca567207cd0d714e5fae83da485b64b0d74a18b84355396b33c28b5eea050484c40967873c540f83d314b9a + checksum: cb20f8baa76deef1af1739d6c1b1a9f57eb22d158fa046d9919a91840e7a00f1b48e96b7ffe7994365b60808f864c963a3476ee98b4c8b63968a3a877068da3a languageName: node linkType: hard -"@storybook/core@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/core@npm:8.6.4" +"@storybook/core@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/core@npm:8.6.7" dependencies: - "@storybook/theming": 8.6.4 + "@storybook/theming": 8.6.7 better-opn: ^3.0.2 browser-assert: ^1.2.1 esbuild: ^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 @@ -1220,18 +1220,18 @@ __metadata: peerDependenciesMeta: prettier: optional: true - checksum: 8352b0f65bd7c0462471409a7f086125f4e1a93e1777fa20268beb78109f9784cc1d75536a4f9136368db87ba3c5c11987c95835937ba4c2776f968365795d8f + checksum: b150b7472766fccbbc1dec74cba3c16e009a9f24c13f01198923f553d12e2a2070ee2a35f5514f9af350b79e34577946ea65a4a495fd1fa18a27655f897c013a languageName: node linkType: hard -"@storybook/csf-plugin@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/csf-plugin@npm:8.6.4" +"@storybook/csf-plugin@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/csf-plugin@npm:8.6.7" dependencies: unplugin: ^1.3.1 peerDependencies: - storybook: ^8.6.4 - checksum: f1750183ad0c83438803da83d705a0e73819ad7e0cfd010182cc504d8a37ab2f500df4c6ea61ec82b464b13e992a2a4cf6756aabb2a66e12e8c2ee3f22553929 + storybook: ^8.6.7 + checksum: 75c799fd222552f447e24c852b696bc00f1399a631c6a29e4da1b0be97600aa6085f0ebb56beb8c22731b6099fdddaf52edf01c0d0803ba8e22dd04f79bf483a languageName: node linkType: hard @@ -1261,143 +1261,143 @@ __metadata: languageName: node linkType: hard -"@storybook/instrumenter@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/instrumenter@npm:8.6.4" +"@storybook/instrumenter@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/instrumenter@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 "@vitest/utils": ^2.1.1 peerDependencies: - storybook: ^8.6.4 - checksum: acfc58fd5c29ec78a00498441c97d4528e8f915956c67600c75e7a30d240fb86551e9ce0dad8c0f83c78a828417a64d8aff38db754b87b854c70507d8d3638d0 + storybook: ^8.6.7 + checksum: 8b5bbdd73637233ddebf6d3f14d3904c6f122f29f2efe4a0172a1f03e066a88a3453ae3eef140b227eb626ee959c0c3522f62944407f4530e24e6a6ac804598b languageName: node linkType: hard -"@storybook/manager-api@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/manager-api@npm:8.6.4" +"@storybook/manager-api@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/manager-api@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 50447d3961dfab2b2f36afa76aaeb779a9b51ca66a912bc763103f18f2f71514191388b101ec83093ac9dee6ab509b955da41325f15d88cfe1c480e7d7d1f9eb + checksum: 6bb0860c3795945189832613da5866e5159b2adb376478a2b596c113928c64f5962efc325f927a6bcb7a48d7257f42cf6489b0c44397876129626ac68c44aa28 languageName: node linkType: hard -"@storybook/preview-api@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/preview-api@npm:8.6.4" +"@storybook/preview-api@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/preview-api@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: d8f642de8053686192e28f7ec748944c99c9e4d0cef7f13d96e840fd159c8bea2e3139b88a84eb16009fbda3152a61d9e075777211c10773e4d01fd103bf0e28 + checksum: 0d24d62444b7b153bde89d3949ab6539a163e15bc80c5bfcc73b7d49bbb34fb02eb74a99434793b8a6446aeec491e07f006c0f4e404f98486c6d1d614d01defa languageName: node linkType: hard -"@storybook/react-dom-shim@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/react-dom-shim@npm:8.6.4" +"@storybook/react-dom-shim@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/react-dom-shim@npm:8.6.7" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 - checksum: 0062191f312c0bf32e622904b9da7176c961cec99258c6b230c3fb6758c1cca95ac4142d4701628dc8eb922601d74c350549b78e146b5af1747edf8cb3def756 + storybook: ^8.6.7 + checksum: 51c20259ac4485d9a996266341a4d9898c949049e2a9af9a08bec58c2ace3a40be1a534005c52fc2db2c81bb010dbd36030bb70581b36c05cf4b34d58f140d3a languageName: node linkType: hard "@storybook/react-vite@npm:^8.3.5": - version: 8.6.4 - resolution: "@storybook/react-vite@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/react-vite@npm:8.6.7" dependencies: "@joshwooding/vite-plugin-react-docgen-typescript": 0.5.0 "@rollup/pluginutils": ^5.0.2 - "@storybook/builder-vite": 8.6.4 - "@storybook/react": 8.6.4 + "@storybook/builder-vite": 8.6.7 + "@storybook/react": 8.6.7 find-up: ^5.0.0 magic-string: ^0.30.0 react-docgen: ^7.0.0 resolve: ^1.22.8 tsconfig-paths: ^4.2.0 peerDependencies: - "@storybook/test": 8.6.4 + "@storybook/test": 8.6.7 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 + storybook: ^8.6.7 vite: ^4.0.0 || ^5.0.0 || ^6.0.0 peerDependenciesMeta: "@storybook/test": optional: true - checksum: 877ea89891e18a860b598b48df086db58d161bb840093dc4563d470eab61a5042730de356a306d7a2b9de96afe522caa8ebceb0a4210e9e1b924a2548c451d3c + checksum: 75ed76ac6293520aaab02365a12ba93f360cb2f97b632e1c213de535e1d01e93c202f4a3795863ad273246b2bf1096e5b696ea531902d490534db470a712349f languageName: node linkType: hard -"@storybook/react@npm:8.6.4, @storybook/react@npm:^8.3.5": - version: 8.6.4 - resolution: "@storybook/react@npm:8.6.4" +"@storybook/react@npm:8.6.7, @storybook/react@npm:^8.3.5": + version: 8.6.7 + resolution: "@storybook/react@npm:8.6.7" dependencies: - "@storybook/components": 8.6.4 + "@storybook/components": 8.6.7 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 8.6.4 - "@storybook/preview-api": 8.6.4 - "@storybook/react-dom-shim": 8.6.4 - "@storybook/theming": 8.6.4 + "@storybook/manager-api": 8.6.7 + "@storybook/preview-api": 8.6.7 + "@storybook/react-dom-shim": 8.6.7 + "@storybook/theming": 8.6.7 peerDependencies: - "@storybook/test": 8.6.4 + "@storybook/test": 8.6.7 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 + storybook: ^8.6.7 typescript: ">= 4.2.x" peerDependenciesMeta: "@storybook/test": optional: true typescript: optional: true - checksum: 4e9860c8e177d0dd496e7d6c53927daa8429b82f9c02d5b004de61244573901160a936ba37ce69810fb13e3602391e18723237a901c57e1bd19cf9f58241c30c + checksum: c98438ddfd764300e1a805623fab976f9ef94a2d939984d6caf98ce92ed29d8a7307389b98e2df2d1302b302dc549c7c95050464731d9c588347cd154c360834 languageName: node linkType: hard -"@storybook/source-loader@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/source-loader@npm:8.6.4" +"@storybook/source-loader@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/source-loader@npm:8.6.7" dependencies: es-toolkit: ^1.22.0 estraverse: ^5.2.0 prettier: ^3.1.1 peerDependencies: - storybook: ^8.6.4 - checksum: 3336f11b99014bb55a7ad88eabc8149ed0ffa4e4cc3d64e22cfc7d7e7f0b36987eda0ca55b6b20d805e89305f277104db6c60c2100eea439bc385808f6193bc2 + storybook: ^8.6.7 + checksum: 74d5dd20384c0e17720ba3492458362bfd2f527614f37cffef438b202d12f4f45c411d2568308975286c34eea05d7bcb1baeaf6605337b7906725f7257b542c6 languageName: node linkType: hard -"@storybook/test@npm:8.6.4, @storybook/test@npm:^8.3.5": - version: 8.6.4 - resolution: "@storybook/test@npm:8.6.4" +"@storybook/test@npm:8.6.7, @storybook/test@npm:^8.3.5": + version: 8.6.7 + resolution: "@storybook/test@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 - "@storybook/instrumenter": 8.6.4 + "@storybook/instrumenter": 8.6.7 "@testing-library/dom": 10.4.0 "@testing-library/jest-dom": 6.5.0 "@testing-library/user-event": 14.5.2 "@vitest/expect": 2.0.5 "@vitest/spy": 2.0.5 peerDependencies: - storybook: ^8.6.4 - checksum: 2c16f1cc8e0f6e57f5972a664839885467c7a8b01cf807b32ea7cdd3508354cd408603f05b3f6d1c118e4560f4224102df6dfc0242deb0d2ea670895e8cdcc81 + storybook: ^8.6.7 + checksum: d269423580cbcc61de74a3940504f00bb580b389b04432aa6a0a7e8fed54536782ef254e8edcf6bac3ce98d35e439fdfd86316cf53f3435396f12cbc2e060541 languageName: node linkType: hard -"@storybook/theming@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/theming@npm:8.6.4" +"@storybook/theming@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/theming@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: b7e13026c381e18e7ad2064e1528876eb01b7563ad16aababcac531ce76f5e59b985a72603f57d75465a611ea564bd46b9b1760634211faf4307f9265f06e044 + checksum: 747a2377df65d5f0962dc8606d06247ad89fb7ecabab0bd9611055d599b5bd0fa15769e4c76e948ae34ae232ba756bf6795ccb3467b1adf35ff961db7350f4de languageName: node linkType: hard "@storybook/types@npm:^8.3.5": - version: 8.6.4 - resolution: "@storybook/types@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/types@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 99c59e960b9b4500c1bfcdcaedf0070fc7eb500c1d3226e39bc17c7ab3671fca89645abe30baf4dcfd65764d4955db6b2c416049aef78ab81535a27a4c671eb5 + checksum: bae7a202bda4f83f8f8d9a176ff79a033f2e67f5db4d9ee05cd468c3921d8bcc2a44d93a11c8401ad7b3a08f6a54510013791ce932117f10fc6b289642be18aa languageName: node linkType: hard @@ -4451,10 +4451,10 @@ __metadata: linkType: hard "storybook@npm:^8.3.5": - version: 8.6.4 - resolution: "storybook@npm:8.6.4" + version: 8.6.7 + resolution: "storybook@npm:8.6.7" dependencies: - "@storybook/core": 8.6.4 + "@storybook/core": 8.6.7 peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: @@ -4464,7 +4464,7 @@ __metadata: getstorybook: ./bin/index.cjs sb: ./bin/index.cjs storybook: ./bin/index.cjs - checksum: 96c59b5c6ac27dfb9fb85d110b0257a77264015454dd0ca7893ae9df04dbf31e523ff351ba45283f33a58ecb28fd985349aa9c1fb83ab51d0c781a4d5809fa15 + checksum: fe21ce4d9cd17069a5b409ed518603f97ec6ec421b7f41cff3e43b409820fcbc2c8dbcb3aed99dd7d0a99a0c6138c7576ddf72f78186b6f86085d503b3c8b32f languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index a6b0a736a0..b86a92c8fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17688,9 +17688,9 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-actions@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-actions@npm:8.6.4" +"@storybook/addon-actions@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-actions@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 "@types/uuid": ^9.0.1 @@ -17698,121 +17698,121 @@ __metadata: polished: ^4.2.2 uuid: ^9.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: b08f73070ac90f2c0d404b63f3148ebe11d4683f0728fd04459df62b521422d8c17b3619f6c012a90571a2d5520ee34d35e02fd104c0298580177dd57e045312 + storybook: ^8.6.7 + checksum: 28add3c30e397894bb13d1d492b88e331cec2a24b47ad9e865002e54851a17a0916387dca02074b834c6d665748bd2a5ec88904ad08795645d1b8a9345fb1328 languageName: node linkType: hard -"@storybook/addon-backgrounds@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-backgrounds@npm:8.6.4" +"@storybook/addon-backgrounds@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-backgrounds@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 memoizerific: ^1.11.3 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 53a67d385d6241730d0d992552de58316cfa4c46f56fa5a81df8647c76356778164783b8a872e31b3624692f456186074e06407778cf4442ffc8596cdaded49e + storybook: ^8.6.7 + checksum: 574b634e49225f52800a7ed0ea7b120f15198ae91068c06842b16e2d197a076bf94c1b42dc05fc0daac328169317768f28294260a14451f928cb0641010bec0d languageName: node linkType: hard -"@storybook/addon-controls@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-controls@npm:8.6.4" +"@storybook/addon-controls@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-controls@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 dequal: ^2.0.2 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: a25c7f2ae7c3b4aee89ba865e5a305293d54bc4723f4e8e4f22d3c42a626d09b83a69521e728e2b3b35107a7709702801c1f5a4fe96e16871d77108282b8a8a2 + storybook: ^8.6.7 + checksum: 002184ac5444ea21bb76e2737f596920d1d06fbf2f7eab75d12d8f4b4f176439132e81e7433ad46f968e379bfb5224992a0a351b19f7673a96bbd74212d6d6c6 languageName: node linkType: hard -"@storybook/addon-docs@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-docs@npm:8.6.4" +"@storybook/addon-docs@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-docs@npm:8.6.7" dependencies: "@mdx-js/react": ^3.0.0 - "@storybook/blocks": 8.6.4 - "@storybook/csf-plugin": 8.6.4 - "@storybook/react-dom-shim": 8.6.4 + "@storybook/blocks": 8.6.7 + "@storybook/csf-plugin": 8.6.7 + "@storybook/react-dom-shim": 8.6.7 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 28705136eb3117fcc46b4038a6fb8bf24207fa39b2b5043ab3dd124a3a186d02d36afdb03a456638ec652e1944679de0721361bca27caa5920b234e92c4e9149 + storybook: ^8.6.7 + checksum: 764c3fddbbb92a2c4c7df4d96d943f9511a96a40e87f94b084dbaed789bec4de8d87a83e3877cb7648aafb1fa61940be8d52c2910c037ade89c6ef02beb3d745 languageName: node linkType: hard "@storybook/addon-essentials@npm:^8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-essentials@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/addon-essentials@npm:8.6.7" dependencies: - "@storybook/addon-actions": 8.6.4 - "@storybook/addon-backgrounds": 8.6.4 - "@storybook/addon-controls": 8.6.4 - "@storybook/addon-docs": 8.6.4 - "@storybook/addon-highlight": 8.6.4 - "@storybook/addon-measure": 8.6.4 - "@storybook/addon-outline": 8.6.4 - "@storybook/addon-toolbars": 8.6.4 - "@storybook/addon-viewport": 8.6.4 + "@storybook/addon-actions": 8.6.7 + "@storybook/addon-backgrounds": 8.6.7 + "@storybook/addon-controls": 8.6.7 + "@storybook/addon-docs": 8.6.7 + "@storybook/addon-highlight": 8.6.7 + "@storybook/addon-measure": 8.6.7 + "@storybook/addon-outline": 8.6.7 + "@storybook/addon-toolbars": 8.6.7 + "@storybook/addon-viewport": 8.6.7 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 564cc7e6f4559572f12c7f015e40a3995c55c681704e4082ef80d9db0c7b06433a67473e810ea9d67a46121f3a4aca8d7851953bc7f109f54e96c069b05230e0 + storybook: ^8.6.7 + checksum: 774b50e98888ece9536ec2a7f491c8486055d3c7515ac9a7f0264916f684c6c4608e95da7db14bceb65dfdf05f3fc93011a0b74a690eec2d44b6c969511b9313 languageName: node linkType: hard -"@storybook/addon-highlight@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-highlight@npm:8.6.4" +"@storybook/addon-highlight@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-highlight@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: e080b543bd3fbe0e8d6e916f2abd562b7136371dff64e96d196532dca4958016b7890c6dcd48545f11c2ac31aa0d3a713b98d6fd2cde2a1f94b1ebaf7031095d + storybook: ^8.6.7 + checksum: 7baae25d40e717e5138d10b4ea7ef424b55500ab7496ef38738ea0fb99f910bdf3a56651efbfa85d3e4218382498b045894653b47cdd066c6b16ed0076537940 languageName: node linkType: hard "@storybook/addon-interactions@npm:^8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-interactions@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/addon-interactions@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 - "@storybook/instrumenter": 8.6.4 - "@storybook/test": 8.6.4 + "@storybook/instrumenter": 8.6.7 + "@storybook/test": 8.6.7 polished: ^4.2.2 ts-dedent: ^2.2.0 peerDependencies: - storybook: ^8.6.4 - checksum: 6abfd78b17aef00708eb6221d3fdfc45fb738e1fd206a5c08c3909476abe6f042a507b6226ff99708538196294f37aea1d743ca7c33ea270ca0456c0f332ab55 + storybook: ^8.6.7 + checksum: f7a66307aa4e83b1a230d0103123eef15ce7d27aa25c47270624b9ddb6653293e9d0dfe9bb93d3c348604ec05c774716bd513f4d3987ae0b9818a0f865fa0d69 languageName: node linkType: hard -"@storybook/addon-measure@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-measure@npm:8.6.4" +"@storybook/addon-measure@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-measure@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 tiny-invariant: ^1.3.1 peerDependencies: - storybook: ^8.6.4 - checksum: b020d052c87aab591b4b7e31dd60764af9f70140ad4d529d468cdf0c8eb45d02ad7ec2bc01a83d88a1547cf567da8db5e4ba0b4c7294e968df2bace3f07f4fd7 + storybook: ^8.6.7 + checksum: 38c51463366405216aa21f5e99a5c66acf8a626084427a439bbbdf76f41119cf66a5fd25e1b27f7859e180101b4a536ee058a3978b03cbe6a48f2e0807927c83 languageName: node linkType: hard -"@storybook/addon-outline@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-outline@npm:8.6.4" +"@storybook/addon-outline@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-outline@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: d705c2dda8fc4b9af2ecb8217a0463f0f8213f836150627f67e4702d449071e5982580617ff75ae8c48960ca27e957fe3700c17cd854e05d326ceeaf622202c2 + storybook: ^8.6.7 + checksum: 8919842d53079cb6ae8efcecc5673d1fcd3ec8f9cf2dbf2f44de0fa2648ef684bd626c9be187ef570e7ff2b21eb92bfe1759b8e72bd41f9f0cb82e2e57073cc7 languageName: node linkType: hard @@ -17828,33 +17828,33 @@ __metadata: linkType: hard "@storybook/addon-themes@npm:^8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-themes@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/addon-themes@npm:8.6.7" dependencies: ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 11ae08e570df4d94ed452c0be6b15773d51c0a8003c6a238156262fafbb8e094fb5c3d20c11bceaae68461ba12fe305732e4d3ea53bf16c8e115ec2ef6fd1f00 + storybook: ^8.6.7 + checksum: 209793b93774e3e1696e33fcf3a62dd63a4ca60920e45b465a86a2504545d00463ebc683f4ff65606b502175d575a969698efe96538daebc5254adfe9b767929 languageName: node linkType: hard -"@storybook/addon-toolbars@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-toolbars@npm:8.6.4" +"@storybook/addon-toolbars@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-toolbars@npm:8.6.7" peerDependencies: - storybook: ^8.6.4 - checksum: c15ef11c50ac067e5b226dba30db956405d94b5ff56d67279697bcdcc63367ef0ab523f091b8755f8b8ab5c1ac6e55c3ded9cef6f5b917261ea9a232bcf9a8dc + storybook: ^8.6.7 + checksum: 72de8200fcbd95714b79deae7194451725abfd75dac56862b76d9f19150aa844829d7e2c99597fc3be650c6cd952c3fe4789866512314fb26f5d112620ae8145 languageName: node linkType: hard -"@storybook/addon-viewport@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/addon-viewport@npm:8.6.4" +"@storybook/addon-viewport@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/addon-viewport@npm:8.6.7" dependencies: memoizerific: ^1.11.3 peerDependencies: - storybook: ^8.6.4 - checksum: 746cd771f371b825da4c5b974602a1c14287212c19ddff9f593e77e9867a3efe76ccc9ee3e503efdcf91949bf3a03979c8f37aa2fe62eb888a3eb11dd208def2 + storybook: ^8.6.7 + checksum: 2a83a8683ca8306e13578266aeffbc24968f9bf11b1b71c19a5aba0239e0365f19d335950ec261f11c4907577a9600ab6182ccc0ad8e60c13f9a9ea02b6b0adc languageName: node linkType: hard @@ -17868,30 +17868,30 @@ __metadata: languageName: node linkType: hard -"@storybook/blocks@npm:8.6.4, @storybook/blocks@npm:^8.6.4": - version: 8.6.4 - resolution: "@storybook/blocks@npm:8.6.4" +"@storybook/blocks@npm:8.6.7, @storybook/blocks@npm:^8.6.4": + version: 8.6.7 + resolution: "@storybook/blocks@npm:8.6.7" dependencies: "@storybook/icons": ^1.2.12 ts-dedent: ^2.0.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^8.6.4 + storybook: ^8.6.7 peerDependenciesMeta: react: optional: true react-dom: optional: true - checksum: fb891491f99fa63c02c90e00d166c9299cf93512d2d6036a932a1c243cd568f7ca45af961b89a19ba1c1c51c4ad76d0de8d687249f1dcb8b3411fbec2b7cf238 + checksum: 89b600680772712500318d82195d2a78885d84127a05ab3e2e6474170f871239ab5de72669d0bfdeede99186f8487c48e197ed33fc3e7fc17d0aea228f915bff languageName: node linkType: hard -"@storybook/builder-webpack5@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/builder-webpack5@npm:8.6.4" +"@storybook/builder-webpack5@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/builder-webpack5@npm:8.6.7" dependencies: - "@storybook/core-webpack": 8.6.4 + "@storybook/core-webpack": 8.6.7 "@types/semver": ^7.3.4 browser-assert: ^1.2.1 case-sensitive-paths-webpack-plugin: ^2.4.0 @@ -17916,39 +17916,39 @@ __metadata: webpack-hot-middleware: ^2.25.1 webpack-virtual-modules: ^0.6.0 peerDependencies: - storybook: ^8.6.4 + storybook: ^8.6.7 peerDependenciesMeta: typescript: optional: true - checksum: 1de3fe0c3e6143aeb31c3d1952fad56cb896e00d6fbe1652ac78e230b5787c079c9b977c481f224b31e8ad6f08e0f4a6b65ec5262c87fe682e916d5068c671ff + checksum: 87ee61663dc418385f6b04f48b0790d5df34f1bcc267714cedd63062fd304dfeb35f1f3c71ee123d0dd3122b7d29d06e32a56618d280e6b0cae12d7eac72b59d languageName: node linkType: hard -"@storybook/components@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/components@npm:8.6.4" +"@storybook/components@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/components@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: b50923e759eea99320fdf8946056fb33614b9d993ca567207cd0d714e5fae83da485b64b0d74a18b84355396b33c28b5eea050484c40967873c540f83d314b9a + checksum: cb20f8baa76deef1af1739d6c1b1a9f57eb22d158fa046d9919a91840e7a00f1b48e96b7ffe7994365b60808f864c963a3476ee98b4c8b63968a3a877068da3a languageName: node linkType: hard -"@storybook/core-webpack@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/core-webpack@npm:8.6.4" +"@storybook/core-webpack@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/core-webpack@npm:8.6.7" dependencies: ts-dedent: ^2.0.0 peerDependencies: - storybook: ^8.6.4 - checksum: 48d39eb184662b0c1e6e5a8acfba2057b35ea9151874dddc406322811a65d9f58b7cc454a06b913b239f7215cf62e6d8939994a78f9fa38d6e9744e9232758f1 + storybook: ^8.6.7 + checksum: a2b7d8db89cc96ba7278c82ba1ea43303baa7dba9f4c7aff2d576de473c09c572140d7f7ab9db2a4eb453c47aeee0a5124e2f18b4312d67c2670bbc244b4bc26 languageName: node linkType: hard -"@storybook/core@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/core@npm:8.6.4" +"@storybook/core@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/core@npm:8.6.7" dependencies: - "@storybook/theming": 8.6.4 + "@storybook/theming": 8.6.7 better-opn: ^3.0.2 browser-assert: ^1.2.1 esbuild: ^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 @@ -17964,18 +17964,18 @@ __metadata: peerDependenciesMeta: prettier: optional: true - checksum: 8352b0f65bd7c0462471409a7f086125f4e1a93e1777fa20268beb78109f9784cc1d75536a4f9136368db87ba3c5c11987c95835937ba4c2776f968365795d8f + checksum: b150b7472766fccbbc1dec74cba3c16e009a9f24c13f01198923f553d12e2a2070ee2a35f5514f9af350b79e34577946ea65a4a495fd1fa18a27655f897c013a languageName: node linkType: hard -"@storybook/csf-plugin@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/csf-plugin@npm:8.6.4" +"@storybook/csf-plugin@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/csf-plugin@npm:8.6.7" dependencies: unplugin: ^1.3.1 peerDependencies: - storybook: ^8.6.4 - checksum: f1750183ad0c83438803da83d705a0e73819ad7e0cfd010182cc504d8a37ab2f500df4c6ea61ec82b464b13e992a2a4cf6756aabb2a66e12e8c2ee3f22553929 + storybook: ^8.6.7 + checksum: 75c799fd222552f447e24c852b696bc00f1399a631c6a29e4da1b0be97600aa6085f0ebb56beb8c22731b6099fdddaf52edf01c0d0803ba8e22dd04f79bf483a languageName: node linkType: hard @@ -18005,24 +18005,24 @@ __metadata: languageName: node linkType: hard -"@storybook/instrumenter@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/instrumenter@npm:8.6.4" +"@storybook/instrumenter@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/instrumenter@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 "@vitest/utils": ^2.1.1 peerDependencies: - storybook: ^8.6.4 - checksum: acfc58fd5c29ec78a00498441c97d4528e8f915956c67600c75e7a30d240fb86551e9ce0dad8c0f83c78a828417a64d8aff38db754b87b854c70507d8d3638d0 + storybook: ^8.6.7 + checksum: 8b5bbdd73637233ddebf6d3f14d3904c6f122f29f2efe4a0172a1f03e066a88a3453ae3eef140b227eb626ee959c0c3522f62944407f4530e24e6a6ac804598b languageName: node linkType: hard -"@storybook/manager-api@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/manager-api@npm:8.6.4" +"@storybook/manager-api@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/manager-api@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: 50447d3961dfab2b2f36afa76aaeb779a9b51ca66a912bc763103f18f2f71514191388b101ec83093ac9dee6ab509b955da41325f15d88cfe1c480e7d7d1f9eb + checksum: 6bb0860c3795945189832613da5866e5159b2adb376478a2b596c113928c64f5962efc325f927a6bcb7a48d7257f42cf6489b0c44397876129626ac68c44aa28 languageName: node linkType: hard @@ -18035,12 +18035,12 @@ __metadata: languageName: node linkType: hard -"@storybook/preset-react-webpack@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/preset-react-webpack@npm:8.6.4" +"@storybook/preset-react-webpack@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/preset-react-webpack@npm:8.6.7" dependencies: - "@storybook/core-webpack": 8.6.4 - "@storybook/react": 8.6.4 + "@storybook/core-webpack": 8.6.7 + "@storybook/react": 8.6.7 "@storybook/react-docgen-typescript-plugin": 1.0.6--canary.9.0c3f3b7.0 "@types/semver": ^7.3.4 find-up: ^5.0.0 @@ -18053,20 +18053,20 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 + storybook: ^8.6.7 peerDependenciesMeta: typescript: optional: true - checksum: 9327cda765833877e77305767cfd7e90056d22c551593fc4a99557936bfd41972ad0702abf3e53f2112f020fcc850595176e226b595c87795ff9f4e5b2cf2fa0 + checksum: b40194dd66538104ace7abe96fa5100caa795bb562faf1612fb0769f54fc19303ad4914953c99be7298383989a4b1844db086e22df0ff458a9cd7409f36cd998 languageName: node linkType: hard -"@storybook/preview-api@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/preview-api@npm:8.6.4" +"@storybook/preview-api@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/preview-api@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: d8f642de8053686192e28f7ec748944c99c9e4d0cef7f13d96e840fd159c8bea2e3139b88a84eb16009fbda3152a61d9e075777211c10773e4d01fd103bf0e28 + checksum: 0d24d62444b7b153bde89d3949ab6539a163e15bc80c5bfcc73b7d49bbb34fb02eb74a99434793b8a6446aeec491e07f006c0f4e404f98486c6d1d614d01defa languageName: node linkType: hard @@ -18088,84 +18088,84 @@ __metadata: languageName: node linkType: hard -"@storybook/react-dom-shim@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/react-dom-shim@npm:8.6.4" +"@storybook/react-dom-shim@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/react-dom-shim@npm:8.6.7" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 - checksum: 0062191f312c0bf32e622904b9da7176c961cec99258c6b230c3fb6758c1cca95ac4142d4701628dc8eb922601d74c350549b78e146b5af1747edf8cb3def756 + storybook: ^8.6.7 + checksum: 51c20259ac4485d9a996266341a4d9898c949049e2a9af9a08bec58c2ace3a40be1a534005c52fc2db2c81bb010dbd36030bb70581b36c05cf4b34d58f140d3a languageName: node linkType: hard "@storybook/react-webpack5@npm:^8.6.4": - version: 8.6.4 - resolution: "@storybook/react-webpack5@npm:8.6.4" + version: 8.6.7 + resolution: "@storybook/react-webpack5@npm:8.6.7" dependencies: - "@storybook/builder-webpack5": 8.6.4 - "@storybook/preset-react-webpack": 8.6.4 - "@storybook/react": 8.6.4 + "@storybook/builder-webpack5": 8.6.7 + "@storybook/preset-react-webpack": 8.6.7 + "@storybook/react": 8.6.7 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 + storybook: ^8.6.7 typescript: ">= 4.2.x" peerDependenciesMeta: typescript: optional: true - checksum: e30788afe3e5de10b9f5e061e4b180dadc6fcb607c6ef330f5dc0252249eef4ded5c809e2bb4491edd865bb3528f4ae9044b29e9a40fe8f5278fceaac8fbea8d + checksum: b741566e5b17c66c3993fcd7550d193aef7f00205328e8dd03561b1cb12f7ad963e493e3db3146b93fffdf67ab17a960fe94ce0c15926b9dfe769340d0606c71 languageName: node linkType: hard -"@storybook/react@npm:8.6.4, @storybook/react@npm:^8.6.4": - version: 8.6.4 - resolution: "@storybook/react@npm:8.6.4" +"@storybook/react@npm:8.6.7, @storybook/react@npm:^8.6.4": + version: 8.6.7 + resolution: "@storybook/react@npm:8.6.7" dependencies: - "@storybook/components": 8.6.4 + "@storybook/components": 8.6.7 "@storybook/global": ^5.0.0 - "@storybook/manager-api": 8.6.4 - "@storybook/preview-api": 8.6.4 - "@storybook/react-dom-shim": 8.6.4 - "@storybook/theming": 8.6.4 + "@storybook/manager-api": 8.6.7 + "@storybook/preview-api": 8.6.7 + "@storybook/react-dom-shim": 8.6.7 + "@storybook/theming": 8.6.7 peerDependencies: - "@storybook/test": 8.6.4 + "@storybook/test": 8.6.7 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.6.4 + storybook: ^8.6.7 typescript: ">= 4.2.x" peerDependenciesMeta: "@storybook/test": optional: true typescript: optional: true - checksum: 4e9860c8e177d0dd496e7d6c53927daa8429b82f9c02d5b004de61244573901160a936ba37ce69810fb13e3602391e18723237a901c57e1bd19cf9f58241c30c + checksum: c98438ddfd764300e1a805623fab976f9ef94a2d939984d6caf98ce92ed29d8a7307389b98e2df2d1302b302dc549c7c95050464731d9c588347cd154c360834 languageName: node linkType: hard -"@storybook/test@npm:8.6.4, @storybook/test@npm:^8.6.4": - version: 8.6.4 - resolution: "@storybook/test@npm:8.6.4" +"@storybook/test@npm:8.6.7, @storybook/test@npm:^8.6.4": + version: 8.6.7 + resolution: "@storybook/test@npm:8.6.7" dependencies: "@storybook/global": ^5.0.0 - "@storybook/instrumenter": 8.6.4 + "@storybook/instrumenter": 8.6.7 "@testing-library/dom": 10.4.0 "@testing-library/jest-dom": 6.5.0 "@testing-library/user-event": 14.5.2 "@vitest/expect": 2.0.5 "@vitest/spy": 2.0.5 peerDependencies: - storybook: ^8.6.4 - checksum: 2c16f1cc8e0f6e57f5972a664839885467c7a8b01cf807b32ea7cdd3508354cd408603f05b3f6d1c118e4560f4224102df6dfc0242deb0d2ea670895e8cdcc81 + storybook: ^8.6.7 + checksum: d269423580cbcc61de74a3940504f00bb580b389b04432aa6a0a7e8fed54536782ef254e8edcf6bac3ce98d35e439fdfd86316cf53f3435396f12cbc2e060541 languageName: node linkType: hard -"@storybook/theming@npm:8.6.4": - version: 8.6.4 - resolution: "@storybook/theming@npm:8.6.4" +"@storybook/theming@npm:8.6.7": + version: 8.6.7 + resolution: "@storybook/theming@npm:8.6.7" peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - checksum: b7e13026c381e18e7ad2064e1528876eb01b7563ad16aababcac531ce76f5e59b985a72603f57d75465a611ea564bd46b9b1760634211faf4307f9265f06e044 + checksum: 747a2377df65d5f0962dc8606d06247ad89fb7ecabab0bd9611055d599b5bd0fa15769e4c76e948ae34ae232ba756bf6795ccb3467b1adf35ff961db7350f4de languageName: node linkType: hard @@ -44217,10 +44217,10 @@ __metadata: linkType: hard "storybook@npm:^8.6.4": - version: 8.6.4 - resolution: "storybook@npm:8.6.4" + version: 8.6.7 + resolution: "storybook@npm:8.6.7" dependencies: - "@storybook/core": 8.6.4 + "@storybook/core": 8.6.7 peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: @@ -44230,7 +44230,7 @@ __metadata: getstorybook: ./bin/index.cjs sb: ./bin/index.cjs storybook: ./bin/index.cjs - checksum: 96c59b5c6ac27dfb9fb85d110b0257a77264015454dd0ca7893ae9df04dbf31e523ff351ba45283f33a58ecb28fd985349aa9c1fb83ab51d0c781a4d5809fa15 + checksum: fe21ce4d9cd17069a5b409ed518603f97ec6ec421b7f41cff3e43b409820fcbc2c8dbcb3aed99dd7d0a99a0c6138c7576ddf72f78186b6f86085d503b3c8b32f languageName: node linkType: hard From 275b3edb84d0126bf79bc6e645707f439e7265ea Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Mon, 17 Mar 2025 19:05:52 +0100 Subject: [PATCH 13/52] Made "sentry:project:create" action idempotent Signed-off-by: Bogdan Nechyporenko --- .../src/actions/createProject.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index b0a17f1947..6c173deb59 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -90,7 +90,6 @@ export function createSentryCreateProjectAction(options: { config: Config }) { const { result } = await ctx.checkpoint({ key: `create.project.${organizationSlug}.${teamSlug}`, - // eslint-disable-next-line no-loop-func fn: async () => { const response = await fetch( `https://sentry.io/api/0/teams/${organizationSlug}/${teamSlug}/projects/`, From 186d01615547a870d54d68b5de2e4118ee4b0826 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sun, 16 Mar 2025 15:23:46 +0100 Subject: [PATCH 14/52] catalog-react: add operation to default groups Signed-off-by: Patrik Oldsberg --- .changeset/sad-pots-try.md | 5 +++++ plugins/catalog-react/report-alpha.api.md | 1 + plugins/catalog-react/src/alpha/blueprints/extensionData.tsx | 1 + 3 files changed, 7 insertions(+) create mode 100644 .changeset/sad-pots-try.md diff --git a/.changeset/sad-pots-try.md b/.changeset/sad-pots-try.md new file mode 100644 index 0000000000..68c442fc6e --- /dev/null +++ b/.changeset/sad-pots-try.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Add `operation` to alpha `defaultEntityContentGroups`. diff --git a/plugins/catalog-react/report-alpha.api.md b/plugins/catalog-react/report-alpha.api.md index 4a154356d1..2df3371353 100644 --- a/plugins/catalog-react/report-alpha.api.md +++ b/plugins/catalog-react/report-alpha.api.md @@ -99,6 +99,7 @@ export const defaultEntityContentGroups: { documentation: string; development: string; deployment: string; + operation: string; observability: string; }; diff --git a/plugins/catalog-react/src/alpha/blueprints/extensionData.tsx b/plugins/catalog-react/src/alpha/blueprints/extensionData.tsx index c085912123..b5092d99b7 100644 --- a/plugins/catalog-react/src/alpha/blueprints/extensionData.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/extensionData.tsx @@ -41,6 +41,7 @@ export const defaultEntityContentGroups = { documentation: 'Documentation', development: 'Development', deployment: 'Deployment', + operation: 'Operation', observability: 'Observability', }; From 6ed42b764ceb163da691cfcfe5eecc662753737e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Vit=C3=A1sek?= Date: Tue, 18 Mar 2025 11:26:20 +0100 Subject: [PATCH 15/52] feat: add TemplateDetailButton to CardHeader and update tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ladislav Vitásek --- .changeset/honest-ties-worry.md | 5 ++ plugins/home/report.api.md | 3 +- plugins/scaffolder-react/report-alpha.api.md | 1 + .../TemplateCard/CardHeader.test.tsx | 48 ++++++++++++++- .../components/TemplateCard/CardHeader.tsx | 9 ++- .../TemplateCard/TemplateCard.test.tsx | 49 ++++++--------- .../TemplateCard/TemplateDetailButton.tsx | 61 +++++++++++++++++++ plugins/scaffolder-react/src/translation.ts | 3 + 8 files changed, 143 insertions(+), 36 deletions(-) create mode 100644 .changeset/honest-ties-worry.md create mode 100644 plugins/scaffolder-react/src/next/components/TemplateCard/TemplateDetailButton.tsx diff --git a/.changeset/honest-ties-worry.md b/.changeset/honest-ties-worry.md new file mode 100644 index 0000000000..74d8c591c1 --- /dev/null +++ b/.changeset/honest-ties-worry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Scaffolding - Template card - button to show template entity detail diff --git a/plugins/home/report.api.md b/plugins/home/report.api.md index ef5a0d5a7a..eacf1a99a9 100644 --- a/plugins/home/report.api.md +++ b/plugins/home/report.api.md @@ -50,8 +50,7 @@ export const ComponentAccordion: (props: { expanded?: boolean; Content: () => JSX.Element; Actions?: () => JSX.Element; - Settings?: () => JSX./** @public */ - Element; + Settings?: () => JSX.Element; ContextProvider?: (props: any) => JSX.Element; }) => JSX_2.Element; diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md index b007fa7d49..fbd539f96e 100644 --- a/plugins/scaffolder-react/report-alpha.api.md +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -347,6 +347,7 @@ export const scaffolderReactTranslationRef: TranslationRef< readonly 'templateCategoryPicker.title': 'Categories'; readonly 'templateCard.noDescription': 'No description'; readonly 'templateCard.chooseButtonText': 'Choose'; + readonly 'cardHeader.detailBtnTitle': 'Show template entity details'; readonly 'templateOutputs.title': 'Text Output'; } >; diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx index 9ae2a507dd..3c7eef5f8d 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.test.tsx @@ -24,12 +24,21 @@ import { renderInTestApp, TestApiProvider, } from '@backstage/test-utils'; -import { starredEntitiesApiRef } from '@backstage/plugin-catalog-react'; +import { + entityRouteRef, + starredEntitiesApiRef, +} from '@backstage/plugin-catalog-react'; import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import Observable from 'zen-observable'; import { stringifyEntityRef } from '@backstage/catalog-model'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +const mountedRoutes = { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, +}; + describe('CardHeader', () => { it('should select the correct theme from the theme provider from the header', async () => { // Can't really test what we want here. @@ -64,6 +73,7 @@ describe('CardHeader', () => { /> , + mountedRoutes, ); expect(mockTheme.getPageTheme).toHaveBeenCalledWith({ themeId: 'service' }); @@ -93,6 +103,7 @@ describe('CardHeader', () => { }} /> , + mountedRoutes, ); expect(getByText('service')).toBeInTheDocument(); @@ -118,6 +129,7 @@ describe('CardHeader', () => { , + mountedRoutes, ); const favorite = getByRole('button', { name: 'Add to favorites' }); @@ -129,6 +141,38 @@ describe('CardHeader', () => { ); }); + it('renders TemplateDetailButton with link to entity page', async () => { + const { getByTitle } = await renderInTestApp( + + + , + mountedRoutes, + ); + + const detailButton = getByTitle('Show template entity details'); + const link = detailButton.querySelector('a'); + expect(link).toBeInTheDocument(); + }); + it('should render the name of the entity', async () => { const { getByText } = await renderInTestApp( { }} /> , + mountedRoutes, ); expect(getByText('bob')).toBeInTheDocument(); @@ -182,6 +227,7 @@ describe('CardHeader', () => { }} /> , + mountedRoutes, ); expect(getByText('Iamtitle')).toBeInTheDocument(); diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.tsx index 467d26ce76..5e5c6fe8bf 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/CardHeader.tsx @@ -15,10 +15,11 @@ */ import React from 'react'; -import { Theme, makeStyles, useTheme } from '@material-ui/core/styles'; +import { makeStyles, Theme, useTheme } from '@material-ui/core/styles'; import { ItemCardHeader } from '@backstage/core-components'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { FavoriteEntity } from '@backstage/plugin-catalog-react'; +import { TemplateDetailButton } from './TemplateDetailButton.tsx'; const useStyles = makeStyles< Theme, @@ -66,7 +67,11 @@ export const CardHeader = (props: CardHeaderProps) => {
{type}
- + +
); diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx index 673f1e4a9e..e25952131b 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateCard.test.tsx @@ -33,6 +33,12 @@ import { permissionApiRef } from '@backstage/plugin-permission-react'; import { AuthorizeResult } from '@backstage/plugin-permission-common'; import { SWRConfig } from 'swr'; +const mountedRoutes = { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, +}; + describe('TemplateCard', () => { it('should render the card title', async () => { const mockTemplate: TemplateEntityV1beta3 = { @@ -59,6 +65,7 @@ describe('TemplateCard', () => { > , + mountedRoutes, ); expect(getByText('bob')).toBeInTheDocument(); @@ -89,6 +96,7 @@ describe('TemplateCard', () => { > , + mountedRoutes, ); const description = getByText('hello'); @@ -121,6 +129,7 @@ describe('TemplateCard', () => { > , + mountedRoutes, ); expect(getByText('No description')).toBeInTheDocument(); @@ -151,6 +160,7 @@ describe('TemplateCard', () => { > , + mountedRoutes, ); expect(queryByTestId('template-card-separator')).toBeInTheDocument(); @@ -187,6 +197,7 @@ describe('TemplateCard', () => { > , + mountedRoutes, ); for (const tag of mockTemplate.metadata.tags!) { @@ -227,11 +238,7 @@ describe('TemplateCard', () => { > , - { - mountedRoutes: { - '/catalog/:kind/:namespace/:name': entityRouteRef, - }, - }, + mountedRoutes, ); expect(queryByTestId('template-card-separator')).toBeInTheDocument(); @@ -272,11 +279,7 @@ describe('TemplateCard', () => { > , - { - mountedRoutes: { - '/catalog/:kind/:namespace/:name': entityRouteRef, - }, - }, + mountedRoutes, ); expect(queryByTestId('template-card-separator')).toBeInTheDocument(); @@ -321,11 +324,7 @@ describe('TemplateCard', () => { > , - { - mountedRoutes: { - '/catalog/:kind/:namespace/:name': entityRouteRef, - }, - }, + mountedRoutes, ); expect(queryByTestId('template-card-separator')).not.toBeInTheDocument(); @@ -364,17 +363,13 @@ describe('TemplateCard', () => { > , - { - mountedRoutes: { - '/catalog/:kind/:namespace/:name': entityRouteRef, - }, - }, + mountedRoutes, ); expect(getByRole('link', { name: /.*my-test-user$/ })).toBeInTheDocument(); expect(getByRole('link', { name: /.*my-test-user$/ })).toHaveAttribute( 'href', - '/catalog/group/default/my-test-user', + '/catalog/default/group/my-test-user', ); }); @@ -404,11 +399,7 @@ describe('TemplateCard', () => { > , - { - mountedRoutes: { - '/catalog/:kind/:namespace/:name': entityRouteRef, - }, - }, + mountedRoutes, ); expect(getByRole('button', { name: 'Choose' })).toBeInTheDocument(); @@ -448,11 +439,7 @@ describe('TemplateCard', () => { , - { - mountedRoutes: { - '/catalog/:kind/:namespace/:name': entityRouteRef, - }, - }, + mountedRoutes, ); expect(queryByText('Choose')).toBeNull(); diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateDetailButton.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateDetailButton.tsx new file mode 100644 index 0000000000..1a352d8967 --- /dev/null +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateDetailButton.tsx @@ -0,0 +1,61 @@ +/* + * Copyright 2025 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 Tooltip from '@material-ui/core/Tooltip'; +import IconButton from '@material-ui/core/IconButton'; +import Typography from '@material-ui/core/Typography'; +import DescriptionIcon from '@material-ui/icons/Description'; +import { Link } from '@backstage/core-components'; +import { + entityRouteParams, + entityRouteRef, +} from '@backstage/plugin-catalog-react'; +import { useRouteRef } from '@backstage/core-plugin-api'; +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; +import { scaffolderReactTranslationRef } from '../../../translation'; +import { useTranslationRef } from '@backstage/frontend-plugin-api'; + +export interface TemplateDetailButtonProps { + template: Entity; +} + +export const TemplateDetailButton = ({ + template, +}: TemplateDetailButtonProps) => { + const catalogEntityRoute = useRouteRef(entityRouteRef); + const { t } = useTranslationRef(scaffolderReactTranslationRef); + const entityRef = stringifyEntityRef(template); + + return ( + + + + + + + + + + ); +}; diff --git a/plugins/scaffolder-react/src/translation.ts b/plugins/scaffolder-react/src/translation.ts index f490b52064..c097d78e3e 100644 --- a/plugins/scaffolder-react/src/translation.ts +++ b/plugins/scaffolder-react/src/translation.ts @@ -44,6 +44,9 @@ export const scaffolderReactTranslationRef = createTranslationRef({ noDescription: 'No description', chooseButtonText: 'Choose', }, + cardHeader: { + detailBtnTitle: 'Show template entity details', + }, templateOutputs: { title: 'Text Output', }, From 609a3a123e8fae38cd45874d1bbda5722d975eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Vit=C3=A1sek?= Date: Tue, 18 Mar 2025 12:28:30 +0100 Subject: [PATCH 16/52] test fix + button system icon as default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ladislav Vitásek --- .../TemplateCard/TemplateDetailButton.tsx | 7 +++++-- .../TemplateListPage.test.tsx | 21 +++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateDetailButton.tsx b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateDetailButton.tsx index 1a352d8967..6ecfc2a1e9 100644 --- a/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateDetailButton.tsx +++ b/plugins/scaffolder-react/src/next/components/TemplateCard/TemplateDetailButton.tsx @@ -23,7 +23,7 @@ import { entityRouteParams, entityRouteRef, } from '@backstage/plugin-catalog-react'; -import { useRouteRef } from '@backstage/core-plugin-api'; +import { useApp, useRouteRef } from '@backstage/core-plugin-api'; import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; import { scaffolderReactTranslationRef } from '../../../translation'; import { useTranslationRef } from '@backstage/frontend-plugin-api'; @@ -39,6 +39,9 @@ export const TemplateDetailButton = ({ const { t } = useTranslationRef(scaffolderReactTranslationRef); const entityRef = stringifyEntityRef(template); + const app = useApp(); + const TemplateIcon = app.getSystemIcon('kind:template') || DescriptionIcon; + return ( - + diff --git a/plugins/scaffolder/src/alpha/components/TemplateListPage/TemplateListPage.test.tsx b/plugins/scaffolder/src/alpha/components/TemplateListPage/TemplateListPage.test.tsx index 01274cf6a6..03175786b1 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateListPage/TemplateListPage.test.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateListPage/TemplateListPage.test.tsx @@ -17,6 +17,7 @@ import { DefaultStarredEntitiesApi } from '@backstage/plugin-catalog'; import { catalogApiRef, + entityRouteRef, starredEntitiesApiRef, } from '@backstage/plugin-catalog-react'; import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; @@ -30,6 +31,13 @@ import React from 'react'; import { rootRouteRef } from '../../../routes'; import { TemplateListPage } from './TemplateListPage'; +const mountedRoutes = { + mountedRoutes: { + '/': rootRouteRef, + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, +}; + describe('TemplateListPage', () => { const mockCatalogApi = catalogApiMock({ entities: [ @@ -60,7 +68,7 @@ describe('TemplateListPage', () => { > , - { mountedRoutes: { '/': rootRouteRef } }, + mountedRoutes, ); expect(getByPlaceholderText('Search')).toBeInTheDocument(); @@ -82,7 +90,7 @@ describe('TemplateListPage', () => { > , - { mountedRoutes: { '/': rootRouteRef } }, + mountedRoutes, ); expect(getByRole('menuitem', { name: /All/ })).toBeInTheDocument(); @@ -105,7 +113,7 @@ describe('TemplateListPage', () => { > , - { mountedRoutes: { '/': rootRouteRef } }, + mountedRoutes, ); expect(getByText('Categories')).toBeInTheDocument(); @@ -127,7 +135,7 @@ describe('TemplateListPage', () => { > , - { mountedRoutes: { '/': rootRouteRef } }, + mountedRoutes, ); expect(getByText('Owner')).toBeInTheDocument(); @@ -150,6 +158,7 @@ describe('TemplateListPage', () => { > , + mountedRoutes, ); expect(getByText('Tags')).toBeInTheDocument(); @@ -172,7 +181,7 @@ describe('TemplateListPage', () => { > , - { mountedRoutes: { '/': rootRouteRef } }, + mountedRoutes, ); expect(queryByTestId('menu-button')).toBeInTheDocument(); }); @@ -199,7 +208,7 @@ describe('TemplateListPage', () => { }} /> , - { mountedRoutes: { '/': rootRouteRef } }, + mountedRoutes, ); expect(queryByTestId('menu-button')).not.toBeInTheDocument(); }); From 5aab8e24e651cbc8505fe7a770c8fc8ccb092ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Vit=C3=A1sek?= Date: Tue, 18 Mar 2025 14:37:34 +0100 Subject: [PATCH 17/52] fix: restore missing translations in scaffolderReactTranslationRef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ladislav Vitásek --- plugins/scaffolder-react/report-alpha.api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md index fbd539f96e..ad9f31480a 100644 --- a/plugins/scaffolder-react/report-alpha.api.md +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -332,10 +332,9 @@ export type ScaffolderReactTemplateCategoryPickerClassKey = 'root' | 'label'; export const scaffolderReactTranslationRef: TranslationRef< 'scaffolder-react', { - readonly 'workflow.noDescription': 'No description'; readonly 'passwordWidget.content': 'This widget is insecure. Please use [`ui:field: Secret`](https://backstage.io/docs/features/software-templates/writing-templates/#using-secrets) instead of `ui:widget: password`'; - readonly 'scaffolderPageContextMenu.createLabel': 'Create'; readonly 'scaffolderPageContextMenu.moreLabel': 'more'; + readonly 'scaffolderPageContextMenu.createLabel': 'Create'; readonly 'scaffolderPageContextMenu.editorLabel': 'Manage Templates'; readonly 'scaffolderPageContextMenu.actionsLabel': 'Installed Actions'; readonly 'scaffolderPageContextMenu.tasksLabel': 'Task List'; @@ -349,6 +348,7 @@ export const scaffolderReactTranslationRef: TranslationRef< readonly 'templateCard.chooseButtonText': 'Choose'; readonly 'cardHeader.detailBtnTitle': 'Show template entity details'; readonly 'templateOutputs.title': 'Text Output'; + readonly 'workflow.noDescription': 'No description'; } >; From 948908f0f74f02c60b8452f89cde1775daa45de7 Mon Sep 17 00:00:00 2001 From: Paul Schultz Date: Tue, 18 Mar 2025 09:59:57 -0500 Subject: [PATCH 18/52] docs: update auditor naming conventions Signed-off-by: Paul Schultz --- docs/backend-system/core-services/auditor.md | 87 +++++++++++++++++--- 1 file changed, 76 insertions(+), 11 deletions(-) diff --git a/docs/backend-system/core-services/auditor.md b/docs/backend-system/core-services/auditor.md index d4cbf70325..53242500ae 100644 --- a/docs/backend-system/core-services/auditor.md +++ b/docs/backend-system/core-services/auditor.md @@ -7,7 +7,7 @@ description: Documentation for the Auditor service ## Overview -This document describes the Auditor Service, a software service designed to record and report on security-relevant events within an application. This service utilizes the `winston` library for logging and provides a flexible way to capture and format audit events. +This document describes the Auditor Service, a core service designed to record and report on security-relevant events within an application. By default, this service utilizes the `rootLogger` core service for logging. ## Key Features @@ -16,15 +16,13 @@ This document describes the Auditor Service, a software service designed to reco - Supports detailed metadata for each event. - Offers success/failure reporting for events. - Integrates with authentication and plugin services for enhanced context. -- Uses `winston` for flexible log formatting and transport. - Provides a service factory for easy integration with Backstage plugins. -- Supports configurable log transports (console, file). ## How it Works -The Auditor Service defines a core class, `Auditor`, which implements the `AuditorService` interface. This class uses `winston` to log audit events with varying levels of severity and associated metadata. It also integrates with authentication and plugin services to capture actor details and plugin context. +The Auditor Service defines a class, `Auditor`, which implements the `AuditorService` interface. This class uses a `logFn` to log audit events with varying levels of severity and associated metadata. It also integrates with authentication and plugin services to capture actor details and plugin context. -The `auditorServiceFactory` creates an `Auditor` instance for the root context and provides a factory function for creating child loggers for individual plugins. This allows each plugin to have its own logger with inherited and additional metadata. +The `auditorServiceFactory` wraps the `rootLogger` core service and provides a factory function for creating child loggers for individual plugins. This allows each plugin to have its own logger with inherited and additional metadata. ## Usage Guidance @@ -78,10 +76,77 @@ In this example, an audit event is created for each request to `/my-endpoint`. T ## Naming Conventions -When defining `eventId` and `subEventId` for your audit events, follow these guidelines: +When defining audit events, follow these guidelines to ensure consistency and clarity: -- Use kebab-case (e.g., `user-login`, `file-download`, `fetch`, `entity-create`, `entity-update`). -- The `eventId` represents a logical group of similar events or operations. For example, "fetch" could be used as an `eventId` encompassing various fetch methods like `by-id` or `by-location`. -- Use `subEventId` to further categorize events within a logical group. For example, if the `eventId` is "fetch", the `subEventId` could be "by-id" or "by-location" to specify the method used for fetching. -- Avoid redundant prefixes related to the plugin ID, as that context is already provided. -- Choose names that clearly and concisely describe the event being audited. +- **Use kebab-case:** Event IDs should be in kebab-case (e.g., `user-session`, `file-download`, `entity-fetch`). +- **`eventId` for Logical Grouping:** The `eventId` represents a broad category or logical group of related operations. For example, `entity-fetch` would group all entity retrieval events. `location-mutate` would group all actions that mutate a location. +- **`meta.queryType` (or related field) for Specific Actions within a Group:** Use a `meta` field (like `queryType`, `actionType` or similar) to specify the particular action or query that occurred within the broader `eventId` group. + - For instance, with `eventId: entity-fetch`, use `meta: { queryType: 'by-id' }` to represent fetching an entity by its ID. Other examples could be: + - `meta: { queryType: 'all' }` for fetching all entities. + - `meta: { queryType: 'by-query' }` for fetching entities by a query. + - `meta: { actionType: 'delete' }` for `eventId: entity-mutate` when an entity was deleted. + - `meta: { actionType: 'create' }` for `eventId: location-mutate` when a location was added. + - Use `meta` fields to add more context to the event being tracked. +- **Avoid Redundant Prefixes:** Do not include redundant prefixes related to the plugin ID in your event names. The plugin context is already provided separately. +- **Clear and Concise:** Choose names that clearly and concisely describe the event being audited. + +## Common Meta Keys and Values + +The following table details common keys found within the `meta` object of audit events and their formats: + +| Key | Description | Format | Example(s) | +| ------------- | ------------------------------------------------------------------------------ | ------------------------------------- | ------------------------------------------------------------------------- | +| `queryType` | Specifies the type of query performed when fetching data. | A kebab-case string | `all`, `by-id`, `by-name`, `by-query`, `by-refs`, `ancestry`, `by-entity` | +| `actionType` | Specifies the type of action performed when modifying data. | A kebab-case string | `create`, `delete`, `refresh` | +| `entityRef` | The full reference of an entity, including kind, namespace, and name. | `[kind]:[namespace]/[name]` | `component:default/my-component`, `group:my-org/team-a` | +| `locationRef` | A specific reference to a location being operated on. | Any string representing the location. | `Url:https://example.com/catalog-info.yaml`, `custom:default/my-location` | +| `uid` | The unique identifier of a location or other object involved in the operation. | Any valid unique ID string | `9a4e740b-e557-427f-b9f2-0d4f092b1c1e` | + +By following these conventions, you create a more structured and informative audit trail that is easier to search, filter, and understand. This allows you to better group and understand the events being logged. + +## Audit Event Examples + +To illustrate how these naming conventions and the meta field are used in practice, the following examples demonstrate typical audit events for common operations. + +**Typical Read Operation Example:** + +For an operation that fetches all entities, a typical audit event would look like this: + +```json +{ + "eventId": "entity-fetch", + "meta": { + "queryType": "all" + } + ... +} +``` + +**Typical Write Operation Example:** + +For an operation that deletes an entity, a typical audit event would look like this: + +```json +{ + "eventId": "entity-mutate", + "meta": { + "actionType": "delete", + "uid": "some-entity-uid" + }, + "severityLevel": "medium" + ... +} +``` + +## Practical Examples for Auditor Implementation + +To clarify how to utilize the Auditor feature effectively, we recommend exploring the Catalog Backend. It offers two valuable resources: + +- **Code Implementation Example (createRouter.ts):** + - The [`createRouter.ts`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/src/service/createRouter.ts) file within the Catalog Backend showcases a practical integration of the `AuditorService` within a Backstage backend plugin. + - Specifically, the lines that demonstrate the creation of an audit event. This includes setting critical parameters such as `eventId` and `severityLevel`, as well as incorporating relevant metadata like `queryType` and `entityRef`. +- **Documentation Example (README.md):** + - The "Audit Events" section of the Catalog Backend's [`README.md`](https://github.com/backstage/backstage/blob/master/plugins/catalog-backend/README.md#audit-events) provides a well-structured example of documenting emitted audit events. + - It illustrates how to detail various `eventId` values and their corresponding `meta` fields (e.g., `queryType`, `actionType`) for different plugin operations. + +These examples provide both a code-level demonstration and a documentation guideline for effectively utilizing the `AuditorService` to manage audit events within your Backstage plugins. From 7f56c442aae6ddd6e947e969b91ac0a09d03d6d7 Mon Sep 17 00:00:00 2001 From: Matt Benson Date: Wed, 12 Mar 2025 00:21:17 -0500 Subject: [PATCH 19/52] improve return types of createTemplateFilter() and createTemplateGlobalFunction(); accommodate in ScaffolderTemplatingExtensionPoint Signed-off-by: Matt Benson --- plugins/scaffolder-node/report-alpha.api.md | 12 +++++++----- .../src/alpha/filters/createTemplateFilter.ts | 6 +++--- .../src/alpha/globals/createTemplateGlobal.ts | 2 +- plugins/scaffolder-node/src/alpha/index.ts | 4 +++- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/plugins/scaffolder-node/report-alpha.api.md b/plugins/scaffolder-node/report-alpha.api.md index fa9e022bb4..151af9ea37 100644 --- a/plugins/scaffolder-node/report-alpha.api.md +++ b/plugins/scaffolder-node/report-alpha.api.md @@ -91,12 +91,12 @@ export type CreatedTemplateGlobalValue = { // @alpha export const createTemplateFilter: < TSchema extends TemplateFilterSchema | undefined, - TFunctionSchema extends TSchema extends TemplateFilterSchema + TFilterSchema extends TSchema extends TemplateFilterSchema ? z.infer> : (arg: JsonValue, ...rest: JsonValue[]) => JsonValue | undefined, >( - filter: CreatedTemplateFilter, -) => CreatedTemplateFilter; + filter: CreatedTemplateFilter, +) => CreatedTemplateFilter; // @alpha export const createTemplateGlobalFunction: < @@ -106,7 +106,7 @@ export const createTemplateGlobalFunction: < : (...args: JsonValue[]) => JsonValue | undefined, >( fn: CreatedTemplateGlobalFunction, -) => CreatedTemplateGlobalFunction; +) => CreatedTemplateGlobalFunction; // @alpha export const createTemplateGlobalValue: ( @@ -156,7 +156,9 @@ export const scaffolderTaskBrokerExtensionPoint: ExtensionPoint | CreatedTemplateFilter[], + filters: + | Record + | CreatedTemplateFilter[], ): void; // (undocumented) addTemplateGlobals( diff --git a/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts b/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts index 1f4bac4ab7..219884b704 100644 --- a/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts +++ b/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts @@ -24,9 +24,9 @@ import { z } from 'zod'; */ export const createTemplateFilter = < TSchema extends TemplateFilterSchema | undefined, - TFunctionSchema extends TSchema extends TemplateFilterSchema + TFilterSchema extends TSchema extends TemplateFilterSchema ? z.infer> : (arg: JsonValue, ...rest: JsonValue[]) => JsonValue | undefined, >( - filter: CreatedTemplateFilter, -): CreatedTemplateFilter => filter; + filter: CreatedTemplateFilter, +): CreatedTemplateFilter => filter; diff --git a/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts b/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts index 1f9e090d7f..2361a50964 100644 --- a/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts +++ b/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts @@ -45,4 +45,4 @@ export const createTemplateGlobalFunction = < : (...args: JsonValue[]) => JsonValue | undefined, >( fn: CreatedTemplateGlobalFunction, -): CreatedTemplateGlobalFunction => fn; +): CreatedTemplateGlobalFunction => fn; diff --git a/plugins/scaffolder-node/src/alpha/index.ts b/plugins/scaffolder-node/src/alpha/index.ts index d97aa54557..1fd5abee18 100644 --- a/plugins/scaffolder-node/src/alpha/index.ts +++ b/plugins/scaffolder-node/src/alpha/index.ts @@ -73,7 +73,9 @@ export const scaffolderTaskBrokerExtensionPoint = */ export interface ScaffolderTemplatingExtensionPoint { addTemplateFilters( - filters: Record | CreatedTemplateFilter[], + filters: + | Record + | CreatedTemplateFilter[], ): void; addTemplateGlobals( From 497d47aafa53a6c4de2aee24d9281785471329a6 Mon Sep 17 00:00:00 2001 From: Matt Benson Date: Fri, 7 Feb 2025 14:16:51 -0600 Subject: [PATCH 20/52] document built-in template filters Signed-off-by: Matt Benson --- .changeset/odd-bobcats-hang.md | 5 ++ .../src/lib/templating/filters.ts | 40 ------------ .../src/lib/templating/filters/index.ts | 29 +++++++++ .../filters/parseEntityRef/examples.ts | 48 +++++++++++++++ .../filters/parseEntityRef/index.ts | 61 +++++++++++++++++++ .../filters/parseRepoUrl/examples.ts | 31 ++++++++++ .../templating/filters/parseRepoUrl/index.ts | 50 +++++++++++++++ .../lib/templating/filters/pick/examples.ts | 31 ++++++++++ .../src/lib/templating/filters/pick/index.ts | 31 ++++++++++ .../filters/projectSlug/examples.ts | 32 ++++++++++ .../templating/filters/projectSlug/index.ts | 37 +++++++++++ .../actions/builtin/fetch/template.ts | 2 +- .../actions/builtin/fetch/templateFile.ts | 2 +- .../tasks/NunjucksWorkflowRunner.ts | 2 +- .../src/util/templating.test.ts | 4 +- 15 files changed, 360 insertions(+), 45 deletions(-) create mode 100644 .changeset/odd-bobcats-hang.md delete mode 100644 plugins/scaffolder-backend/src/lib/templating/filters.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/index.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/examples.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/pick/examples.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/examples.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts diff --git a/.changeset/odd-bobcats-hang.md b/.changeset/odd-bobcats-hang.md new file mode 100644 index 0000000000..a7c0d59754 --- /dev/null +++ b/.changeset/odd-bobcats-hang.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +document built-in template filters diff --git a/plugins/scaffolder-backend/src/lib/templating/filters.ts b/plugins/scaffolder-backend/src/lib/templating/filters.ts deleted file mode 100644 index bc3f95b18c..0000000000 --- a/plugins/scaffolder-backend/src/lib/templating/filters.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 { parseEntityRef } from '@backstage/catalog-model'; -import { ScmIntegrations } from '@backstage/integration'; -import type { JsonObject, JsonValue } from '@backstage/types'; -import { - parseRepoUrl, - TemplateFilter, -} from '@backstage/plugin-scaffolder-node'; -import get from 'lodash/get'; - -export default ({ - integrations, -}: { - integrations: ScmIntegrations; -}): Record => { - return { - parseRepoUrl: url => parseRepoUrl(url as string, integrations), - parseEntityRef: (ref: JsonValue, context?: JsonValue) => - parseEntityRef(ref as string, context as JsonObject), - pick: (obj: JsonValue, key: JsonValue) => get(obj, key as string), - projectSlug: repoUrl => { - const { owner, repo } = parseRepoUrl(repoUrl as string, integrations); - return `${owner}/${repo}`; - }, - }; -}; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/index.ts new file mode 100644 index 0000000000..5eb4de5ac3 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2025 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 { ScmIntegrations } from '@backstage/integration'; +import { createParseRepoUrl } from './parseRepoUrl'; +import { parseEntityRef } from './parseEntityRef'; +import { pick } from './pick'; +import { createProjectSlug } from './projectSlug'; + +export const createDefaultFilters = (options: { + integrations: ScmIntegrations; +}) => [ + createParseRepoUrl(options.integrations), + parseEntityRef, + pick, + createProjectSlug(options.integrations), +]; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts new file mode 100644 index 0000000000..fd6219c998 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts @@ -0,0 +1,48 @@ +import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; + +/* + * Copyright 2025 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 examples: TemplateFilterExample[] = [ + { + description: 'Without context', + example: `\ +- id: log + name: Parse Entity Reference + action: debug:log + input: + message: \${{ parameters.owner | parseEntityRef }} +`, + notes: `\ +- **Input**: \`group:techdocs\` +- **Output**: \`{"kind": "group", "namespace": "default", "name": "techdocs"}\` +`, + }, + { + description: 'With context', + example: `\ +- id: log + name: Parse Entity Reference + action: debug:log + input: + message: \${{ parameters.owner | parseEntityRef({ defaultKind:"group", defaultNamespace:"another-namespace" }) }} +`, + notes: `\ +- **Input**: \`techdocs\` +- **Arguments:**: \`[{ "defaultKind": "group", "defaultNamespace": "another-namespace" }]\` +- **Output**: \`{"kind": "group", "namespace": "another-namespace", "name": "techdocs"}\` +`, + }, +]; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts new file mode 100644 index 0000000000..221be44055 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts @@ -0,0 +1,61 @@ +/* + * Copyright 2025 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 { parseEntityRef as filter } from '@backstage/catalog-model'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const parseEntityRef = createTemplateFilter({ + id: 'parseEntityRef', + description: + 'Extracts the parts of an entity reference, such as the kind, namespace, and name.', + schema: z => + z.function( + z.tuple([ + z.union([ + z.string().describe('compact entity reference'), + z + .object({ + kind: z.string().optional(), + namespace: z.string().optional(), + name: z.string(), + }) + .describe('`CompoundEntityRef`'), + ]), + z + .object({ + defaultKind: z + .string() + .describe('The default kind, if none is given in the reference'), + defaultNamespace: z + .string() + .describe( + 'The default namespace, if none is given in the reference', + ), + }) + .partial() + .optional(), + ]), + z + .object({ + kind: z.string(), + namespace: z.string(), + name: z.string(), + }) + .describe('`CompoundEntityRef`'), + ), + examples, + filter, +}); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/examples.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/examples.ts new file mode 100644 index 0000000000..4348305737 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/examples.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 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 { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; + +export const examples: TemplateFilterExample[] = [ + { + example: `\ +- id: log + name: Parse Repo URL + action: debug:log + input: + message: \${{ parameters.repoUrl | parseRepoUrl }}`, + notes: ` - **Input**: \`github.com?repo=backstage&owner=backstage\` + - **Output**: \`{"host":"github.com","owner":"backstage","repo":"backstage"}\` +`, + }, +]; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts new file mode 100644 index 0000000000..a726c140cf --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2025 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 { ScmIntegrations } from '@backstage/integration'; +import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const createParseRepoUrl = (integrations: ScmIntegrations) => + createTemplateFilter({ + id: 'parseRepoUrl', + description: + 'Parses a repository URL into its constituent parts: owner, repository name, etc.', + schema: z => + z.function( + z.tuple([ + z.string().describe('repo URL as collected from repository picker'), + ]), + z + .object({ + repo: z.string(), + host: z.string(), + }) + .merge( + z + .object({ + owner: z.string(), + organization: z.string(), + workspace: z.string(), + project: z.string(), + }) + .partial(), + ) + .describe('`RepoSpec`'), + ), + examples, + filter: (url: string) => parseRepoUrl(url, integrations), + }); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/pick/examples.ts b/plugins/scaffolder-backend/src/lib/templating/filters/pick/examples.ts new file mode 100644 index 0000000000..28593847ef --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/pick/examples.ts @@ -0,0 +1,31 @@ +import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; + +/* + * Copyright 2025 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 examples: TemplateFilterExample[] = [ + { + example: `\ +- id: log + name: Pick + action: debug:log + input: + message: \${{ parameters.owner | parseEntityRef | pick('name') }}`, + notes: `\ +- **Input**: \`{ kind: 'Group', namespace: 'default', name: 'techdocs'\` } +- **Output**: \`techdocs\` +`, + }, +]; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts new file mode 100644 index 0000000000..5d8a0d664a --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 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 { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { get as filter } from 'lodash'; +import { examples } from './examples'; + +export const pick = createTemplateFilter({ + id: 'pick', + description: + 'Selects a specific property (e.g. kind, namespace, name) from an object.', + schema: z => + z.function( + z.tuple([z.any(), z.string().describe('Property')]), + z.any().describe('Selected property'), + ), + examples, + filter, +}); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/examples.ts b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/examples.ts new file mode 100644 index 0000000000..dde36ea888 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/examples.ts @@ -0,0 +1,32 @@ +import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; + +/* + * Copyright 2025 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 examples: TemplateFilterExample[] = [ + { + example: `\ +- id: log + name: Project Slug + action: debug:log + input: + message: \${{ parameters.repoUrl | projectSlug }} +`, + notes: `\ +- **Input**: \`github.com?repo=backstage&owner=backstage\` +- **Output**: backstage/backstage +`, + }, +]; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts new file mode 100644 index 0000000000..a833121423 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2025 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 { ScmIntegrations } from '@backstage/integration'; +import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const createProjectSlug = (integrations: ScmIntegrations) => + createTemplateFilter({ + id: 'projectSlug', + description: 'Generates a project slug from a repository URL.', + schema: z => + z.function( + z.tuple([ + z.string().describe('repo URL as collected from repository picker'), + ]), + z.string(), + ), + examples, + filter: (repoUrl: string) => { + const { owner, repo } = parseRepoUrl(repoUrl, integrations); + return `${owner}/${repo}`; + }, + }); diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts index 543c25ab3e..2e036abc19 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts @@ -29,7 +29,7 @@ import globby from 'globby'; import fs from 'fs-extra'; import { isBinaryFile } from 'isbinaryfile'; import { SecureTemplater } from '../../../../lib/templating/SecureTemplater'; -import createDefaultFilters from '../../../../lib/templating/filters'; +import { createDefaultFilters } from '../../../../lib/templating/filters'; import { examples } from './template.examples'; import { convertFiltersToRecord } from '../../../../util/templating'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts index f3b98d148a..9353f5e8d2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts @@ -25,7 +25,7 @@ import { TemplateGlobal, } from '@backstage/plugin-scaffolder-node'; import { SecureTemplater } from '../../../../lib/templating/SecureTemplater'; -import createDefaultFilters from '../../../../lib/templating/filters'; +import { createDefaultFilters } from '../../../../lib/templating/filters'; import path from 'path'; import fs from 'fs-extra'; import { convertFiltersToRecord } from '../../../../util/templating'; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index b771c5ded1..e918511354 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -55,7 +55,7 @@ import { TemplateFilter, TemplateGlobal, } from '@backstage/plugin-scaffolder-node'; -import createDefaultFilters from '../../lib/templating/filters'; +import { createDefaultFilters } from '../../lib/templating/filters'; import { scaffolderActionRules } from '../../service/rules'; import { createCounterMetric, createHistogramMetric } from '../../util/metrics'; import { BackstageLoggerTransport, WinstonLogger } from './logger'; diff --git a/plugins/scaffolder-backend/src/util/templating.test.ts b/plugins/scaffolder-backend/src/util/templating.test.ts index 5ac6db601b..51493f08a1 100644 --- a/plugins/scaffolder-backend/src/util/templating.test.ts +++ b/plugins/scaffolder-backend/src/util/templating.test.ts @@ -28,14 +28,14 @@ import { extractGlobalValueMetadata, } from './templating'; import { JsonValue } from '@backstage/types'; -import builtInFilters from '../lib/templating/filters'; +import { createDefaultFilters } from '../lib/templating/filters'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; describe('templating utilities', () => { describe('built-in filters', () => { const integrations = ScmIntegrations.fromConfig(new ConfigReader({})); - const filters = builtInFilters({ integrations }); + const filters = createDefaultFilters({ integrations }); it('generates equivalent filter metadata', () => { const metadata = extractFilterMetadata(filters); expect(metadata).toMatchObject(extractFilterMetadata(filters)); From 180ea6eae4e8942189d8f555af30c33345ec0e4f Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 18 Mar 2025 20:20:43 +0100 Subject: [PATCH 21/52] Made "github:branch-protection:create" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/spotty-towns-show.md | 5 ++ .../src/actions/githubBranchProtection.ts | 53 +++++++++++-------- 2 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 .changeset/spotty-towns-show.md diff --git a/.changeset/spotty-towns-show.md b/.changeset/spotty-towns-show.md new file mode 100644 index 0000000000..8ec69f3f5e --- /dev/null +++ b/.changeset/spotty-towns-show.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Made "github:branch-protection:create" action idempotent diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts index 6de447541b..ae8965ef9a 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts @@ -130,29 +130,40 @@ export function createGithubBranchProtectionAction(options: { }); const client = new Octokit(octokitOptions); - const repository = await client.rest.repos.get({ - owner: owner, - repo: repo, + const defaultBranch = await ctx.checkpoint({ + key: `read.default.branch.${owner}.${repo}`, + fn: async () => { + const repository = await client.rest.repos.get({ + owner: owner, + repo: repo, + }); + return repository.data.default_branch; + }, }); - await enableBranchProtectionOnDefaultRepoBranch({ - repoName: repo, - client, - owner, - logger: ctx.logger, - requireCodeOwnerReviews, - bypassPullRequestAllowances, - requiredApprovingReviewCount, - restrictions, - requiredStatusCheckContexts, - requireBranchesToBeUpToDate, - requiredConversationResolution, - requireLastPushApproval, - defaultBranch: branch ?? repository.data.default_branch, - enforceAdmins, - dismissStaleReviews, - requiredCommitSigning, - requiredLinearHistory, + await ctx.checkpoint({ + key: `enable.branch.protection.${owner}.${repo}`, + fn: async () => { + await enableBranchProtectionOnDefaultRepoBranch({ + repoName: repo, + client, + owner, + logger: ctx.logger, + requireCodeOwnerReviews, + bypassPullRequestAllowances, + requiredApprovingReviewCount, + restrictions, + requiredStatusCheckContexts, + requireBranchesToBeUpToDate, + requiredConversationResolution, + requireLastPushApproval, + defaultBranch: branch ?? defaultBranch, + enforceAdmins, + dismissStaleReviews, + requiredCommitSigning, + requiredLinearHistory, + }); + }, }); }, }); From 1af427ab0b2cc0ca50c738df9fcd04c9ff0029f2 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 18 Mar 2025 20:24:23 +0100 Subject: [PATCH 22/52] Made "github:autolinks:create" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/metal-animals-notice.md | 5 +++++ .../src/actions/githubAutolinks.ts | 21 ++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 .changeset/metal-animals-notice.md diff --git a/.changeset/metal-animals-notice.md b/.changeset/metal-animals-notice.md new file mode 100644 index 0000000000..c1a844ddb0 --- /dev/null +++ b/.changeset/metal-animals-notice.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Made "github:autolinks:create" action idempotent diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts index 85c7f5da6f..396d85708f 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts @@ -108,15 +108,20 @@ export function createGithubAutolinksAction(options: { }), ); - await client.rest.repos.createAutolink({ - owner, - repo, - key_prefix: keyPrefix, - url_template: urlTemplate, - is_alphanumeric: isAlphanumeric, - }); + await ctx.checkpoint({ + key: `create.auto.link.${owner}.${repo}`, + fn: async () => { + await client.rest.repos.createAutolink({ + owner, + repo, + key_prefix: keyPrefix, + url_template: urlTemplate, + is_alphanumeric: isAlphanumeric, + }); - ctx.logger.info(`Autolink reference created successfully`); + ctx.logger.info(`Autolink reference created successfully`); + }, + }); }, }); } From a833f0f46d894340edefa0f2d47361d9cdc4e932 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 18 Mar 2025 20:26:33 +0100 Subject: [PATCH 23/52] Made "github:actions:dispatch" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/twenty-walls-join.md | 5 +++++ .../src/actions/githubActionsDispatch.ts | 21 ++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 .changeset/twenty-walls-join.md diff --git a/.changeset/twenty-walls-join.md b/.changeset/twenty-walls-join.md new file mode 100644 index 0000000000..2282e28775 --- /dev/null +++ b/.changeset/twenty-walls-join.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Made "github:actions:dispatch" action idempotent diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts index 8e185a9567..4faa53e6b8 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts @@ -115,15 +115,20 @@ export function createGithubActionsDispatchAction(options: { }), ); - await client.rest.actions.createWorkflowDispatch({ - owner, - repo, - workflow_id: workflowId, - ref: branchOrTagName, - inputs: workflowInputs, - }); + await ctx.checkpoint({ + key: `create.workflow.dispatch.${owner}.${repo}.${workflowId}`, + fn: async () => { + await client.rest.actions.createWorkflowDispatch({ + owner, + repo, + workflow_id: workflowId, + ref: branchOrTagName, + inputs: workflowInputs, + }); - ctx.logger.info(`Workflow ${workflowId} dispatched successfully`); + ctx.logger.info(`Workflow ${workflowId} dispatched successfully`); + }, + }); }, }); } From 0be1a1eeace9cac4f90510df990b1133f4d405c2 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 18 Mar 2025 20:31:03 +0100 Subject: [PATCH 24/52] Made "publish:github" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/swift-boats-add.md | 5 ++ .../src/actions/github.ts | 65 ++++++++++--------- 2 files changed, 41 insertions(+), 29 deletions(-) create mode 100644 .changeset/swift-boats-add.md diff --git a/.changeset/swift-boats-add.md b/.changeset/swift-boats-add.md new file mode 100644 index 0000000000..42682437b0 --- /dev/null +++ b/.changeset/swift-boats-add.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Made "publish:github" action idempotent diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.ts b/plugins/scaffolder-backend-module-github/src/actions/github.ts index 6c47a2dade..02b1fbbe32 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.ts @@ -241,36 +241,43 @@ export function createPublishGithubAction(options: { }); const client = new Octokit(octokitOptions); - const newRepo = await createGithubRepoWithCollaboratorsAndTopics( - client, - repo, - owner, - repoVisibility, - description, - homepage, - deleteBranchOnMerge, - allowMergeCommit, - allowSquashMerge, - squashMergeCommitTitle, - squashMergeCommitMessage, - allowRebaseMerge, - allowAutoMerge, - access, - collaborators, - hasProjects, - hasWiki, - hasIssues, - topics, - repoVariables, - secrets, - oidcCustomization, - customProperties, - subscribe, - ctx.logger, - ); + const { remoteUrl, repoContentsUrl } = await ctx.checkpoint({ + key: `create.github.repo.${owner}.${repo}`, + fn: async () => { + const newRepo = await createGithubRepoWithCollaboratorsAndTopics( + client, + repo, + owner, + repoVisibility, + description, + homepage, + deleteBranchOnMerge, + allowMergeCommit, + allowSquashMerge, + squashMergeCommitTitle, + squashMergeCommitMessage, + allowRebaseMerge, + allowAutoMerge, + access, + collaborators, + hasProjects, + hasWiki, + hasIssues, + topics, + repoVariables, + secrets, + oidcCustomization, + customProperties, + subscribe, + ctx.logger, + ); - const remoteUrl = newRepo.clone_url; - const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`; + return { + remoteUrl: newRepo.clone_url, + repoContentsUrl: `${newRepo.html_url}/blob/${defaultBranch}`, + }; + }, + }); const commitResult = await initRepoPushAndProtect( remoteUrl, From 2bd41ceac2a56e59e9ceb2111463086330d088c5 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 18 Mar 2025 20:36:31 +0100 Subject: [PATCH 25/52] Made "publish:azure" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/giant-donkeys-punch.md | 5 + .../src/actions/azure.ts | 96 ++++++++++++------- 2 files changed, 64 insertions(+), 37 deletions(-) create mode 100644 .changeset/giant-donkeys-punch.md diff --git a/.changeset/giant-donkeys-punch.md b/.changeset/giant-donkeys-punch.md new file mode 100644 index 0000000000..522055832a --- /dev/null +++ b/.changeset/giant-donkeys-punch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-azure': patch +--- + +Made "publish:azure" action idempotent diff --git a/plugins/scaffolder-backend-module-azure/src/actions/azure.ts b/plugins/scaffolder-backend-module-azure/src/actions/azure.ts index acb4754520..8c1f5afec8 100644 --- a/plugins/scaffolder-backend-module-azure/src/actions/azure.ts +++ b/plugins/scaffolder-backend-module-azure/src/actions/azure.ts @@ -174,37 +174,49 @@ export function createPublishAzureAction(options: { const webApi = new WebApi(url, authHandler); const client = await webApi.getGitApi(); const createOptions: GitRepositoryCreateOptions = { name: repo }; - const returnedRepo = await client.createRepository( - createOptions, - project, - ); - if (!returnedRepo) { - throw new InputError( - `Unable to create the repository with Organization ${organization}, Project ${project} and Repo ${repo}. + const { remoteUrl, repositoryId, repoContentsUrl } = await ctx.checkpoint( + { + key: `create.repo.${repo}`, + fn: async () => { + const returnedRepo = await client.createRepository( + createOptions, + project, + ); + + if (!returnedRepo) { + throw new InputError( + `Unable to create the repository with Organization ${organization}, Project ${project} and Repo ${repo}. Please make sure that both the Org and Project are typed corrected and exist.`, - ); - } - const remoteUrl = returnedRepo.remoteUrl; + ); + } - if (!remoteUrl) { - throw new InputError( - 'No remote URL returned from create repository for Azure', - ); - } - const repositoryId = returnedRepo.id; + if (!returnedRepo.remoteUrl) { + throw new InputError( + 'No remote URL returned from create repository for Azure', + ); + } - if (!repositoryId) { - throw new InputError('No Id returned from create repository for Azure'); - } + if (!returnedRepo.id) { + throw new InputError( + 'No Id returned from create repository for Azure', + ); + } - const repoContentsUrl = returnedRepo.webUrl; + if (!returnedRepo.webUrl) { + throw new InputError( + 'No web URL returned from create repository for Azure', + ); + } - if (!repoContentsUrl) { - throw new InputError( - 'No web URL returned from create repository for Azure', - ); - } + return { + remoteUrl: returnedRepo.remoteUrl, + repositoryId: returnedRepo.id, + repoContentsUrl: returnedRepo.webUrl, + }; + }, + }, + ); const gitAuthorInfo = { name: gitAuthorName @@ -229,20 +241,30 @@ export function createPublishAzureAction(options: { ); } - const commitResult = await initRepoAndPush({ - dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath), - remoteUrl, - defaultBranch, - auth: auth, - logger: ctx.logger, - commitMessage: gitCommitMessage - ? gitCommitMessage - : config.getOptionalString('scaffolder.defaultCommitMessage'), - gitAuthorInfo, - signingKey: signCommit ? signingKey : undefined, + const commitHash = await ctx.checkpoint({ + key: `init.repo.and.push.${remoteUrl}`, + fn: async () => { + const commitResult = await initRepoAndPush({ + dir: getRepoSourceDirectory( + ctx.workspacePath, + ctx.input.sourcePath, + ), + remoteUrl, + defaultBranch, + auth: auth, + logger: ctx.logger, + commitMessage: gitCommitMessage + ? gitCommitMessage + : config.getOptionalString('scaffolder.defaultCommitMessage'), + gitAuthorInfo, + signingKey: signCommit ? signingKey : undefined, + }); + + return commitResult?.commitHash; + }, }); - ctx.output('commitHash', commitResult?.commitHash); + ctx.output('commitHash', commitHash); ctx.output('remoteUrl', remoteUrl); ctx.output('repoContentsUrl', repoContentsUrl); ctx.output('repositoryId', repositoryId); From adfceee583ffcf46f01f0e1fe61db351d4f8ae07 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 18 Mar 2025 20:45:21 +0100 Subject: [PATCH 26/52] Made "publish:bitbucket" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/itchy-times-behave.md | 5 ++ .../src/actions/bitbucket.ts | 55 ++++++++++++------- 2 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 .changeset/itchy-times-behave.md diff --git a/.changeset/itchy-times-behave.md b/.changeset/itchy-times-behave.md new file mode 100644 index 0000000000..dc883487b0 --- /dev/null +++ b/.changeset/itchy-times-behave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-bitbucket': patch +--- + +Made "publish:bitbucket" action idempotent diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts index e52eb50976..e2978470bd 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts @@ -368,15 +368,19 @@ export function createPublishBitbucketAction(options: { ? createBitbucketCloudRepository : createBitbucketServerRepository; - const { remoteUrl, repoContentsUrl } = await createMethod({ - authorization, - workspace: workspace || '', - project, - repo, - repoVisibility, - mainBranch: defaultBranch, - description, - apiBaseUrl, + const { remoteUrl, repoContentsUrl } = await ctx.checkpoint({ + key: `create.repo.${host}.${repo}`, + fn: async () => + createMethod({ + authorization, + workspace: workspace || '', + project, + repo, + repoVisibility, + mainBranch: defaultBranch, + description, + apiBaseUrl, + }), }); const gitAuthorInfo = { @@ -414,24 +418,33 @@ export function createPublishBitbucketAction(options: { }; } - const commitResult = await initRepoAndPush({ - dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath), - remoteUrl, - auth, - defaultBranch, - logger: ctx.logger, - commitMessage: gitCommitMessage - ? gitCommitMessage - : config.getOptionalString('scaffolder.defaultCommitMessage'), - gitAuthorInfo, - signingKey: signCommit ? signingKey : undefined, + const commitHash = await ctx.checkpoint({ + key: `init.repo.and.push${host}.${repo}`, + fn: async () => { + const commitResult = await initRepoAndPush({ + dir: getRepoSourceDirectory( + ctx.workspacePath, + ctx.input.sourcePath, + ), + remoteUrl, + auth, + defaultBranch, + logger: ctx.logger, + commitMessage: gitCommitMessage + ? gitCommitMessage + : config.getOptionalString('scaffolder.defaultCommitMessage'), + gitAuthorInfo, + signingKey: signCommit ? signingKey : undefined, + }); + return commitResult?.commitHash; + }, }); if (enableLFS && host !== 'bitbucket.org') { await performEnableLFS({ authorization, host, project, repo }); } - ctx.output('commitHash', commitResult?.commitHash); + ctx.output('commitHash', commitHash); ctx.output('remoteUrl', remoteUrl); ctx.output('repoContentsUrl', repoContentsUrl); }, From 5266f1cef391457c7fc7a227dff7e307fe59fa2b Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 18 Mar 2025 20:50:21 +0100 Subject: [PATCH 27/52] Made "publish:bitbucketCloud" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/silver-rocks-invite.md | 5 ++ .../src/actions/bitbucketCloud.ts | 55 ++++++++++++------- 2 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 .changeset/silver-rocks-invite.md diff --git a/.changeset/silver-rocks-invite.md b/.changeset/silver-rocks-invite.md new file mode 100644 index 0000000000..3a08bc72af --- /dev/null +++ b/.changeset/silver-rocks-invite.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch +--- + +Made "publish:bitbucketCloud" action idempotent diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts index 945aab1216..ff61213e1a 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts @@ -224,15 +224,19 @@ export function createPublishBitbucketCloudAction(options: { const apiBaseUrl = integrationConfig.config.apiBaseUrl; - const { remoteUrl, repoContentsUrl } = await createRepository({ - authorization, - workspace: workspace || '', - project, - repo, - repoVisibility, - mainBranch: defaultBranch, - description, - apiBaseUrl, + const { remoteUrl, repoContentsUrl } = await ctx.checkpoint({ + key: `create.repo.${host}.${repo}`, + fn: async () => + await createRepository({ + authorization, + workspace: workspace || '', + project, + repo, + repoVisibility, + mainBranch: defaultBranch, + description, + apiBaseUrl, + }), }); const gitAuthorInfo = { @@ -272,20 +276,29 @@ export function createPublishBitbucketCloudAction(options: { ); } - const commitResult = await initRepoAndPush({ - dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath), - remoteUrl, - auth, - defaultBranch, - logger: ctx.logger, - commitMessage: - gitCommitMessage || - config.getOptionalString('scaffolder.defaultCommitMessage'), - gitAuthorInfo, - signingKey: signCommit ? signingKey : undefined, + const commitHash = await ctx.checkpoint({ + key: `init.repo.and.push${host}.${repo}`, + fn: async () => { + const commitResult = await initRepoAndPush({ + dir: getRepoSourceDirectory( + ctx.workspacePath, + ctx.input.sourcePath, + ), + remoteUrl, + auth, + defaultBranch, + logger: ctx.logger, + commitMessage: + gitCommitMessage || + config.getOptionalString('scaffolder.defaultCommitMessage'), + gitAuthorInfo, + signingKey: signCommit ? signingKey : undefined, + }); + return commitResult?.commitHash; + }, }); - ctx.output('commitHash', commitResult?.commitHash); + ctx.output('commitHash', commitHash); ctx.output('remoteUrl', remoteUrl); ctx.output('repoContentsUrl', repoContentsUrl); }, From 25a76750a7dc0f6892bc43ced5a609e766ca6281 Mon Sep 17 00:00:00 2001 From: Bogdan Nechyporenko Date: Tue, 18 Mar 2025 20:55:31 +0100 Subject: [PATCH 28/52] Made "notification:send" action idempotent Signed-off-by: Bogdan Nechyporenko --- .changeset/tame-sloths-brake.md | 5 +++++ .../src/actions/sendNotification.ts | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 .changeset/tame-sloths-brake.md diff --git a/.changeset/tame-sloths-brake.md b/.changeset/tame-sloths-brake.md new file mode 100644 index 0000000000..eae1321175 --- /dev/null +++ b/.changeset/tame-sloths-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-notifications': patch +--- + +Made "notification:send" action idempotent diff --git a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts index 9646de0001..d1954dfd8c 100644 --- a/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts +++ b/plugins/scaffolder-backend-module-notifications/src/actions/sendNotification.ts @@ -133,9 +133,14 @@ export function createSendNotificationAction(options: { }; try { - await notifications.send({ - recipients: notificationRecipients, - payload, + await ctx.checkpoint({ + key: `send.notification.${payload.title}`, + fn: async () => { + await notifications.send({ + recipients: notificationRecipients, + payload, + }); + }, }); } catch (e) { ctx.logger.error(`Failed to send notification: ${e}`); From 99e95a6c3870bd251d36d5ecf78450666fb07fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Vit=C3=A1sek?= Date: Wed, 19 Mar 2025 08:32:12 +0100 Subject: [PATCH 29/52] new generated file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ladislav Vitásek --- plugins/scaffolder-react/report-alpha.api.md | 524 ----------------- plugins/scaffolder-react/report.api.md | 567 ------------------- 2 files changed, 1091 deletions(-) delete mode 100644 plugins/scaffolder-react/report-alpha.api.md delete mode 100644 plugins/scaffolder-react/report.api.md diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md deleted file mode 100644 index ad9f31480a..0000000000 --- a/plugins/scaffolder-react/report-alpha.api.md +++ /dev/null @@ -1,524 +0,0 @@ -## API Report File for "@backstage/plugin-scaffolder-react" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { AnyApiFactory } from '@backstage/frontend-plugin-api'; -import { AnyApiRef } from '@backstage/core-plugin-api'; -import { ApiHolder } from '@backstage/core-plugin-api'; -import { ApiRef } from '@backstage/frontend-plugin-api'; -import { ComponentType } from 'react'; -import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; -import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react'; -import { Dispatch } from 'react'; -import { ExtensionBlueprint } from '@backstage/frontend-plugin-api'; -import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; -import { ExtensionInput } from '@backstage/frontend-plugin-api'; -import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react'; -import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; -import { FieldSchema } from '@backstage/plugin-scaffolder-react'; -import { FieldValidation } from '@rjsf/utils'; -import { FormField } from '@internal/scaffolder'; -import { FormProps } from '@backstage/plugin-scaffolder-react'; -import { IconComponent } from '@backstage/core-plugin-api'; -import { JsonObject } from '@backstage/types'; -import { JsonValue } from '@backstage/types'; -import { LayoutOptions } from '@backstage/plugin-scaffolder-react'; -import { Overrides } from '@material-ui/core/styles/overrides'; -import { PropsWithChildren } from 'react'; -import { default as React_2 } from 'react'; -import { ReactElement } from 'react'; -import { ReactNode } from 'react'; -import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderRJSFFormProps } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderStep } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react'; -import { SetStateAction } from 'react'; -import { StyleRules } from '@material-ui/core/styles/withStyles'; -import { TaskStep } from '@backstage/plugin-scaffolder-common'; -import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; -import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; -import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { TranslationRef } from '@backstage/core-plugin-api/alpha'; -import { UiSchema } from '@rjsf/utils'; -import { WidgetProps } from '@rjsf/utils'; -import { z } from 'zod'; - -// @alpha (undocumented) -export type BackstageOverrides = Overrides & { - [Name in keyof ScaffolderReactComponentsNameToClassKey]?: Partial< - StyleRules - >; -}; - -// @alpha (undocumented) -export type BackstageTemplateStepperClassKey = - | 'backButton' - | 'footer' - | 'formWrapper'; - -// @alpha (undocumented) -export const createAsyncValidators: ( - rootSchema: JsonObject, - validators: Record< - string, - undefined | CustomFieldValidator - >, - context: { - apiHolder: ApiHolder; - }, -) => (formData: JsonObject) => Promise; - -// @alpha -export const createFieldValidation: () => FieldValidation; - -// @alpha -export function createFormField< - TReturnValue extends z.ZodType, - TUiOptions extends z.ZodType, ->(opts: FormFieldExtensionData): FormField; - -// @alpha -export function createScaffolderFormDecorator< - TInputSchema extends { - [key in string]: (zImpl: typeof z) => z.ZodType; - } = { - [key in string]: (zImpl: typeof z) => z.ZodType; - }, - TDeps extends { - [key in string]: AnyApiRef; - } = { - [key in string]: AnyApiRef; - }, - TInput extends JsonObject = { - [key in keyof TInputSchema]: z.infer>; - }, ->(options: { - id: string; - schema?: { - input?: TInputSchema; - }; - deps?: TDeps; - decorator: ( - ctx: ScaffolderFormDecoratorContext, - deps: TDeps extends { - [key in string]: AnyApiRef; - } - ? { - [key in keyof TDeps]: TDeps[key]['T']; - } - : never, - ) => Promise; -}): ScaffolderFormDecorator; - -// @alpha -export const DefaultTemplateOutputs: (props: { - output?: ScaffolderTaskOutput; -}) => React_2.JSX.Element | null; - -// @alpha (undocumented) -export const EmbeddableWorkflow: (props: WorkflowProps) => React_2.JSX.Element; - -// @alpha -export const extractSchemaFromStep: (inputStep: JsonObject) => { - uiSchema: UiSchema; - schema: JsonObject; -}; - -// @alpha -export const Form: ( - props: PropsWithChildren, -) => React_2.JSX.Element; - -// @alpha -export const FormDecoratorBlueprint: ExtensionBlueprint<{ - kind: 'scaffolder-form-decorator'; - name: undefined; - params: { - decorator: ScaffolderFormDecorator; - }; - output: ConfigurableExtensionDataRef< - ScaffolderFormDecorator, - 'scaffolder.form-decorator-loader', - {} - >; - inputs: {}; - config: {}; - configInput: {}; - dataRefs: { - formDecoratorLoader: ConfigurableExtensionDataRef< - ScaffolderFormDecorator, - 'scaffolder.form-decorator-loader', - {} - >; - }; -}>; - -// @alpha -export const FormFieldBlueprint: ExtensionBlueprint<{ - kind: 'scaffolder-form-field'; - name: undefined; - params: { - field: () => Promise; - }; - output: ConfigurableExtensionDataRef< - () => Promise, - 'scaffolder.form-field-loader', - {} - >; - inputs: {}; - config: {}; - configInput: {}; - dataRefs: { - formFieldLoader: ConfigurableExtensionDataRef< - () => Promise, - 'scaffolder.form-field-loader', - {} - >; - }; -}>; - -// @alpha (undocumented) -export type FormFieldExtensionData< - TReturnValue extends z.ZodType = z.ZodType, - TUiOptions extends z.ZodType = z.ZodType, -> = { - name: string; - component: ( - props: FieldExtensionComponentProps< - z.output, - z.output - >, - ) => JSX.Element | null; - validation?: CustomFieldValidator< - z.output, - z.output - >; - schema?: FieldSchema, z.output>; -}; - -// @alpha (undocumented) -export const formFieldsApi: ExtensionDefinition<{ - config: {}; - configInput: {}; - output: ConfigurableExtensionDataRef; - inputs: { - formFields: ExtensionInput< - ConfigurableExtensionDataRef< - () => Promise, - 'scaffolder.form-field-loader', - {} - >, - { - singleton: false; - optional: false; - } - >; - }; - kind: 'api'; - name: 'form-fields'; - params: { - factory: AnyApiFactory; - }; -}>; - -// @alpha @deprecated (undocumented) -export const formFieldsApiRef: ApiRef; - -// @alpha (undocumented) -export type FormValidation = { - [name: string]: FieldValidation | FormValidation; -}; - -// @alpha -export interface ParsedTemplateSchema { - // (undocumented) - description?: string; - // (undocumented) - mergedSchema: JsonObject; - // (undocumented) - schema: JsonObject; - // (undocumented) - title: string; - // (undocumented) - uiSchema: UiSchema; -} - -// @alpha -export const ReviewState: (props: ReviewStateProps) => React_2.JSX.Element; - -// @alpha -export type ReviewStateProps = { - schemas: ParsedTemplateSchema[]; - formState: JsonObject; -}; - -// @alpha -export const ScaffolderField: ( - props: PropsWithChildren, -) => React_2.JSX.Element; - -// @alpha -export interface ScaffolderFieldProps { - // (undocumented) - disabled?: boolean; - // (undocumented) - displayLabel?: boolean; - // (undocumented) - errors?: ReactElement; - // (undocumented) - help?: ReactElement; - // (undocumented) - rawDescription?: string; - // (undocumented) - rawErrors?: string[]; - // (undocumented) - rawHelp?: string; - // (undocumented) - required?: boolean; -} - -// @alpha (undocumented) -export type ScaffolderFormDecorator = { - readonly $$type: '@backstage/scaffolder/FormDecorator'; - readonly id: string; - readonly TInput: TInput; -}; - -// @alpha (undocumented) -export type ScaffolderFormDecoratorContext< - TInput extends JsonObject = JsonObject, -> = { - input: TInput; - formState: Record; - setFormState: ( - fn: (currentState: Record) => Record, - ) => void; - setSecrets: ( - fn: (currentState: Record) => Record, - ) => void; -}; - -// @alpha @deprecated (undocumented) -export interface ScaffolderFormFieldsApi { - // (undocumented) - getFormFields(): Promise; -} - -// @alpha (undocumented) -export function ScaffolderPageContextMenu( - props: ScaffolderPageContextMenuProps, -): React_2.JSX.Element | null; - -// @alpha (undocumented) -export type ScaffolderPageContextMenuProps = { - onEditorClicked?: () => void; - onActionsClicked?: () => void; - onTasksClicked?: () => void; - onCreateClicked?: () => void; -}; - -// @alpha (undocumented) -export type ScaffolderReactComponentsNameToClassKey = { - ScaffolderReactTemplateCategoryPicker: ScaffolderReactTemplateCategoryPickerClassKey; - BackstageTemplateStepper: BackstageTemplateStepperClassKey; -}; - -// @alpha (undocumented) -export type ScaffolderReactTemplateCategoryPickerClassKey = 'root' | 'label'; - -// @alpha (undocumented) -export const scaffolderReactTranslationRef: TranslationRef< - 'scaffolder-react', - { - readonly 'passwordWidget.content': 'This widget is insecure. Please use [`ui:field: Secret`](https://backstage.io/docs/features/software-templates/writing-templates/#using-secrets) instead of `ui:widget: password`'; - readonly 'scaffolderPageContextMenu.moreLabel': 'more'; - readonly 'scaffolderPageContextMenu.createLabel': 'Create'; - readonly 'scaffolderPageContextMenu.editorLabel': 'Manage Templates'; - readonly 'scaffolderPageContextMenu.actionsLabel': 'Installed Actions'; - readonly 'scaffolderPageContextMenu.tasksLabel': 'Task List'; - readonly 'stepper.backButtonText': 'Back'; - readonly 'stepper.createButtonText': 'Create'; - readonly 'stepper.reviewButtonText': 'Review'; - readonly 'stepper.stepIndexLabel': 'Step {{index, number}}'; - readonly 'stepper.nextButtonText': 'Next'; - readonly 'templateCategoryPicker.title': 'Categories'; - readonly 'templateCard.noDescription': 'No description'; - readonly 'templateCard.chooseButtonText': 'Choose'; - readonly 'cardHeader.detailBtnTitle': 'Show template entity details'; - readonly 'templateOutputs.title': 'Text Output'; - readonly 'workflow.noDescription': 'No description'; - } ->; - -// @alpha -export const SecretWidget: ( - props: Pick< - WidgetProps, - 'name' | 'onChange' | 'schema' | 'required' | 'disabled' - >, -) => React_2.JSX.Element; - -// @alpha -export const Stepper: (stepperProps: StepperProps) => React_2.JSX.Element; - -// @alpha -export type StepperProps = { - manifest: TemplateParameterSchema; - extensions: FieldExtensionOptions[]; - templateName?: string; - formProps?: FormProps; - initialState?: Record; - onCreate: (values: Record) => Promise; - components?: { - ReviewStepComponent?: ComponentType; - ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element; - backButtonText?: ReactNode; - createButtonText?: ReactNode; - reviewButtonText?: ReactNode; - }; - layouts?: LayoutOptions[]; -}; - -// @alpha -export const TaskLogStream: (props: { - logs: { - [k: string]: string[]; - }; -}) => React_2.JSX.Element; - -// @alpha -export const TaskSteps: (props: TaskStepsProps) => React_2.JSX.Element; - -// @alpha -export interface TaskStepsProps { - // (undocumented) - activeStep?: number; - // (undocumented) - isComplete?: boolean; - // (undocumented) - isError?: boolean; - // (undocumented) - steps: (TaskStep & ScaffolderStep)[]; -} - -// @alpha -export const TemplateCard: (props: TemplateCardProps) => React_2.JSX.Element; - -// @alpha -export interface TemplateCardProps { - // (undocumented) - additionalLinks?: { - icon: IconComponent; - text: string; - url: string; - }[]; - // (undocumented) - onSelected?: (template: TemplateEntityV1beta3) => void; - // (undocumented) - template: TemplateEntityV1beta3; -} - -// @alpha -export const TemplateCategoryPicker: () => React_2.JSX.Element | null; - -// @alpha -export const TemplateGroup: ( - props: TemplateGroupProps, -) => React_2.JSX.Element | null; - -// @alpha -export interface TemplateGroupProps { - // (undocumented) - components?: { - CardComponent?: React_2.ComponentType; - }; - // (undocumented) - onSelected: (template: TemplateEntityV1beta3) => void; - // (undocumented) - templates: { - template: TemplateEntityV1beta3; - additionalLinks?: { - icon: IconComponent; - text: string; - url: string; - }[]; - }[]; - // (undocumented) - title: React_2.ReactNode; -} - -// @alpha (undocumented) -export const TemplateGroups: ( - props: TemplateGroupsProps, -) => React_2.JSX.Element | null; - -// @alpha (undocumented) -export interface TemplateGroupsProps { - // (undocumented) - additionalLinksForEntity?: (template: TemplateEntityV1beta3) => { - icon: IconComponent; - text: string; - url: string; - }[]; - // (undocumented) - groups: TemplateGroupFilter[]; - // (undocumented) - onTemplateSelected?: (template: TemplateEntityV1beta3) => void; - // (undocumented) - TemplateCardComponent?: React_2.ComponentType<{ - template: TemplateEntityV1beta3; - }>; - // (undocumented) - templateFilter?: (entity: TemplateEntityV1beta3) => boolean; -} - -// @alpha -export const useFilteredSchemaProperties: ( - manifest: TemplateParameterSchema | undefined, -) => TemplateParameterSchema | undefined; - -// @alpha -export const useFormDataFromQuery: ( - initialState?: Record, -) => [Record, Dispatch>>]; - -// @alpha (undocumented) -export const useTemplateParameterSchema: (templateRef: string) => { - manifest?: TemplateParameterSchema; - loading: boolean; - error?: Error; -}; - -// @alpha -export const useTemplateSchema: (manifest: TemplateParameterSchema) => { - steps: ParsedTemplateSchema[]; - presentation?: TemplatePresentationV1beta3; -}; - -// @alpha (undocumented) -export const Workflow: (workflowProps: WorkflowProps) => JSX.Element | null; - -// @alpha (undocumented) -export type WorkflowProps = { - title?: string; - description?: string; - namespace: string; - templateName: string; - components?: { - ReviewStepComponent?: React_2.ComponentType; - }; - onError(error: Error | undefined): JSX.Element | null; -} & Pick< - StepperProps, - | 'extensions' - | 'formProps' - | 'components' - | 'onCreate' - | 'initialState' - | 'layouts' ->; - -// (No @packageDocumentation comment for this package) -``` diff --git a/plugins/scaffolder-react/report.api.md b/plugins/scaffolder-react/report.api.md deleted file mode 100644 index d62a2b43d4..0000000000 --- a/plugins/scaffolder-react/report.api.md +++ /dev/null @@ -1,567 +0,0 @@ -## API Report File for "@backstage/plugin-scaffolder-react" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { ApiHolder } from '@backstage/core-plugin-api'; -import { ApiRef } from '@backstage/frontend-plugin-api'; -import { ComponentType } from 'react'; -import { CustomValidator } from '@rjsf/utils'; -import { ElementType } from 'react'; -import { ErrorSchema } from '@rjsf/utils'; -import { ErrorTransformer } from '@rjsf/utils'; -import { Experimental_DefaultFormStateBehavior } from '@rjsf/utils'; -import { Extension } from '@backstage/core-plugin-api'; -import { FieldValidation } from '@rjsf/utils'; -import Form from '@rjsf/core'; -import { FormContextType } from '@rjsf/utils'; -import { FormEvent } from 'react'; -import type { FormProps as FormProps_2 } from '@rjsf/core'; -import { GenericObjectType } from '@rjsf/utils'; -import { HTMLAttributes } from 'react'; -import { IChangeEvent } from '@rjsf/core'; -import { IdSchema } from '@rjsf/utils'; -import { JsonObject } from '@backstage/types'; -import { JSONSchema7 } from 'json-schema'; -import { JsonValue } from '@backstage/types'; -import { Observable } from '@backstage/types'; -import { PropsWithChildren } from 'react'; -import { default as React_2 } from 'react'; -import { ReactNode } from 'react'; -import { Ref } from 'react'; -import { Registry } from '@rjsf/utils'; -import { RegistryWidgetsType } from '@rjsf/utils'; -import { RJSFSchema } from '@rjsf/utils'; -import { RJSFValidationError } from '@rjsf/utils'; -import { StrictRJSFSchema } from '@rjsf/utils'; -import { TaskSpec } from '@backstage/plugin-scaffolder-common'; -import { TaskStep } from '@backstage/plugin-scaffolder-common'; -import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; -import { TemplatesType } from '@rjsf/utils'; -import { UIOptionsType } from '@rjsf/utils'; -import { UiSchema } from '@rjsf/utils'; -import { ValidatorType } from '@rjsf/utils'; -import { z } from 'zod'; - -// @public -export type Action = { - id: string; - description?: string; - schema?: { - input?: JSONSchema7; - output?: JSONSchema7; - }; - examples?: ActionExample[]; -}; - -// @public -export type ActionExample = { - description: string; - example: string; -}; - -// @public -export function createScaffolderFieldExtension< - TReturnValue = unknown, - TInputProps extends UIOptionsType = {}, ->( - options: FieldExtensionOptions, -): Extension>; - -// @public -export function createScaffolderLayout( - options: LayoutOptions, -): Extension>; - -// @public -export type CustomFieldExtensionSchema = { - returnValue: JSONSchema7; - uiOptions?: JSONSchema7; -}; - -// @public -export type CustomFieldValidator = ( - data: TFieldReturnValue, - field: FieldValidation, - context: { - apiHolder: ApiHolder; - formData: JsonObject; - schema: JsonObject; - uiSchema?: FieldExtensionUiSchema; - }, -) => void | Promise; - -// @public -export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null; - -// @public -export interface FieldExtensionComponentProps< - TFieldReturnValue, - TUiOptions = {}, -> extends PropsWithChildren> { - // (undocumented) - uiSchema: FieldExtensionUiSchema; -} - -// @public -export type FieldExtensionOptions< - TFieldReturnValue = unknown, - TUiOptions = unknown, -> = { - name: string; - component: ( - props: FieldExtensionComponentProps, - ) => JSX.Element | null; - validation?: CustomFieldValidator; - schema?: CustomFieldExtensionSchema; -}; - -// @public -export interface FieldExtensionUiSchema - extends UiSchema { - // (undocumented) - 'ui:options'?: TUiOptions & UIOptionsType; -} - -// @public -export interface FieldSchema { - // (undocumented) - readonly schema: CustomFieldExtensionSchema; - // (undocumented) - readonly TOutput: TReturn; - // (undocumented) - readonly TProps: FieldExtensionComponentProps; - // @deprecated (undocumented) - readonly type: FieldExtensionComponentProps; - // @deprecated (undocumented) - readonly uiOptionsType: TUiOptions; -} - -// @public -export type FormProps = Pick< - FormProps_2, - | 'transformErrors' - | 'noHtml5Validate' - | 'uiSchema' - | 'formContext' - | 'omitExtraData' - | 'liveOmit' ->; - -// @public -export type LayoutComponent<_TInputProps> = () => null; - -// @public -export interface LayoutOptions

{ - // (undocumented) - component: LayoutTemplate

; - // (undocumented) - name: string; -} - -// @public -export type LayoutTemplate = NonNullable< - FormProps_2['uiSchema'] ->['ui:ObjectFieldTemplate']; - -// @public -export type ListActionsResponse = Array; - -// @public -export type LogEvent = { - type: 'log' | 'completion' | 'cancelled' | 'recovered'; - body: { - message: string; - stepId?: string; - status?: ScaffolderTaskStatus; - }; - createdAt: string; - id: string; - taskId: string; -}; - -// @public (undocumented) -export function makeFieldSchema< - TReturnType extends z.ZodType, - TUiOptions extends z.ZodType, ->(options: { - output: (zImpl: typeof z) => TReturnType; - uiOptions?: (zImpl: typeof z) => TUiOptions; -}): FieldSchema, z.output>; - -// @public -export type ReviewStepProps = { - disableButtons: boolean; - formData: JsonObject; - handleBack: () => void; - handleReset: () => void; - handleCreate: () => void; - steps: { - uiSchema: UiSchema; - mergedSchema: JsonObject; - schema: JsonObject; - }[]; -}; - -// @public -export interface ScaffolderApi { - // (undocumented) - autocomplete?(options: { - token: string; - provider: string; - resource: string; - context?: Record; - }): Promise<{ - results: { - title?: string; - id: string; - }[]; - }>; - cancelTask(taskId: string): Promise; - // (undocumented) - dryRun?(options: ScaffolderDryRunOptions): Promise; - // (undocumented) - getIntegrationsList( - options: ScaffolderGetIntegrationsListOptions, - ): Promise; - // (undocumented) - getTask(taskId: string): Promise; - // (undocumented) - getTemplateParameterSchema( - templateRef: string, - ): Promise; - listActions(): Promise; - // (undocumented) - listTasks?(options: { - filterByOwnership: 'owned' | 'all'; - limit?: number; - offset?: number; - }): Promise<{ - tasks: ScaffolderTask[]; - totalTasks?: number; - }>; - retry?(taskId: string): Promise; - scaffold( - options: ScaffolderScaffoldOptions, - ): Promise; - // (undocumented) - streamLogs(options: ScaffolderStreamLogsOptions): Observable; -} - -// @public (undocumented) -export const scaffolderApiRef: ApiRef; - -// @public (undocumented) -export interface ScaffolderDryRunOptions { - // (undocumented) - directoryContents: { - path: string; - base64Content: string; - }[]; - // (undocumented) - secrets?: Record; - // (undocumented) - template: JsonValue; - // (undocumented) - values: JsonObject; -} - -// @public (undocumented) -export interface ScaffolderDryRunResponse { - // (undocumented) - directoryContents: Array<{ - path: string; - base64Content: string; - executable: boolean; - }>; - // (undocumented) - log: Array>; - // (undocumented) - output: ScaffolderTaskOutput; - // (undocumented) - steps: TaskStep[]; -} - -// @public -export const ScaffolderFieldExtensions: React.ComponentType< - React.PropsWithChildren<{}> ->; - -// @public -export interface ScaffolderGetIntegrationsListOptions { - // (undocumented) - allowedHosts: string[]; -} - -// @public -export interface ScaffolderGetIntegrationsListResponse { - // (undocumented) - integrations: { - type: string; - title: string; - host: string; - }[]; -} - -// @public -export const ScaffolderLayouts: React_2.ComponentType< - React_2.PropsWithChildren<{}> ->; - -// @public (undocumented) -export type ScaffolderOutputLink = { - title?: string; - icon?: string; - url?: string; - entityRef?: string; -}; - -// @public (undocumented) -export type ScaffolderOutputText = { - title?: string; - icon?: string; - content?: string; - default?: boolean; -}; - -// @public -export type ScaffolderRJSFField< - T = any, - S extends StrictRJSFSchema = RJSFSchema, - F extends FormContextType = any, -> = ComponentType>; - -// @public -export interface ScaffolderRJSFFieldProps< - T = any, - S extends StrictRJSFSchema = RJSFSchema, - F extends FormContextType = any, -> extends GenericObjectType, - Pick< - HTMLAttributes, - Exclude< - keyof HTMLAttributes, - 'onBlur' | 'onFocus' | 'onChange' - > - > { - autofocus?: boolean; - disabled: boolean; - errorSchema?: ErrorSchema; - formContext?: F; - formData?: T; - hideError?: boolean; - idPrefix?: string; - idSchema: IdSchema; - idSeparator?: string; - name: string; - onBlur: (id: string, value: any) => void; - onChange: ( - newFormData: T | undefined, - es?: ErrorSchema, - id?: string, - ) => any; - onFocus: (id: string, value: any) => void; - rawErrors: string[]; - readonly: boolean; - registry: Registry; - required?: boolean; - schema: S; - uiSchema: UiSchema; -} - -// @public -export interface ScaffolderRJSFFormProps< - T = any, - S extends StrictRJSFSchema = RJSFSchema, - F extends FormContextType = any, -> { - acceptcharset?: string; - action?: string; - autoComplete?: string; - children?: ReactNode; - className?: string; - customValidate?: CustomValidator; - disabled?: boolean; - enctype?: string; - experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior; - extraErrors?: ErrorSchema; - fields?: ScaffolderRJSFRegistryFieldsType; - focusOnFirstError?: boolean | ((error: RJSFValidationError) => void); - formContext?: F; - formData?: T; - id?: string; - idPrefix?: string; - idSeparator?: string; - _internalFormWrapper?: ElementType; - liveOmit?: boolean; - liveValidate?: boolean; - method?: string; - name?: string; - noHtml5Validate?: boolean; - // @deprecated - noValidate?: boolean; - omitExtraData?: boolean; - onBlur?: (id: string, data: any) => void; - onChange?: (data: IChangeEvent, id?: string) => void; - onError?: (errors: RJSFValidationError[]) => void; - onFocus?: (id: string, data: any) => void; - onSubmit?: (data: IChangeEvent, event: FormEvent) => void; - readonly?: boolean; - ref?: Ref>; - schema: S; - showErrorList?: false | 'top' | 'bottom'; - tagName?: ElementType; - target?: string; - templates?: Partial, 'ButtonTemplates'>> & { - ButtonTemplates?: Partial['ButtonTemplates']>; - }; - transformErrors?: ErrorTransformer; - translateString?: Registry['translateString']; - uiSchema?: UiSchema; - validator: ValidatorType; - widgets?: RegistryWidgetsType; -} - -// @public -export type ScaffolderRJSFRegistryFieldsType< - T = any, - S extends StrictRJSFSchema = RJSFSchema, - F extends FormContextType = any, -> = { - [name: string]: ScaffolderRJSFField; -}; - -// @public -export interface ScaffolderScaffoldOptions { - // (undocumented) - secrets?: Record; - // (undocumented) - templateRef: string; - // (undocumented) - values: Record; -} - -// @public -export interface ScaffolderScaffoldResponse { - // (undocumented) - taskId: string; -} - -// @public -export type ScaffolderStep = { - id: string; - status: ScaffolderTaskStatus; - endedAt?: string; - startedAt?: string; -}; - -// @public -export interface ScaffolderStreamLogsOptions { - // (undocumented) - after?: number; - // (undocumented) - isTaskRecoverable?: boolean; - // (undocumented) - taskId: string; -} - -// @public -export type ScaffolderTask = { - id: string; - spec: TaskSpec; - status: 'failed' | 'completed' | 'processing' | 'open' | 'cancelled'; - lastHeartbeatAt: string; - createdAt: string; -}; - -// @public (undocumented) -export type ScaffolderTaskOutput = { - links?: ScaffolderOutputLink[]; - text?: ScaffolderOutputText[]; -} & { - [key: string]: unknown; -}; - -// @public -export type ScaffolderTaskStatus = - | 'cancelled' - | 'completed' - | 'failed' - | 'open' - | 'processing' - | 'skipped'; - -// @public -export interface ScaffolderUseTemplateSecrets { - // (undocumented) - secrets: Record; - // (undocumented) - setSecrets: (input: Record) => void; -} - -// @public -export const SecretsContextProvider: ( - props: PropsWithChildren<{ - initialSecrets?: Record; - }>, -) => React_2.JSX.Element; - -// @public -export type TaskStream = { - cancelled: boolean; - loading: boolean; - error?: Error; - stepLogs: { - [stepId in string]: string[]; - }; - completed: boolean; - task?: ScaffolderTask; - steps: { - [stepId in string]: ScaffolderStep; - }; - output?: ScaffolderTaskOutput; -}; - -// @public (undocumented) -export type TemplateGroupFilter = { - title?: React.ReactNode; - filter: (entity: TemplateEntityV1beta3) => boolean; -}; - -// @public -export type TemplateParameterSchema = { - title: string; - description?: string; - presentation?: TemplatePresentationV1beta3; - steps: Array<{ - title: string; - description?: string; - schema: JsonObject; - }>; - EXPERIMENTAL_formDecorators?: { - id: string; - input?: JsonObject; - }[]; -}; - -// @public -export const useCustomFieldExtensions: < - TComponentDataType = FieldExtensionOptions, ->( - outlet: React.ReactNode, -) => TComponentDataType[]; - -// @public -export const useCustomLayouts: >( - outlet: React.ReactNode, -) => TComponentDataType[]; - -// @public -export const useTaskEventStream: (taskId: string) => TaskStream; - -// @public -export const useTemplateSecrets: () => ScaffolderUseTemplateSecrets; - -// (No @packageDocumentation comment for this package) -``` From 1bf0867dee0196985d988e38301ba911247316a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ladislav=20Vit=C3=A1sek?= Date: Wed, 19 Mar 2025 08:38:37 +0100 Subject: [PATCH 30/52] feat: add usage documentation for backstage-cli config:docs command and create new configuration files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ladislav Vitásek --- plugins/scaffolder-react/report-alpha.api.md | 524 +++++++++++++++++ plugins/scaffolder-react/report.api.md | 567 +++++++++++++++++++ 2 files changed, 1091 insertions(+) create mode 100644 plugins/scaffolder-react/report-alpha.api.md create mode 100644 plugins/scaffolder-react/report.api.md diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md new file mode 100644 index 0000000000..ad9f31480a --- /dev/null +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -0,0 +1,524 @@ +## API Report File for "@backstage/plugin-scaffolder-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { AnyApiFactory } from '@backstage/frontend-plugin-api'; +import { AnyApiRef } from '@backstage/core-plugin-api'; +import { ApiHolder } from '@backstage/core-plugin-api'; +import { ApiRef } from '@backstage/frontend-plugin-api'; +import { ComponentType } from 'react'; +import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; +import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react'; +import { Dispatch } from 'react'; +import { ExtensionBlueprint } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; +import { ExtensionInput } from '@backstage/frontend-plugin-api'; +import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react'; +import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; +import { FieldSchema } from '@backstage/plugin-scaffolder-react'; +import { FieldValidation } from '@rjsf/utils'; +import { FormField } from '@internal/scaffolder'; +import { FormProps } from '@backstage/plugin-scaffolder-react'; +import { IconComponent } from '@backstage/core-plugin-api'; +import { JsonObject } from '@backstage/types'; +import { JsonValue } from '@backstage/types'; +import { LayoutOptions } from '@backstage/plugin-scaffolder-react'; +import { Overrides } from '@material-ui/core/styles/overrides'; +import { PropsWithChildren } from 'react'; +import { default as React_2 } from 'react'; +import { ReactElement } from 'react'; +import { ReactNode } from 'react'; +import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderRJSFFormProps } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderStep } from '@backstage/plugin-scaffolder-react'; +import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react'; +import { SetStateAction } from 'react'; +import { StyleRules } from '@material-ui/core/styles/withStyles'; +import { TaskStep } from '@backstage/plugin-scaffolder-common'; +import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; +import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; +import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TranslationRef } from '@backstage/core-plugin-api/alpha'; +import { UiSchema } from '@rjsf/utils'; +import { WidgetProps } from '@rjsf/utils'; +import { z } from 'zod'; + +// @alpha (undocumented) +export type BackstageOverrides = Overrides & { + [Name in keyof ScaffolderReactComponentsNameToClassKey]?: Partial< + StyleRules + >; +}; + +// @alpha (undocumented) +export type BackstageTemplateStepperClassKey = + | 'backButton' + | 'footer' + | 'formWrapper'; + +// @alpha (undocumented) +export const createAsyncValidators: ( + rootSchema: JsonObject, + validators: Record< + string, + undefined | CustomFieldValidator + >, + context: { + apiHolder: ApiHolder; + }, +) => (formData: JsonObject) => Promise; + +// @alpha +export const createFieldValidation: () => FieldValidation; + +// @alpha +export function createFormField< + TReturnValue extends z.ZodType, + TUiOptions extends z.ZodType, +>(opts: FormFieldExtensionData): FormField; + +// @alpha +export function createScaffolderFormDecorator< + TInputSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + } = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, + TDeps extends { + [key in string]: AnyApiRef; + } = { + [key in string]: AnyApiRef; + }, + TInput extends JsonObject = { + [key in keyof TInputSchema]: z.infer>; + }, +>(options: { + id: string; + schema?: { + input?: TInputSchema; + }; + deps?: TDeps; + decorator: ( + ctx: ScaffolderFormDecoratorContext, + deps: TDeps extends { + [key in string]: AnyApiRef; + } + ? { + [key in keyof TDeps]: TDeps[key]['T']; + } + : never, + ) => Promise; +}): ScaffolderFormDecorator; + +// @alpha +export const DefaultTemplateOutputs: (props: { + output?: ScaffolderTaskOutput; +}) => React_2.JSX.Element | null; + +// @alpha (undocumented) +export const EmbeddableWorkflow: (props: WorkflowProps) => React_2.JSX.Element; + +// @alpha +export const extractSchemaFromStep: (inputStep: JsonObject) => { + uiSchema: UiSchema; + schema: JsonObject; +}; + +// @alpha +export const Form: ( + props: PropsWithChildren, +) => React_2.JSX.Element; + +// @alpha +export const FormDecoratorBlueprint: ExtensionBlueprint<{ + kind: 'scaffolder-form-decorator'; + name: undefined; + params: { + decorator: ScaffolderFormDecorator; + }; + output: ConfigurableExtensionDataRef< + ScaffolderFormDecorator, + 'scaffolder.form-decorator-loader', + {} + >; + inputs: {}; + config: {}; + configInput: {}; + dataRefs: { + formDecoratorLoader: ConfigurableExtensionDataRef< + ScaffolderFormDecorator, + 'scaffolder.form-decorator-loader', + {} + >; + }; +}>; + +// @alpha +export const FormFieldBlueprint: ExtensionBlueprint<{ + kind: 'scaffolder-form-field'; + name: undefined; + params: { + field: () => Promise; + }; + output: ConfigurableExtensionDataRef< + () => Promise, + 'scaffolder.form-field-loader', + {} + >; + inputs: {}; + config: {}; + configInput: {}; + dataRefs: { + formFieldLoader: ConfigurableExtensionDataRef< + () => Promise, + 'scaffolder.form-field-loader', + {} + >; + }; +}>; + +// @alpha (undocumented) +export type FormFieldExtensionData< + TReturnValue extends z.ZodType = z.ZodType, + TUiOptions extends z.ZodType = z.ZodType, +> = { + name: string; + component: ( + props: FieldExtensionComponentProps< + z.output, + z.output + >, + ) => JSX.Element | null; + validation?: CustomFieldValidator< + z.output, + z.output + >; + schema?: FieldSchema, z.output>; +}; + +// @alpha (undocumented) +export const formFieldsApi: ExtensionDefinition<{ + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef; + inputs: { + formFields: ExtensionInput< + ConfigurableExtensionDataRef< + () => Promise, + 'scaffolder.form-field-loader', + {} + >, + { + singleton: false; + optional: false; + } + >; + }; + kind: 'api'; + name: 'form-fields'; + params: { + factory: AnyApiFactory; + }; +}>; + +// @alpha @deprecated (undocumented) +export const formFieldsApiRef: ApiRef; + +// @alpha (undocumented) +export type FormValidation = { + [name: string]: FieldValidation | FormValidation; +}; + +// @alpha +export interface ParsedTemplateSchema { + // (undocumented) + description?: string; + // (undocumented) + mergedSchema: JsonObject; + // (undocumented) + schema: JsonObject; + // (undocumented) + title: string; + // (undocumented) + uiSchema: UiSchema; +} + +// @alpha +export const ReviewState: (props: ReviewStateProps) => React_2.JSX.Element; + +// @alpha +export type ReviewStateProps = { + schemas: ParsedTemplateSchema[]; + formState: JsonObject; +}; + +// @alpha +export const ScaffolderField: ( + props: PropsWithChildren, +) => React_2.JSX.Element; + +// @alpha +export interface ScaffolderFieldProps { + // (undocumented) + disabled?: boolean; + // (undocumented) + displayLabel?: boolean; + // (undocumented) + errors?: ReactElement; + // (undocumented) + help?: ReactElement; + // (undocumented) + rawDescription?: string; + // (undocumented) + rawErrors?: string[]; + // (undocumented) + rawHelp?: string; + // (undocumented) + required?: boolean; +} + +// @alpha (undocumented) +export type ScaffolderFormDecorator = { + readonly $$type: '@backstage/scaffolder/FormDecorator'; + readonly id: string; + readonly TInput: TInput; +}; + +// @alpha (undocumented) +export type ScaffolderFormDecoratorContext< + TInput extends JsonObject = JsonObject, +> = { + input: TInput; + formState: Record; + setFormState: ( + fn: (currentState: Record) => Record, + ) => void; + setSecrets: ( + fn: (currentState: Record) => Record, + ) => void; +}; + +// @alpha @deprecated (undocumented) +export interface ScaffolderFormFieldsApi { + // (undocumented) + getFormFields(): Promise; +} + +// @alpha (undocumented) +export function ScaffolderPageContextMenu( + props: ScaffolderPageContextMenuProps, +): React_2.JSX.Element | null; + +// @alpha (undocumented) +export type ScaffolderPageContextMenuProps = { + onEditorClicked?: () => void; + onActionsClicked?: () => void; + onTasksClicked?: () => void; + onCreateClicked?: () => void; +}; + +// @alpha (undocumented) +export type ScaffolderReactComponentsNameToClassKey = { + ScaffolderReactTemplateCategoryPicker: ScaffolderReactTemplateCategoryPickerClassKey; + BackstageTemplateStepper: BackstageTemplateStepperClassKey; +}; + +// @alpha (undocumented) +export type ScaffolderReactTemplateCategoryPickerClassKey = 'root' | 'label'; + +// @alpha (undocumented) +export const scaffolderReactTranslationRef: TranslationRef< + 'scaffolder-react', + { + readonly 'passwordWidget.content': 'This widget is insecure. Please use [`ui:field: Secret`](https://backstage.io/docs/features/software-templates/writing-templates/#using-secrets) instead of `ui:widget: password`'; + readonly 'scaffolderPageContextMenu.moreLabel': 'more'; + readonly 'scaffolderPageContextMenu.createLabel': 'Create'; + readonly 'scaffolderPageContextMenu.editorLabel': 'Manage Templates'; + readonly 'scaffolderPageContextMenu.actionsLabel': 'Installed Actions'; + readonly 'scaffolderPageContextMenu.tasksLabel': 'Task List'; + readonly 'stepper.backButtonText': 'Back'; + readonly 'stepper.createButtonText': 'Create'; + readonly 'stepper.reviewButtonText': 'Review'; + readonly 'stepper.stepIndexLabel': 'Step {{index, number}}'; + readonly 'stepper.nextButtonText': 'Next'; + readonly 'templateCategoryPicker.title': 'Categories'; + readonly 'templateCard.noDescription': 'No description'; + readonly 'templateCard.chooseButtonText': 'Choose'; + readonly 'cardHeader.detailBtnTitle': 'Show template entity details'; + readonly 'templateOutputs.title': 'Text Output'; + readonly 'workflow.noDescription': 'No description'; + } +>; + +// @alpha +export const SecretWidget: ( + props: Pick< + WidgetProps, + 'name' | 'onChange' | 'schema' | 'required' | 'disabled' + >, +) => React_2.JSX.Element; + +// @alpha +export const Stepper: (stepperProps: StepperProps) => React_2.JSX.Element; + +// @alpha +export type StepperProps = { + manifest: TemplateParameterSchema; + extensions: FieldExtensionOptions[]; + templateName?: string; + formProps?: FormProps; + initialState?: Record; + onCreate: (values: Record) => Promise; + components?: { + ReviewStepComponent?: ComponentType; + ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element; + backButtonText?: ReactNode; + createButtonText?: ReactNode; + reviewButtonText?: ReactNode; + }; + layouts?: LayoutOptions[]; +}; + +// @alpha +export const TaskLogStream: (props: { + logs: { + [k: string]: string[]; + }; +}) => React_2.JSX.Element; + +// @alpha +export const TaskSteps: (props: TaskStepsProps) => React_2.JSX.Element; + +// @alpha +export interface TaskStepsProps { + // (undocumented) + activeStep?: number; + // (undocumented) + isComplete?: boolean; + // (undocumented) + isError?: boolean; + // (undocumented) + steps: (TaskStep & ScaffolderStep)[]; +} + +// @alpha +export const TemplateCard: (props: TemplateCardProps) => React_2.JSX.Element; + +// @alpha +export interface TemplateCardProps { + // (undocumented) + additionalLinks?: { + icon: IconComponent; + text: string; + url: string; + }[]; + // (undocumented) + onSelected?: (template: TemplateEntityV1beta3) => void; + // (undocumented) + template: TemplateEntityV1beta3; +} + +// @alpha +export const TemplateCategoryPicker: () => React_2.JSX.Element | null; + +// @alpha +export const TemplateGroup: ( + props: TemplateGroupProps, +) => React_2.JSX.Element | null; + +// @alpha +export interface TemplateGroupProps { + // (undocumented) + components?: { + CardComponent?: React_2.ComponentType; + }; + // (undocumented) + onSelected: (template: TemplateEntityV1beta3) => void; + // (undocumented) + templates: { + template: TemplateEntityV1beta3; + additionalLinks?: { + icon: IconComponent; + text: string; + url: string; + }[]; + }[]; + // (undocumented) + title: React_2.ReactNode; +} + +// @alpha (undocumented) +export const TemplateGroups: ( + props: TemplateGroupsProps, +) => React_2.JSX.Element | null; + +// @alpha (undocumented) +export interface TemplateGroupsProps { + // (undocumented) + additionalLinksForEntity?: (template: TemplateEntityV1beta3) => { + icon: IconComponent; + text: string; + url: string; + }[]; + // (undocumented) + groups: TemplateGroupFilter[]; + // (undocumented) + onTemplateSelected?: (template: TemplateEntityV1beta3) => void; + // (undocumented) + TemplateCardComponent?: React_2.ComponentType<{ + template: TemplateEntityV1beta3; + }>; + // (undocumented) + templateFilter?: (entity: TemplateEntityV1beta3) => boolean; +} + +// @alpha +export const useFilteredSchemaProperties: ( + manifest: TemplateParameterSchema | undefined, +) => TemplateParameterSchema | undefined; + +// @alpha +export const useFormDataFromQuery: ( + initialState?: Record, +) => [Record, Dispatch>>]; + +// @alpha (undocumented) +export const useTemplateParameterSchema: (templateRef: string) => { + manifest?: TemplateParameterSchema; + loading: boolean; + error?: Error; +}; + +// @alpha +export const useTemplateSchema: (manifest: TemplateParameterSchema) => { + steps: ParsedTemplateSchema[]; + presentation?: TemplatePresentationV1beta3; +}; + +// @alpha (undocumented) +export const Workflow: (workflowProps: WorkflowProps) => JSX.Element | null; + +// @alpha (undocumented) +export type WorkflowProps = { + title?: string; + description?: string; + namespace: string; + templateName: string; + components?: { + ReviewStepComponent?: React_2.ComponentType; + }; + onError(error: Error | undefined): JSX.Element | null; +} & Pick< + StepperProps, + | 'extensions' + | 'formProps' + | 'components' + | 'onCreate' + | 'initialState' + | 'layouts' +>; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/scaffolder-react/report.api.md b/plugins/scaffolder-react/report.api.md new file mode 100644 index 0000000000..d62a2b43d4 --- /dev/null +++ b/plugins/scaffolder-react/report.api.md @@ -0,0 +1,567 @@ +## API Report File for "@backstage/plugin-scaffolder-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +import { ApiHolder } from '@backstage/core-plugin-api'; +import { ApiRef } from '@backstage/frontend-plugin-api'; +import { ComponentType } from 'react'; +import { CustomValidator } from '@rjsf/utils'; +import { ElementType } from 'react'; +import { ErrorSchema } from '@rjsf/utils'; +import { ErrorTransformer } from '@rjsf/utils'; +import { Experimental_DefaultFormStateBehavior } from '@rjsf/utils'; +import { Extension } from '@backstage/core-plugin-api'; +import { FieldValidation } from '@rjsf/utils'; +import Form from '@rjsf/core'; +import { FormContextType } from '@rjsf/utils'; +import { FormEvent } from 'react'; +import type { FormProps as FormProps_2 } from '@rjsf/core'; +import { GenericObjectType } from '@rjsf/utils'; +import { HTMLAttributes } from 'react'; +import { IChangeEvent } from '@rjsf/core'; +import { IdSchema } from '@rjsf/utils'; +import { JsonObject } from '@backstage/types'; +import { JSONSchema7 } from 'json-schema'; +import { JsonValue } from '@backstage/types'; +import { Observable } from '@backstage/types'; +import { PropsWithChildren } from 'react'; +import { default as React_2 } from 'react'; +import { ReactNode } from 'react'; +import { Ref } from 'react'; +import { Registry } from '@rjsf/utils'; +import { RegistryWidgetsType } from '@rjsf/utils'; +import { RJSFSchema } from '@rjsf/utils'; +import { RJSFValidationError } from '@rjsf/utils'; +import { StrictRJSFSchema } from '@rjsf/utils'; +import { TaskSpec } from '@backstage/plugin-scaffolder-common'; +import { TaskStep } from '@backstage/plugin-scaffolder-common'; +import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplatePresentationV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { TemplatesType } from '@rjsf/utils'; +import { UIOptionsType } from '@rjsf/utils'; +import { UiSchema } from '@rjsf/utils'; +import { ValidatorType } from '@rjsf/utils'; +import { z } from 'zod'; + +// @public +export type Action = { + id: string; + description?: string; + schema?: { + input?: JSONSchema7; + output?: JSONSchema7; + }; + examples?: ActionExample[]; +}; + +// @public +export type ActionExample = { + description: string; + example: string; +}; + +// @public +export function createScaffolderFieldExtension< + TReturnValue = unknown, + TInputProps extends UIOptionsType = {}, +>( + options: FieldExtensionOptions, +): Extension>; + +// @public +export function createScaffolderLayout( + options: LayoutOptions, +): Extension>; + +// @public +export type CustomFieldExtensionSchema = { + returnValue: JSONSchema7; + uiOptions?: JSONSchema7; +}; + +// @public +export type CustomFieldValidator = ( + data: TFieldReturnValue, + field: FieldValidation, + context: { + apiHolder: ApiHolder; + formData: JsonObject; + schema: JsonObject; + uiSchema?: FieldExtensionUiSchema; + }, +) => void | Promise; + +// @public +export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null; + +// @public +export interface FieldExtensionComponentProps< + TFieldReturnValue, + TUiOptions = {}, +> extends PropsWithChildren> { + // (undocumented) + uiSchema: FieldExtensionUiSchema; +} + +// @public +export type FieldExtensionOptions< + TFieldReturnValue = unknown, + TUiOptions = unknown, +> = { + name: string; + component: ( + props: FieldExtensionComponentProps, + ) => JSX.Element | null; + validation?: CustomFieldValidator; + schema?: CustomFieldExtensionSchema; +}; + +// @public +export interface FieldExtensionUiSchema + extends UiSchema { + // (undocumented) + 'ui:options'?: TUiOptions & UIOptionsType; +} + +// @public +export interface FieldSchema { + // (undocumented) + readonly schema: CustomFieldExtensionSchema; + // (undocumented) + readonly TOutput: TReturn; + // (undocumented) + readonly TProps: FieldExtensionComponentProps; + // @deprecated (undocumented) + readonly type: FieldExtensionComponentProps; + // @deprecated (undocumented) + readonly uiOptionsType: TUiOptions; +} + +// @public +export type FormProps = Pick< + FormProps_2, + | 'transformErrors' + | 'noHtml5Validate' + | 'uiSchema' + | 'formContext' + | 'omitExtraData' + | 'liveOmit' +>; + +// @public +export type LayoutComponent<_TInputProps> = () => null; + +// @public +export interface LayoutOptions

{ + // (undocumented) + component: LayoutTemplate

; + // (undocumented) + name: string; +} + +// @public +export type LayoutTemplate = NonNullable< + FormProps_2['uiSchema'] +>['ui:ObjectFieldTemplate']; + +// @public +export type ListActionsResponse = Array; + +// @public +export type LogEvent = { + type: 'log' | 'completion' | 'cancelled' | 'recovered'; + body: { + message: string; + stepId?: string; + status?: ScaffolderTaskStatus; + }; + createdAt: string; + id: string; + taskId: string; +}; + +// @public (undocumented) +export function makeFieldSchema< + TReturnType extends z.ZodType, + TUiOptions extends z.ZodType, +>(options: { + output: (zImpl: typeof z) => TReturnType; + uiOptions?: (zImpl: typeof z) => TUiOptions; +}): FieldSchema, z.output>; + +// @public +export type ReviewStepProps = { + disableButtons: boolean; + formData: JsonObject; + handleBack: () => void; + handleReset: () => void; + handleCreate: () => void; + steps: { + uiSchema: UiSchema; + mergedSchema: JsonObject; + schema: JsonObject; + }[]; +}; + +// @public +export interface ScaffolderApi { + // (undocumented) + autocomplete?(options: { + token: string; + provider: string; + resource: string; + context?: Record; + }): Promise<{ + results: { + title?: string; + id: string; + }[]; + }>; + cancelTask(taskId: string): Promise; + // (undocumented) + dryRun?(options: ScaffolderDryRunOptions): Promise; + // (undocumented) + getIntegrationsList( + options: ScaffolderGetIntegrationsListOptions, + ): Promise; + // (undocumented) + getTask(taskId: string): Promise; + // (undocumented) + getTemplateParameterSchema( + templateRef: string, + ): Promise; + listActions(): Promise; + // (undocumented) + listTasks?(options: { + filterByOwnership: 'owned' | 'all'; + limit?: number; + offset?: number; + }): Promise<{ + tasks: ScaffolderTask[]; + totalTasks?: number; + }>; + retry?(taskId: string): Promise; + scaffold( + options: ScaffolderScaffoldOptions, + ): Promise; + // (undocumented) + streamLogs(options: ScaffolderStreamLogsOptions): Observable; +} + +// @public (undocumented) +export const scaffolderApiRef: ApiRef; + +// @public (undocumented) +export interface ScaffolderDryRunOptions { + // (undocumented) + directoryContents: { + path: string; + base64Content: string; + }[]; + // (undocumented) + secrets?: Record; + // (undocumented) + template: JsonValue; + // (undocumented) + values: JsonObject; +} + +// @public (undocumented) +export interface ScaffolderDryRunResponse { + // (undocumented) + directoryContents: Array<{ + path: string; + base64Content: string; + executable: boolean; + }>; + // (undocumented) + log: Array>; + // (undocumented) + output: ScaffolderTaskOutput; + // (undocumented) + steps: TaskStep[]; +} + +// @public +export const ScaffolderFieldExtensions: React.ComponentType< + React.PropsWithChildren<{}> +>; + +// @public +export interface ScaffolderGetIntegrationsListOptions { + // (undocumented) + allowedHosts: string[]; +} + +// @public +export interface ScaffolderGetIntegrationsListResponse { + // (undocumented) + integrations: { + type: string; + title: string; + host: string; + }[]; +} + +// @public +export const ScaffolderLayouts: React_2.ComponentType< + React_2.PropsWithChildren<{}> +>; + +// @public (undocumented) +export type ScaffolderOutputLink = { + title?: string; + icon?: string; + url?: string; + entityRef?: string; +}; + +// @public (undocumented) +export type ScaffolderOutputText = { + title?: string; + icon?: string; + content?: string; + default?: boolean; +}; + +// @public +export type ScaffolderRJSFField< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> = ComponentType>; + +// @public +export interface ScaffolderRJSFFieldProps< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> extends GenericObjectType, + Pick< + HTMLAttributes, + Exclude< + keyof HTMLAttributes, + 'onBlur' | 'onFocus' | 'onChange' + > + > { + autofocus?: boolean; + disabled: boolean; + errorSchema?: ErrorSchema; + formContext?: F; + formData?: T; + hideError?: boolean; + idPrefix?: string; + idSchema: IdSchema; + idSeparator?: string; + name: string; + onBlur: (id: string, value: any) => void; + onChange: ( + newFormData: T | undefined, + es?: ErrorSchema, + id?: string, + ) => any; + onFocus: (id: string, value: any) => void; + rawErrors: string[]; + readonly: boolean; + registry: Registry; + required?: boolean; + schema: S; + uiSchema: UiSchema; +} + +// @public +export interface ScaffolderRJSFFormProps< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> { + acceptcharset?: string; + action?: string; + autoComplete?: string; + children?: ReactNode; + className?: string; + customValidate?: CustomValidator; + disabled?: boolean; + enctype?: string; + experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior; + extraErrors?: ErrorSchema; + fields?: ScaffolderRJSFRegistryFieldsType; + focusOnFirstError?: boolean | ((error: RJSFValidationError) => void); + formContext?: F; + formData?: T; + id?: string; + idPrefix?: string; + idSeparator?: string; + _internalFormWrapper?: ElementType; + liveOmit?: boolean; + liveValidate?: boolean; + method?: string; + name?: string; + noHtml5Validate?: boolean; + // @deprecated + noValidate?: boolean; + omitExtraData?: boolean; + onBlur?: (id: string, data: any) => void; + onChange?: (data: IChangeEvent, id?: string) => void; + onError?: (errors: RJSFValidationError[]) => void; + onFocus?: (id: string, data: any) => void; + onSubmit?: (data: IChangeEvent, event: FormEvent) => void; + readonly?: boolean; + ref?: Ref>; + schema: S; + showErrorList?: false | 'top' | 'bottom'; + tagName?: ElementType; + target?: string; + templates?: Partial, 'ButtonTemplates'>> & { + ButtonTemplates?: Partial['ButtonTemplates']>; + }; + transformErrors?: ErrorTransformer; + translateString?: Registry['translateString']; + uiSchema?: UiSchema; + validator: ValidatorType; + widgets?: RegistryWidgetsType; +} + +// @public +export type ScaffolderRJSFRegistryFieldsType< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +> = { + [name: string]: ScaffolderRJSFField; +}; + +// @public +export interface ScaffolderScaffoldOptions { + // (undocumented) + secrets?: Record; + // (undocumented) + templateRef: string; + // (undocumented) + values: Record; +} + +// @public +export interface ScaffolderScaffoldResponse { + // (undocumented) + taskId: string; +} + +// @public +export type ScaffolderStep = { + id: string; + status: ScaffolderTaskStatus; + endedAt?: string; + startedAt?: string; +}; + +// @public +export interface ScaffolderStreamLogsOptions { + // (undocumented) + after?: number; + // (undocumented) + isTaskRecoverable?: boolean; + // (undocumented) + taskId: string; +} + +// @public +export type ScaffolderTask = { + id: string; + spec: TaskSpec; + status: 'failed' | 'completed' | 'processing' | 'open' | 'cancelled'; + lastHeartbeatAt: string; + createdAt: string; +}; + +// @public (undocumented) +export type ScaffolderTaskOutput = { + links?: ScaffolderOutputLink[]; + text?: ScaffolderOutputText[]; +} & { + [key: string]: unknown; +}; + +// @public +export type ScaffolderTaskStatus = + | 'cancelled' + | 'completed' + | 'failed' + | 'open' + | 'processing' + | 'skipped'; + +// @public +export interface ScaffolderUseTemplateSecrets { + // (undocumented) + secrets: Record; + // (undocumented) + setSecrets: (input: Record) => void; +} + +// @public +export const SecretsContextProvider: ( + props: PropsWithChildren<{ + initialSecrets?: Record; + }>, +) => React_2.JSX.Element; + +// @public +export type TaskStream = { + cancelled: boolean; + loading: boolean; + error?: Error; + stepLogs: { + [stepId in string]: string[]; + }; + completed: boolean; + task?: ScaffolderTask; + steps: { + [stepId in string]: ScaffolderStep; + }; + output?: ScaffolderTaskOutput; +}; + +// @public (undocumented) +export type TemplateGroupFilter = { + title?: React.ReactNode; + filter: (entity: TemplateEntityV1beta3) => boolean; +}; + +// @public +export type TemplateParameterSchema = { + title: string; + description?: string; + presentation?: TemplatePresentationV1beta3; + steps: Array<{ + title: string; + description?: string; + schema: JsonObject; + }>; + EXPERIMENTAL_formDecorators?: { + id: string; + input?: JsonObject; + }[]; +}; + +// @public +export const useCustomFieldExtensions: < + TComponentDataType = FieldExtensionOptions, +>( + outlet: React.ReactNode, +) => TComponentDataType[]; + +// @public +export const useCustomLayouts: >( + outlet: React.ReactNode, +) => TComponentDataType[]; + +// @public +export const useTaskEventStream: (taskId: string) => TaskStream; + +// @public +export const useTemplateSecrets: () => ScaffolderUseTemplateSecrets; + +// (No @packageDocumentation comment for this package) +``` From d48525c9f8bda08943c5e07909e9225116d275e7 Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Wed, 19 Mar 2025 08:41:50 +0100 Subject: [PATCH 31/52] chore: fix type inference with different ways to define functions Signed-off-by: benjdlambert --- plugins/scaffolder-backend/report.api.md | 2 +- .../src/ScaffolderPlugin.ts | 2 +- .../templating/filters/parseRepoUrl/index.ts | 2 +- .../templating/filters/projectSlug/index.ts | 2 +- .../scaffolder-backend/src/service/router.ts | 2 +- .../src/util/templating.test.ts | 4 +- .../scaffolder-backend/src/util/templating.ts | 17 +-- plugins/scaffolder-node/report-alpha.api.md | 108 +++++++----------- .../src/alpha/filters/createTemplateFilter.ts | 23 ++-- .../src/alpha/filters/types.ts | 46 +++----- .../src/alpha/globals/createTemplateGlobal.ts | 20 ++-- .../src/alpha/globals/types.ts | 35 +----- plugins/scaffolder-node/src/alpha/index.ts | 4 +- 13 files changed, 108 insertions(+), 159 deletions(-) diff --git a/plugins/scaffolder-backend/report.api.md b/plugins/scaffolder-backend/report.api.md index 37afe780a9..c3100d8259 100644 --- a/plugins/scaffolder-backend/report.api.md +++ b/plugins/scaffolder-backend/report.api.md @@ -529,7 +529,7 @@ export interface RouterOptions { // (undocumented) additionalTemplateFilters?: | Record - | CreatedTemplateFilter[]; + | CreatedTemplateFilter[]; // (undocumented) additionalTemplateGlobals?: | Record diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index 4882b3cb2e..9fe78c7119 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -82,7 +82,7 @@ export const scaffolderPlugin = createBackendPlugin({ }, }); - const additionalTemplateFilters: CreatedTemplateFilter[] = []; + const additionalTemplateFilters: CreatedTemplateFilter[] = []; const additionalTemplateGlobals: CreatedTemplateGlobal[] = []; env.registerExtensionPoint(scaffolderTemplatingExtensionPoint, { diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts index a726c140cf..1c65852bbb 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts @@ -46,5 +46,5 @@ export const createParseRepoUrl = (integrations: ScmIntegrations) => .describe('`RepoSpec`'), ), examples, - filter: (url: string) => parseRepoUrl(url, integrations), + filter: url => parseRepoUrl(url, integrations), }); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts index a833121423..05bb6d61cd 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts @@ -30,7 +30,7 @@ export const createProjectSlug = (integrations: ScmIntegrations) => z.string(), ), examples, - filter: (repoUrl: string) => { + filter: repoUrl => { const { owner, repo } = parseRepoUrl(repoUrl, integrations); return `${owner}/${repo}`; }, diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 1186e7d4f6..8258d8c36f 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -179,7 +179,7 @@ export interface RouterOptions { taskBroker?: TaskBroker; additionalTemplateFilters?: | Record - | CreatedTemplateFilter[]; + | CreatedTemplateFilter[]; additionalTemplateGlobals?: | Record | CreatedTemplateGlobal[]; diff --git a/plugins/scaffolder-backend/src/util/templating.test.ts b/plugins/scaffolder-backend/src/util/templating.test.ts index 51493f08a1..f32e94f95c 100644 --- a/plugins/scaffolder-backend/src/util/templating.test.ts +++ b/plugins/scaffolder-backend/src/util/templating.test.ts @@ -64,7 +64,7 @@ describe('templating utilities', () => { z.string().describe('separator').optional(), ) .returns(z.string()), - filter: (input: string, times: number, separator?: string) => + filter: (input, times, separator) => Array(times) .fill(input) .join(separator ?? ''), @@ -149,7 +149,7 @@ describe('templating utilities', () => { id: 'respond', schema: z => z.function().args(z.string().describe('prompt')).returns(z.string()), - fn: (prompt: string) => + fn: prompt => prompt === 'knock knock' ? "who's there?" : "nobody's home", }), ]; diff --git a/plugins/scaffolder-backend/src/util/templating.ts b/plugins/scaffolder-backend/src/util/templating.ts index 1f97e98b83..2607d5bef6 100644 --- a/plugins/scaffolder-backend/src/util/templating.ts +++ b/plugins/scaffolder-backend/src/util/templating.ts @@ -22,7 +22,7 @@ import { CreatedTemplateGlobal, CreatedTemplateGlobalFunction, CreatedTemplateGlobalValue, - TemplateGlobalFunctionSchema, + ZodFunctionSchema, } from '@backstage/plugin-scaffolder-node/alpha'; import { JsonValue } from '@backstage/types'; import { Schema } from 'jsonschema'; @@ -63,8 +63,12 @@ type ExportFilterSchema = { * Converts a Zod function schema to JSON schema */ function convertZodFunctionToJsonSchema( - t: ReturnType>, + t: ReturnType>, ): ExportFunctionSchema { + if (!('parameters' in t) || !('returnType' in t)) { + throw new Error('Invalid Zod function schema'); + } + const args = (t.parameters().items as ZodType[]).map( zt => zodToJsonSchema(zt) as Schema, ); @@ -142,7 +146,9 @@ export function extractFilterMetadata( if (filter.schema) { metadata.schema = convertToFilterSchema( - convertZodFunctionToJsonSchema(filter.schema(z)), + convertZodFunctionToJsonSchema( + filter.schema(z) as z.ZodFunction, + ), ); } @@ -167,10 +173,7 @@ export function extractFilterMetadata( */ function isGlobalFunction( global: CreatedTemplateGlobal, -): global is CreatedTemplateGlobalFunction< - TemplateGlobalFunctionSchema | undefined, - any -> { +): global is CreatedTemplateGlobalFunction { return 'fn' in global; } diff --git a/plugins/scaffolder-node/report-alpha.api.md b/plugins/scaffolder-node/report-alpha.api.md index 151af9ea37..6ff02c7ad0 100644 --- a/plugins/scaffolder-node/report-alpha.api.md +++ b/plugins/scaffolder-node/report-alpha.api.md @@ -29,56 +29,31 @@ export type AutocompleteHandler = ({ // @alpha (undocumented) export type CreatedTemplateFilter< - TSchema extends - | TemplateFilterSchema - | undefined - | unknown = unknown, - TFilterSchema extends TSchema extends TemplateFilterSchema - ? z.infer> - : TSchema extends unknown - ? unknown - : TemplateFilter = TSchema extends TemplateFilterSchema - ? z.infer> - : TSchema extends unknown - ? unknown - : TemplateFilter, + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, > = { id: string; description?: string; examples?: TemplateFilterExample[]; - schema?: TSchema; - filter: TFilterSchema; + schema?: ZodFunctionSchema; + filter: (...args: z.infer>) => z.infer; }; // @alpha (undocumented) export type CreatedTemplateGlobal = | CreatedTemplateGlobalValue - | CreatedTemplateGlobalFunction; + | CreatedTemplateGlobalFunction; // @alpha (undocumented) export type CreatedTemplateGlobalFunction< - TSchema extends - | TemplateGlobalFunctionSchema - | undefined - | unknown = unknown, - TFilterSchema extends TSchema extends TemplateGlobalFunctionSchema - ? z.infer> - : TSchema extends unknown - ? unknown - : Exclude< - TemplateGlobal, - JsonValue - > = TSchema extends TemplateGlobalFunctionSchema - ? z.infer> - : TSchema extends unknown - ? unknown - : Exclude, + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, > = { id: string; description?: string; examples?: TemplateGlobalFunctionExample[]; - schema?: TSchema; - fn: TFilterSchema; + schema?: ZodFunctionSchema; + fn: (...args: z.infer>) => z.infer; }; // @alpha (undocumented) @@ -90,23 +65,27 @@ export type CreatedTemplateGlobalValue = { // @alpha export const createTemplateFilter: < - TSchema extends TemplateFilterSchema | undefined, - TFilterSchema extends TSchema extends TemplateFilterSchema - ? z.infer> - : (arg: JsonValue, ...rest: JsonValue[]) => JsonValue | undefined, ->( - filter: CreatedTemplateFilter, -) => CreatedTemplateFilter; + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, +>(options: { + id: string; + description?: string; + examples?: TemplateFilterExample[]; + schema?: ZodFunctionSchema; + filter: (...args: z.infer>) => z.infer; +}) => CreatedTemplateFilter; // @alpha export const createTemplateGlobalFunction: < - TSchema extends TemplateGlobalFunctionSchema | undefined, - TFilterSchema extends TSchema extends TemplateGlobalFunctionSchema - ? z.infer> - : (...args: JsonValue[]) => JsonValue | undefined, ->( - fn: CreatedTemplateGlobalFunction, -) => CreatedTemplateGlobalFunction; + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, +>(options: { + id: string; + description?: string; + examples?: TemplateGlobalFunctionExample[]; + schema?: ZodFunctionSchema; + fn: (...args: z.infer>) => z.infer; +}) => CreatedTemplateGlobalFunction; // @alpha export const createTemplateGlobalValue: ( @@ -158,7 +137,7 @@ export interface ScaffolderTemplatingExtensionPoint { addTemplateFilters( filters: | Record - | CreatedTemplateFilter[], + | CreatedTemplateFilter[], ): void; // (undocumented) addTemplateGlobals( @@ -196,16 +175,6 @@ export type TemplateFilterExample = { notes?: string; }; -// @alpha (undocumented) -export type TemplateFilterSchema< - Args extends z.ZodTuple< - | [z.ZodType] - | [z.ZodType, ...(z.ZodType | z.ZodUnknown)[]], - z.ZodType | z.ZodUnknown | null - >, - Result extends z.ZodType | z.ZodUndefined, -> = (zod: typeof z) => z.ZodFunction; - // @public (undocumented) export type TemplateGlobal = | ((...args: JsonValue[]) => JsonValue | undefined) @@ -218,15 +187,6 @@ export type TemplateGlobalFunctionExample = { notes?: string; }; -// @alpha (undocumented) -export type TemplateGlobalFunctionSchema< - Args extends z.ZodTuple< - [] | [z.ZodType, ...(z.ZodType | z.ZodUnknown)[]], - z.ZodType | z.ZodUnknown | null - >, - Result extends z.ZodType | z.ZodUndefined, -> = (zod: typeof z) => z.ZodFunction; - // @alpha export interface WorkspaceProvider { // (undocumented) @@ -246,5 +206,17 @@ export interface WorkspaceProvider { }): Promise; } +// @alpha +export type ZodFunctionSchema< + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, +> = ( + zod: typeof z, +) => + | z.ZodFunction, TReturnType> + | z.ZodType< + (...args: z.infer>) => z.infer + >; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts b/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts index 219884b704..03fb7fd18e 100644 --- a/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts +++ b/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts @@ -14,8 +14,11 @@ * limitations under the License. */ -import { JsonValue } from '@backstage/types'; -import { CreatedTemplateFilter, TemplateFilterSchema } from './types'; +import { + CreatedTemplateFilter, + TemplateFilterExample, + ZodFunctionSchema, +} from './types'; import { z } from 'zod'; /** @@ -23,10 +26,12 @@ import { z } from 'zod'; * @alpha */ export const createTemplateFilter = < - TSchema extends TemplateFilterSchema | undefined, - TFilterSchema extends TSchema extends TemplateFilterSchema - ? z.infer> - : (arg: JsonValue, ...rest: JsonValue[]) => JsonValue | undefined, ->( - filter: CreatedTemplateFilter, -): CreatedTemplateFilter => filter; + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, +>(options: { + id: string; + description?: string; + examples?: TemplateFilterExample[]; + schema?: ZodFunctionSchema; + filter: (...args: z.infer>) => z.infer; +}): CreatedTemplateFilter => options; diff --git a/plugins/scaffolder-node/src/alpha/filters/types.ts b/plugins/scaffolder-node/src/alpha/filters/types.ts index 2f65baaefc..741d4e2ca7 100644 --- a/plugins/scaffolder-node/src/alpha/filters/types.ts +++ b/plugins/scaffolder-node/src/alpha/filters/types.ts @@ -14,21 +14,9 @@ * limitations under the License. */ import { z } from 'zod'; -import { TemplateFilter } from '../../types'; -import { JsonValue } from '@backstage/types'; export type { TemplateFilter } from '../../types'; -/** @alpha */ -export type TemplateFilterSchema< - Args extends z.ZodTuple< - | [z.ZodType] - | [z.ZodType, ...(z.ZodType | z.ZodUnknown)[]], - z.ZodType | z.ZodUnknown | null - >, - Result extends z.ZodType | z.ZodUndefined, -> = (zod: typeof z) => z.ZodFunction; - /** @alpha */ export type TemplateFilterExample = { description?: string; @@ -36,25 +24,29 @@ export type TemplateFilterExample = { notes?: string; }; +/** + * Type for template filter schema functions that supports both Zod function definition methods: + * @alpha + */ +export type ZodFunctionSchema< + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, +> = ( + zod: typeof z, +) => + | z.ZodFunction, TReturnType> + | z.ZodType< + (...args: z.infer>) => z.infer + >; + /** @alpha */ export type CreatedTemplateFilter< - TSchema extends - | TemplateFilterSchema - | undefined - | unknown = unknown, - TFilterSchema extends TSchema extends TemplateFilterSchema - ? z.infer> - : TSchema extends unknown - ? unknown - : TemplateFilter = TSchema extends TemplateFilterSchema - ? z.infer> - : TSchema extends unknown - ? unknown - : TemplateFilter, + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, > = { id: string; description?: string; examples?: TemplateFilterExample[]; - schema?: TSchema; - filter: TFilterSchema; + schema?: ZodFunctionSchema; + filter: (...args: z.infer>) => z.infer; }; diff --git a/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts b/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts index 2361a50964..a277363f3a 100644 --- a/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts +++ b/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts @@ -18,9 +18,9 @@ import { z } from 'zod'; import { CreatedTemplateGlobalFunction, CreatedTemplateGlobalValue, - TemplateGlobalFunctionSchema, + TemplateGlobalFunctionExample, } from './types'; -import { JsonValue } from '@backstage/types'; +import { ZodFunctionSchema } from '../filters'; /** * This function is used to create new template global values in type-safe manner. @@ -39,10 +39,12 @@ export const createTemplateGlobalValue = ( * @alpha */ export const createTemplateGlobalFunction = < - TSchema extends TemplateGlobalFunctionSchema | undefined, - TFilterSchema extends TSchema extends TemplateGlobalFunctionSchema - ? z.infer> - : (...args: JsonValue[]) => JsonValue | undefined, ->( - fn: CreatedTemplateGlobalFunction, -): CreatedTemplateGlobalFunction => fn; + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, +>(options: { + id: string; + description?: string; + examples?: TemplateGlobalFunctionExample[]; + schema?: ZodFunctionSchema; + fn: (...args: z.infer>) => z.infer; +}): CreatedTemplateGlobalFunction => options; diff --git a/plugins/scaffolder-node/src/alpha/globals/types.ts b/plugins/scaffolder-node/src/alpha/globals/types.ts index cbe74f1610..4754bcaa88 100644 --- a/plugins/scaffolder-node/src/alpha/globals/types.ts +++ b/plugins/scaffolder-node/src/alpha/globals/types.ts @@ -15,7 +15,7 @@ */ import { JsonValue } from '@backstage/types'; import { z } from 'zod'; -import { TemplateGlobal } from '../../types'; +import { ZodFunctionSchema } from '../filters/types'; export type { TemplateGlobal } from '../../types'; @@ -26,15 +26,6 @@ export type CreatedTemplateGlobalValue = { description?: string; }; -/** @alpha */ -export type TemplateGlobalFunctionSchema< - Args extends z.ZodTuple< - [] | [z.ZodType, ...(z.ZodType | z.ZodUnknown)[]], - z.ZodType | z.ZodUnknown | null - >, - Result extends z.ZodType | z.ZodUndefined, -> = (zod: typeof z) => z.ZodFunction; - /** @alpha */ export type TemplateGlobalFunctionExample = { description?: string; @@ -44,31 +35,17 @@ export type TemplateGlobalFunctionExample = { /** @alpha */ export type CreatedTemplateGlobalFunction< - TSchema extends - | TemplateGlobalFunctionSchema - | undefined - | unknown = unknown, - TFilterSchema extends TSchema extends TemplateGlobalFunctionSchema - ? z.infer> - : TSchema extends unknown - ? unknown - : Exclude< - TemplateGlobal, - JsonValue - > = TSchema extends TemplateGlobalFunctionSchema - ? z.infer> - : TSchema extends unknown - ? unknown - : Exclude, + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, > = { id: string; description?: string; examples?: TemplateGlobalFunctionExample[]; - schema?: TSchema; - fn: TFilterSchema; + schema?: ZodFunctionSchema; + fn: (...args: z.infer>) => z.infer; }; /** @alpha */ export type CreatedTemplateGlobal = | CreatedTemplateGlobalValue - | CreatedTemplateGlobalFunction; + | CreatedTemplateGlobalFunction; diff --git a/plugins/scaffolder-node/src/alpha/index.ts b/plugins/scaffolder-node/src/alpha/index.ts index 1fd5abee18..eb97447a5c 100644 --- a/plugins/scaffolder-node/src/alpha/index.ts +++ b/plugins/scaffolder-node/src/alpha/index.ts @@ -73,9 +73,7 @@ export const scaffolderTaskBrokerExtensionPoint = */ export interface ScaffolderTemplatingExtensionPoint { addTemplateFilters( - filters: - | Record - | CreatedTemplateFilter[], + filters: Record | CreatedTemplateFilter[], ): void; addTemplateGlobals( From 726734002914bbf2486d6f275d3a228adb38924e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 19 Mar 2025 16:04:40 +0100 Subject: [PATCH 32/52] Update docs/backend-system/core-services/auditor.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- docs/backend-system/core-services/auditor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-system/core-services/auditor.md b/docs/backend-system/core-services/auditor.md index 53242500ae..4daaa8d0bb 100644 --- a/docs/backend-system/core-services/auditor.md +++ b/docs/backend-system/core-services/auditor.md @@ -99,7 +99,7 @@ The following table details common keys found within the `meta` object of audit | `queryType` | Specifies the type of query performed when fetching data. | A kebab-case string | `all`, `by-id`, `by-name`, `by-query`, `by-refs`, `ancestry`, `by-entity` | | `actionType` | Specifies the type of action performed when modifying data. | A kebab-case string | `create`, `delete`, `refresh` | | `entityRef` | The full reference of an entity, including kind, namespace, and name. | `[kind]:[namespace]/[name]` | `component:default/my-component`, `group:my-org/team-a` | -| `locationRef` | A specific reference to a location being operated on. | Any string representing the location. | `Url:https://example.com/catalog-info.yaml`, `custom:default/my-location` | +| `locationRef` | A specific reference to a location being operated on. | Any string representing the location. | `url:https://example.com/catalog-info.yaml`, `custom:default/my-location` | | `uid` | The unique identifier of a location or other object involved in the operation. | Any valid unique ID string | `9a4e740b-e557-427f-b9f2-0d4f092b1c1e` | By following these conventions, you create a more structured and informative audit trail that is easier to search, filter, and understand. This allows you to better group and understand the events being logged. From b9e82880947d17c0425330ffef0824e5444719c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Wed, 19 Mar 2025 16:04:50 +0100 Subject: [PATCH 33/52] Update docs/backend-system/core-services/auditor.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- docs/backend-system/core-services/auditor.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/backend-system/core-services/auditor.md b/docs/backend-system/core-services/auditor.md index 4daaa8d0bb..43e789a70f 100644 --- a/docs/backend-system/core-services/auditor.md +++ b/docs/backend-system/core-services/auditor.md @@ -131,7 +131,8 @@ For an operation that deletes an entity, a typical audit event would look like t "eventId": "entity-mutate", "meta": { "actionType": "delete", - "uid": "some-entity-uid" + "uid": "some-entity-uid", + "entityRef": "component:default/petstore" }, "severityLevel": "medium" ... From 418ebe19eac9b5365519bea360051133c1dc5847 Mon Sep 17 00:00:00 2001 From: Andre Wanlin Date: Wed, 19 Mar 2025 12:54:34 -0500 Subject: [PATCH 34/52] Adjust Deploy Microsite Clean Command Signed-off-by: Andre Wanlin --- .github/workflows/deploy_microsite.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index ea9b6c2e06..ea0a433fe0 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -235,7 +235,7 @@ jobs: run: rm -r docs/reference - name: clear OpenAPI reference - run: find . -name '*.api.mdx' -delete + run: find . -name '*.api.mdx' -type f -delete # Next docs - name: checkout master From b8f40b020ea1e6e06830a427b6a0687e96d73cb9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 20:52:12 +0000 Subject: [PATCH 35/52] Update react monorepo Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index e5471a78c8..9712288d32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20220,12 +20220,12 @@ __metadata: linkType: hard "@types/react@npm:^18.0.0": - version: 18.3.18 - resolution: "@types/react@npm:18.3.18" + version: 18.3.19 + resolution: "@types/react@npm:18.3.19" dependencies: "@types/prop-types": "*" csstype: ^3.0.2 - checksum: 5933597bc9f53e282f0438f0bb76d0f0fab60faabe760ea806e05ffe6f5c61b9b4d363e1a03a8fea47c510d493c6cf926cdeeba9f7074fa97b61940c350245e7 + checksum: 41305614686cfc618ef154f06d3f80e7b2df4673ebbc474880c524ecbbaa48f14620b3b1c6cff9f225176932d362c62fe617020027069157cb040752902c35cb languageName: node linkType: hard From db78baef26c950f86e79d31c5d03435ae5853478 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Mar 2025 13:39:43 +0100 Subject: [PATCH 36/52] cli: repo lint pass --max-warnings option Signed-off-by: Vincenzo Scamporlino --- packages/cli/src/modules/lint/alpha.ts | 4 ++++ packages/cli/src/modules/lint/commands/repo/lint.ts | 4 ++-- packages/cli/src/modules/lint/index.ts | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/modules/lint/alpha.ts b/packages/cli/src/modules/lint/alpha.ts index 8703e73b5e..c7b9ab66ed 100644 --- a/packages/cli/src/modules/lint/alpha.ts +++ b/packages/cli/src/modules/lint/alpha.ts @@ -76,6 +76,10 @@ export default createCliPlugin({ '--since ', 'Only lint packages that changed since the specified ref', ); + command.option( + '--max-warnings ', + 'Fail if more than this number of warnings. -1 allows warnings. (default: 0)', + ); command.description('Lint a repository'); command.action(lazy(() => import('./commands/repo/lint'), 'command')); diff --git a/packages/cli/src/modules/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index 15a3584020..246324785e 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -111,6 +111,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { fix: Boolean(opts.fix), format: opts.format as string | undefined, shouldCache: Boolean(cacheContext), + maxWarnings: Number(opts.maxWarnings) || 0, successCache: cacheContext?.entries, rootDir: paths.targetRoot, }, @@ -120,6 +121,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { shouldCache, successCache, rootDir, + maxWarnings, }) => { const { ESLint } = require('eslint') as typeof import('eslint'); const crypto = require('crypto') as typeof import('crypto'); @@ -131,7 +133,6 @@ export async function command(opts: OptionValues, cmd: Command): Promise { return async ({ fullDir, relativeDir, - lintOptions, parentHash, }): Promise<{ relativeDir: string; @@ -199,7 +200,6 @@ export async function command(opts: OptionValues, cmd: Command): Promise { await ESLint.outputFixes(results); } - const maxWarnings = lintOptions?.maxWarnings ?? 0; const ignoreWarnings = +maxWarnings === -1; const resultText = formatter.format(results) as string; diff --git a/packages/cli/src/modules/lint/index.ts b/packages/cli/src/modules/lint/index.ts index e2bfcd0779..5be76d8928 100644 --- a/packages/cli/src/modules/lint/index.ts +++ b/packages/cli/src/modules/lint/index.ts @@ -62,6 +62,10 @@ export function registerRepoCommands(command: Command) { '--successCacheDir ', 'Set the success cache location, (default: node_modules/.cache/backstage-cli)', ) + .option( + '--max-warnings ', + 'Fail if more than this number of warnings. -1 allows warnings. (default: 0)', + ) .option('--fix', 'Attempt to automatically fix violations') .action(lazy(() => import('./commands/repo/lint'), 'command')); } From 87a5cb49c8b07610c5460a3a56e0c78a590d8b0f Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Mar 2025 13:41:14 +0100 Subject: [PATCH 37/52] cli: changesets Signed-off-by: Vincenzo Scamporlino --- .changeset/every-ties-wink.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/every-ties-wink.md diff --git a/.changeset/every-ties-wink.md b/.changeset/every-ties-wink.md new file mode 100644 index 0000000000..31eff3fb9a --- /dev/null +++ b/.changeset/every-ties-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fixed an issue causing the `repo lint` command to fail when the `--max-warnings` option was used. From d7419c92bd121e254b349245005b1de270e99fe2 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Mar 2025 16:29:35 +0100 Subject: [PATCH 38/52] cli: update api-reports Signed-off-by: Vincenzo Scamporlino --- packages/cli/cli-report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 32918caad2..3dfacbd3f3 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -452,6 +452,7 @@ Options: --since --successCache --successCacheDir + --max-warnings --fix -h, --help ``` From 4e9da9de010fb595e170cb5cfd6901d7857a38f1 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Mar 2025 17:02:51 +0100 Subject: [PATCH 39/52] cli: allow multiple --require Signed-off-by: Vincenzo Scamporlino --- packages/cli/src/commands/index.ts | 5 ++++- packages/cli/src/lib/runner/runBackend.ts | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 9a76711d08..969fba7c25 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -86,7 +86,10 @@ export function registerScriptCommand(program: Command) { '--inspect-brk [host]', 'Enable debugger in Node.js environments, breaking before code starts', ) - .option('--require ', 'Add a --require argument to the node process') + .option( + '--require ', + 'Add a --require argument to the node process', + ) .option('--link ', 'Link an external workspace for module resolution') .action(lazy(() => import('./start'), 'command')); diff --git a/packages/cli/src/lib/runner/runBackend.ts b/packages/cli/src/lib/runner/runBackend.ts index fb8fdd9d55..c085e183f1 100644 --- a/packages/cli/src/lib/runner/runBackend.ts +++ b/packages/cli/src/lib/runner/runBackend.ts @@ -39,7 +39,7 @@ export type RunBackendOptions = { /** Whether to forward the --inspect-brk flag to the node process */ inspectBrkEnabled: boolean; /** Additional module to require via the --require flag to the node process */ - require?: string; + require?: string | string[]; /** An external linked workspace to override module resolution towards */ linkedWorkspace?: string; }; @@ -107,7 +107,10 @@ export async function runBackend(options: RunBackendOptions) { optionArgs.push(inspect); } if (options.require) { - optionArgs.push(`--require=${options.require}`); + const requires = [options.require].flat(); + for (const r of requires) { + optionArgs.push(`--require=${r}`); + } } const userArgs = process.argv From d83f3f461c48ea227cfbb9f30369bd4cdcd92835 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Mar 2025 17:05:13 +0100 Subject: [PATCH 40/52] cli: --require changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/thin-snails-judge.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/thin-snails-judge.md diff --git a/.changeset/thin-snails-judge.md b/.changeset/thin-snails-judge.md new file mode 100644 index 0000000000..c2328ed64f --- /dev/null +++ b/.changeset/thin-snails-judge.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Resolved a problem where the `start` command did not correctly handle multiple `--require` flags, ensuring all specified modules are now properly loaded. From 71665b739cb7780de1196953e8da063bfb494f1c Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 20 Mar 2025 17:08:30 +0100 Subject: [PATCH 41/52] cli: api-reports --require option Signed-off-by: Vincenzo Scamporlino --- packages/cli/cli-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 32918caad2..3c2e01a08e 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -272,7 +272,7 @@ Options: --check --inspect [host] --inspect-brk [host] - --require + --require --link -h, --help ``` From efe88dfa42853f05ea3fbb793dffd67ee4ae3c29 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 21 Mar 2025 08:53:24 +0100 Subject: [PATCH 42/52] cli: update usage docs Signed-off-by: Vincenzo Scamporlino --- packages/cli/src/modules/lint/alpha.ts | 4 ++-- packages/cli/src/modules/lint/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/modules/lint/alpha.ts b/packages/cli/src/modules/lint/alpha.ts index c7b9ab66ed..617f71d5c9 100644 --- a/packages/cli/src/modules/lint/alpha.ts +++ b/packages/cli/src/modules/lint/alpha.ts @@ -38,7 +38,7 @@ export default createCliPlugin({ ); command.option( '--max-warnings ', - 'Fail if more than this number of warnings. -1 allows warnings. (default: 0)', + 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', ); command.description('Lint a package'); command.action( @@ -78,7 +78,7 @@ export default createCliPlugin({ ); command.option( '--max-warnings ', - 'Fail if more than this number of warnings. -1 allows warnings. (default: 0)', + 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', ); command.description('Lint a repository'); command.action(lazy(() => import('./commands/repo/lint'), 'command')); diff --git a/packages/cli/src/modules/lint/index.ts b/packages/cli/src/modules/lint/index.ts index 5be76d8928..dfa0916efb 100644 --- a/packages/cli/src/modules/lint/index.ts +++ b/packages/cli/src/modules/lint/index.ts @@ -31,7 +31,7 @@ export function registerPackageCommands(command: Command) { .option('--fix', 'Attempt to automatically fix violations') .option( '--max-warnings ', - 'Fail if more than this number of warnings. -1 allows warnings. (default: 0)', + 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', ) .description('Lint a package') .action(lazy(() => import('./commands/package/lint'), 'default')); @@ -64,7 +64,7 @@ export function registerRepoCommands(command: Command) { ) .option( '--max-warnings ', - 'Fail if more than this number of warnings. -1 allows warnings. (default: 0)', + 'Fail if more than this number of warnings. -1 allows warnings. (default: -1)', ) .option('--fix', 'Attempt to automatically fix violations') .action(lazy(() => import('./commands/repo/lint'), 'command')); From 69607e580d3e6abed33e800b5b43a7d43637c153 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 21 Mar 2025 09:00:45 +0100 Subject: [PATCH 43/52] cli: fix max-warnings default Signed-off-by: Vincenzo Scamporlino --- packages/cli/src/modules/lint/commands/repo/lint.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/modules/lint/commands/repo/lint.ts b/packages/cli/src/modules/lint/commands/repo/lint.ts index 246324785e..ab6597c70a 100644 --- a/packages/cli/src/modules/lint/commands/repo/lint.ts +++ b/packages/cli/src/modules/lint/commands/repo/lint.ts @@ -111,7 +111,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { fix: Boolean(opts.fix), format: opts.format as string | undefined, shouldCache: Boolean(cacheContext), - maxWarnings: Number(opts.maxWarnings) || 0, + maxWarnings: opts.maxWarnings ?? -1, successCache: cacheContext?.entries, rootDir: paths.targetRoot, }, From 3cfc7f06d17f04e5d9916b3154857aa3a55a71c3 Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Fri, 21 Mar 2025 11:07:00 +0100 Subject: [PATCH 44/52] feat: small refactor to move some logic out of the index files and move to using `.args()` and `.returns()` as it's cleaner Signed-off-by: benjdlambert --- .../{index.ts => createDefaultFilters.ts} | 0 .../filters/parseEntityRef/examples.ts | 4 +- .../filters/parseEntityRef/filter.ts | 63 +++++++++++++++++++ .../filters/parseEntityRef/index.ts | 47 +------------- .../templating/filters/parseRepoUrl/filter.ts | 52 +++++++++++++++ .../templating/filters/parseRepoUrl/index.ts | 36 +---------- .../src/lib/templating/filters/pick/filter.ts | 31 +++++++++ .../src/lib/templating/filters/pick/index.ts | 17 +---- .../templating/filters/projectSlug/filter.ts | 37 +++++++++++ .../templating/filters/projectSlug/index.ts | 23 +------ .../actions/builtin/fetch/template.ts | 2 +- .../actions/builtin/fetch/templateFile.ts | 2 +- .../tasks/NunjucksWorkflowRunner.ts | 2 +- .../src/util/templating.test.ts | 2 +- plugins/scaffolder-node/report-alpha.api.md | 2 +- .../src/alpha/filters/createTemplateFilter.ts | 7 +-- .../src/alpha/filters/types.ts | 16 +---- .../src/alpha/globals/createTemplateGlobal.ts | 2 +- .../src/alpha/globals/types.ts | 2 +- plugins/scaffolder-node/src/alpha/index.ts | 1 + plugins/scaffolder-node/src/alpha/types.ts | 30 +++++++++ 21 files changed, 230 insertions(+), 148 deletions(-) rename plugins/scaffolder-backend/src/lib/templating/filters/{index.ts => createDefaultFilters.ts} (100%) create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/filter.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/filter.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/pick/filter.ts create mode 100644 plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/filter.ts create mode 100644 plugins/scaffolder-node/src/alpha/types.ts diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/createDefaultFilters.ts similarity index 100% rename from plugins/scaffolder-backend/src/lib/templating/filters/index.ts rename to plugins/scaffolder-backend/src/lib/templating/filters/createDefaultFilters.ts diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts index fd6219c998..aef5b451bb 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/examples.ts @@ -1,5 +1,3 @@ -import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; - /* * Copyright 2025 The Backstage Authors * @@ -15,6 +13,8 @@ import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; * See the License for the specific language governing permissions and * limitations under the License. */ +import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; + export const examples: TemplateFilterExample[] = [ { description: 'Without context', diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/filter.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/filter.ts new file mode 100644 index 0000000000..23ce340370 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/filter.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2025 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 { parseEntityRef as filter } from '@backstage/catalog-model'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const parseEntityRef = createTemplateFilter({ + id: 'parseEntityRef', + description: + 'Extracts the parts of an entity reference, such as the kind, namespace, and name.', + schema: z => + z + .function() + .args( + z.union([ + z.string().describe('compact entity reference'), + z + .object({ + kind: z.string().optional(), + namespace: z.string().optional(), + name: z.string(), + }) + .describe('`CompoundEntityRef`'), + ]), + z + .object({ + defaultKind: z + .string() + .describe('The default kind, if none is given in the reference'), + defaultNamespace: z + .string() + .describe( + 'The default namespace, if none is given in the reference', + ), + }) + .partial() + .optional(), + ) + .returns( + z + .object({ + kind: z.string(), + namespace: z.string(), + name: z.string(), + }) + .describe('`CompoundEntityRef`'), + ), + examples, + filter, +}); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts index 221be44055..b11d925161 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseEntityRef/index.ts @@ -13,49 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { parseEntityRef as filter } from '@backstage/catalog-model'; -import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; -import { examples } from './examples'; - -export const parseEntityRef = createTemplateFilter({ - id: 'parseEntityRef', - description: - 'Extracts the parts of an entity reference, such as the kind, namespace, and name.', - schema: z => - z.function( - z.tuple([ - z.union([ - z.string().describe('compact entity reference'), - z - .object({ - kind: z.string().optional(), - namespace: z.string().optional(), - name: z.string(), - }) - .describe('`CompoundEntityRef`'), - ]), - z - .object({ - defaultKind: z - .string() - .describe('The default kind, if none is given in the reference'), - defaultNamespace: z - .string() - .describe( - 'The default namespace, if none is given in the reference', - ), - }) - .partial() - .optional(), - ]), - z - .object({ - kind: z.string(), - namespace: z.string(), - name: z.string(), - }) - .describe('`CompoundEntityRef`'), - ), - examples, - filter, -}); +export { parseEntityRef } from './filter'; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/filter.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/filter.ts new file mode 100644 index 0000000000..8a7daea3bc --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/filter.ts @@ -0,0 +1,52 @@ +/* + * Copyright 2025 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 { ScmIntegrations } from '@backstage/integration'; +import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const createParseRepoUrl = (integrations: ScmIntegrations) => + createTemplateFilter({ + id: 'parseRepoUrl', + description: + 'Parses a repository URL into its constituent parts: owner, repository name, etc.', + schema: z => + z + .function() + .args( + z.string().describe('repo URL as collected from repository picker'), + ) + .returns( + z + .object({ + repo: z.string(), + host: z.string(), + }) + .merge( + z + .object({ + owner: z.string(), + organization: z.string(), + workspace: z.string(), + project: z.string(), + }) + .partial(), + ) + .describe('`RepoSpec`'), + ), + examples, + filter: url => parseRepoUrl(url, integrations), + }); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts index 1c65852bbb..ed505315b5 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/parseRepoUrl/index.ts @@ -13,38 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ScmIntegrations } from '@backstage/integration'; -import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; -import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; -import { examples } from './examples'; - -export const createParseRepoUrl = (integrations: ScmIntegrations) => - createTemplateFilter({ - id: 'parseRepoUrl', - description: - 'Parses a repository URL into its constituent parts: owner, repository name, etc.', - schema: z => - z.function( - z.tuple([ - z.string().describe('repo URL as collected from repository picker'), - ]), - z - .object({ - repo: z.string(), - host: z.string(), - }) - .merge( - z - .object({ - owner: z.string(), - organization: z.string(), - workspace: z.string(), - project: z.string(), - }) - .partial(), - ) - .describe('`RepoSpec`'), - ), - examples, - filter: url => parseRepoUrl(url, integrations), - }); +export { createParseRepoUrl } from './filter'; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/pick/filter.ts b/plugins/scaffolder-backend/src/lib/templating/filters/pick/filter.ts new file mode 100644 index 0000000000..a38855becc --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/pick/filter.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2025 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 { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { get as filter } from 'lodash'; +import { examples } from './examples'; + +export const pick = createTemplateFilter({ + id: 'pick', + description: + 'Selects a specific property (e.g. kind, namespace, name) from an object.', + schema: z => + z + .function() + .args(z.any(), z.string().describe('Property')) + .returns(z.any().describe('Selected property')), + examples, + filter, +}); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts index 5d8a0d664a..b3ca69bc38 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/pick/index.ts @@ -13,19 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; -import { get as filter } from 'lodash'; -import { examples } from './examples'; - -export const pick = createTemplateFilter({ - id: 'pick', - description: - 'Selects a specific property (e.g. kind, namespace, name) from an object.', - schema: z => - z.function( - z.tuple([z.any(), z.string().describe('Property')]), - z.any().describe('Selected property'), - ), - examples, - filter, -}); +export { pick } from './filter'; diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/filter.ts b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/filter.ts new file mode 100644 index 0000000000..f6d0eaf681 --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/filter.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2025 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 { ScmIntegrations } from '@backstage/integration'; +import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; +import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; +import { examples } from './examples'; + +export const createProjectSlug = (integrations: ScmIntegrations) => + createTemplateFilter({ + id: 'projectSlug', + description: 'Generates a project slug from a repository URL.', + schema: z => + z + .function() + .args( + z.string().describe('repo URL as collected from repository picker'), + ) + .returns(z.string()), + examples, + filter: repoUrl => { + const { owner, repo } = parseRepoUrl(repoUrl, integrations); + return `${owner}/${repo}`; + }, + }); diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts index 05bb6d61cd..71a092232c 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/index.ts @@ -13,25 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ScmIntegrations } from '@backstage/integration'; -import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; -import { createTemplateFilter } from '@backstage/plugin-scaffolder-node/alpha'; -import { examples } from './examples'; - -export const createProjectSlug = (integrations: ScmIntegrations) => - createTemplateFilter({ - id: 'projectSlug', - description: 'Generates a project slug from a repository URL.', - schema: z => - z.function( - z.tuple([ - z.string().describe('repo URL as collected from repository picker'), - ]), - z.string(), - ), - examples, - filter: repoUrl => { - const { owner, repo } = parseRepoUrl(repoUrl, integrations); - return `${owner}/${repo}`; - }, - }); +export { createProjectSlug } from './filter'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts index 2e036abc19..8dfa26057b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts @@ -29,7 +29,7 @@ import globby from 'globby'; import fs from 'fs-extra'; import { isBinaryFile } from 'isbinaryfile'; import { SecureTemplater } from '../../../../lib/templating/SecureTemplater'; -import { createDefaultFilters } from '../../../../lib/templating/filters'; +import { createDefaultFilters } from '../../../../lib/templating/filters/createDefaultFilters'; import { examples } from './template.examples'; import { convertFiltersToRecord } from '../../../../util/templating'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts index 9353f5e8d2..2cd4ce883c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/templateFile.ts @@ -25,7 +25,7 @@ import { TemplateGlobal, } from '@backstage/plugin-scaffolder-node'; import { SecureTemplater } from '../../../../lib/templating/SecureTemplater'; -import { createDefaultFilters } from '../../../../lib/templating/filters'; +import { createDefaultFilters } from '../../../../lib/templating/filters/createDefaultFilters'; import path from 'path'; import fs from 'fs-extra'; import { convertFiltersToRecord } from '../../../../util/templating'; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index e918511354..c352714d9d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -55,7 +55,7 @@ import { TemplateFilter, TemplateGlobal, } from '@backstage/plugin-scaffolder-node'; -import { createDefaultFilters } from '../../lib/templating/filters'; +import { createDefaultFilters } from '../../lib/templating/filters/createDefaultFilters'; import { scaffolderActionRules } from '../../service/rules'; import { createCounterMetric, createHistogramMetric } from '../../util/metrics'; import { BackstageLoggerTransport, WinstonLogger } from './logger'; diff --git a/plugins/scaffolder-backend/src/util/templating.test.ts b/plugins/scaffolder-backend/src/util/templating.test.ts index f32e94f95c..61d8637016 100644 --- a/plugins/scaffolder-backend/src/util/templating.test.ts +++ b/plugins/scaffolder-backend/src/util/templating.test.ts @@ -28,7 +28,7 @@ import { extractGlobalValueMetadata, } from './templating'; import { JsonValue } from '@backstage/types'; -import { createDefaultFilters } from '../lib/templating/filters'; +import { createDefaultFilters } from '../lib/templating/filters/createDefaultFilters'; import { ScmIntegrations } from '@backstage/integration'; import { ConfigReader } from '@backstage/config'; diff --git a/plugins/scaffolder-node/report-alpha.api.md b/plugins/scaffolder-node/report-alpha.api.md index 6ff02c7ad0..a96f312d2d 100644 --- a/plugins/scaffolder-node/report-alpha.api.md +++ b/plugins/scaffolder-node/report-alpha.api.md @@ -206,7 +206,7 @@ export interface WorkspaceProvider { }): Promise; } -// @alpha +// @alpha (undocumented) export type ZodFunctionSchema< TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], TReturnType extends z.ZodTypeAny, diff --git a/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts b/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts index 03fb7fd18e..f648658588 100644 --- a/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts +++ b/plugins/scaffolder-node/src/alpha/filters/createTemplateFilter.ts @@ -14,11 +14,8 @@ * limitations under the License. */ -import { - CreatedTemplateFilter, - TemplateFilterExample, - ZodFunctionSchema, -} from './types'; +import { ZodFunctionSchema } from '../types'; +import { CreatedTemplateFilter, TemplateFilterExample } from './types'; import { z } from 'zod'; /** diff --git a/plugins/scaffolder-node/src/alpha/filters/types.ts b/plugins/scaffolder-node/src/alpha/filters/types.ts index 741d4e2ca7..1906ba1c9c 100644 --- a/plugins/scaffolder-node/src/alpha/filters/types.ts +++ b/plugins/scaffolder-node/src/alpha/filters/types.ts @@ -14,6 +14,7 @@ * limitations under the License. */ import { z } from 'zod'; +import { ZodFunctionSchema } from '../types'; export type { TemplateFilter } from '../../types'; @@ -24,21 +25,6 @@ export type TemplateFilterExample = { notes?: string; }; -/** - * Type for template filter schema functions that supports both Zod function definition methods: - * @alpha - */ -export type ZodFunctionSchema< - TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], - TReturnType extends z.ZodTypeAny, -> = ( - zod: typeof z, -) => - | z.ZodFunction, TReturnType> - | z.ZodType< - (...args: z.infer>) => z.infer - >; - /** @alpha */ export type CreatedTemplateFilter< TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], diff --git a/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts b/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts index a277363f3a..2687b83bb4 100644 --- a/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts +++ b/plugins/scaffolder-node/src/alpha/globals/createTemplateGlobal.ts @@ -20,7 +20,7 @@ import { CreatedTemplateGlobalValue, TemplateGlobalFunctionExample, } from './types'; -import { ZodFunctionSchema } from '../filters'; +import { ZodFunctionSchema } from '../types'; /** * This function is used to create new template global values in type-safe manner. diff --git a/plugins/scaffolder-node/src/alpha/globals/types.ts b/plugins/scaffolder-node/src/alpha/globals/types.ts index 4754bcaa88..27a3a700e5 100644 --- a/plugins/scaffolder-node/src/alpha/globals/types.ts +++ b/plugins/scaffolder-node/src/alpha/globals/types.ts @@ -15,7 +15,7 @@ */ import { JsonValue } from '@backstage/types'; import { z } from 'zod'; -import { ZodFunctionSchema } from '../filters/types'; +import { ZodFunctionSchema } from '../types'; export type { TemplateGlobal } from '../../types'; diff --git a/plugins/scaffolder-node/src/alpha/index.ts b/plugins/scaffolder-node/src/alpha/index.ts index eb97447a5c..9df968a52d 100644 --- a/plugins/scaffolder-node/src/alpha/index.ts +++ b/plugins/scaffolder-node/src/alpha/index.ts @@ -27,6 +27,7 @@ import { CreatedTemplateGlobal } from './globals'; export * from '../tasks/alpha'; export * from './filters'; export * from './globals'; +export * from './types'; /** * Extension point for managing scaffolder actions. diff --git a/plugins/scaffolder-node/src/alpha/types.ts b/plugins/scaffolder-node/src/alpha/types.ts new file mode 100644 index 0000000000..ca52973775 --- /dev/null +++ b/plugins/scaffolder-node/src/alpha/types.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2025 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 { z } from 'zod'; + +/** + * @alpha + */ +export type ZodFunctionSchema< + TFunctionArgs extends [z.ZodTypeAny, ...z.ZodTypeAny[]], + TReturnType extends z.ZodTypeAny, +> = ( + zod: typeof z, +) => + | z.ZodFunction, TReturnType> + | z.ZodType< + (...args: z.infer>) => z.infer + >; From 95b352ebaccf53883f3b4cb6625546787315ef0d Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Fri, 21 Mar 2025 11:08:53 +0100 Subject: [PATCH 45/52] chore: update changeset Signed-off-by: benjdlambert Signed-off-by: benjdlambert --- .changeset/odd-bobcats-hang.md | 3 ++- .../src/lib/templating/filters/projectSlug/examples.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.changeset/odd-bobcats-hang.md b/.changeset/odd-bobcats-hang.md index a7c0d59754..9b3aeccffc 100644 --- a/.changeset/odd-bobcats-hang.md +++ b/.changeset/odd-bobcats-hang.md @@ -1,5 +1,6 @@ --- '@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder-node': patch --- -document built-in template filters +Document the internal built-in filters, and ensure that the types are validated when using `createTemplateFilter` and `createTemplateGlobalFunction` from the `zod` schema. diff --git a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/examples.ts b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/examples.ts index dde36ea888..2d668baee4 100644 --- a/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/examples.ts +++ b/plugins/scaffolder-backend/src/lib/templating/filters/projectSlug/examples.ts @@ -1,5 +1,3 @@ -import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; - /* * Copyright 2025 The Backstage Authors * @@ -15,6 +13,8 @@ import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; * See the License for the specific language governing permissions and * limitations under the License. */ +import { TemplateFilterExample } from '@backstage/plugin-scaffolder-node/alpha'; + export const examples: TemplateFilterExample[] = [ { example: `\ From 221ddbad86ba04f3813c5e0208d632d51497a155 Mon Sep 17 00:00:00 2001 From: Hellgren Heikki Date: Fri, 21 Mar 2025 12:37:25 +0200 Subject: [PATCH 46/52] fix(catalog): reset offset on filter change in useEntityList Signed-off-by: Hellgren Heikki --- .changeset/twenty-forks-cheat.md | 5 +++++ .../src/hooks/useEntityListProvider.test.tsx | 5 ++++- .../catalog-react/src/hooks/useEntityListProvider.tsx | 9 +++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 .changeset/twenty-forks-cheat.md diff --git a/.changeset/twenty-forks-cheat.md b/.changeset/twenty-forks-cheat.md new file mode 100644 index 0000000000..c0a7f03ee8 --- /dev/null +++ b/.changeset/twenty-forks-cheat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fix offset pagination to reset when updating filters in `useEntityList` diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index 2a922cf417..35e34b4063 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -23,7 +23,7 @@ import { identityApiRef, storageApiRef, } from '@backstage/core-plugin-api'; -import { TestApiProvider, mockApis } from '@backstage/test-utils'; +import { mockApis, TestApiProvider } from '@backstage/test-utils'; import { act, renderHook, waitFor } from '@testing-library/react'; import qs from 'qs'; import React, { PropsWithChildren } from 'react'; @@ -593,6 +593,7 @@ describe(``, () => { expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ filter: { kind: 'component' }, limit, + offset: 0, orderFields, fullTextFilter: { term: '2', @@ -620,6 +621,7 @@ describe(``, () => { expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith({ filter: { kind: 'component' }, limit, + offset: 0, orderFields, }); }); @@ -746,6 +748,7 @@ describe(``, () => { expect(mockCatalogApi.queryEntities).toHaveBeenNthCalledWith(2, { filter: { kind: 'api', 'spec.type': ['service'] }, limit, + offset: 0, orderFields, }); }); diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index fc2dfe6a73..e3ca95cebb 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -379,14 +379,19 @@ export const EntityListProvider = ( // TODO(vinzscam): this is currently causing issues at page reload // where the state is not kept. Unfortunately we need to rethink // the way filters work in order to fix this. - setCursor(undefined); + if (paginationMode === 'cursor') { + setCursor(undefined); + } else if (paginationMode === 'offset') { + // Same thing with offset + setOffset(0); + } setRequestedFilters(prevFilters => { const newFilters = typeof update === 'function' ? update(prevFilters) : update; return { ...prevFilters, ...newFilters }; }); }, - [], + [paginationMode], ); const pageInfo = useMemo(() => { From 8d8a101b510f4ee0caf8d895d66e4cb3e8f6fc34 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 13:38:12 +0000 Subject: [PATCH 47/52] chore(deps): update actions/download-artifact digest to 95815c3 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/deploy_microsite.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index ea0a433fe0..cf86b33ab1 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -211,13 +211,13 @@ jobs: working-directory: microsite - name: download stable reference - uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: stable-reference path: docs/reference - name: download stable OpenAPI API docs - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: stable-openapi-docs path: docs/**/*.api.mdx @@ -248,13 +248,13 @@ jobs: working-directory: microsite - name: download next reference - uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: next-reference path: docs/reference - name: download next OpenAPI API docs - uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: next-openapi-docs path: docs/**/*.api.mdx @@ -263,7 +263,7 @@ jobs: run: yarn build working-directory: microsite - - uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4 + - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: storybook path: microsite/build/storybook From 08ccd60a000649bb9a6a73e149a23905fb101eec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 13:38:18 +0000 Subject: [PATCH 48/52] chore(deps): update actions/upload-artifact digest to ea165f8 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/api-breaking-changes.yml | 2 +- .github/workflows/deploy_microsite.yml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/api-breaking-changes.yml b/.github/workflows/api-breaking-changes.yml index 281507f99b..fb2a443f58 100644 --- a/.github/workflows/api-breaking-changes.yml +++ b/.github/workflows/api-breaking-changes.yml @@ -46,7 +46,7 @@ jobs: cat ${{ github.event_path }} > event.json - name: Upload Artifacts - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: preview-spec path: | diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index ea0a433fe0..4febea2937 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -73,7 +73,7 @@ jobs: run: yarn build:api-docs - name: upload API reference - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: stable-reference path: docs/reference/ @@ -89,7 +89,7 @@ jobs: run: yarn docusaurus gen-api-docs all - name: upload OpenAPI API docs - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: stable-openapi-docs path: docs/**/*.api.mdx @@ -129,7 +129,7 @@ jobs: run: yarn build:api-docs - name: upload API reference - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: next-reference path: docs/reference/ @@ -146,7 +146,7 @@ jobs: working-directory: storybook - name: storybook upload - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: storybook path: storybook/dist/ @@ -162,7 +162,7 @@ jobs: run: yarn docusaurus gen-api-docs all - name: upload OpenAPI API docs - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: next-openapi-docs path: docs/**/*.api.mdx From fedb6a94f38c47a8385d4b102a506d820b709399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Fri, 21 Mar 2025 14:40:51 +0100 Subject: [PATCH 49/52] fix reports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fredrik Adelöw --- plugins/home/report.api.md | 3 ++- plugins/scaffolder-react/report-alpha.api.md | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/home/report.api.md b/plugins/home/report.api.md index eacf1a99a9..ef5a0d5a7a 100644 --- a/plugins/home/report.api.md +++ b/plugins/home/report.api.md @@ -50,7 +50,8 @@ export const ComponentAccordion: (props: { expanded?: boolean; Content: () => JSX.Element; Actions?: () => JSX.Element; - Settings?: () => JSX.Element; + Settings?: () => JSX./** @public */ + Element; ContextProvider?: (props: any) => JSX.Element; }) => JSX_2.Element; diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md index ad9f31480a..fbd539f96e 100644 --- a/plugins/scaffolder-react/report-alpha.api.md +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -332,9 +332,10 @@ export type ScaffolderReactTemplateCategoryPickerClassKey = 'root' | 'label'; export const scaffolderReactTranslationRef: TranslationRef< 'scaffolder-react', { + readonly 'workflow.noDescription': 'No description'; readonly 'passwordWidget.content': 'This widget is insecure. Please use [`ui:field: Secret`](https://backstage.io/docs/features/software-templates/writing-templates/#using-secrets) instead of `ui:widget: password`'; - readonly 'scaffolderPageContextMenu.moreLabel': 'more'; readonly 'scaffolderPageContextMenu.createLabel': 'Create'; + readonly 'scaffolderPageContextMenu.moreLabel': 'more'; readonly 'scaffolderPageContextMenu.editorLabel': 'Manage Templates'; readonly 'scaffolderPageContextMenu.actionsLabel': 'Installed Actions'; readonly 'scaffolderPageContextMenu.tasksLabel': 'Task List'; @@ -348,7 +349,6 @@ export const scaffolderReactTranslationRef: TranslationRef< readonly 'templateCard.chooseButtonText': 'Choose'; readonly 'cardHeader.detailBtnTitle': 'Show template entity details'; readonly 'templateOutputs.title': 'Text Output'; - readonly 'workflow.noDescription': 'No description'; } >; From 2e4cb15188789bf085b90126305ab8803cdf7e61 Mon Sep 17 00:00:00 2001 From: Adam Kunicki Date: Fri, 21 Mar 2025 09:53:45 -0700 Subject: [PATCH 50/52] Fixes previous attempt to auto-hide divider The divider prop was only being set when title was present, and the default value for divider is true. This unconditionally sets the divider prop. Signed-off-by: Adam Kunicki --- .changeset/tiny-swans-warn.md | 5 +++++ plugins/home-react/src/extensions.tsx | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changeset/tiny-swans-warn.md diff --git a/.changeset/tiny-swans-warn.md b/.changeset/tiny-swans-warn.md new file mode 100644 index 0000000000..45c6435a5d --- /dev/null +++ b/.changeset/tiny-swans-warn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-home-react': patch +--- + +Fixes auto-hiding of content divider when title not specified diff --git a/plugins/home-react/src/extensions.tsx b/plugins/home-react/src/extensions.tsx index 71b17a81a4..dd4b1e9df7 100644 --- a/plugins/home-react/src/extensions.tsx +++ b/plugins/home-react/src/extensions.tsx @@ -152,7 +152,8 @@ function CardExtension(props: CardExtensionComponentProps) { } const cardProps = { - ...(title && { title, divider: !!title }), + divider: !!title, + ...(title && { title }), ...(Settings && !isCustomizable ? { action: ( From a4900dd946186a3bc13975671ae8aa642ac93a30 Mon Sep 17 00:00:00 2001 From: Matt Benson Date: Fri, 21 Mar 2025 12:50:12 -0500 Subject: [PATCH 51/52] correct documentation header level Signed-off-by: Matt Benson --- docs/features/software-templates/writing-templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-templates/writing-templates.md b/docs/features/software-templates/writing-templates.md index 85f29cb359..bc2847a81b 100644 --- a/docs/features/software-templates/writing-templates.md +++ b/docs/features/software-templates/writing-templates.md @@ -561,7 +561,7 @@ catalogFilter: metadata.annotations.github.com/team-slug: { exists: true } ``` -#### Custom validation messages +### Custom validation messages You may specify custom JSON Schema validation messages as supported by the [ajv-errors](https://github.com/ajv-validator/ajv-errors) plugin library to [ajv](https://github.com/ajv-validator/ajv). From 79fc2ac8909ba311876c28670cda670e3db3e9a1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Mar 2025 20:19:50 +0000 Subject: [PATCH 52/52] chore(deps): update dependency @playwright/test to v1.51.1 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8e993bf7e4..bb1e6d2214 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14589,13 +14589,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.51.0 - resolution: "@playwright/test@npm:1.51.0" + version: 1.51.1 + resolution: "@playwright/test@npm:1.51.1" dependencies: - playwright: 1.51.0 + playwright: 1.51.1 bin: playwright: cli.js - checksum: 14959f930db55882ff45ba660dfd37e066bea2607619549f85b6c9c0591a895f4dcbc5419e2fc4069b03b02fef6d00628bc9382b65216c99735d6d93eb578374 + checksum: c3c14f37451cc0323234e37fa559a075e5aee9f5e6ca06fa3b4a132ec6c809909b22877daca1fa48c95a1112d859346c10111e7003f44582a05100dd5385bbef languageName: node linkType: hard @@ -39302,27 +39302,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.51.0": - version: 1.51.0 - resolution: "playwright-core@npm:1.51.0" +"playwright-core@npm:1.51.1": + version: 1.51.1 + resolution: "playwright-core@npm:1.51.1" bin: playwright-core: cli.js - checksum: e14798a7323539e1d6f076a6aa0492ea7c5fa89f4db85a53b27001b0f84bde2a5f8b14e25e05c5396594c89173a48398728522932bb7bd2006dd4bb48c8b0979 + checksum: 1eb37e22e97435a5ed6389b4caa666fbe618348861cae97e67586e20c8fed9ac3d3dc899ff3b9237d0ddfcf087d5b552b80be247e246fc45b75282f96be714bb languageName: node linkType: hard -"playwright@npm:1.51.0": - version: 1.51.0 - resolution: "playwright@npm:1.51.0" +"playwright@npm:1.51.1": + version: 1.51.1 + resolution: "playwright@npm:1.51.1" dependencies: fsevents: 2.3.2 - playwright-core: 1.51.0 + playwright-core: 1.51.1 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 02ec1077e2997872415fd40c9a5df6fd796d9cc15dade24bff9a88a16a451217744d850bdfc09efd4812d05c2fc856f92bfe106aae036fe21defa62c6d5b8ea5 + checksum: 2d78f53eed438d26df9743f98227d2e33bb5a378c8d0144a4ed75b4010c9c517d5a6ee6c1c9245ad61dc615054c5e19d2ded5a6e285e35d2bca39b05bc9c4a35 languageName: node linkType: hard