为确保软件质量,团队通常会使用 持续集成(CI)工作流。通过 CI,团队会针对代码库的每一次变更持续运行一套自动化验证。 在 CI 期间,团队可能执行多种验证:
- 编译或构建最新版本,以确保其不被破坏。
- 代码静态检查,确保符合接受的代码规范。
- 单元测试,验证各个组件是否按预期工作,并确保对代码库的更改不会引起其他领域的回归。
- 安全扫描,确保代码库中未引入已知漏洞。
- 以及更多!
从与 Ent 社区的讨论中,我们了解到许多使用 Ent 的团队已经在使用 CI,并希望在其工作流中加入一些特定于 Ent 的验证。
为支持社区的这一工作,我们在文档中新增了一个指南,记录了在 CI 中验证的常见最佳实践,并介绍了我们维护的 ent/contrib/ci:一个将这些实践编入代码的 GitHub Action。
在本文中,我想分享一些我们初步建议,说明如何将 CI 融入您的 Ent 项目。文章后半部分将分享我们正在进行的一些项目,并希望获取社区的反馈。
验证所有生成文件已提交
Ent 大量依赖代码生成。根据我们的经验,生成的代码应始终提交到版本控制。这样做的原因有两个:
- 如果生成的代码已提交到版本控制,它可以与主应用代码一起查看。在代码审查或仓库浏览时,拥有生成代码是了解其工作机制完整的必要条件。
- 团队成员的开发环境差异可以很容易被发现并解决。这进一步降低了“仅在我的机器上能跑”的问题,因为所有人都运行相同的代码。
如果您使用 GitHub 做版本控制,您可以使用 ent/contrib/ci GitHub Action 轻松验证所有生成文件已提交。否则,我们提供一个简单的 Bash 脚本,您可以将其集成到现有 CI 流程中。
- GitHub Action
- Bash
只需在您的仓库中添加一个名为 .github/workflows/ent-ci.yaml 的文件:
name: EntCI
on:
push:
# Run whenever code is changed in the master.
branches:
- master
# Run on PRs where something changed under the `ent/` directory.
pull_request:
paths:
- 'ent/*'
jobs:
ent:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.0.1
- uses: actions/setup-go@v3
with:
go-version: 1.18
- uses: ent/contrib/ci@master
go generate ./...
status=$(git status --porcelain)
if [ -n "$status" ]; then
echo "you need to run 'go generate ./...' and commit the changes"
echo "$status"
exit 1
fi
检查迁移文件
对项目的 Ent 模式进行更改几乎总会导致数据库的修改。如果您正在使用 版本化迁移 来管理数据库模式的更改,您可以将 迁移检查 作为持续集成流程的一部分运行。这样做的原因有多种:
- 语法检查会在数据库容器中重新执行您的迁移目录,以确保所有 SQL 语句有效且顺序正确。
- 迁移目录完整性 得到强制执行——确保历史记录未被意外更改,并且并行计划的迁移统一为干净的线性历史。
- 破坏性更改被检测,提前通知您迁移可能导致的潜在数据丢失,在到达生产数据库之前就可以发现。
- 语法检查还能发现依赖数据的更改,这些更改在部署时可能失败,需要您进行更仔细的审查。
如果您使用 GitHub,您可以使用官方 Atlas Action 在 CI 期间运行迁移检查。
在您的仓库中添加 .github/workflows/atlas-ci.yaml,内容如下:
- MySQL
- MariaDB
- PostgreSQL
name: Atlas CI
on:
# Run whenever code is changed in the master branch,
# change this to your root branch.
push:
branches:
- master
# Run on PRs where something changed under the `ent/migrate/migrations/` directory.
pull_request:
paths:
- 'ent/migrate/migrations/*'
jobs:
lint:
services:
# Spin up a mysql:8.0.29 container to be used as the dev-database for analysis.
mysql:
image: mysql:8.0.29
env:
MYSQL_ROOT_PASSWORD: pass
MYSQL_DATABASE: test
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.0.1
with:
fetch-depth: 0 # Mandatory unless "latest" is set below.
- uses: ariga/atlas-action@v0
with:
dir: ent/migrate/migrations
dir-format: golang-migrate # Or: atlas, goose, dbmate
dev-url: mysql://root:pass@localhost:3306/test
name: Atlas CI
on:
# Run whenever code is changed in the master branch,
# change this to your root branch.
push:
branches:
- master
# Run on PRs where something changed under the `ent/migrate/migrations/` directory.
pull_request:
paths:
- 'ent/migrate/migrations/*'
jobs:
lint:
services:
# Spin up a maria:10.7 container to be used as the dev-database for analysis.
maria:
image: mariadb:10.7
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.0.1
with:
fetch-depth: 0 # Mandatory unless "latest" is set below.
- uses: ariga/atlas-action@v0
with:
dir: ent/migrate/migrations
dir-format: golang-migrate # Or: atlas, goose, dbmate
dev-url: maria://root:pass@localhost:3306/test
name: Atlas CI
on:
# Run whenever code is changed in the master branch,
# change this to your root branch.
push:
branches:
- master
# Run on PRs where something changed under the `ent/migrate/migrations/` directory.
pull_request:
paths:
- 'ent/migrate/migrations/*'
jobs:
lint:
services:
# Spin up a postgres:10 container to be used as the dev-database for analysis.
postgres:
image: postgres:10
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.0.1
with:
fetch-depth: 0 # Mandatory unless "latest" is set below.
- uses: ariga/atlas-action@v0
with:
dir: ent/migrate/migrations
dir-format: golang-migrate # Or: atlas, goose, dbmate
dev-url: postgres://postgres:pass@localhost:5432/test?sslmode=disable
请注意,运行 atlas migrate lint 需要一个干净的[dev-database],它由上述示例代码中的 services 块提供。
Ent CI 的未来
为了在此基础上继续发展,我想分享一些我们在 Ariga 正在实验的功能,希望能够得到社区的反馈。
在线迁移的 Linting —— 许多 Ent 项目使用 Ent 提供的自动模式迁移机制(在应用启动时调用
ent.Schema.Create)。假设项目的源代码在版本控制系统(如 Git)中管理,我们将主分支(master/main等)中的模式与当前功能分支中的模式进行比较,并使用Atlas 的模式差异功能计算将对数据库执行的 SQL 语句。随后我们可以使用Atlas 的 Linting 功能来提供关于所提议更改可能产生的危险的见解。变更可视化 —— 为帮助审阅者理解特定拉取请求中提出的更改影响,我们生成可视化差异(使用类似于 entviz 的 ERD)以反映对项目模式的更改。
模式 Linting —— 使用官方的 go/analysis 包创建检查器,分析 Ent 模式的 Go 代码,并在模式定义层面强制执行政策(如命名或索引约定)。
总结
本文介绍了 CI 的概念,并讨论了在 Ent 项目中实践 CI 的方法。随后,我们展示了我们正在内部试验的 CI 检查。若您希望看到这些检查成为 Ent 的一部分,或有其他关于为 Ent 提供 CI 工具的想法,请在 Ent Discord 服务器 与我们联系。
- 订阅我们的新闻简报
- 在 Twitter 上关注我们
- 加入 #ent 在 Gophers Slack 上
- 加入我们的Ent Discord 服务器