Skip to content

Commit 2582fa6

Browse files
OhYeeCopilot
andauthored
feat(ci): 增加覆盖率测试 (#20)
* ci(workflow): add workflow_call support and improve version bump logic - Add `workflow_call` trigger to allow this workflow to be invoked by other workflows - Default version bump type to `patch` when input is unspecified - Improve robustness of LLM mocking in integration tests by patching module-level imports - Add new CI workflow file, coverage configuration, and coverage checking script - Update dependencies and fix mypy configuration This commit enhances the release testing workflow to support automated triggering from other workflows, ensuring more flexible and reliable CI/CD processes. It also improves test stability by addressing edge cases in LLM mocking and introduces better tooling for code coverage analysis. Change-Id: Iba20089a66ad6e996dfb5930b6d039058d1b1646 Signed-off-by: OhYee <[email protected]> * Update .github/workflows/ci.yml Co-authored-by: Copilot <[email protected]> Signed-off-by: OhYee <[email protected]> * Update scripts/check_coverage.py Co-authored-by: Copilot <[email protected]> Signed-off-by: OhYee <[email protected]> --------- Signed-off-by: OhYee <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 5d56c14 commit 2582fa6

File tree

8 files changed

+1034
-4
lines changed

8 files changed

+1034
-4
lines changed

.github/workflows/ci.yml

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
name: CI
2+
3+
on:
4+
# 仅在 push 时触发测试
5+
push:
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
strategy:
11+
matrix:
12+
python-version: ['3.10']
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0 # 获取完整历史用于增量覆盖率检查
19+
20+
- name: Set up Python ${{ matrix.python-version }}
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: ${{ matrix.python-version }}
24+
25+
- name: Install dependencies
26+
run: |
27+
make setup PYTHON_VERSION=${{ matrix.python-version }}
28+
29+
- name: Run type check (mypy)
30+
run: |
31+
make mypy-check
32+
33+
- name: Run unit tests
34+
run: |
35+
make test-unit
36+
37+
- name: Run coverage
38+
run: |
39+
make coverage
40+
41+
# 检测文件更改并决定是否构建测试包
42+
- name: Check for changes in agentrun directory
43+
id: changes
44+
run: |
45+
echo "Checking if agentrun directory has changes..."
46+
# 获取最近两次提交之间的差异;如果没有父提交,则将所有跟踪文件视为已更改
47+
if git rev-parse HEAD^ >/dev/null 2>&1; then
48+
git diff --name-only HEAD^ HEAD > changed_files.txt
49+
else
50+
echo "No parent commit; treating all tracked files as changed."
51+
git ls-files > changed_files.txt
52+
fi
53+
echo "Changed files:"
54+
cat changed_files.txt || echo "No changed files detected"
55+
56+
# 检查是否有任何以 agentrun/ 开头的文件
57+
if grep -q "^agentrun/" changed_files.txt 2>/dev/null; then
58+
echo "agentrun directory has changes"
59+
echo "agentrun_changed=true" >> $GITHUB_OUTPUT
60+
else
61+
echo "agentrun directory has no changes"
62+
echo "agentrun_changed=false" >> $GITHUB_OUTPUT
63+
fi
64+
65+
# 测试通过后自动构建测试包(仅在 agentrun 目录有变化时触发)
66+
- name: Get latest version from PyPI and calculate next version
67+
id: version
68+
if: steps.changes.outputs.agentrun_changed == 'true'
69+
run: |
70+
# 从 PyPI 获取 agentrun-inner-test 的最新版本
71+
PYPI_RESPONSE=$(curl -s https://pypi.org/pypi/agentrun-inner-test/json 2>/dev/null || echo "")
72+
73+
if [ -z "$PYPI_RESPONSE" ] || echo "$PYPI_RESPONSE" | grep -q "Not Found"; then
74+
# 如果包不存在,从 0.0.0 开始
75+
CURRENT_VERSION="0.0.0"
76+
echo "Package not found on PyPI, starting from 0.0.0"
77+
else
78+
# 从 PyPI 响应中提取最新版本
79+
CURRENT_VERSION=$(echo "$PYPI_RESPONSE" | python3 -c "import sys, json; print(json.load(sys.stdin)['info']['version'])")
80+
echo "Latest version on PyPI: $CURRENT_VERSION"
81+
fi
82+
83+
# 解析版本号
84+
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
85+
86+
# 默认为 patch
87+
BUMP_TYPE="patch"
88+
case "$BUMP_TYPE" in
89+
major)
90+
MAJOR=$((MAJOR + 1))
91+
MINOR=0
92+
PATCH=0
93+
;;
94+
minor)
95+
MINOR=$((MINOR + 1))
96+
PATCH=0
97+
;;
98+
patch)
99+
PATCH=$((PATCH + 1))
100+
;;
101+
esac
102+
103+
NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}"
104+
NEW_TAG="agentrun-inner-test-v${NEW_VERSION}"
105+
106+
echo "VERSION=${NEW_VERSION}" >> $GITHUB_OUTPUT
107+
echo "TAG=${NEW_TAG}" >> $GITHUB_OUTPUT
108+
echo "New version: ${NEW_VERSION}"
109+
echo "New tag: ${NEW_TAG}"
110+
111+
- name: Update package name and version in pyproject.toml
112+
if: steps.changes.outputs.agentrun_changed == 'true'
113+
run: |
114+
VERSION="${{ steps.version.outputs.VERSION }}"
115+
# 修改包名为 agentrun-inner-test
116+
sed -i 's/name = "agentrun-sdk"/name = "agentrun-inner-test"/' pyproject.toml
117+
# 修改版本号
118+
sed -i 's/version = "[^"]*"/version = "'${VERSION}'"/' pyproject.toml
119+
echo "Updated pyproject.toml:"
120+
head -10 pyproject.toml
121+
122+
- name: Update __version__ in __init__.py
123+
if: steps.changes.outputs.agentrun_changed == 'true'
124+
run: |
125+
VERSION="${{ steps.version.outputs.VERSION }}"
126+
if grep -q "__version__" agentrun/__init__.py; then
127+
sed -i 's/__version__ = "[^"]*"/__version__ = "'${VERSION}'"/' agentrun/__init__.py
128+
else
129+
sed -i '1a __version__ = "'${VERSION}'"' agentrun/__init__.py
130+
fi
131+
echo "Updated __init__.py version to ${VERSION}"
132+
grep "__version__" agentrun/__init__.py
133+
134+
- name: Build package
135+
if: steps.changes.outputs.agentrun_changed == 'true'
136+
run: |
137+
python -m pip install --upgrade pip
138+
pip install build twine
139+
python -m build
140+
echo "Package built successfully"
141+
ls -la dist/
142+
143+
- name: Verify package
144+
if: steps.changes.outputs.agentrun_changed == 'true'
145+
run: |
146+
python -m twine check dist/*
147+
echo "Package verification completed"
148+
149+
- name: Publish to PyPI
150+
if: steps.changes.outputs.agentrun_changed == 'true'
151+
uses: pypa/gh-action-pypi-publish@release/v1
152+
with:
153+
password: ${{ secrets.PYPI_API_TOKEN }}
154+
verify-metadata: false
155+
156+
- name: Create and push tag
157+
if: steps.changes.outputs.agentrun_changed == 'true'
158+
run: |
159+
TAG="${{ steps.version.outputs.TAG }}"
160+
git config --local user.email "[email protected]"
161+
git config --local user.name "GitHub Action"
162+
git tag -a "$TAG" -m "Release test package version ${{ steps.version.outputs.VERSION }}"
163+
git push origin "$TAG"
164+
echo "Created and pushed tag: $TAG"
165+
166+
- name: Summary
167+
if: steps.changes.outputs.agentrun_changed == 'true'
168+
run: |
169+
echo "## 🎉 Test Package Released!" >> $GITHUB_STEP_SUMMARY
170+
echo "" >> $GITHUB_STEP_SUMMARY
171+
echo "- **Package Name:** agentrun-inner-test" >> $GITHUB_STEP_SUMMARY
172+
echo "- **Version:** ${{ steps.version.outputs.VERSION }}" >> $GITHUB_STEP_SUMMARY
173+
echo "- **Tag:** ${{ steps.version.outputs.TAG }}" >> $GITHUB_STEP_SUMMARY
174+
echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
175+
echo "" >> $GITHUB_STEP_SUMMARY
176+
echo "Install with: \`pip install agentrun-inner-test==${{ steps.version.outputs.VERSION }}\`" >> $GITHUB_STEP_SUMMARY
177+

.github/workflows/release-test.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ on:
1313
- patch # 0.0.1 -> 0.0.2
1414
- minor # 0.0.1 -> 0.1.0
1515
- major # 0.0.1 -> 1.0.0
16+
17+
# 支持被其他工作流调用(CI 测试通过后自动触发)
18+
workflow_call:
19+
inputs:
20+
version_bump:
21+
description: '版本递增类型'
22+
required: false
23+
default: 'patch'
24+
type: string
1625

1726
jobs:
1827
release-test:
@@ -49,8 +58,8 @@ jobs:
4958
# 解析版本号
5059
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
5160
52-
# 根据用户选择递增版本
53-
BUMP_TYPE="${{ inputs.version_bump }}"
61+
# 根据用户选择递增版本(默认为 patch)
62+
BUMP_TYPE="${{ inputs.version_bump || 'patch' }}"
5463
case "$BUMP_TYPE" in
5564
major)
5665
MAJOR=$((MAJOR + 1))

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,6 @@ dmypy.json
102102
.pytest_cache
103103
.env
104104

105-
uv.lock
105+
uv.lock
106+
coverage.json
107+
coverage.json

Makefile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,29 @@ install-deps:
122122
--dev \
123123
--all-extras \
124124
-i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
125+
126+
# ============================================================================
127+
# 测试和覆盖率
128+
# ============================================================================
129+
130+
.PHONY: test
131+
test: ## 运行所有测试
132+
@uv run pytest tests/
133+
134+
.PHONY: test-unit
135+
test-unit: ## 运行单元测试
136+
@uv run pytest tests/unittests/
137+
138+
.PHONY: test-e2e
139+
test-e2e: ## 运行端到端测试
140+
@uv run pytest tests/e2e/
141+
142+
.PHONY: mypy-check
143+
mypy-check: ## 运行 mypy 类型检查
144+
@uv run mypy --config-file mypy.ini .
145+
146+
.PHONY: coverage
147+
coverage: ## 运行测试并显示覆盖率报告(全量代码 + 增量代码)
148+
@echo "📊 运行覆盖率测试..."
149+
@uv run python scripts/check_coverage.py
150+

coverage.yaml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# 覆盖率配置文件
2+
# Coverage Configuration File
3+
4+
# ============================================================================
5+
# 全量代码覆盖率要求
6+
# ============================================================================
7+
full:
8+
# 分支覆盖率要求 (百分比)
9+
branch_coverage: 0
10+
# 行覆盖率要求 (百分比)
11+
line_coverage: 0
12+
13+
# ============================================================================
14+
# 增量代码覆盖率要求 (相对于基准分支的变更代码)
15+
# ============================================================================
16+
incremental:
17+
# 分支覆盖率要求 (百分比)
18+
branch_coverage: 0
19+
# 行覆盖率要求 (百分比)
20+
line_coverage: 0
21+
22+
# ============================================================================
23+
# 特定目录的覆盖率要求
24+
# 可以为特定目录设置不同的覆盖率阈值
25+
# ============================================================================
26+
directory_overrides:
27+
# 为除 server 外的所有文件夹设置 0% 覆盖率要求
28+
# 这样可以逐个文件夹增加测试,暂时跳过未测试的文件夹
29+
agentrun/agent_runtime:
30+
full:
31+
branch_coverage: 0
32+
line_coverage: 0
33+
incremental:
34+
branch_coverage: 0
35+
line_coverage: 0
36+
37+
agentrun/credential:
38+
full:
39+
branch_coverage: 0
40+
line_coverage: 0
41+
incremental:
42+
branch_coverage: 0
43+
line_coverage: 0
44+
45+
agentrun/integration:
46+
full:
47+
branch_coverage: 0
48+
line_coverage: 0
49+
incremental:
50+
branch_coverage: 0
51+
line_coverage: 0
52+
53+
agentrun/model:
54+
full:
55+
branch_coverage: 0
56+
line_coverage: 0
57+
incremental:
58+
branch_coverage: 0
59+
line_coverage: 0
60+
61+
agentrun/sandbox:
62+
full:
63+
branch_coverage: 0
64+
line_coverage: 0
65+
incremental:
66+
branch_coverage: 0
67+
line_coverage: 0
68+
69+
agentrun/toolset:
70+
full:
71+
branch_coverage: 0
72+
line_coverage: 0
73+
incremental:
74+
branch_coverage: 0
75+
line_coverage: 0
76+
77+
agentrun/utils:
78+
full:
79+
branch_coverage: 0
80+
line_coverage: 0
81+
incremental:
82+
branch_coverage: 0
83+
line_coverage: 0
84+
85+
# server 模块保持默认的 95% 覆盖率要求
86+
agentrun/server:
87+
full:
88+
branch_coverage: 0
89+
line_coverage: 0
90+
incremental:
91+
branch_coverage: 0
92+
line_coverage: 0
93+
94+
# ============================================================================
95+
# 排除配置
96+
# ============================================================================
97+
98+
# 排除的目录(不计入覆盖率统计)
99+
exclude_directories:
100+
- "tests/"
101+
- "*__pycache__*"
102+
- "*_async_template.py"
103+
- "codegen/"
104+
- "examples/"
105+
- "build/"
106+
- "*.egg-info"
107+
108+
# 排除的文件模式
109+
exclude_patterns:
110+
- "*_test.py"
111+
- "test_*.py"
112+
- "conftest.py"
113+

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ dev = [
7070
"pyyaml>=6.0.3",
7171
"fastapi>=0.104.0",
7272
"uvicorn>=0.24.0",
73+
"langchain_mcp_adapters>=0.2.1",
7374
]
7475

7576
[tool.pyink]
@@ -101,7 +102,7 @@ known_third_party = ["alibabacloud_tea_openapi", "alibabacloud_devs20230714", "a
101102
sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"]
102103

103104
[tool.mypy]
104-
python_version = "0.0.8"
105+
python_version = "3.10"
105106
exclude = "tests/"
106107
plugins = ["pydantic.mypy"]
107108
# Start with non-strict mode, and switch to strict mode later.

0 commit comments

Comments
 (0)