持续集成
为确保软件质量,团队通常会采用持续集成(CI)工作流。通过 CI,团队会对代码库的每次变更持续运行一套自动化验证流程。在 CI 过程中,团队可能运行多种验证:
- 编译或构建最新版本以确保没有破坏性变更
- 代码检查以强制执行公认的代码风格标准
- 单元测试以验证各个组件按预期工作,且代码库的变更不会导致其他领域出现回归问题
- 安全扫描以确保代码库不会引入已知漏洞
- 以及更多!
通过与 Ent 社区的交流,我们了解到许多使用 Ent 的团队已经采用 CI,并希望在其工作流中强制执行一些 Ent 特定的验证。
为支持社区这一需求,我们编写了本指南,其中记录了 CI 中常见的验证最佳实践,并介绍了我们维护的 GitHub Action ent/contrib/ci,该 Action 将这些最佳实践代码化。
验证所有生成文件已提交
Ent 重度依赖代码生成。根据我们的经验,生成的代码应始终提交到源代码控制中。这样做有两个原因:
- 如果将生成的代码提交到源代码控制中,它可以与主应用程序代码一起被阅读。在代码审查或浏览代码库时,存在生成的代码对于全面了解工作原理至关重要
- 可以轻松发现并修复团队成员之间开发环境的差异。这进一步减少了「在我机器上能运行」这类问题的发生几率,因为每个人都在运行相同的代码
如果您使用 GitHub 进行源代码控制,使用 ent/contrib/ci GitHub Action 可以轻松验证所有生成的文件是否已提交。否则,我们提供了一个简单的 bash 脚本,您可以将其集成到现有的 CI 流程中。
- GitHub Action
- Bash
只需在您的代码库中添加名为 `.github/workflows/ent-ci.yaml` 的文件:
name: EntCI
on:
push:
# 当 master 分支代码发生变更时运行
branches:
- master
# 在 PR 中 `ent/` 目录下有变更时运行
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-file: "go.mod"
- 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 schema 的更改几乎总是会导致数据库的修改。如果您使用版本化迁移来管理数据库模式变更,可以在持续集成流程中运行迁移检查。这样做有多个原因:
- 检查会在数据库容器上重放您的迁移目录,以确保所有 SQL 语句有效且顺序正确
- 强制执行迁移目录完整性——确保历史记录未被意外更改,并且并行规划的迁移能够统一为清晰的线性历史记录
- 检测破坏性变更,在迁移到达生产数据库之前通知您可能由迁移导致的任何潜在数据丢失
- 检查检测到数据依赖的变更,这些变更在部署时可能失败,需要您进行更仔细的审查
如果您使用 GitHub,可以使用官方 Atlas Action在 CI 期间运行迁移检查。
在您的代码库中添加 .github/workflows/atlas-ci.yaml 文件,内容如下:
- MySQL
- MariaDB
- PostgreSQL
- SQLite
name: Atlas CI
on:
# 当 master 分支代码发生变更时运行,
# 请将此更改为您的根分支。
push:
branches:
- master
# 在 PR 中 `ent/migrate/migrations/` 目录下有变更时运行
pull_request:
paths:
- "ent/migrate/migrations/*"
jobs:
lint:
services:
# 启动 mysql:8.0.29 容器作为开发数据库用于分析
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
- uses: ariga/setup-atlas@v0
with:
cloud-token: ${{ secrets.ATLAS_CLOUD_TOKEN }}
- uses: ariga/atlas-action/migrate/lint@v1
with:
dir: "file://ent/migrate/migrations"
dir-name: "my-project" # Atlas Cloud 中的项目名称
dev-url: "mysql://root:pass@localhost:3306/dev"
name: Atlas CI
on:
# 当 master 分支代码发生变更时运行,
# 请将此更改为您的根分支。
push:
branches:
- master
# 在 PR 中 `ent/migrate/migrations/` 目录下有变更时运行
pull_request:
paths:
- "ent/migrate/migrations/*"
jobs:
lint:
services:
# 启动 maria:11 容器作为开发数据库用于分析
mariadb:
image: mariadb:11
env:
MYSQL_DATABASE: dev
MYSQL_ROOT_PASSWORD: pass
ports:
- "3306:3306"
options: >-
--health-cmd "healthcheck.sh --su-mysql --connect --innodb_initialized"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ariga/setup-atlas@v0
with:
cloud-token: ${{ secrets.ATLAS_CLOUD_TOKEN }}
- uses: ariga/atlas-action/migrate/lint@v1
with:
dir: "file://ent/migrate/migrations"
dir-name: "my-project" # Atlas Cloud 中的项目名称
dev-url: "maria://root:pass@localhost:3306/dev"
name: Atlas CI
on:
# 当 master 分支代码发生变更时运行,
# 请将此更改为您的根分支。
push:
branches:
- master
# 在 PR 中 `ent/migrate/migrations/` 目录下有变更时运行
pull_request:
paths:
- "ent/migrate/migrations/*"
jobs:
lint:
services:
# 启动 postgres:15 容器作为开发数据库用于分析
postgres:
image: postgres:15
env:
POSTGRES_DB: dev
POSTGRES_PASSWORD: pass
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ariga/setup-atlas@v0
with:
cloud-token: ${{ secrets.ATLAS_CLOUD_TOKEN }}
- uses: ariga/atlas-action/migrate/lint@v1
with:
dir: "file://ent/migrate/migrations"
dir-name: "my-project" # Atlas Cloud 中的项目名称
dev-url: postgres://postgres:pass@localhost:5432/dev?sslmode=disable
name: Atlas CI
on:
# 当 master 分支代码发生变更时运行,
# 请将此更改为您的根分支。
push:
branches:
- master
# 在 PR 中 `ent/migrate/migrations/` 目录下有变更时运行
pull_request:
paths:
- "ent/migrate/migrations/*"
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ariga/setup-atlas@v0
with:
cloud-token: ${{ secrets.ATLAS_CLOUD_TOKEN }}
- uses: ariga/atlas-action/migrate/lint@v1
with:
dir: "file://ent/migrate/migrations"
dir-name: "my-project" # Atlas Cloud 中的项目名称
dev-url: sqlite://file?mode=memory&_fk=1
请注意,运行 atlas migrate lint 需要一个干净的开发数据库,该数据库由上述示例代码中的 services 块提供。