Backstage v1.12.0 版本解析:Catalog 游标分页、Scaffolder Zod 动作定义与后端系统导出重命名
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
本篇技术指南围绕 Backstage 开源开发者门户框架的 v1.12.0 版本发布展开,系统梳理该版本引入的核心能力:软件目录(Catalog)基于游标(cursor)的分页查询接口、Scaffolder 模板动作的zod声明式输入输出、新后端系统模块的命名规范重命名,以及两个新插件(Octopus Deploy、StackStorm)的落地方式。读者读完本篇后,能够掌握 v1.12.0 新增 API 的请求/响应结构与配置要点,了解如何利用zod编写类型安全的 Scaffolder 动作,并能在升级时正确迁移被重命名的导出符号。
一、版本概览与升级说明
v1.12.0 是 Backstage 的一个常规增量版本,主体由一批小的功能增强与缺陷修复构成,同时在开发体验上有若干明显改进。本仓库的正式发布说明位于 docs/releases/v1.12.0.md,对应的完整逐包变更记录(changeset)位于 docs/releases/v1.12.0-changelog.md。
- 安全修复:该版本不包含任何安全修复项。
- 升级建议:官方推荐将 Backstage 项目持续保持到最新版本,具体升级指引可参考 keeping-backstage-updated。
- 版本配套:本次发布伴随多个核心包的主/次版本号更新,例如
@backstage/backend-plugin-api升至 0.5.0、@backstage/backend-tasks升至 0.5.0、@backstage/catalog-client升至 1.4.0、@backstage/core-app-api升至 1.6.0、@backstage/plugin-catalog-backend升至 1.8.0、@backstage/plugin-scaffolder-backend升至 1.12.0 等。
二、核心亮点:用 zod 定义 Scaffolder 动作的输入输出
2.1 为什么引入 zod
此前编写自定义 Scaffolder 动作时,需要在input与output中手写 JSON Schema,并同时维护对应的 TypeScript 类型,二者极易失步。v1.12.0 起,动作作者可以改用zodschema 声明输入与输出,编辑器内即可获得即时类型反馈,比手工编写 JSON Schema 更直观、更安全。
2.2 源码层面的实现机制
本仓库 plugins/scaffolder-node/src/actions/createTemplateAction.ts 中,createTemplateAction被泛型化为同时接受"普通 JSON Schema 风格对象"与"zod schema(zImpl => z.ZodType)"两种形态:
- 泛型参数
TInputSchema/TOutputSchema既可以是一组字段函数对象{ [key in string]: (zImpl: typeof z) => z.ZodType },也可以是单个函数(zImpl: typeof z) => z.ZodType; - 内部通过
z.infer<...>与z.output<...>推导出输入/输出的精确 TypeScript 类型,从而让动作的handler参数获得完整类型检查; - 函数内部(createTemplateAction.ts)通过
parseSchemas将 zod schema 转换为 JSON Schema,再以统一格式交给系统校验与渲染。也就是说,zod 只是"编写时"的便利层,最终在整个系统中流转的仍是 JSON Schema,TemplateAction的对外契约保持不变。
在 plugins/scaffolder-node/src/actions/createTemplateAction.test.ts 中可找到对应测试,验证了 zod 定义被正确转换为 JSON Schema 并参与safeParse校验。
2.3 编写一个使用 zod 的模板动作
在自定义动作模块中,createTemplateAction的入参可简化为如下形态(示意,需按实际安装的版本引入依赖):
import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; import { z } from 'zod/v3'; export const exampleAction = createTemplateAction({ id: 'example:hello', description: '输出一段问候', schema: { input: (zImpl) => zImpl.object({ name: zImpl.string().describe('被问候者的名字'), times: zImpl.number().default(1).describe('重复次数'), }), output: (zImpl) => zImpl.object({ message: zImpl.string(), }), }, async handler(ctx) { ctx.output('message', `hello ${ctx.input.name}`.repeat(ctx.input.times)); }, });要点说明:
input/output中每个字段的.describe()会被带入最终的 JSON Schema 描述,供模板参数表单展示;- 通过
zod的.default()、.optional()等能力,可以自然表达参数默认值与可选性; - 由于类型由 schema 自动推导,
ctx.input与ctx.output的键和值在编辑器内即可获得静态校验,避免了"类型与 schema 不一致"的经典问题。
2.4 配套的 Scaffolder 前端与行为增强
同版本中@backstage/plugin-scaffolder、@backstage/plugin-scaffolder-react与@backstage/plugin-scaffolder-backend也同步更新:
EntityPicker改为使用完整限定的实体引用(fully qualified entity ref)而不是"人类可读"的简化名称;- 将
useTaskStream、TaskBorder、TaskLogStream、TaskSteps等组件/钩子从plugin-scaffolder迁移进plugin-scaffolder-react,便于其他前端复用任务流展示; catalog:fetch动作扩展为可按实体引用一次获取多个实体;catalog:write动作允许写入任意形状的对象;当catalog:fetch获取不到实体且optional为false时会抛出错误。
三、核心亮点:从目录读取分页数据(/entities/by-query)
3.1 新增的后端端点与客户端方法
v1.12.0 为软件目录新增了带游标的分页查询端点GET /entities/by-query与对应的客户端方法queryEntities。它支持:
- 游标式分页:首请求返回
nextCursor,后续请求携带cursor获取下一页,同时响应中包含prevCursor以便回溯; - 服务端过滤:支持传统的 key-value
filter语法与基于谓词的query语法($all、$any、$not、$exists、$in、$hasPrefix、$contains等逻辑与匹配操作符); - 服务端排序:通过
orderFields(如metadata.name,asc)指定排序字段与方向; - 字段裁剪:通过
fields仅返回所需字段,减小响应体积。
3.2 请求与响应类型
本仓库 packages/catalog-client/src/types/api.ts 中完整定义了相关类型:
QueryEntitiesRequest = QueryEntitiesInitialRequest | QueryEntitiesCursorRequest(api.ts);QueryEntitiesInitialRequest支持fields、limit、offset、filter、query、orderFields、fullTextFilter以及totalItems(取值'include'/'exclude',默认'include',设'exclude'可跳过总数统计以提升游标分页 UI 的性能)(api.ts);QueryEntitiesCursorRequest仅需cursor,并可选fields与limit(api.ts);QueryEntitiesResponse返回items、totalItems以及含nextCursor/prevCursor的pageInfo(api.ts)。
其中filter用于传统 key-value 过滤,query用于谓词式过滤,二者可以同时提供。
3.3 客户端调用示例
// 首次请求:过滤 + 排序 + 限制条数 const response = await catalogClient.queryEntities({ filter: [{ kind: 'group' }], limit: 20, fields: ['metadata', 'kind'], fullTextFilter: { term: 'A' }, orderFields: { field: 'metadata.name', order: 'asc' }, }); // 游标翻页:携带 nextCursor 获取下一批 const nextPage = await catalogClient.queryEntities({ cursor: response.pageInfo.nextCursor, limit: 20, fields: ['metadata', 'kind'], });上述示例会匹配所有名称以 "A" 开头、kind 为 group 的实体,按名称升序返回;若结果超过 20 条,则可通过nextCursor继续获取,prevCursor用于回到上一批。
3.4 服务端路由与 OpenAPI 契约
后端路由定义位于 plugins/catalog-backend/src/service/createRouter.ts:
POST /entities/by-query(createRouter.ts)承载谓词式过滤查询;GET /entities/by-query(createRouter.ts)承载 key-value 过滤与排序查询。
服务端的 OpenAPI 描述位于 plugins/catalog-backend/src/schema/openapi.yaml,其中给出了丰富的过滤示例,例如:
/entities/by-query?filter=kind=user,metadata.namespace=default&filter=kind=group,spec.type表示"kind=user 且 namespace=default,或 kind=group 且存在 spec.type"(同一 filter 内条件为 AND,多个 filter 之间为 OR)。排序示例:
/entities/by-query?orderField=metadata.name,asc默认情况下实体按其内部uid排序;orderField后可跟asc(升序)或desc(降序)。此外该版本还同步新增了POST /locations/by-query,用于对 Location 实体做同样的游标式查询。
对应的路由测试集中在 plugins/catalog-backend/src/service/createRouter.test.ts(如GET /entities/by-query与POST /entities/by-query两组 describe),覆盖了过滤、排序、游标编解码以及非法游标/非法 limit 的错误处理,可作为接口行为的权威参照。
3.5 目录客户端与其他配套更新
@backstage/catalog-client新增queryEntities方法,并修复了getEntitiesByRefs对缺失项返回undefined而非null的问题;- 批量按引用获取(batch fetch by ref)与过滤(例如启用授权时)组合使用的缺陷得到修复;
@backstage/plugin-catalog-backend为一批久已迁往@backstage/plugin-catalog-node的符号(CatalogProcessor、EntityProvider、processingResult、EntityRelationSpec等)补充了弃用标记,并将locationSpecToLocationEntity、locationSpecToMetadataName迁至plugin-catalog-node作为新家;- 前端
@backstage/plugin-catalog-react支持在EntityPicker过滤器中复用多选能力。
四、新后端系统:插件导出重命名(按推荐命名模式)
随着新后端系统(new backend system)逐步定型,v1.12.0 将一批插件的模块导出更名为官方推荐的命名模式(推荐规范可参见仓库文档 docs/backend-system/architecture/naming-patterns.md)。核心规则为:以catalogModule<Name>、eventsModule<Name>等作为前缀,例如:
| 变更前(旧导出) | 变更后(新导出) | 所属包 |
|---|---|---|
githubEntityProviderCatalogModule | catalogModuleGithubEntityProvider | plugin-catalog-backend-module-github |
awsS3EntityProviderCatalogModule | catalogModuleAwsS3EntityProviders | plugin-catalog-backend-module-aws |
azureDevOpsEntityProviderCatalogModule | catalogModuleAzureDevOpsEntityProvider | plugin-catalog-backend-module-azure |
bitbucketCloudEntityProviderCatalogModule | catalogModuleBitbucketCloudEntityProvider | plugin-catalog-backend-module-bitbucket-cloud |
bitbucketServerEntityProviderCatalogModule | catalogModuleBitbucketServerEntityProvider | plugin-catalog-backend-module-bitbucket-server |
gerritEntityProviderCatalogModule | catalogModuleGerritEntityProvider | plugin-catalog-backend-module-gerrit |
gitlabDiscoveryEntityProviderCatalogModule | catalogModuleGitlabDiscoveryEntityProvider | plugin-catalog-backend-module-gitlab |
incrementalIngestionEntityProviderCatalogModule | catalogModuleIncrementalIngestionEntityProvider | plugin-catalog-backend-module-incremental-ingestion |
microsoftGraphOrgEntityProviderCatalogModule | catalogModuleMicrosoftGraphOrgEntityProvider | plugin-catalog-backend-module-msgraph |
awsSqsConsumingEventPublisherEventsModule | eventsModuleAwsSqsConsumingEventPublisher | plugin-events-backend-module-aws-sqs |
githubEventRouterEventsModule | eventsModuleGithubEventRouter | plugin-events-backend-module-github |
githubWebhookEventsModule | eventsModuleGithubWebhook | plugin-events-backend-module-github |
gitlabEventRouterEventsModule | eventsModuleGitlabEventRouter | plugin-events-backend-module-gitlab |
azureDevOpsEventRouterEventsModule | eventsModuleAzureDevOpsEventRouter | plugin-events-backend-module-azure |
这些导出仍处于 alpha 阶段,因此本次重命名被官方视为非破坏性变更(non-breaking),但如果你已经在使用新后端系统,需要同步更新import语句。同一批变更还对所有包的/alpha导出做了内部重构(changeset928a12a9b3e),并在@backstage/plugin-catalog-backend-module-gitlab中弃用了GitlabDiscoveryEntityProvider的branch配置键,改用fallbackBranch。
五、新插件:catalog-backend 的 PuppetDB 模块
@backstage/plugin-catalog-backend-module-puppetdb@0.1.0为本版本首次发布,用于将 PuppetDB,可作为 Entity Provider 定时把 PuppetDB 中的节点/事实同步为目录实体,适用于以 Puppet 做配置管理的团队构建基础设施目录视图。
六、新插件:Octopus Deploy 与 StackStorm
6.1 Octopus Deploy 部署插件
@backstage/plugin-octopus-deploy@0.1.0为本版本首次发布的正式插件,用于集成 Octopus 部署平台,源码位于 plugins/octopus-deploy。它面向使用 Octopus 作为发布/部署编排工具的团队,可将部署信息(环境、项目、发布版本等)纳入 Backstage 的软件目录实体详情页。该插件随包携带 Octopus Deploy 官方 Logo 资源。
6.2 StackStorm 集成插件
@backstage/plugin-stackstorm@0.1.0提供与 StackStorm 的集成,源码位于 plugins/stackstorm,通过对接 StackStorm API 让用户直接在 Backstage 中查看工作流执行(workflow executions)、包(packs)与动作(actions)。安装与配置指引以该插件目录内的 README 为准。
七、其他值得关注的功能与修复
7.1 目录前端:EntitySwitch 支持渲染多个匹配分支
@backstage/plugin-catalog的EntitySwitch组件新增renderMultipleMatches="all"参数:当多个EntitySwitch.Case的if条件同时为真时,将所有匹配分支一并渲染,未匹配时渲染默认分支(若有)。典型场景是在同一页面上展示多个 CI/CD 系统:
<EntitySwitch renderMultipleMatches="all"> <EntitySwitch.Case if={isJenkinsAvailable}>Jenkins</EntitySwitch.Case> <EntitySwitch.Case if={isCodebuildAvailable}>CodeBuild</EntitySwitch.Case> <EntitySwitch.Case>No CI/CD</EntitySwitch.Case> </EntitySwitch>7.2 OAuth2 与 OIDC 语义对齐
@backstage/core-app-api中OAuth2在申请openidscope 的会话时现在会显式获取 ID Token。这并非破坏性变更——符合规范的 OIDC 提供方本就会在授予openidscope 时返回 ID Token;该改动只是将这一依赖显式化,使基于 OAuth2 的提供方无需再手动把openid加入默认 scope,从而可以避免为资源型访问令牌申请多余的 ID Token 相关 scope。同时 GitLab 认证提供方现在可以用于获取 OpenID 令牌。
7.3 UrlReaderService 的 lastModified 支持
@backstage/backend-plugin-api的UrlReaderService.readUrl响应新增lastModifiedAt字段,并支持lastModifiedAfter选项,便于按文件修改时间做增量读取或缓存决策。
7.4 后端基础设施细节
@backstage/backend-common新增backend.database.role配置,用于设置 Postgres 中新建 schema 与表的归属用户(配合pluginDivisionMode: schema),例如:backend: database: client: pg pluginDivisionMode: schema role: backstage connection: user: v-backstage-123 # ...上例以
v-backstage-123连接数据库,但新建对象的属主为backstage;AwsS3UrlReader升级到 AWS SDK v3;@backstage/errors新增NotImplementedError,@backstage/backend-app-api会将其正确映射为 501 状态码;@backstage/plugin-proxy-backend的createRouter支持reviveConsumedRequestBodies: true,可恢复被 express 中间件(如express.json())消费过的请求体,默认不启用;backend-tasks新增从调度器获取任务描述(description)的能力,便于展示任务触发原因。
7.5 TechDocs 与 CLI
@techdocs/cli generate --verbose会输出 mkdocs 构建过程日志;techdocs AWS S3 请求支持 HTTPS 代理;@backstage/plugin-techdocs-backend引入新后端系统下的techdocsPluginalpha 导出;- TechDocs 前端修复了某些 mkdocs-material 版本下上一篇/下一篇链接失效的问题,并保留插入到 shadow DOM 中文档内容的 HTML 标签属性以改善可访问性;
@backstage/cli新增migrate package-exports命令,用于同步所有package.json的exports字段,并新增了 Web 与 Node.js 库类型的新插件模板。
7.6 其余代表性修复
- Catalog 相关:
getEntitiesByRefs缺失项返回undefined;修复批量按引用获取与过滤(如授权)组合使用的缺陷; - Scaffolder 相关:
RepoUrlPicker对无 owner 的目标(如 Bitbucket Server)也能获取凭据;修复数组字段校验、空对象hasErrors判断等; - 前端通用:
core-components中 Sidebar 按钮文案不再强制大写(按给定大小写原样显示);Table组件支持columns[*].headerStyle;搜索分页在最后一页正确禁用"下一页"按钮;快捷方式插件修复了新增快捷方式会覆盖整个列表的问题; - 主题相关:一批插件将硬编码的黑/白颜色改为感知主题(theme aware)。
八、升级到 v1.12.0 的注意事项清单
综合以上变更,从旧版本升级到 v1.12.0 时建议重点检查以下几点:
- 新后端系统导入路径:如已使用 alpha 导出,按上文表格将旧的
xxxEntityProviderCatalogModule/xxxEventRouterEventsModule等重命名为新命名模式; - Scaffolder 动作 schema:可逐步将手写 JSON Schema 迁移为
zod声明以获得类型安全;系统仍兼容原有 JSON Schema 形态; - GitLab Discovery Provider 配置:若使用了
branch键,重命名为fallbackBranch; - 目录查询:需要游标分页/服务端排序时,优先采用
queryEntities//entities/by-query;getEntities依旧可用; - 数据库归属:如使用 Postgres schema 划分模式,可评估
backend.database.role以统一对象属主; - 代理行为:proxy-backend 默认不复活已消费请求体,需要该行为时显式开启
reviveConsumedRequestBodies: true; - UI 覆盖样式:Sidebar 按钮文案不再自动大写、多个组件切换为主题感知颜色,如有自定义样式覆盖需复核。
九、相关文档与进一步阅读
- 发布说明:docs/releases/v1.12.0.md
- 逐包变更记录:docs/releases/v1.12.0-changelog.md
- 新后端系统架构:docs/backend-system/architecture
- 后端系统命名模式:docs/backend-system/architecture/naming-patterns.md
- 保持 Backstage 更新:docs/getting-started/keeping-backstage-updated.md
- 版本化与支持策略:docs/overview/versioning-policy.md
说明:本仓库为 Backstage 官方仓库的快照,文章中引用的源码路径(如 createTemplateAction.ts、api.ts、createRouter.ts)与文档路径均可在当前仓库中直接查阅;文中所有版本号与配置均以本仓库 v1.12.0 版本内容为准。
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考