干货分享!基于 Github Action 的 taosX CI 搭建
使用 GitHub Action 优化现有 CI 流程
.github/workflows
目录下。其定义分为以下几个部分:# 名称 name: PR-QA-workflow # 触发方式 on: workflow_dispatch: pull_request: # 全局变量 env: RELEASE_HOST: 192.168.1.45 RUSTFLAGS: "-C instrument-coverage --cfg tokio_unstable" ARTIFACT_BASE_DIR: /data/artifacts COVERAGE_BASE_DIR: /data/coverage DIR_PATH: ${{ github.event.number }} RUN_UNIT_TEST_FILE_FLAG: /etc/taos/taosx_run_unit_test # 具体的job jobs: build_rust: ... build_go: ...
下文将按照 workflow 的顺序,对每个环节进行逐一介绍。
1.触发
on: workflow_dispatch: pull_request:
说明:
- on.workflow_dispatch:表示该 workflow 可以手动触发,不过 GitHub 限制该 workflow 必须位于默认分支上才可以手动触发,并且也只会在默认分支上生效。
- on.pull_request:表示当提交 PR 的时候对当前分支(PR 的源分支)触发。
2.全局环境变量
env: RELEASE_HOST: 192.168.1.45 RUSTFLAGS: "-C instrument-coverage --cfg tokio_unstable" # rust 用于获取覆盖率的编译用环境变量 ARTIFACT_BASE_DIR: /data/artifacts # 编译之后编译中间文件及可执行文件存放的根目录 COVERAGE_BASE_DIR: /data/coverage # 生成报告后报告存放的根目录 DIR_PATH_3_0: "3.0" # 下一级使用 3.0 或 PR Number DIR_PATH: ${{ github.event.number }} # 下一级使用 3.0 或 PR Number RUN_UNIT_TEST_FILE_FLAG: /etc/taos/taosx_run_unit_test
3.编译
1.在编译过程中,taosx、taosx-agent、opc 以及 mqtt 各个组件需要设置特定的环境变量,以便输出插桩程序。由于这些组件在编译过程中没有相互依赖,因此设置了三个可以并行执行的任务,分别负责各自组件的编译工作。
build_rust: runs-on: [self-hosted, linux, x64, qa, rust] build_go: runs-on: [self-hosted, linux, x64, qa, go] build_java: runs-on: [self-hosted, linux, x64, qa, java]
三个编译任务—Rust编译、Go编译、Java编译—之间不存在依赖关系,且各自在不同的机器上运行。因此,这三个任务可以同时并行执行。
2.在 taosx 及 taox-agent 编译和单元测试执行完成之后,需要将编译过程中产生的中间文件及可执行程序拷贝至特定目录,用以留存和区分。
- name: Copy files run: | ls $ARTIFACT_BASE_DIR/$DIR_PATH/bin || mkdir -p $ARTIFACT_BASE_DIR/$DIR_PATH/bin cp ./target/debug/taosx-build/debug/taosx ./target/debug/taosx-agent-build/debug/taosx-agent $ARTIFACT_BASE_DIR/$DIR_PATH/bin/ cp -r ./target/debug/taosx-profraw/ $ARTIFACT_BASE_DIR/$DIR_PATH/ cp -r ./target/debug/taosx-agent-profraw/ $ARTIFACT_BASE_DIR/$DIR_PATH/ cd .. tar --exclude=./taosx/target/* -zcvf taosx.tar.gz ./taosx cp taosx.tar.gz $ARTIFACT_BASE_DIR/$DIR_PATH/ rm taosx.tar.gz tar -xzf $ARTIFACT_BASE_DIR/$DIR_PATH/taosx.tar.gz -C $ARTIFACT_BASE_DIR/$DIR_PATH/ rm $ARTIFACT_BASE_DIR/$DIR_PATH/taosx.tar.gz
4.单元测试
1.前期由于单元测试可能存在不稳定,或者单元测试耗时较长等问题的存在,添加了依据 /etc/taos/taosx_run_unit_test 该文件是否存在执行单元测试的逻辑。若该文件存在,则执行。
2.taosx 编译及运行单元测试的配置如下:
- name: Build taosx run: | # build taosx and taosx-agent # export RUSTFLAGS="-C instrument-coverage --cfg tokio_unstable" rm -rf ./target/debug/taosx-profraw/ export LLVM_PROFILE_FILE="./target/debug/taosx-profraw/taosx-%p-%m.profraw" cargo build --target-dir ./target/debug/taosx-build/ - name: taosx unit test continue-on-error: true run: | if [ -f "$RUN_UNIT_TEST_FILE_FLAG" ]; then echo "run taosx unit test" cargo llvm-cov nextest --workspace cargo llvm-cov report --lcov --output-path $ARTIFACT_BASE_DIR/$DIR_PATH/taosx-unit-test-lcov.info fi
taosx 运行完单元测试之后,会输出单元测试覆盖率报告到 $ARTIFACT_BASE_DIR/$DIR_PATH/,用于之后与端到端测试的覆盖率结果进行合并。
3.MQTT 编译机运行单元测试的配置如下:
- name: Build mqtt run: | cd plugins/mqtt go build -cover -o taosx-mqtt - name: Run Mqtt Unit Test continue-on-error: true run: | cd plugins/mqtt if [ -f "$RUN_UNIT_TEST_FILE_FLAG" ]; then echo "run mqtt unit test" go test -coverpkg=./... -coverprofile=mqtt_unit_report.txt -timeout=5s ./... fi - name: Copy MQTT Files run: | cd plugins/mqtt if [ -f "mqtt_unit_report.txt" ]; then ssh root@$RELEASE_HOST "ls $ARTIFACT_BASE_DIR/$DIR_PATH/go_cover/mqtt_cover_data/ || mkdir -p $ARTIFACT_BASE_DIR/$DIR_PATH/go_cover/mqtt_cover_data/" scp mqtt_unit_report.txt root@$RELEASE_HOST:$ARTIFACT_BASE_DIR/$DIR_PATH/go_cover/mqtt_cover_data/ rm mqtt_unit_report.txt fi ssh root@$RELEASE_HOST "ls $ARTIFACT_BASE_DIR/$DIR_PATH/bin/mqtt || mkdir -p $ARTIFACT_BASE_DIR/$DIR_PATH/bin/mqtt/" scp taosx-mqtt root@$RELEASE_HOST:$ARTIFACT_BASE_DIR/$DIR_PATH/bin/mqtt/
同样,MQTT 的单元测试报告在单元测试完成之后会输出,并拷贝到 $ARTIFACT_BASE_DIR/$DIR_PATH/go_cover/mqtt_cover_data/
,用于之后与端到端测试覆盖率报告合并。
5.部署
1.在部署过程中,需要进行两次部署操作。首先是为 MQTT 用例的执行进行部署。在这一阶段,由于 taosx 或 taosx-agent 需要以子进程的形式启动 taosx-mqtt,因此在运行 MQTT 用例时,必须配置相应的环境变量。如下:
steps: - name: Deploy taosx run: | pwd ls ${{ github.workspace }} # run taosx ssh root@$RELEASE_HOST "ls $ARTIFACT_BASE_DIR/$DIR_PATH_3_0/go_cover/mqtt_cover_data/ || mkdir -p $ARTIFACT_BASE_DIR/$DIR_PATH_3_0/go_cover/mqtt_cover_data/" ssh root@$RELEASE_HOST "nohup sh -c 'DATABASE_URL=/var/lib/taos/taosx/taosx.db LLVM_PROFILE_FILE=$ARTIFACT_BASE_DIR/$DIR_PATH_3_0/taosx-profraw/taosx-%p-%m.profraw GOCOVERDIR=$ARTIFACT_BASE_DIR/$DIR_PATH_3_0/go_cover/mqtt_cover_data/ PLUGINS_HOME=$ARTIFACT_BASE_DIR/$DIR_PATH_3_0/bin/ ENABLE_COVERAGE=true nohup $ARTIFACT_BASE_DIR/$DIR_PATH_3_0/bin/taosx serve > $ARTIFACT_BASE_DIR/$DIR_PATH_3_0/bin/taosx.log 2>&1 &'" - name: Deploy taosx-agent run: | pwd ls ${{ github.workspace }} # run taosx-agent ssh root@$RELEASE_HOST "nohup sh -c 'GOCOVERDIR=$ARTIFACT_BASE_DIR/$DIR_PATH_3_0/go_cover/mqtt_cover_data/ PLUGINS_HOME=$ARTIFACT_BASE_DIR/$DIR_PATH_3_0/bin/ ENABLE_COVERAGE=true LLVM_PROFILE_FILE=$ARTIFACT_BASE_DIR/$DIR_PATH_3_0/taosx-agent-profraw/taosx-agent-%p-%m.profraw nohup $ARTIFACT_BASE_DIR/$DIR_PATH_3_0/bin/taosx-agent > $ARTIFACT_BASE_DIR/$DIR_PATH_3_0/bin/taosx-agent.log 2>&1 &'"
2.第二次部署与第一次部署大体相同,区别是 GOCOVERDIR 的赋值会修改为 OPC 准备的目录。
GOCOVERDIR=$ARTIFACT_BASE_DIR/$DIR_PATH/go_cover/opc_cover_data
6.端到端测试
1.在部署完成之后,就可以执行端到端的测试。由于第一次部署设置的是 MQTT 的覆盖率文件的路径,所以第一次运行的测试也是 MQTT 的用例。
2.端到端测试的代码已经存放至 /data/github/TestNG_taosX
,每次执行之前只需要使用 git pull 更新代码即可。
3.在执行完端到端测试之后应该停止 taosx 及 taosx-agent 用于获取 taosx 及 agent 的覆盖率信息。此时需要通过 kill -2 关闭,这样能够发送 SIGINT 信号给指定的进程,使得进程能够优雅退出,不能通过 kill -9 否则无法成功获取覆盖率信息。
4.MQTT 的端到端测试用例的执行配置如下:
test_mqtt: runs-on: [self-hosted, linux, x64, qa, rust] needs: deploy_for_mqtt steps: - name: Update Repo run: | # 这里最好是 TestNG_taosx 已经被拉取到一个固定的位置 # 重新登录执行 git pull,因为当前的 git 仓库对应的是 taosx ssh root@$RELEASE_HOST "cd /data/github/TestNG_taosX && git pull" - name: Run Test run: | ls $COVERAGE_BASE_DIR/$DIR_PATH/allure_profile || mkdir -p $COVERAGE_BASE_DIR/$DIR_PATH/allure_profile cd /data/github/TestNG_taosX && source ./setenv.sh && poetry install && cd tests && poetry run pytest --alluredir=$COVERAGE_BASE_DIR/$DIR_PATH/allure_profile --timeout=300 -m sanity mqtt_test.py - name: Stop taosx-agent & taosx run: | pids=$(pgrep taosx-agent); if [ -n "$pids" ]; then for pid in $pids; do "run kill -9 taosx-agent"; kill -2 "$pid"; done; fi pids=$(pgrep taosx); if [ -n "$pids" ]; then for pid in $pids; do "run kill -9 taosx"; kill -2 "$pid"; done; fi - name: Force stop taosx-agent & taosx if: always() run: | pids=$(pgrep taosx-agent); if [ -n "$pids" ]; then for pid in $pids; do "run kill -9 taosx-agent"; kill -9 "$pid"; done; fi pids=$(pgrep taosx); if [ -n "$pids" ]; then for pid in $pids; do "run kill -9 taosx"; kill -9 "$pid"; done; fi
5.执行除 MQTT 之外的用例的 pytest 命令:
cd /data/github/TestNG_taosX && source ./setenv.sh && poetry install && cd tests \ && poetry run pytest --alluredir=$COVERAGE_BASE_DIR/$DIR_PATH_3_0/allure_profile \ --timeout=300 -m sanity -k "not mqtt_test.py"
说明:
- 执行
poetry install
安装测试依赖 - 执行
pytest
命令来运行自动化测试,通过-m
参数指定执行带有 sanity 标签的用例 - 通过
--alluredir
参数指定报告的目录 - 通过
--timeout
指定每个用例的超时时间,避免出现用例长时间挂起的情况
7.生成覆盖率报告
8.生成测试报告
- name: allure report run: | allure generate $COVERAGE_BASE_DIR/$DIR_PATH_3_0/allure_profile -o $COVERAGE_BASE_DIR/$DIR_PATH_3_0/allure_report/ --clean # 这里会直接输出报告的地址 echo "see report at $REPORT_BASE_URL/$DIR_PATH_3_0/allure_report/"
Job 的日志如下:
一个完整的例子
- 开发者通过提交 PR 触发 CI 运行。
- 通过点击执行的 Action 可以查看执行的结果。
- 可以通过点击下方的出错的任务查看任务出错的原因。
- 最后可以通过点击 generate_report 中查看报告的具体结果。