Skip to main content

本文档描述了一个 future Backstage > 插件开发人员在开发一个涉及 > Backstage > 许多不同方面的插件时可能经历的旅程。 这个故事发明了许多新的东西,这些东西现在还不是 > Backstage > 的一部分,但我建议我们将其作为长期目标或 > 北极星目标来添加。 我们的目的是讨论这个故事的哪些部分是有意义的 > 目标,以及我们希望以不同的方式来做或根本不做哪些事情。 章节 "采用了 > 编号,以便于对故事的某些部分进行评论。

主人公

Sam 是一名经验丰富的开发人员,曾在 Backstage 工作过一段时间,了解构建插件的最佳实践和可用工具。 Sam 还喜欢音乐,希望为 Backstage 的每一项服务都配上主题曲。

结束

Sam 为 Backstage 构建了一个 Spotify 插件,允许服务 Owners 为其服务定义主题曲。 只要用户访问 Backstage 中的服务页面,主题曲就会播放。 该插件已发布到 npm,任何组织都可以轻松安装并添加到其 Backstage 安装中。

1.一个新插件

Sam 选择在独立项目中开发该插件,并使用npx @backstage/cli new --select plugin会检测到它不是在现有项目中运行,因此会创建一个单独的插件 repo。

使用yarn start通过安装几个依赖项和创建一个漂亮的用户界面,播放器就基本完成了。

2. Auth 的威胁

Sam 意识到用户需要通过 Spotify API 认证才能播放音乐,而 Backstage 还不支持 Spotify 登录。 Sam 添加了@backstage/plugin-auth-backend作为项目中的本地开发中间件,并提供必要的封装逻辑和配置,以便passport-spotify策略。 Spotify 验证提供程序现在可以在本地开发后端使用,通过添加一个前端SpotifyAuth实现OAuthApi类型,现在它也能在前端工作了。

const spotifyAuthApiRef = createApiRef<OAuthApi>({
id: 'core.auth.spotify',
});

山姆意识到 Spotify Auth 可能对其他人有用,如果将其作为Backstage核心的一部分会更方便。 在提交并合并了一个普拉请求,并将其添加到@backstage/plugin-auth-backend@backstage/core-plugin-api由于 Backstage Core 团队也将其添加到了公共演示服务器,Sam 现在可以在本地设置中摆脱它,转而依赖共享的开发认证提供商。

现在唯一剩下的事情就是确保插件用户在应用程序中提供 Spotify 授权。 萨姆通过添加spotifyAuthApiRef到插件所需的 API 列表中,并将其列在 README 中的需求部分。

## Requirements

This plugin requires the following APIs to function:

- `spotifyAuthApiRef` from `@@backstage/core-plugin-api@^1.1.0`

3.目录觉醒

Sam 现在已经有了一个可用的播放器和用户登录听音乐的方法,但目标是为服务提供主题曲。 Sam 通过定义一个新的元数据注释(名为sam.wise/spotify-track-id注释的值是 Spotify 曲目 ID,可以在类似这样的组件中定义:

apiVersion: backstage.io/v1
kind: Component
metadata:
name: my-component
annotations:
sam.wise/spotify-track-id: '4uLU6hMCjMI75M1A2tKUQC'
spec:
type: service

Sam 创建了一个 JSON 模式,用于记录注释,并允许选择采用该插件的组织将其用于验证和记录。

{
"sam.wise/spotify-track-id": {
"$id": "https://raw.githubusercontent.com/sam/backstage-spotify-theme/master/annotation.json#/sam.wise/spotify-track-id",
"type": "string",
"title": "Spotify Track Annotation",
"description": "Spotify track ID to associated with the entity",
"examples": ["4uLU6hMCjMI75M1A2tKUQC"]
}
}

4.小工具的兴起

Sam 还将音乐播放器封装在实体页面 widget 中,这样,任何想使用该插件的人都可以将播放器添加到任何实体布局模板中,从而使其显示在所有实体中。

export const PlayerWidget = plugin.createEntityWidget({
component: WebPlayer,
locations: ['header', 'card', 'footer'],
cardSize: [2, 4],
});

该 widget 会接收嵌入其页面的实体的信息,这样就可以很容易地从注释中获取曲目 ID 并连接播放器。

萨姆还修改了独立插件的开发设置,在基本实体页面中加入了这个新部件,并将其添加到插件用户可能希望放置播放器的几个不同位置,以确保它们都能正常工作。

5.第一个用户

此时,想要使用 Sam 插件的用户只需将 https://raw.githubusercontent.com/sam/backstage-spotify-theme/master/annotation.json#/sam.wise/spotify-track-id 添加到目录模式中,导入并添加PlayerWidget在所需的实体模板页面上,并确保它们提供 Spotify 授权。

很快,Sam 就在 GitHub 上看到了第一个 "Used by",反馈也开始不断涌现。 用户非常喜欢这个插件,有些用户要求在创建新组件时选择主题曲。 Sam 立即采纳了这个想法,并添加了一个新的创建钩子,由插件导出。 这个钩子可以安装在单个、全部或与标签匹配的组件模板中。 它在组件创建过程中添加了一个字段,带有一个漂亮的搜索框,允许用户搜索他们想用作主题曲的曲目。

6.

在这一点上,Sam 非常满意,但他希望用户在创建后能更方便地更改轨道,最好使用与创建表格相同的搜索框。 通过在PlayerWidget以及一个很好的空状态,Sam 就能在图形用户界面中提供适当的钩子来打开搜索对话框。

要保存所选轨道,Sam 使用RepoApi这将为使用 GitHub 的组织创建一个 "拉取请求",为 GitLab 用户创建一个 "合并请求",以此类推。

const repoApi = useApi(repoApiRef);
const alertApi = useApi(alertApiRef);

const onSave = async () => {
const { url } = await repoApi.createChangeRequest({
title: `Change theme tune to ${track.title} by ${track.artist}`,
changes: [
{
path: entityYamlPath,
content: newEntityYamlContent,
},
],
});

alertApi.post({ message: `Requested change, ${url}` });
};

现在,用户更改主题曲就简单多了,因为他们不再需要去查找曲目 ID 和编辑 YAML 文件。 相反,他们现在可以留在 Backstage 内搜索曲目,然后从那里请求更改。 此外,请求的更改可以由各组织的常规流程进行审核。

7 用户反击

在这一点上,Sam 的插件相当受欢迎,已经被许多组织机构所接受和使用。 但有些用户开始担心,他们的实体描述中有太多不同的手工制作的注释,希望能够避免其中一些注释。 不过,他们非常喜欢主题曲,希望能够保留这些主题曲,而不必将其放在实体描述中,即使这意味着无法通过常规的源代码控制审核流程。

有一天,Sam 收到了一份关于该插件的 Pull Request。@backstage/backend-common这一切都被打包到一个新的后端插件中,该插件还将通过模式和功能扩展目录后端,以自动加载sam.wise/spotify-track-id后端插件还通过突变扩展了通用 GraphQL 模式,以更新数据库中的轨道 ID。

在前端,"拉取请求 "没有太大变化,它定义了保存操作,而之前使用的是RepoApi在自己的应用程序接口中。

type ThemeTuneStorageApi = {
save(entity: Entity, trackId: string): Promise<void>;
};

该插件还提供了两种不同的应用程序接口实现,一种是使用旧的RepoApi和一个调用GraphQL新的应用程序接口依赖于IdentityApi作为授权更改的机制,而不是源控制审查。IdentityApi提供了一个令牌,该令牌包含在向后端发出的请求中,然后必须与用户试图更改主题曲的组件的 Owners 匹配。

实际上,我认为每个 GraphQL 请求 > 都应包含用户的 ID 标记,但我还是发明了一个在这里包含 ID 标记的理由。

应用程序接口根据插件的配置参数进行选择,但默认情况下使用原始的RepoApi行为。

if (config.getBoolean('storeTrackInDatabase')) {
return new GraphQLThemeTuneStore(graphqlClient, identityApi, alertApi);
} else {
return new RepoThemeTuneStore(repoApi, alertApi);
}

山姆对这一纯粹惊人的变化感到惊讶,回复了一个"👍",然后点击了合并。

8.克隆人的进攻

Sam 刚刚发布了该插件的 v1.8.4,目前它非常受欢迎,以至于其他一些插件也开始依赖该插件。sam.wise/spotify-track-id其中一个插件是spotify-album-artSam 认为这一切都很酷,但他不喜欢曾经是插件内部问题的注释现在却成为社区的标准。

为了使 Backstage 中的注释标准化,Sam 向 Backstage Core repo 提交了一份 Pull Request。 该请求提出了一个新的众所周知的元数据注释,名为spotify.com/track-id,其模式定义与 Sam 的标签相同,并指向 Sam 自己的插件和spotify-album-artBackstage 维护者在与 Spotify 的人员确认他们对注释没有意见,并对注释描述中的一些小语法错误进行纠结后,合并了 Pull Request。

由于注释现在可以在 Backstage Core 中使用,Sam 发布了使用新注释的 v2 插件。 为了向后兼容,它仍然可以使用旧注释,但插件的新用户不再需要将 https://raw.githubusercontent.com/sam/backstage-spotify-theme/master/annotation.json#/sam.wise/spotify-track-id 扩展名添加到他们的目录模式中,因为它现在是核心模式的一部分。 Sam 的新版插件指定了对 Backstage 的依赖关系,其最小版本设置为与注释添加到核心模式的版本相同。

9.山姆的复仇

山姆现在完全控制了Backstage中的所有主题曲,他发布了 v2.0.1,将所有曲目切换为 4uLU6hMCjMI75M1A2tKUQC。 山姆想做一些更邪恶的事情,但由于Backstage沙盒中有敏感操作,而且大部分是只读的,有严格的 CSP,所以山姆束手无策。