Focalboard Jira 导入器实战:从 Jira XML 导出到 Focalboard 归档的完整迁移指南
【免费下载链接】focalboardFocalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.项目地址: https://gitcode.com/GitHub_Trending/fo/focalboard
导读
Focalboard 的import/jira目录下内置了一个基于 Node.js 的命令行导入器,它能把 Jira 通过"高级搜索 + XML 导出"得到的数据文件,转换成一个可在 Focalboard 中直接"导入归档"的.boardarchive文件,从而实现从 Jira 到 Focalboard 的自托管迁移。本文以仓库中的 import/jira/README.md 为主体,结合 importJira.ts、jiraImporter.ts 等源码,完整讲解环境准备、命令行用法、字段映射规则、归档格式原理与已知限制,让你读完即可独立完成一次 Jira 数据迁移。
一、迁移原理与整体流程
Jira 导入器是一个独立于 Focalboard 服务端与 WebApp 的 Node 命令行程序,核心入口为 importJira.ts。它不直接访问 Jira API,而是消费 Jira 官方"Export XML"功能生成的标准 RSS/XML 文件。
整条链路可以分为四个阶段:
- 导出:在 Jira 高级搜索(Advanced Search)中筛选出所有需要迁移的 Issue,通过
Export → Export XML得到本地 XML 文件; - 解析:导入器使用
xml2js把 XML 解析为 JavaScript 对象,遍历<channel>下的每一个<item>(对应一条 Jira Issue); - 转换:将每条 Issue 映射为 Focalboard 的 Card(卡片),并为整批数据创建一个 Board(看板)与一个 Board View(视图);
- 归档:通过
ArchiveUtils.buildBlockArchive把 Board 与 Block 序列化为 Focalboard 的标准归档格式.boardarchive,最后在 Focalboard 界面执行"导入归档"即可。
从源码看,jiraImporter.ts 的run(inputFile, outputFile)函数完整实现了"读取输入 → 校验 → 解析 → 转换 → 写出"的主流程,其返回值为导出的 Block 数量,这也是 jiraImporter.test.ts 断言blockCount === 4的依据(2 张卡片 + 1 个视图 + 1 个文本块等)。
二、环境准备与依赖安装
导入器依赖仓库内两处npm install,缺一不可:
- WebApp 依赖:导入器直接 import 了
../../webapp/src/blocks/下的类型与工厂函数(如createBoard、createCard、createTextBlock),因此需要先在focalboard/webapp下安装依赖; - 导入器自身依赖:
import/jira/package.json声明了minimist(命令行参数解析)、xml2js(XML 解析)、turndown(HTML 转 Markdown)三个运行时依赖,以及ts-node、typescript、jest等开发依赖。
安装命令(建议按顺序执行):
cd focalboard/webapp npm install cd focalboard/import/jira npm installimport/jira/tsconfig.json使用module: commonjs、target: es2019并开启strict严格模式,说明该工具按 CommonJS 模块体系在 Node 环境中运行,配合ts-node可以直接执行 TypeScript 源码,无需预先编译。
三、使用步骤与命令行参数
3.1 在 Jira 中导出 XML
- 打开 Jira 的高级搜索(Advanced Search),用 JQL 筛选出需要迁移的所有 Issue;
- 点击搜索结果页的
Export,选择Export XML; - 将文件保存到本地,例如
jira_export.xml。
仓库中的测试样例 test/jira-export.xml 展示了 Jira XML 导出的真实结构:根节点为<rss version="0.92">,包含<channel>,其中每条 Issue 是一个<item>,内含<title>、<summary>、<type>、<priority>、<status>、<resolution>、<assignee>、<reporter>、<created>、<link>、<description>、<comments>、<attachments>与<customfields>等元素。文件头部的注释还提示:可以通过field=key&field=summary之类的参数限制导出字段。
3.2 执行导入命令
在focalboard/import/jira目录下运行:
npx ts-node importJira.ts -i <path-to-jira.xml> -o archive.boardarchive参数说明(对应 importJira.ts 的minimist解析逻辑):
| 参数 | 含义 | 默认值 | 说明 |
|---|---|---|---|
-i | 输入 Jira XML 文件路径 | 无(必填) | 缺失时打印用法并退出,文件不存在时以错误码 2 退出 |
-o | 输出归档文件路径 | archive.boardarchive | 可省略,默认写到当前目录 |
命令行帮助信息在 jiraImporter.ts 的showHelp()中定义为import -i <input.xml> -o [output.boardarchive]。若输入文件不存在或 XML 中缺少<rss><channel>结构,程序会打印File not found、No channels in xml等错误并退出。
3.3 在 Focalboard 中导入归档
- 打开 Focalboard 应用;
- 点击
Settings(设置); - 选择
Import archive(导入归档); - 选中生成的
archive.boardarchive文件。
导入后即可看到一个名为Jira import的看板,其中每条 Jira Issue 对应一张卡片。
3.4 测试与调试脚本
import/jira/package.json提供了两条便捷脚本,可用于验证环境与流程:
npm test # 运行 jest 测试,使用 test/jira-export.xml 执行完整导入 npm run testRun # ts-node importJira.ts -i test/jira_export.xml -o test/jira-import.focalboard其中npm run debug:test会以node --inspect=5858的方式启动调试端口,方便在 IDE 中逐步跟踪转换逻辑。
四、字段映射规则:Jira Issue → Focalboard Card
转换的核心逻辑集中在 jiraImporter.ts 的convert()函数中。迁移后看板名为Jira import,并创建一个名为Board View的看板视图(boardView.ts 中定义,viewType: 'board')。
4.1 标准属性映射
导入器为看板预置了 8 个卡片属性,其中 6 个为 Select(单选)类型,2 个为 URL / 日期类型:
| Jira XML 字段 | Focalboard 属性名 | 属性类型 | 说明 |
|---|---|---|---|
<priority> | Priority | select | 优先级,如 Medium |
<status> | Status | select | 状态,如 In Progress、To Do |
<resolution> | Resolution | select | 解决结果,如 Unresolved |
<type> | Type | select | 问题类型,如 Task、Epic |
<assignee> | Assignee | select | 经办人 |
<reporter> | Reporter | select | 报告人 |
<link> | Original URL | url | 原始 Issue 链接 |
<created> | Created Date | date | 创建时间(毫秒时间戳) |
Select 属性的选项(Option)由buildCardPropertyFromValues动态生成:先对全部 Issue 的取值去重,再为每个取值生成一个带颜色的 Option。颜色取自optionColors数组(propColorGray到propColorRed共 9 色循环分配),见 jiraImporter.ts 与 board.ts 中IPropertyOption的定义。设置卡片属性值时,setSelectProperty通过optionForPropertyValue按值查找对应 Option 的 ID 写入卡片;Created Date则由Date.parse转换为毫秒时间戳后存储。
4.2 描述文本转换
Jira 的<description>字段会通过turndownService.turndown()从 HTML 转换为 Markdown,然后创建一个text类型的文本块挂在卡片下,并通过card.fields.contentOrder指定其在卡片内容区的顺序(对应 card.ts 中CardFields.contentOrder字段)。转换后的描述文本会同步打印到控制台,便于核对。
4.3 未导入的内容
按 README.md 的说明与源码中的// TODO: Map custom properties注释,以下内容当前不会被导入:
- 自定义属性(Custom properties):
<customfields>下的 Development、Sprint、Rank、Start date 等自定义字段均被忽略; - 评论(Comments):
<comments>元素不会被转换; - 内嵌文件(Embedded files):
<attachments>附件不会被转换。
此外,README 明确提醒:Jira 的 XML 导出单次上限为 1000 条 Issue,超过后需要分批导出再分别导入。从实现看,jiraImporter.ts 中buildCardPropertyFromValues只读取了priority、status等标准元素,确实未解析<customfields>子节点,与文档所述限制一致。
五、输出归档格式:.boardarchive 的结构原理
导出的.boardarchive并非二进制,而是一种基于 JSON Lines 的文本归档格式,由 import/util/archive.ts 中的ArchiveUtils.buildBlockArchive生成:
- 首行为版本头:
{"version":1,"date":<时间戳>}; - 后续每行是一条记录,格式为
{"type":"board"|"block","data":{...}},其中board行承载看板定义(含cardProperties),block行承载视图、卡片、文本块等; - 行与行之间以换行符分隔,末尾空行会被忽略。
对应的ArchiveUtils.parseBlockArchive负责反向解析,它要求首行版本号>= 1且包含date,否则抛出ERROR parsing header;解析时按line.type分发,目前仅处理block类型。正是这套格式保证了导入器生成的归档可以被 Focalboard 的"导入归档"功能无缝识别。
六、验证方式与测试用例
仓库提供了可独立运行的 Jest 测试 jiraImporter.test.ts,它使用test/jira-export.xml作为输入、test/jira.focalboard作为输出,完成两件事:
- 数量断言:
expect(blockCount === 4),验证导入生成了 4 个 Block; - 内容断言:通过
ArchiveUtils.parseBlockArchive读回归档,断言其中包含Board View(类型view)、Investigate feature area与Investigate feature(类型card)。
运行npm test即可复现这一验证流程。测试还展示了run()返回 Block 数量这一返回值契约,以及归档文件可被parseBlockArchive完整读回的特性。
七、已知限制与扩展方向
综合 README 与源码,当前版本的导入器存在以下边界,规划迁移前应提前评估:
- 单看板迁移:所有 Issue 被导入到名为
Jira import的单个看板,不会按项目(Project)或 Epic 拆分多个看板; - 1000 条上限:Jira XML 导出单次最多 1000 条 Issue,大数据量需分批导出、多次导入;
- 用户以文本形式呈现:Assignee、Reporter 仅作为 Select 属性选项存在,不映射为 Focalboard 的成员(Person)属性;
- 三类内容缺失:自定义属性、评论、附件当前不在导入范围内;
- 描述仅限单文本块:每条 Issue 的多个描述段落会合并进一个 text 块,不会按段落拆分成多个内容块。
对于自定义属性等缺口,源码在convert()中预留了// TODO: Map custom properties的扩展点,buildCardPropertyFromValues也提供了"从取值集合自动生成 Select 属性"的通用模式,可作为自行扩展 Jira 导入能力的参考起点。
【免费下载链接】focalboardFocalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.项目地址: https://gitcode.com/GitHub_Trending/fo/focalboard
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考