CI: Add GitHub Actions to test on multiple platforms (amd64, arm64, msvc) (#22)

feat: 添加 AIMRT github action

Key features of this workflow:
Runs automated tests on the mentioned platforms using matrix strategy in GitHub Actions.
Ensures that the code compiles and runs correctly on each platform.
The workflow is automatically triggered whenever the "ci ready" label is applied to a pull request or a new release is published, ensuring thorough testing and validation at critical stages of the development process.

---------
Co-authored-by: yuguanlin <yuguanlin@agibot.com>
This commit is contained in:
AimRT 2024-10-12 20:51:43 +08:00 committed by GitHub
parent 7d5fe68319
commit 7e4a55c39d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 897 additions and 2 deletions

138
.github/workflows/Main.yml vendored Normal file
View File

@ -0,0 +1,138 @@
name: CI/CD Workflow
on:
pull_request_target:
branches:
- '*'
types: [labeled]
release:
types: [published]
jobs:
check:
if: github.event.label.name == 'ci ready' || github.event_name == 'release'
uses: ./.github/workflows/cppcheck.yml
with:
image_name: registry.agibot.com/agibot-tech/gitlab-ci
image_tag: latest
secrets: inherit
test_gcc11_amd64:
uses: ./.github/workflows/test-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-amd64-gcc11-ubuntu22_04
image_tag: latest
run_platform: amd64
test_report: true
secrets: inherit
needs: [check]
test_gcc11_arm64:
uses: ./.github/workflows/test-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-arm64-gcc11-ubuntu22_04
image_tag: latest
run_platform: arm64
secrets: inherit
needs: [test_gcc11_amd64]
test_msvc:
uses: ./.github/workflows/test-msvc-workflow.yml
with:
run_platform: msvc
secrets: inherit
needs: [test_gcc11_amd64]
test_gcc12_amd64:
uses: ./.github/workflows/test-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-amd64-gcc12-ubuntu22_04
image_tag: latest
run_platform: amd64
secrets: inherit
needs: [test_gcc11_amd64]
test_gcc13_amd64:
uses: ./.github/workflows/test-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-amd64-gcc13-ubuntu22_04
image_tag: latest
run_platform: amd64
secrets: inherit
needs: [test_gcc11_amd64]
test_clang15_amd64:
uses: ./.github/workflows/test-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-amd64-clang15-ubuntu22_04
image_tag: latest
run_platform: amd64
secrets: inherit
needs: [test_gcc11_amd64]
test_clang16_amd64:
uses: ./.github/workflows/test-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-amd64-clang16-ubuntu22_04
image_tag: latest
run_platform: amd64
secrets: inherit
needs: [test_gcc11_amd64]
test_clang17_amd64:
uses: ./.github/workflows/test-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-amd64-clang17-ubuntu22_04
image_tag: latest
run_platform: amd64
secrets: inherit
needs: [test_gcc11_amd64]
test_clang18_amd64:
uses: ./.github/workflows/test-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-amd64-clang18-ubuntu22_04
image_tag: latest
run_platform: amd64
secrets: inherit
needs: [test_gcc11_amd64]
build_x86:
uses: ./.github/workflows/build-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-amd64-gcc11-ubuntu22_04
image_tag: v20240927
run_platform: amd64
secrets: inherit
needs: [test_msvc, test_gcc11_arm64, test_gcc12_amd64, test_gcc13_amd64, test_clang15_amd64, test_clang16_amd64, test_clang17_amd64, test_clang18_amd64]
build_arm64:
uses: ./.github/workflows/build-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/aimrt_ci-arm64-gcc11-ubuntu22_04
image_tag: latest
run_platform: arm64
secrets: inherit
needs: [test_msvc, test_gcc11_arm64, test_gcc12_amd64, test_gcc13_amd64, test_clang15_amd64, test_clang16_amd64, test_clang17_amd64, test_clang18_amd64]
build_msvc:
uses: ./.github/workflows/build-msvc-workflow.yml
with:
run_platform: msvc
secrets: inherit
needs: [test_msvc, test_gcc11_arm64, test_gcc12_amd64, test_gcc13_amd64, test_clang15_amd64, test_clang16_amd64, test_clang17_amd64, test_clang18_amd64]
release:
uses: ./.github/workflows/release-workflow.yml
with:
image_name: registry.agibot.com/agibot-tech/gitlab-ci
image_tag: latest
secrets: inherit
if: |
github.event_name == 'release' ||
startsWith(github.ref, 'refs/tags/release') ||
startsWith(github.ref, 'refs/tags/v') ||
startsWith(github.ref, 'refs/heads/release')
needs: [build_x86, build_arm64, build_msvc]

View File

@ -0,0 +1,79 @@
name: build Workflow
on:
workflow_call:
inputs:
run_platform:
required: false
type: string
default: msvc
secrets:
BUILD_CMD:
required: true
jobs:
build:
runs-on: ${{ inputs.run_platform }}
steps:
- name: Checkout code
uses: actions/checkout@v4
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Setup Visual Studio Developer Command Prompt
uses: microsoft/setup-msbuild@v1.0.2
- name: Install Chocolatey
run: |
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
if (Test-Path "C:\ProgramData\chocolatey\bin\choco.exe") {
Write-Host "Chocolatey is installed."
} else {
Write-Host "Chocolatey installation failed."
}
$env:Path += ";C:\ProgramData\chocolatey\bin"
[Environment]::SetEnvironmentVariable("Path", $env:Path, "Machine")
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
- name: Install Python using Chocolatey
run: |
$chocoPath = "C:\ProgramData\chocolatey"
$env:Path += ";$chocoPath\bin"
[Environment]::SetEnvironmentVariable("Path", $env:Path, "Machine")
# 使用完整路径执行 choco 命令
& "$chocoPath\bin\choco.exe" install python --version=3.11.0 -y
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
- name: Run build stage
shell: powershell
run: |
python --version
${{ secrets.BUILD_CMD_MSVC}}
if ($LASTEXITCODE -eq 1) {
Write-Host "build failed"
exit 1
} else {
Write-Host "build succeeded"
}
- name: upload build artifact
if: github.action
uses: actions/upload-artifact@v3
with:
name: build_artifact
path: |
${{vars.WHL_ARTIFACTS_DIR}}
retention-days: 3

68
.github/workflows/build-workflow.yml vendored Normal file
View File

@ -0,0 +1,68 @@
name: build Workflow
on:
workflow_call:
inputs:
image_name:
required: true
type: string
default: ubuntu
image_tag:
required: false
type: string
default: latest
run_platform:
required: false
type: string
default: amd64
secrets:
TEST_CMD:
required: true
jobs:
build:
runs-on: ${{ inputs.run_platform }}
container:
image: ${{ inputs.image_name }}:${{ inputs.image_tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Run build stage
env:
https_proxy: ""
http_proxy: ""
no_proxy: "*"
shell: bash
run: |
if [ -d "./build" ]; then
ls -lah ./build
fi
echo "removing CMakeCache.txt"
rm -rf ./build/CMakeCache.txt
source /opt/ros/humble/setup.bash
eval "${{ secrets.BUILD_CMD}}"
echo "ls -lah ${{vars.PROJECT_ARTIFACTS_DIR}}"
ls -lah ${{vars.PROJECT_ARTIFACTS_DIR}}
echo "ls -lah ${{vars.WHL_ARTIFACTS_DIR}}"
ls -lah ${{vars.WHL_ARTIFACTS_DIR}}
- name: upload build artifact
if: github.action
uses: actions/upload-artifact@v3
with:
name: build_artifact
path: |
${{vars.WHL_ARTIFACTS_DIR}}
retention-days: 3

246
.github/workflows/cppcheck.yml vendored Normal file
View File

@ -0,0 +1,246 @@
name: check Workflow
on:
workflow_call:
inputs:
image_name:
required: true
type: string
default: ubuntu
image_tag:
required: false
type: string
default: latest
jobs:
check:
runs-on: amd64
container:
image: ${{ inputs.image_name }}:${{ inputs.image_tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Get short sha
id: slug
run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT
- name: generate cppcheck.sh
run: |
echo "generate /tmp/cppcheck.sh ..."
cat << EOF >/tmp/cppcheck.sh
#!/bin/bash
echo "Running check.sh"
default_ignore=(
"build/"
".*_test.cc"
\${CPPCHECK_IGNORE[@]}
)
echo "default_ignore is : \${default_ignore[@]}"
# 构造忽略参数
ignore_args=""
for ignore in \${default_ignore[@]}; do
# 判断是否为目录
if [ -d "\$ignore" ]; then
ignore_args="-i\$ignore \$ignore_args"
else
files=\$(find . ! -path '*/build/*' -regex "\$ignore" -type f)
for file in \$files; do
ignore_args="-i\$file \$ignore_args"
done
fi
done
# 如果当前目录下没有cc或者cpp或者cxx或者c文件则直接退出不需要进行cppcheck检查
if [ -z "\$(find . -name "*.cc" -o -name "*.cpp" -o -name "*.cxx" -o -name "*.c")" ]; then
echo "no cc or cpp or cxx files, not need to cppcheck"
exit 0
fi
echo "check cmd is :"
echo "cppcheck . --enable=warning,style,performance,portability,missingInclude --xml \$ignore_args"
cppcheck . --enable=warning,style,performance,portability,missingInclude --xml \$ignore_args 2>/tmp/cppcheck.xml
# 如果cppcheck检查出错直接退出
if [ \$? -ne 0 ]; then
echo "cppcheck failed"
exit -1
fi
echo "github.sha is : ${{ github.sha }}"
echo "short_sha is : ${{ steps.slug.outputs.sha8 }}"
# 生成报告并提交到指定http文件服务器上
if [ -n "${{secrets.CPPCHECK_REPORT_POST_URL}}" ]; then
check_report_dir=${{ github.repository }}/${{ github.ref_name }}/${{ steps.slug.outputs.sha8 }}
mkdir -p \$check_report_dir
echo "github.repository_owner is : ${{ github.repository_owner }}"
echo "github.repository.name is : ${{ github.repository }}"
echo "github.ref_name is : ${{ github.ref_name }}"
echo "steps.slug.outputs.sha8 is : ${{ steps.slug.outputs.sha8 }}"
echo "check_report_dir is : \$check_report_dir"
cppcheck-htmlreport --file=/tmp/cppcheck.xml --title=CSA --report-dir=\$check_report_dir --source-dir=./
echo "check_report_dir is : \$check_report_dir"
# zip 压缩 \$check_report_dir
zip -r \${{ steps.slug.outputs.sha8 }}.zip \$check_report_dir
curl -F file=@${{ steps.slug.outputs.sha8 }}.zip -F unzip=true \${{secrets.CPPCHECK_REPORT_POST_URL}}
# 判断推送是否成功
if [ \$? -ne 0 ]; then
echo "cppcheck report push failed"
exit -1
fi
# 删除临时文件
rm -rf \$check_report_dir
rm -rf \${{ steps.slug.outputs.sha8 }}.zip
# 打印报告地址
# echo "cppcheck report url: ${{secrets.CPPCHECK_REPORT_POST_URL}}/\$check_report_dir/index.html"
echo -e "\\033[1;35m cppcheck report url: ${{secrets.CPPCHECK_REPORT_URL}}/\$check_report_dir/index.html \\033[0m"
fi
EOF
- name: generate cppcheck_analyze.py
run: |
echo "generate /tmp/cppcheck_analyze.py ..."
cat << EOF >/tmp/cppcheck_analyze.py
#!/usr/bin/env python3
import os
import sys
import xml.dom.minidom as minidom
#cppcheck 所有的错误类型的严重性
severityList=['information', 'performance', 'style', 'portability', 'warning', 'error']
informationSeverityCount = 0
performanceSeverityCount = 0
styleSeverityCount = 0
portabilitySeverityCount = 0
warningSeverityCount = 0
errorSeverityCount = 0
# 如果 /tmp/cppcheck.xml 文件不存在,则直接退出
if not os.path.exists('/tmp/cppcheck.xml'):
print("/tmp/cppcheck.xml not exists")
sys.exit(0)
# 打开cppcheck输出文件
with open('/tmp/cppcheck.xml', 'r') as file:
# 解析XML文件
dom = minidom.parse(file)
# 获取所有的error元素
errors = dom.getElementsByTagName('error')
for error in errors:
# 分别统计每种严重性的错误数
for i in range(len(severityList)):
if error.getAttribute('severity') == severityList[i]:
if i == 0:
informationSeverityCount += 1
elif i == 1:
performanceSeverityCount += 1
elif i == 2:
styleSeverityCount += 1
elif i == 3:
portabilitySeverityCount += 1
elif i == 4:
warningSeverityCount += 1
elif i == 5:
# 如果是syntaxError则不计入errorSeverityCount
if error.getAttribute('id') == 'syntaxError':
continue
# 如果是internalAstError则不计入errorSeverityCount
if error.getAttribute('id') == 'internalAstError':
continue
# 如果是internalAstError则不计入errorSeverityCount
if error.getAttribute('id') == 'unknownMacro':
continue
# 如 果msg中包含"Syntax"则不计入errorSeverityCount
if error.getAttribute('msg').find("Syntax") != -1:
continue
errorSeverityCount += 1
print(error.getAttribute('msg'))
# 打印结果
# print(severityList)
print("informationSeverityCount: ", informationSeverityCount)
print("performanceSeverityCount: ", performanceSeverityCount)
print("styleSeverityCount: ", styleSeverityCount)
print("portabilitySeverityCount: ", portabilitySeverityCount)
print("warningSeverityCount: ", warningSeverityCount)
print("errorSeverityCount: ", errorSeverityCount)
# 获取环境变量,如果超过阈值则返回-1否则返回0
# 获取环境变量
informationSeverityMax = os.environ.get('INFORMATION_SEVERITY_MAX')
performanceSeverityMax = os.environ.get('PERFORMANCE_SEVERITY_MAX')
styleSeverityMax = os.environ.get('STYLE_SEVERITY_MAX')
portabilitySeverityMax = os.environ.get('PORTABILITY_SEVERITY_MAX')
warningSeverityMax = os.environ.get('WARNING_SEVERITY_MAX')
errorSeverityMax = os.environ.get('ERROR_SEVERITY_MAX')
# 如果环境变量不存在则不做处理
if informationSeverityMax != None:
if informationSeverityCount >= int(informationSeverityMax):
print("informationSeverityCount[{}] >= informationSeverityMax[{}]".format(informationSeverityCount, informationSeverityMax))
sys.exit(-1)
if performanceSeverityMax != None:
if performanceSeverityCount >= int(performanceSeverityMax):
print("performanceSeverityCount[{}] >= performanceSeverityMax[{}]".format(performanceSeverityCount, performanceSeverityMax))
sys.exit(-1)
if styleSeverityMax != None:
if styleSeverityCount >= int(styleSeverityMax):
print("styleSeverityCount[{}] >= styleSeverityMax[{}]".format(styleSeverityCount, styleSeverityMax))
sys.exit(-1)
if portabilitySeverityMax != None:
if portabilitySeverityCount >= int(portabilitySeverityMax):
print("portabilitySeverityCount[{}] >= portabilitySeverityMax[{}]".format(portabilitySeverityCount, portabilitySeverityMax))
sys.exit(-1)
if warningSeverityMax != None:
if warningSeverityCount >= int(warningSeverityMax):
print("warningSeverityCount[{}] >= warningSeverityMax[{}]".format(warningSeverityCount, warningSeverityMax))
sys.exit(-1)
if errorSeverityMax != None:
if errorSeverityCount >= int(errorSeverityMax):
print("errorSeverityCount[{}] >= errorSeverityMax[{}]".format(errorSeverityCount, errorSeverityMax))
sys.exit(-1)
EOF
- name: run cppcheck
run: |
chmod +x /tmp/cppcheck.sh
chmod +x /tmp/cppcheck_analyze.py
/tmp/cppcheck.sh
/tmp/cppcheck_analyze.py
- name: run format
run: |
./format.sh
git config --global --add safe.directory '*'
git status
if [ -n "$(git status --porcelain)" ]; then
echo "check ${{ github.ref_name }} failed"
exit 1
fi

90
.github/workflows/release-workflow.yml vendored Normal file
View File

@ -0,0 +1,90 @@
name: deploy Workflow
on:
workflow_call:
inputs:
image_name:
required: true
type: string
default: ubuntu
image_tag:
required: false
type: string
default: latest
run_platform:
required: false
type: string
default: amd64
secrets:
TEST_CMD:
required: true
jobs:
release:
runs-on: ${{ inputs.run_platform }}
container:
image: ${{ inputs.image_name }}:${{ inputs.image_tag }}
steps:
- name: download build artifact
uses: actions/download-artifact@v3
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
with:
name: build_artifact
path: |
${{vars.WHL_ARTIFACTS_DIR}}
- name: Get short sha
id: slug
run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT
- name: Set up release information
id: release_info
shell: bash
run: |
VERSION=$(echo ${{ github.ref_name }} | sed 's/^v//')
echo "RELEASE_NAME=${{ github.ref_name }}" >> $GITHUB_OUTPUT
echo "RELEASE_DIR=${{ github.repository }}/${{ github.ref_name }}/${{ github.sha }}" >> $GITHUB_OUTPUT
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
- name: Upload wheel packages
shell: bash
id: whl_upload
run: |
set -x
ls -lah ${{ vars.WHL_ARTIFACTS_DIR }}
echo ${{ vars.WHL_ARTIFACTS_DIR }}
echo "${{ secrets.ARTIFACTS_URL }}/${{ steps.release_info.outputs.VERSION }}"
find "${{ vars.WHL_ARTIFACTS_DIR }}" -name "*.whl" -exec curl -F "file=@{}" "${{ secrets.ARTIFACTS_WHL_URL }}/${{ steps.release_info.outputs.VERSION }}" \;
echo "上传 whl 包成功"
- name: 上传Release 产物
uses: softprops/action-gh-release@v1
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
GITHUB_TOKEN: ${{ secrets.PATOKEN }}
with:
name: ${{ github.ref_name }}
files: |
${{ vars.WHL_ARTIFACTS_DIR }}/*.whl
- name: 显示 report 文件
shell: bash
run: |
if [ -n "${{secrets.CPPCHECK_REPORT_POST_URL}}" ]; then
check_report_dir=${{ github.repository }}/${{ github.ref_name }}/${{ steps.slug.outputs.sha8 }}
echo "cppcheck report url: ${{secrets.CPPCHECK_REPORT_URL}}/$check_report_dir/index.html"
fi
if [ -n "${{secrets.TEST_COVERAGE_REPORT_POST_URL}}" ]; then
test_coverage_dir=${{ github.repository_owner }}/${{ github.event.repository.name }}/${{ github.ref_name }}/${{ steps.slug.outputs.sha8 }}
echo "test coverage report url: ${{secrets.TEST_COVERAGE_REPORT_URL}}/$test_coverage_dir/index.html"
fi

View File

@ -0,0 +1,71 @@
name: test Workflow
on:
workflow_call:
inputs:
run_platform:
required: false
type: string
default: msvc
secrets:
BUILD_CMD:
required: true
jobs:
test:
runs-on: ${{ inputs.run_platform }}
steps:
- name: Checkout code
uses: actions/checkout@v4
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Setup Visual Studio Developer Command Prompt
uses: microsoft/setup-msbuild@v1.0.2
- name: Install Chocolatey
run: |
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
if (Test-Path "C:\ProgramData\chocolatey\bin\choco.exe") {
Write-Host "Chocolatey is installed."
} else {
Write-Host "Chocolatey installation failed."
}
$env:Path += ";C:\ProgramData\chocolatey\bin"
[Environment]::SetEnvironmentVariable("Path", $env:Path, "Machine")
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
- name: Install Python using Chocolatey
run: |
$chocoPath = "C:\ProgramData\chocolatey"
$env:Path += ";$chocoPath\bin"
[Environment]::SetEnvironmentVariable("Path", $env:Path, "Machine")
# 使用完整路径执行 choco 命令
& "$chocoPath\bin\choco.exe" install python --version=3.11.0 -y
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
- name: Run test stage
shell: powershell
run: |
python --version
${{ secrets.TEST_CMD_MSVC}}
if ($LASTEXITCODE -eq 1) {
Write-Host "test failed"
exit 1
} else {
Write-Host "test succeeded"
}

203
.github/workflows/test-workflow.yml vendored Normal file
View File

@ -0,0 +1,203 @@
name: test Workflow
on:
workflow_call:
inputs:
image_name:
required: true
type: string
default: ubuntu
image_tag:
required: false
type: string
default: latest
run_platform:
required: false
type: string
default: amd64
test_report:
required: false
type: boolean
default: false
secrets:
TEST_CMD:
required: true
jobs:
test:
runs-on: ${{ inputs.run_platform }}
container:
image: ${{ inputs.image_name }}:${{ inputs.image_tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
env:
https_proxy: ${{ secrets.https_proxy }}
http_proxy: ${{ secrets.http_proxy }}
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Get short sha
id: slug
run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT
- name: generate test_coverage.sh
if: inputs.test_report == true
run: |
echo "generate /tmp/test_coverage.sh ..."
cat << EOF >/tmp/test_coverage.sh
#!/bin/bash
# 生成报告并提交到指定http文件服务器上
if [ -z "${{ secrets.TEST_COVERAGE_REPORT_POST_URL }}" ]; then
echo "TEST_COVERAGE_REPORT_POST_URL is empty, not generate test coverage report"
exit 0
fi
ret=0
# 创建一个\$workdir文件夹用于存放所有的.gcda文件
workdir='/tmp/gtest_report'
rm \$workdir -rf
mkdir -p \$workdir
default_ignore=(
"_test.cc"
"_test.c"
"_test.cpp"
"*/build/_deps/*"
)
default_test_cov_ignore=(
"*/include/*"
"*/build/_deps/*"
\${TEST_COVERAGE_IGNORE[@]}
)
# 查找同时存在 *.gcda 和 *.gcno 文件的文件
gcda_files=\$(find ./build -type f -name "*.gcda")
for gcda_file in \$gcda_files; do
# 如果匹配了 \$default_ignore 中的文件,则跳过
for ignore in \${default_ignore[@]}; do
# 使用正则表达式匹配
if [[ \$gcda_file =~ \$ignore ]]; then
echo "ignore \$gcda_file"
continue 2
fi
done
gcno_file="\${gcda_file%.gcda}.gcno"
if [ -f "\$gcno_file" ]; then
cp "\$gcda_file" "\$workdir"
cp "\$gcno_file" "\$workdir"
fi
done
cd \$workdir
# 如果当前目录下没有gcda文件则直接退出不需要进行测试覆盖率检查
if [ -z "\$(find . -name "*.gcda")" ]; then
echo "no gcda files, not need to test coverage"
exit 0
fi
# 使用 gcov 来生成覆盖率数据
gcov *.gcno >/dev/null 2>&1
# 生成报告
lcov -c -d . -o coverage.info >/dev/null 2>&1
# 过滤掉不需要的信息
for ignore in \${default_test_cov_ignore[@]}; do
lcov --remove coverage.info "\$ignore" -o coverage.info >/dev/null 2>&1
done
# 列出测试覆盖率
lcov -l coverage.info
# 判断整体覆盖率是否达标
test_coverage=\$(lcov -l coverage.info | grep "Total:" | sed 's/|/| /g' | awk '{print \$2}' | awk -F '%' '{print \$1}')
# if error to get test_coverage
if [ -z "\$test_coverage" ];
then
echo "no test coverage, skip"
exit 0
fi
# 生成html报告
test_coverage_dir=${{ github.repository_owner }}/${{ github.event.repository.name }}/${{ github.ref_name }}/${{ steps.slug.outputs.sha8 }}
mkdir -p \$test_coverage_dir
genhtml coverage.info -o \$test_coverage_dir >/dev/null 2>&1
# zip 压缩 \$test_coverage_dir
zip -r ${{ steps.slug.outputs.sha8 }}.zip \$test_coverage_dir
# 生成报告并提交到指定http文件服务器上
curl -F file=@\${{ steps.slug.outputs.sha8 }}.zip -F unzip=true \${{secrets.TEST_COVERAGE_REPORT_POST_URL}}
# 判断推送是否成功
if [ \$? -ne 0 ]; then
echo "test report push failed ..."
ret=1
fi
# 如果 TEST_COVERAGE_THRESHOLD 变量为空,则默认为 0
if [ -z "\$TEST_COVERAGE_THRESHOLD" ]; then
TEST_COVERAGE_THRESHOLD=0
fi
echo "test coverage: \$test_coverage"
# 将TEST_COVERAGE_THRESHOLD转换为数字防止出现字符串比较的情况
test_coverage_threshold=\$(echo \$TEST_COVERAGE_THRESHOLD | tr -d '"')
#比较两个数的大小,一个是小数,一个是整数
if [ \$(echo "\$test_coverage >= \$test_coverage_threshold" | bc) -eq 1 ]; then
echo "test coverage is greater than \$test_coverage_threshold"
else
echo "test coverage is less than \$test_coverage_threshold"
ret=1
fi
# 删除临时文件
rm -rf \$test_coverage_dir
rm -rf ${{ steps.slug.outputs.sha8 }}.zip
# 打印报告地址
echo -e "\\033[1;35m test coverage report url: ${{secrets.TEST_COVERAGE_REPORT_URL}}/\$test_coverage_dir/index.html \\033[0m"
exit \$ret
EOF
- name: Run test stage
shell: bash
env:
https_proxy: ""
http_proxy: ""
no_proxy: "*"
run: |
echo "runnint test in workflow_call"
source /opt/ros/humble/setup.bash
echo "${{ secrets.TEST_CMD}}"
eval "${{ secrets.TEST_CMD}}"
- name: authorize test_coverage.sh
if: inputs.test_report == true
env:
https_proxy: ""
http_proxy: ""
no_proxy: "*"
run: |
chmod +x /tmp/test_coverage.sh
echo "test_coverage.sh is authorized"
bash /tmp/test_coverage.sh

View File

@ -1,7 +1,7 @@
#!/bin/bash
# exit on error and print each command
set -ex
set -e
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \

View File

@ -1,7 +1,7 @@
#!/bin/bash
# exit on error and print each command
set -ex
set -e
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \