关于 metabase-data-app-migrate
用于将 Metabase 数据应用迁移到新契约版本的操作技能。它引导开发者逐版执行并验证升级,同时约束版本变更与提交流程。
主要功能
- 01逐版本顺序升级
- 02按升级指南逐步验证
- 03约束版本号和提交变更
- 04最终类型、资源与构建检查
- 05恢复中断的迁移
适用场景
- 01契约变更后更新数据应用
- 02继续中断的数据应用迁移
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ metabase/ metabase --skill metabase-data-app-migrate安装后在 Claude Code 中输入/metabase-data-app-migrate确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/maintainer-checklist.mdupgrade-guide-template.mdreferences/upgrades/README.md详细介绍
将数据应用迁移到当前契约版本
数据应用会在 data_app.yaml 中声明其代码所针对的契约版本
(version: N;没有该字段的清单即版本 1)。Metabase 仅在该契约发生
破坏性变更时才会提升其所提供的版本:即
@metabase/embedding-sdk-react/data-app API、bundle 工厂、清单、
queries/ 与 actions/ 约定,或应用可声明的内容。处于旧版本的应用会在
管理列表中标记为 已过时,对其他所有用户隐藏,并在迁移完成前拒绝打开。
迁移是一次对升级的遍历:N -> N+1 -> ... -> M,一次一个升级,
每个升级都由 references/upgrades/ 中的一份指南描述。不会跳过任何内容,
会话之间也不会记住任何内容:应用自身的文件和 git 历史承载着全部
状态。
四条不变量
以下每一步都源自这些不变量。切勿违反它们。
version最后写入。 某个升级的version: N+1只会在该升级的 所有检查都通过后,才写入data_app.yaml。- 每个升级在本地一次提交。 只有在目标版本的最终门禁通过后才 推送。版本行每次提交的变动绝不超过一个版本。
- 编译器与构建门禁仅在目标版本运行。 已安装的 SDK 就是目标版本, 因此一个尚处在多个升级中途的应用无法进行类型检查 或构建。不要提前运行它们,也不要提前“修复”它们的失败。
- 任何生成的内容都不得手动编辑。
dist/由npm run build写入,src/metabase.data.ts由类型化 schema 导出写入, 绝不由你写入。应用集合在collections/data_apps/下的文件 及其定义所命名的实体 ID(savedQuestionEntityId、copiedActionEntityId)只在升级指南指明之处更改, 遵循关于编写应用集合文件的数据应用指引(使用技能发现)。
第 0 步 - 定位应用并读取其状态
在应用目录 <repo>/data_apps/<slug>/ 下操作。用 ROOT="$(git rev-parse --show-toplevel)" 解析仓库根目录。实例检查需要仓库根目录下的 .env.local 凭据(DATA_APP_MB_URL、DATA_APP_MB_API_KEY)。在子 shell 中 source 该文件来检查它们,只打印这两个变量是否都已设置;绝不要打印该文件或其变量。该 key 必须属于管理员:API 只向管理员返回 version 和 outdated,并拒绝向其他任何人返回已过时应用的元数据,因此非管理员 key 在这里无法证明任何事情。
下文的 npm 指应用自己的包管理器,即已提交锁文件(package-lock.json、yarn.lock、pnpm-lock.yaml、bun.lock)的那一个。绝不要引入第二个锁文件。
读取三个数字:
# version committed at HEAD (absent line means 1)
git show HEAD:data_apps/<slug>/data_app.yaml | grep -E '^version:' || echo "version: 1"
# version in the working tree
grep -E '^version:' data_app.yaml || echo "version: 1"
# target: the highest upgrade guide shipped with this skill (no guides means 1)
ls <skill-dir>/references/upgrades/ | sed -nE 's/^v[0-9]+-to-v([0-9]+)\.md$/\1/p' | sort -n | tail -1 | grep . || echo 1
<skill-dir> 是加载此 SKILL.md 的目录。当存在随此技能一同安装的 data-app 脚手架模板(<skills-dir>/*/template/data_app.yaml)时,目标必须等于其中的 version:;如果两者不同,说明这些技能来自不同的 Metabase 版本。停止,并告诉用户使用 Admin > Data apps 下显示的命令重新安装所有 data-app 技能。等待回答。
然后判断:
| HEAD 版本 | 工作区 | 执行 |
|---|---|---|
| 等于目标 | 干净 | 无需迁移。说明这一点;仅当用户要求验证时才运行最终门禁。 |
| 高于目标 | 任意 | 停止。 没有降级。要么 Metabase、SDK 和技能都比应用旧,要么是针对错误实例提交了一次版本提升(git log -- data_apps/<slug>/data_app.yaml 会显示)。等待回答。 |
| 低于目标 | 干净 | 从 第 1 步 开始。 |
| 任意 | data_apps/<slug> 下有改动 | 上一次会话被中断。先去 恢复。 |
第 1 步 - 预检,仅一次
- 用应用的包管理器安装与目标 Metabase 版本匹配的 SDK(
npm install @metabase/embedding-sdk-react@<tag>或等效命令);每份升级指南都会列出它所针对的 dist-tag。锁文件的变更随最终升级一起提交。 - 确认应用在其当前版本下仍符合模板形态:
vite.config.ts是单行export default dataAppConfig(),且src/index.tsx默认导出DataAppFactory。如果不是,停止:这不是版本迁移,而是结构性偏离。可提议在同一 slug 下搭建一个全新应用(单独任务:使用技能发现来创建 data app),并把src/、queries/和actions/迁移过去,或者按用户自担风险继续。等待回答。 - 在编辑任何内容之前,阅读从当前版本到目标的每一份升级指南,这样后续的升级就不会在较早升级进行到一半时给你带来意外。
第 2 步 - 升级循环
对于从 HEAD 版本到 target - 1 的每个 N:
- 打开
references/upgrades/v<N>-to-v<N+1>.md并运行其中的 Preconditions。 - 按顺序应用该指南的 Steps。每一步都是机械性的,并以一条 Done when 命令结束。先运行该命令:如果它已经通过,就跳过这一步; 如果没有通过,就应用修改并再次运行它。一步的命令是它被执行过的唯一 证明;绝不要通过阅读就把某一步标记为完成。
- 应用 Instance steps(如果有)。它们的 Done when 是来自已连接的
Metabase 的 API 响应,使用
.env.local中的凭据获取:( source "$ROOT/.env.local"; curl -s -H "x-api-key: $DATA_APP_MB_API_KEY" "$DATA_APP_MB_URL/api/apps/<slug>" ) - 运行该指南的 Done-check summary。每一行都必须打印
ok。 - 只有到这时,才在
data_app.yaml中设置version: N+1。这是对该行的唯一 一次修改。 - 如果
N+1 < target:从仓库根目录执行git add data_apps/<slug> collections/data_apps && git commit -m "Migrate <slug> data app to data-app version N+1" -- data_apps/<slug> collections/data_apps。 该路径规范会把应用之外任何已暂存的内容排除在提交之外。 不推送,不做类型检查,不构建。如果用户问为什么,就说应用在最后一次升级 完成前无法编译。 - 如果
N+1 == target:在提交前运行 Step 3。
不要跨升级批次处理步骤。在第 5 项之前不要改动 version。
第 3 步 - 仅在目标版本进行的最终关卡
npm run typecheck。在应用自身的源代码中修复失败。如果失败信息提到的 某个 SDK 符号没有任何升级指南提及,那是指南的缺口,而不是用户的问题: 展示确切的错误,说明本应由哪份指南覆盖它,然后停止。否则,最多进行三轮 修复,然后停止并询问。npm run check-resources,然后npm run build,当应用的集合文件无法支撑 这些定义时,构建会拒绝打包。遵循它们的提示信息;两者都不会调用 Metabase。npm run dev,然后从 Vite 打印的Local:行中获取预览 URL。 模板要求使用端口 5174,但当该端口被占用时 Vite 会迁移到下一个空闲端口, 所以绝不要假定它就是该端口。打开该 URL,然后从同一来源读取一次诊断 feed:
预期为curl -s "<preview-url>/__data-app/diagnostics?startEventId=0"clients: 1,且没有任何条目的"alert": true。clients: 0表示 没有打开预览标签页,因此空的 feed 什么也证明不了。- 从仓库根目录执行
git status必须只显示:升级修改、data_app.yaml、构建出的 bundle、应用集合文件(如果有升级改动了它们), 以及 package lockfile(如果 SDK 被重新锁定)。应用目录内的任何其他内容 都是用户修改;在提交前要说明这一点。 - 从仓库根目录执行
git add data_apps/<slug> collections/data_apps && git commit -m "Migrate <slug> data app to data-app version M" -- data_apps/<slug> collections/data_apps, 推送,并告诉用户在 Admin > Data apps 下点击 Pull changes。 - 证明它。拉取之后:
必须显示( source "$ROOT/.env.local"; curl -s -H "x-api-key: $DATA_APP_MB_API_KEY" "$DATA_APP_MB_URL/api/apps/<slug>" )"version": M和"outdated": false。 仅包含name和display_name的响应意味着该 key 不属于管理员:请索取 一个管理员 key,或让用户读取管理员列表,并说明证明仍然待定。报告该命令 和结果。没有它就不要声称迁移已完成。
恢复被中断的迁移
新会话对上一次会话没有任何记忆,也不需要。从 Step 0 读取三个数字,以及 git status --porcelain -- data_apps/<slug>,然后:
| tree | working-tree version | 含义 | 操作 |
|---|---|---|---|
| clean | 等于 HEAD | 每个已完成的升级都是一次提交;没有做到一半的事 | 从 HEAD 版本继续循环 |
| dirty | 等于 HEAD | HEAD -> HEAD+1 升级正在进行中,其检查尚未全部通过 | 重新运行该升级的每个 Done when;只应用命令失败的步骤;从循环第 4 项继续 |
| dirty | 等于 HEAD + 1 | 所有检查都已通过,版本号也已写入,但缺少提交(或版本号写入后的最终门禁失败) | 重新运行该升级的 Done-check summary(全部 ok,或有人在版本号写入后编辑过:停止并显示 git diff);如果它就是目标,运行最终门禁;提交 |
| any | 大于 HEAD + 1,或低于 HEAD | 不变量被破坏 | 停止。 显示 git diff -- data_apps/<slug>/data_app.yaml 并询问是把这一个文件恢复到 HEAD 并重新推导,还是暂存这棵工作树。等待回答。 |
在 data_apps/<slug> 之外变脏的文件不属于你:绝不要对它们执行 git add。
汇报
每次升级一行,按顺序:v1 -> v2: done (commit abc1234) 或
v2 -> v3: blocked - <失败的确切 Done-when 命令及其输出>。
绝不要弱化失败的检查。将 tsc 输出按根本原因分组,保留少量有代表性的诊断信息,而不是整段粘贴。
绝不要做
- 在升级的检查通过之前设置或编辑
version,或一次改动超过一个版本。 - 跳过某个升级,或同时应用两个升级的步骤。
- 在最后一次升级之前运行
npm run typecheck或npm run build,或在最终门禁通过之前推送。 - 手工编辑
dist/或src/metabase.data.ts,或更改应用的集合文件,或超出升级指南所述范围更改定义的实体 ID。 - 从上一会话的聊天中复制某一步的结果,而不是重新运行其 Done when。
- 在已有升级指南的情况下按自己的清单进行迁移;当你需要的升级没有指南时,停下来并说明这一点。
升级指南
指南位于 references/upgrades/,每个升级一份,命名为 v<N>-to-v<N+1>.md。它们由 Metabase 在契约版本被提升时根据 references/upgrade-guide-template.md 中的模板编写;references/maintainer-checklist.md 描述了该流程。你需要的升级缺少指南,说明技能安装有问题,而不是要靠临场发挥来绕过。