11name : Run tests
2+
23on :
34 push :
45 branches : ["main"]
@@ -10,46 +11,184 @@ permissions:
1011 pull-requests : write
1112
1213jobs :
13- tests :
14+ core- tests :
1415 runs-on : ubuntu-latest
1516 steps :
16- - name : Checkout code
17+ - name : Checkout
1718 uses : actions/checkout@v4
19+ with : { fetch-depth: 0 }
20+
21+ - name : Detect core changes
22+ id : changed
23+ uses : tj-actions/changed-files@v44
24+ with :
25+ files : |
26+ openhands/core/**
27+ pyproject.toml
28+ uv.lock
29+ .github/workflows/tests.yml
30+
31+ - name : Install uv
32+ if : steps.changed.outputs.any_changed == 'true'
33+ uses : astral-sh/setup-uv@v3
34+ with :
35+ enable-cache : true
36+
37+ - name : Install deps
38+ if : steps.changed.outputs.any_changed == 'true'
39+ run : uv sync --frozen --group dev
40+
41+ - name : Run core tests with coverage
42+ if : steps.changed.outputs.any_changed == 'true'
43+ env :
44+ COVERAGE_FILE : .coverage.core
45+ run : |
46+ CI=true uv run pytest -vvxss \
47+ --cov=openhands/core \
48+ --cov-report=term-missing \
49+ openhands/core/tests
50+
51+ - name : Upload core coverage
52+ if : steps.changed.outputs.any_changed == 'true' && always()
53+ uses : actions/upload-artifact@v4
54+ with :
55+ name : coverage-core
56+ path : .coverage.core
57+
58+ tools-tests :
59+ runs-on : ubuntu-latest
60+ steps :
61+ - name : Checkout
62+ uses : actions/checkout@v4
63+ with : { fetch-depth: 0 }
64+
65+ - name : Detect tools changes
66+ id : changed
67+ uses : tj-actions/changed-files@v44
68+ with :
69+ files : |
70+ openhands/tools/**
71+ pyproject.toml
72+ uv.lock
73+ .github/workflows/tests.yml
74+
75+ - name : Install uv
76+ if : steps.changed.outputs.any_changed == 'true'
77+ uses : astral-sh/setup-uv@v3
78+ with :
79+ enable-cache : true
80+
81+ - name : Install deps
82+ if : steps.changed.outputs.any_changed == 'true'
83+ run : uv sync --frozen --group dev
84+
85+ - name : Run tools tests with coverage
86+ if : steps.changed.outputs.any_changed == 'true'
87+ env :
88+ COVERAGE_FILE : .coverage.tools
89+ run : |
90+ CI=true uv run pytest -vvxss \
91+ --cov=openhands/tools \
92+ --cov-report=term-missing \
93+ openhands/tools/tests
1894
19- - name : Set up Python
20- uses : actions/setup-python@v5
95+ - name : Upload tools coverage
96+ if : steps.changed.outputs.any_changed == 'true' && always()
97+ uses : actions/upload-artifact@v4
2198 with :
22- python-version : " 3.12"
99+ name : coverage-tools
100+ path : .coverage.tools
101+
102+ integration-tests :
103+ runs-on : ubuntu-latest
104+ steps :
105+ - name : Checkout
106+ uses : actions/checkout@v4
107+ with : { fetch-depth: 0 }
23108
109+ - name : Detect integration changes
110+ id : changed
111+ uses : tj-actions/changed-files@v44
112+ with :
113+ files : |
114+ tests/**
115+ openhands/**
116+ pyproject.toml
117+ uv.lock
118+ .github/workflows/tests.yml
119+
24120 - name : Install uv
121+ if : steps.changed.outputs.any_changed == 'true'
25122 uses : astral-sh/setup-uv@v3
123+ with :
124+ enable-cache : true
26125
27- - name : Install dependencies
126+ - name : Install deps
127+ if : steps.changed.outputs.any_changed == 'true'
28128 run : uv sync --frozen --group dev
29-
30- - name : Run tests with coverage
129+
130+ - name : Run integration tests with coverage
131+ if : steps.changed.outputs.any_changed == 'true'
132+ env :
133+ COVERAGE_FILE : .coverage.integration
31134 run : |
32- CI=true uv run pytest \
33- -vvxss \
135+ CI=true uv run pytest -vvxss \
34136 --basetemp="${{ runner.temp }}/pytest" \
35137 -o tmp_path_retention=none \
36138 -o tmp_path_retention_count=0 \
37- --cov=openhands/core \
38- --cov=openhands/tools \
139+ --cov=openhands \
39140 --cov-report=term-missing \
40- openhands/core/tests openhands/tools/tests tests
141+ tests
41142
42- - name : Build coverage XML (separate step, lower mem)
43- if : always()
44- run : uv run coverage xml -i -o coverage.xml
143+ - name : Upload integration coverage
144+ if : steps.changed.outputs.any_changed == 'true' && always()
145+ uses : actions/upload-artifact@v4
146+ with :
147+ name : coverage-integration
148+ path : .coverage.integration
149+
150+ coverage-report :
151+ runs-on : ubuntu-latest
152+ needs : [core-tests, tools-tests, integration-tests]
153+ if : always() && github.event_name == 'pull_request'
154+ steps :
155+ - name : Checkout
156+ uses : actions/checkout@v4
157+
158+ - name : Install uv
159+ uses : astral-sh/setup-uv@v3
160+ with :
161+ enable-cache : true
162+
163+ - name : Install deps (for coverage CLI)
164+ run : uv sync --frozen --group dev
165+
166+ - name : Download coverage artifacts
167+ uses : actions/download-artifact@v4
168+ with :
169+ path : ./cov
170+ continue-on-error : true
171+
172+ - name : Combine coverage data
173+ run : |
174+ shopt -s nullglob
175+ files=(cov/**/.coverage*)
176+ if [ ${#files[@]} -eq 0 ]; then
177+ echo "No coverage files found; skipping combined report."
178+ exit 0
179+ fi
180+ # Bring files to cwd so coverage can find them easily
181+ cp "${files[@]}" .
182+ uv run coverage combine
183+ uv run coverage xml -i -o coverage.xml
184+ uv run coverage report -m || true
45185
46186 - name : Pytest coverage PR comment
47- if : ${{ always() && github.event_name == 'pull_request' }}
187+ if : always()
48188 continue-on-error : true
49189 uses : MishaKav/pytest-coverage-comment@v1
50190 with :
51191 github-token : ${{ secrets.GITHUB_TOKEN }}
52192 pytest-xml-coverage-path : coverage.xml
53193 title : Coverage Report
54194 create-new-comment : false
55-
0 commit comments