拆分成多个文件的 Structurizr 工作区,现在可以导入 Archyl 了

有些 Structurizr 工作区几乎什么都不放在 workspace.dsl 里。一个头部、一个 model 块,再加一列 !include 行,每个系统一行,真正的模型分散在这些行指向的文件里。

直到本周,Archyl 都无法导入这种工作区。我们 8 月 4 日关于 Structurizr Cloud 关停的文章用一句话提过:多文件工作区必须先合并成一个文件。这就把每个系统单独放在一个文件里的工作区排除在外了。Structurizr Cloud 将于 9 月 30 日关停,也就是两周之后。

现在你可以把工作区作为 .zip 上传,Archyl 会依据其中的文件解析每一个 !include。

为什么单个文件从来就行不通

以这样组织的工作区为例:

workspace.dsl
model/
  people.dsl
  relationships.dsl
systems/
  ledger.dsl
  notifications.dsl
  payments.dsl

根文件只负责把各部分拼接起来:

workspace "Payments Platform" "Card payments and settlement" {
    model {
        !include model/people.dsl
        !include systems
        !include model/relationships.dsl
    }
}

单独上传或粘贴这个根文件,导入器就没有任何依据来解析这些路径。它会解析手头已有的内容,跳过每个 include,并提示你:

line 3: directive '!include' is not supported and was skipped
line 4: directive '!include' is not supported and was skipped
line 5: directive '!include' is not supported and was skipped

这些警告是准确的,但它们也就是全部结果:那六个文件的内容一点都没有进来。自成一体的单个 .dsl 文件仍然和以前完全一样地导入。zip 是为其他所有情况准备的。

打包工作区目录,而不是整个仓库

如果你的工作区用了 !include,那些拆分出来的文件一定以文件形式存在于某个地方。Structurizr 的 include 文档这样描述文件 include:"a single local file, specified by a relative path" ——通过相对路径指定的单个本地文件。所以真正要紧的那份在磁盘上或 Git 里,不在云端。找到包含 workspace.dsl 的目录,把它打成 zip。

在该目录内执行:

zip -r workspace.zip workspace.dsl model systems

或者,如果工作区在某个仓库里,直接从一个 commit 打包:

git archive --format=zip -o workspace.zip HEAD:docs/architecture

这个区别很重要,因为归档最多只能有 500 个条目,而且这个数量是在做任何过滤之前检查的。把整个仓库连同 .git 文件夹一起打包,可能还没读到一个 .dsl 文件就已经超出上限。归档顶层多一层外包文件夹没有问题,因为 include 是相对于发起 include 的那个文件来解析的。

上传之后会发生什么

在导入弹窗里,Structurizr DSL 标签页上的按钮现在显示为 上传 .dsl 或 .zip。选择一个归档后,代码编辑器会被一张显示其名称和大小的卡片取代。点击 验证,卡片上会再加上文件数量和它选定的根文件。

无论是导入到已有项目,还是新建项目,都可以这样用。新项目的名称取自工作区头部,所以 workspace "Payments Platform" { ... } 可以创建项目,而不带名称的 workspace { ... } 不行。

在服务器端,归档会经过四个步骤:

  1. 选定根文件。 如果归档里有 workspace.dsl 就用它,否则用层级最浅的 .dsl 文件。当需要在多个文件之间选择、而且没有一个叫 workspace.dsl 时,会有一条警告写明它用了哪个文件。
  2. 在解析之前,以文本方式展开 include。 被 include 的文件内容会替换 !include 那一行,这和 Structurizr 自己做的内联是同一种方式。路径相对于发起 include 的文件,所以 systems/index.dsl include shared/platform.dsl 时,找到的是 systems/shared/platform.dsl。
  3. 解析目录 include。 !include systems 会按名称顺序引入 systems/ 下直接包含的每个 .dsl 文件。不会遍历子目录。
  4. 在边界处停下。 如果某个文件最终 include 了自己,无论是直接还是经由其他文件,这个循环会被切断并报告。嵌套最多 10 层。

展开后的工作区随后会经过与单个文件相同的 Structurizr 导入器,保真度相同,对跳过的内容也给出同样的警告列表。

无法解析的 include,比如文件缺失或路径指向归档之外,同样会变成一条警告。工作区的其余部分照常导入。

远程 include 是有意拒绝的

Structurizr 还允许 !include 指向一个 HTTPS URL。Archyl 不会跟随这类地址。如果去解析它们,任何上传的文件都能让我们的服务器去请求它自己指定的地址,无论上传者是谁,这都是一条服务端请求伪造的攻击途径。这一行会被跳过并给出警告:

!include: remote target "https://example.com/shared/identity.dsl" is not supported and was skipped

如果远程文件里有你需要的模型元素,把它下载到归档里,并把这一行改成相对路径。

限制

限制项 值 超出时
归档大小 10 MiB 拒绝上传
归档中的条目数 500 拒绝上传
展开后的总大小 50 MiB 拒绝上传
任意单个文件 5 MiB 跳过该文件,并给出警告
include 嵌套 10 层 跳过更深层的 include,并给出警告

路径试图逃出归档的条目,无论是通过绝对路径还是 .. 片段,都会被跳过并给出警告。只保留文本文件:.dsl、.md、.json、.yaml、.yml 和 .txt。图片和其他所有文件都会被直接丢弃,不给警告,因为 DSL 导入器用不上它们。

它仍然做不到的事

Git 同步不会解析 include。 仓库同步读取的是 archyl.yaml,而不是 Structurizr 工作区,所以目前还没有任何路径能让 Archyl 直接从仓库拉取多文件 DSL。如果你的 DSL 在 Git 里,眼下的工作流就是上面那条 git archive 命令。

Structurizr 保真度方面没有其他变化。 布局、样式和 deployment view 以前不导入,从 zip 导入时也不导入。同样还没有 workspace.json 的导入路径:Archyl 读取的是 DSL 文本。如果你在 Structurizr 里最看重的是手工调整过的布局,那么关停文章中那些让你继续使用 Structurizr 自家工具的选项,仍然更合适。

9 月 30 日之前

  1. 确认源文件在你手里。 用 !include 拆分的工作区本来就是以文件形式编写的,所以把它们找出来。如果有东西只存在于云端副本里,比如在浏览器里微调过的布局,或者在那里写的文档,8 月 4 日的文章讲了怎么把它们导出来。
  2. 把包含 workspace.dsl 的目录打成 zip,而不是它外面的整个仓库。
  3. 上传并验证。 打开 Import Project,或者已有项目内的导入弹窗,选择 Structurizr DSL,上传 zip,然后点击 验证。导入之前,检查它选定的根文件,并逐条阅读警告。
  4. 把这个目录 commit 到一个仓库里,如果它还不在仓库中的话,这样下一个人就不必去你的笔记本电脑上找它了。

导入器的完整行为,包括新项目的命名规则,请见 Architecture as Code 文档。关于 Archyl 能导入的其他格式,请参阅导入 Structurizr、LikeC4 和 IcePanel 项目。