使用 Regal `opa-fmt` 规则统一 Rego 代码风格:从 `opa fmt` 格式化到 Rego v0/v1 兼容实践
2026/9/24 15:16:10 网站建设 项目流程

使用 Regalopa-fmt规则统一 Rego 代码风格:从opa fmt格式化到 Rego v0/v1 兼容实践

【免费下载链接】opaOpen Policy Agent (OPA) is an open source, general-purpose policy engine.项目地址: https://gitcode.com/gh_mirrors/op/opa

本文是 Open Policy Agent(OPA)项目仓库内 Regal 文档中opa-fmt风格规则的深度指南,配套规则文档位于 docs/projects/regal/rules/style/opa-fmt.md。本文以该文档为主体,结合仓库内opa fmt命令源码(cmd/fmt.go)与 Regal 的配置、修复文档,讲解如何借助opa fmt与 Regal 保持团队级 Rego 格式一致,并理清 OPA 1.0 时代 Rego v0/v1 混合代码库的格式化规则。

规则速览:opa-fmt是什么

opa-fmt是 Regal 的Style(风格)类别下的 linter 规则,其核心约束只有一句话:

文件应当使用opa fmt进行格式化。

属性
规则名opa-fmt
类别Style
默认严重级别error
是否可自动修复(见 docs/projects/regal/fixing.md)

它要避免的问题是:策略文件和仓库之间出现不一致的代码风格。例如缩进混用空格与制表符、import顺序混乱、规则体换行风格不一等。opa fmt是 OPA 官方提供的 Rego 源码格式化器,Regal 将其作为风格底线——凡是 Regal 判定的“与opa fmt输出不一致”的文件,都会触发该违规。

为什么需要这条规则:一致性是团队协作的隐形收益

opa fmt能够跨团队、跨项目保证格式一致,而“统一格式化”是收益巨大的工程实践:它能把代码评审中围绕风格细节的争论时间省下来,让评审聚焦于真正的策略逻辑。规则文档的原话是:

Unified formatting is a big win, and saves a lot of time in code reviews arguing over details around style.

Regal 给出的实践建议是:在绝大多数编辑器中,可以配置保存时自动执行opa fmt --write,让格式化成为“无感”的日常动作,而不是评审时的口头约定。

关于 Tab 缩进与.editorconfig

opa fmt使用制表符(tab)作为缩进。默认情况下,GitHub 用 8 个空格宽度来显示 tab,这“多少有点太宽”。有两个办法改善显示效果:

  1. github.com/settings/appearance中调整自己的 tab 显示偏好;
  2. 更推荐的做法:在策略仓库根目录提供.editorconfig文件,GitHub(以及其他工具)会据此正确显示 Rego 文件。

规则文档给出了可直接复制的.editorconfig示例:

[*.rego] end_of_line = lf insert_final_newline = true charset = utf-8 indent_style = tab indent_size = 4

各字段含义:

  • end_of_line = lf:统一使用 LF 换行,避免跨平台(Windows CRLF)差异污染 diff;
  • insert_final_newline = true:文件末尾保留一个换行,这是opa fmt输出也遵循的约定;
  • charset = utf-8:文件统一 UTF-8 编码,兼容中文注释等非 ASCII 内容;
  • indent_style = tab:缩进风格为制表符,与opa fmt保持一致;
  • indent_size = 4:单个 tab 按 4 个空格宽度显示,兼顾紧凑与可读。

opa fmt命令实战:参数与行为

opa-fmt规则的内核就是opa fmt命令。该命令在仓库中的实现位于 cmd/fmt.go,支持从 stdin 读取或按路径处理.rego文件(仅处理.rego扩展名文件,见 formatFile 中对扩展名的判断)。核心参数如下(均来自 initFmt 中的标志注册):

参数简写默认值说明
--write-wfalse直接覆盖原文件,而不是输出到 stdout
--list-lfalse只列出“格式化后会发生改变”的文件名,并抑制其他 stdout 输出
--diff-dfalse只显示格式化前后的差异(基于 go-diff 的 pretty diff)
--failfalse若文件需要被重新格式化则返回非零退出码,常用于 CI
--check-resulttrue断言格式化结果仍是可被成功解析的合法 Rego
--drop-v0-importsfalse从格式化结果中移除 v0 时代导入,如rego.v1future.keywords
--rego-v1false将模块格式化为同时兼容 Rego v0 与 v1
--v0-compatiblefalse按 Rego v0 解析与格式化,v1 输入会被拒绝
--v1-compatiblefalse按 Rego v1 解析与格式化,v0 输入会被拒绝
--capabilities-c当前版本指定能力集(capabilities)文件,控制可用的内置函数与关键词

典型用法组合:

# 查看某文件格式化后的输出(不改动文件) opa fmt policy.rego # 直接写回 opa fmt --write policy.rego # CI 检查:若有文件需要格式化则退出码非 0 opa fmt --fail --list . # 只看差异 opa fmt --diff policy.rego

从源码看,formatFile的执行链路是:读取文件内容 → 以format.SourceWithOpts生成格式化结果 → 用bytes.Equal比较原内容与格式化结果 → 依据--list/--diff/--fail/--write组合决定输出、报错或写回(见 cmd/fmt.go)。其中--fail在文件有改动时抛出 "unexpected diff" 错误并返回退出码 2,这正是 CI 场景的基石。

OPA 1.0 时代:Rego v1 与 v0 的格式化差异

OPA 1.0 起,Rego v1 成为默认版本,这要求opa fmt命令的功能随之调整,并新增了一批用于处理混合版本代码库的选项。opa-fmt规则文档明确指出 Regal 在两种版本下的判定逻辑:

  • v0 文件:除非它已经用opa fmt --v0-v1格式化过,否则报opa-fmt违规;
  • v1 文件:除非它已经用opa fmt格式化过,否则报opa-fmt违规(rego.v1关键词是允许但不强制添加的)。

opa fmt在不同参数下的版本化行为(来自 initFmt 的命令帮助文本):

命令形式行为
opa fmtv1 Rego 按 v1 格式化;rego.v1/future.keywords导入不会被移除,也不会在缺失时补加;v0 Rego 被拒绝
opa fmt --v0-compatiblev0 Rego 按 v0 格式化;v1 Rego 被拒绝
opa fmt --rego-v1v0 Rego 被格式化为同时兼容 v0 与 v1;v1 Rego 被拒绝
opa fmt --rego-v1 --v1-compatiblev1 Rego 被格式化为同时兼容 v0 与 v1;v0 Rego 被拒绝

注意--rego-v1--v0-v1是同一标志的两种写法(源码中由addRegoV0V1FlagWithDescription注册)。这些标志的优先级在regoVersion()函数中有明确约定(见 [cmd/fmt.go#L50-L63]):--rego-v1优先于--v1-compatible--v0-compatible又优先于--v1-compatible;都未指定时使用ast.DefaultRegoVersion

按配置决定版本:混合版本项目的关键实践

Regal 在格式化时如何判断某个文件该用 v1 还是 v0?规则文档给出关键结论:

当根据配置预期某文件是 v1,但文件实际包含 v0 语法时,仍会按opa fmt --v0-v1来格式化。

也就是说,opa-fmt规则(及其修复器)会参考项目的 Rego 版本配置。相关配置方法详见 docs/projects/regal/configuration/rego-version.md:

project: # Rego 版本 1.0;对 1.0 之前的策略设为 0 rego-version: 1

也可以为不同的 project root 指定不同版本,便于在同一仓库中管理新旧代码:

project: roots: - path: lib/legacy rego-version: 0 - path: main rego-version: 1

Regal 还会扫描项目中的.manifest文件,使用其中的rego_version字段作用于该目录及其子目录下的所有策略;配置文件中rego-version的优先级高于 manifest 中的rego_version。版本配置的完整优先级为:project.roots下的rego-versionproject下的rego-version.manifest中的rego_version(详见 docs/projects/regal/opa-one-dot-zero.md)。此外,以_v0.rego后缀结尾的文件会被 Regal 自动按 v0 解析,仅供测试开发场景使用。

配置opa-fmt规则

该规则提供如下配置选项(完整规则清单可见 docs/projects/regal/rules/style/index.md):

rules: style: opa-fmt: # 可选值:"error"、"warning"、"ignore" level: error
  • error:默认值,出现违规时 Regal 以错误级别报告并导致 lint 失败;
  • warning:降级为警告,不阻断;
  • ignore:完全关闭该规则。

如果希望全项目统一格式但不想让老代码一次性“爆红”,可先降级为warning观察存量问题,再逐步通过自动修复收敛到error

自动修复:regal fix与编辑器 Code Action

opa-fmt是 Regal 中可自动修复的规则之一(完整可修复规则清单见 docs/projects/regal/fixing.md)。修复方式有两种:

1. 命令行regal fix:与regal lint是互补关系,配置了 ignore 的规则同样不会被修复。执行前建议先用--dry-run预览将要发生的改动,并先提交或 stash 现有改动,便于事后审查与回退:

# 预览会发生的修复 regal fix --dry-run bundle # 实际应用修复 regal fix bundle

2. 编辑器 Code Action:接入 Regal LSP 后,违规处会显示“灯泡”图标,点击即可应用opa-fmt对应的修复。这种方式一次只作用于当前文件,没有 dry-run,但可以借助编辑器的 Undo 轻松回退。关于编辑器集成可参考 docs/projects/regal/editor-support.md 与 docs/projects/regal/language-server.md。

在 CI 中,除了regal lint之外,也可以直接使用opa fmt --fail --list .作为门禁——这与opa-fmt规则的目标完全一致:任何未被opa fmt格式化的文件都会导致流水线失败。将两者结合(CI 强制 + 编辑器保存时自动opa fmt --write+.editorconfig规范缩进显示)即可形成从“写入代码”到“合并入主干”的完整格式保障链路。

延伸阅读

  • 规则文档原文:docs/projects/regal/rules/style/opa-fmt.md
  • opa fmt命令实现:cmd/fmt.go
  • Regal 的 Rego 版本配置:docs/projects/regal/configuration/rego-version.md
  • Regal 与 OPA 1.0:docs/projects/regal/opa-one-dot-zero.md
  • 违规自动修复指南:docs/projects/regal/fixing.md

【免费下载链接】opaOpen Policy Agent (OPA) is an open source, general-purpose policy engine.项目地址: https://gitcode.com/gh_mirrors/op/opa

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询