用 tbls 把数据库文档纳入 CI:diff、lint 与覆盖率的实际用法
手写 schema 文档的结局基本固定:第一版很完整,之后每次 ALTER TABLE 都少改一处,几个月后没人敢信它。tbls 是一个 Go 写的单二进制工具,从数据库连接直接生成 GFM 格式的 Markdown 文档,也能把 schema 导出成多种格式。它的实际定位不是“文档生成器”,而是让文档和库不同步这件事变得可见:文档当产物生成、进版本库、在 CI 里比对。
项目地址:
最小可用配置
一条命令就能出文档:
$ tbls doc postgres://dbuser:dbpass@hostname:5432/dbname
默认输出到 dbdoc/。想改路径,在 .tbls.yml 里写:
dsn: postgres://dbuser:dbpass@localhost:5432/dbname
docPath: doc/schema # 默认是 dbdoc
密码里含 # 或 `)
没有 action 的 CI,用官方脚本装:
curl -sL https://raw.githubusercontent.com/k1LoW/tbls/main/use > use-tbls.tmp && . ./use-tbls.tmp && rm ./use-tbls.tmp
Debian/Ubuntu 默认 shell 是 dash,上面这段要按原样在 dash 下执行。之后在 CI 脚本里接 tbls diff 和 tbls lint 即可。DSN 走环境变量或 secret 注入,不要写进 .tbls.yml 提交。
其他值得知道的配置
数据源:PostgreSQL(postgres:// 或 pg://)、MySQL(mysql:// 或 my://)、MariaDB、SQLite(sqlite:///path)、BigQuery、Cloud Spanner、Redshift、MSSQL、Azure SQL/Fabric(实验性)、DynamoDB、Snowflake(实验性)、MongoDB(采样,?sampleSize=20、multipleFieldType)、ClickHouse、Databricks(实验性)、JSON、HTTP、GitHub。
MySQL 在 DSN 后加 ?hide_auto_increment,生成的文档里就不会出现 AUTO_INCREMENT 子句,减少噪音。
JSON 数据源值得单独提一句:先用 tbls out -t json 把当前 schema 导出成 json,之后就能用 json://path 把它当数据源读回来。没权限连库、或者想把 schema 快照存进仓库做版本对比时很有用。GitHub 数据源同理,可以直接读仓库里的文件:github://k1LoW/tbls/sample/mysql/schema.json。
外部 driver:PATH 上存在名为 tbls-driver-* 的可执行文件时,tbls 会按 scheme 识别它。driver 通过环境变量 TBLS_DSN 收到 DSN,把 schema.json 打到 STDOUT 即可,不用改 tbls 本体。
TLS:PostgreSQL / MySQL / MariaDB / MSSQL 支持 tls 段,字段为 ca / cert / key / verify: identity。ca 只校验服务端证书链、不校验主机名(等价于 mysql --ssl-mode=VERIFY_CA);verify: identity 才额外校验主机名。空值视为未设置,所以 ca: ${MYSQL_SSL_CA} 这种环境变量写法可用。如果同时写了与之矛盾的原生 TLS 参数(sslmode=disable、encrypt=disable、trustservercertificate=true、tls=preferred),tbls 直接报错;tls=true 保持完整校验,tls=skip-verify 会被升级处理。
输出格式:format 段可以调列宽、表列表和列的排序、行号、showOnlyFirstParagraph、hideColumnsWithoutValues(布尔值或数组)。
ER 图:er.format 支持 png / jpg / svg / mermaid,默认 svg;配合 er.skip、er.comment、er.hideDef、showColumnTypes(related / primary)等开关控制细节。
什么时候别用
- 只想临时看一眼某个库的结构:直接连库或
\d+更快,生成文档再打开反而绕。 - 库有几百张表、命名混乱、注释覆盖接近零:
tbls lint的输出会直接失去信号价值,先治理命名和注释再谈 CI 卡点。 - 需要跨库血缘、字段级 lineage 或数据质量监控:tbls 做的是 schema 文档和结构级 lint,这些不在它的范围内。
- 团队不打算把生成文档提交进版本库:diff 依赖的就是文档在仓库里,只生成不入库等于放弃了 tbls 最有价值的部分。