Skip to content

Commit f89d09b

Browse files
feat(coverage): Enable coverage on any test change (rebased with uv) (ethereum#790)
* coverage on every pr * do not try to detect tests in files do not skip the coverage script for safety * build the changed files array once * simplify regex for gitdiff changed files detection * use uv run in coverage script * refactor(ci): use changed-files action to detect changes in tests/ * fix the coverage script, remove retesteth, simplify * exclude prague * address issues * fix evmone long build fix uv run fill on empty file set --------- Co-authored-by: danceratopz <[email protected]>
1 parent 3b4709b commit f89d09b

File tree

2 files changed

+154
-69
lines changed

2 files changed

+154
-69
lines changed

.github/actions/build-evm-client/evmone/action.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ inputs:
99
description: 'Reference to branch, commit, or tag to use to build the EVM binary'
1010
required: true
1111
default: 'master'
12+
targets:
13+
description: 'Which targets to build from evmone repo'
14+
required: false
15+
default: 'all'
1216
runs:
1317
using: "composite"
1418
steps:
@@ -27,5 +31,5 @@ runs:
2731
mkdir -p $GITHUB_WORKSPACE/bin
2832
cd $GITHUB_WORKSPACE/evmone
2933
cmake -S . -B build -DEVMONE_TESTING=ON
30-
cmake --build build --parallel
31-
echo $GITHUB_WORKSPACE/evmone/build/bin/ >> $GITHUB_PATH
34+
cmake --build build --parallel --target ${{ inputs.targets }}
35+
echo $GITHUB_WORKSPACE/evmone/build/bin/ >> $GITHUB_PATH

.github/workflows/coverage.yaml

Lines changed: 148 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,99 @@ name: Evmone Coverage Report
33
on:
44
pull_request:
55
paths:
6-
- "converted-ethereum-tests.txt" # This triggers the workflow only for changes in file.txt
6+
- 'tests/**' # This triggers the workflow for any changes in the tests folder
7+
- '!tests/prague/**' # exclude changes in 'tests/prague'
8+
- '!tests/osaka/**' # exclude changes in 'tests/osaka'
79

810
jobs:
911
evmone-coverage-diff:
1012
runs-on: ubuntu-latest
11-
strategy:
12-
matrix:
13-
driver: [retesteth, native]
1413

1514
steps:
1615
- name: Checkout code
17-
uses: actions/checkout@v3
16+
uses: actions/checkout@v4
17+
18+
- name: Debug GitHub context
19+
run: |
20+
echo "Git reference: ${{ github.ref }}"
21+
echo "Git head ref: ${{ github.head_ref }}"
22+
echo "Git base ref: ${{ github.base_ref }}"
23+
echo "Node Version: $(node -v)"
24+
echo "NPM Version: $(npm -v)"
25+
26+
27+
- name: Get all changed python files in tests/ and changes to coverted-ethereum-tests.txt
28+
id: changed-tests
29+
uses: tj-actions/changed-files@v45
30+
with:
31+
# TODO: non-test modules such as __init__.py or spec.py could effect coverage - in this case we should
32+
# fill all applicable tests (i.e., all the test_*.py files in or under the changed module's directory)
33+
include_all_old_new_renamed_files: true
34+
output_renamed_files_as_deleted_and_added: true
35+
files_yaml: |
36+
tests:
37+
- tests/**/test_*.py
38+
- '!tests/prague/**'
39+
- '!tests/osaka/**'
40+
converted_tests:
41+
- converted-ethereum-tests.txt
42+
43+
- name: Exit workflow if there are no changed python files
44+
if: steps.changed-tests.outputs.tests_any_changed != 'true'
45+
run: |
46+
echo "No python files were changed in ./tests/ - no action necessary"
47+
exit 0
1848
19-
- name: Fetch target branch
20-
run: git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }}
49+
- name: Report changed python test moudules
50+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
51+
run: |
52+
echo "${{ toJson(steps.changed-tests.outputs) }}"
53+
echo "Changed python test modules: ${{ steps.changed-tests.outputs.tests_all_modified_files }}"
54+
55+
- name: Debug GitHub context
56+
run: |
57+
echo "Git reference: ${{ github.ref }}"
58+
echo "Git head ref: ${{ github.head_ref }}"
59+
echo "Git base ref: ${{ github.base_ref }}"
2160
2261
- name: Log in to Docker Hub
62+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository }}
2363
uses: docker/login-action@v3
24-
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
2564
with:
2665
username: winsvega
2766
password: ${{ secrets.DOCKERHUB_PASSWORD }}
2867

2968
- name: Install deps
69+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
3070
run: |
3171
echo $(pwd)
3272
echo ${{ github.workspace }}
3373
3474
- name: Set up uv
75+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
3576
uses: ./.github/actions/setup-uv
3677

3778
- name: Set up Python
79+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
3880
run: uv python install 3.10
3981

4082
- name: Install EEST
83+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
4184
run: |
4285
uv sync --no-progress
4386
uv run python --version
4487
4588
# Required to fill .py tests
46-
- name: Build GO EVM
47-
uses: ./.github/actions/build-evm-client/geth
48-
id: evm-builder
49-
with:
50-
type: "main"
51-
5289
- name: Build EVMONE EVM
5390
uses: ./.github/actions/build-evm-client/evmone
91+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
5492
id: evm-builder2
5593
with:
56-
type: "main"
94+
targets: "evmone-t8n"
5795

5896
- name: Checkout ethereum/tests
5997
uses: actions/checkout@v4
98+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
6099
with:
61100
repository: ethereum/tests
62101
path: testpath
@@ -66,6 +105,7 @@ jobs:
66105
67106
- name: Checkout ethereum/legacytests
68107
uses: actions/checkout@v4
108+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
69109
with:
70110
repository: ethereum/legacytests
71111
path: legacytestpath
@@ -74,16 +114,19 @@ jobs:
74114
75115
# This command diffs the file and filters in new lines
76116
- name: Parse converted tests from converted-ethereum-tests.txt
117+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
77118
run: |
78119
echo "New lines introduced in converted-ethereum-tests.txt:"
79-
lines=$(git diff origin/${{ github.base_ref }} HEAD -- converted-ethereum-tests.txt | grep "^+" | grep -v "^+++")
80-
files=$(echo "$lines" | grep -oP '(?<=\+).+\.json')
81-
82-
if [ -z "$files" ]; then
83-
echo "Error: No new JSON files found in converted-ethereum-tests.txt"
84-
exit 1
120+
lines=$(git diff origin/${{ github.base_ref }} HEAD -- converted-ethereum-tests.txt | grep "^+" | grep -v "^+++" || true)
121+
if [ -z "$lines" ]; then
122+
echo "No new lines in converted-ethereum-tests.txt, check updates instead:"
123+
echo "converted_skip=true" >> $GITHUB_ENV
124+
exit 0
125+
else
126+
echo "converted_skip=false" >> $GITHUB_ENV
85127
fi
86128
129+
files=$(echo "$lines" | grep -oP '(?<=\+).+\.json')
87130
for file in $files; do
88131
echo $file
89132
done
@@ -123,53 +166,26 @@ jobs:
123166
124167
# This command diffs the .py scripts introduced by a PR
125168
- name: Parse and fill introduced test sources
169+
if: steps.changed-tests.outputs.tests_any_changed == 'true'
170+
env:
171+
CHANGED_TEST_FILES: ${{ steps.changed-tests.outputs.tests_all_changed_files }}
126172
run: |
127-
python3 -m venv ./venv/
128-
source ./venv/bin/activate
129-
130-
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
131-
# Fetch changes when PR comes from remote repo
132-
git fetch origin +refs/heads/${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }}
133-
git fetch origin +refs/pull/${{ github.event.pull_request.number }}/head:refs/remotes/origin/PR-${{ github.event.pull_request.number }}
134-
files=$(git diff --name-status origin/${{ github.base_ref }}...origin/PR-${{ github.event.pull_request.number }} -- tests/ | grep -E '^[AM]' | grep '\.py$')
135-
else
136-
# Fetch the base branch and the head branch
137-
git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }}
138-
git fetch origin ${{ github.head_ref }}:refs/remotes/origin/${{ github.head_ref }}
139-
140-
# Perform the diff
141-
files=$(git diff --name-status origin/${{ github.base_ref }}...origin/${{ github.head_ref }} -- tests/ | grep -E '^[AM]' | grep '\.py$')
142-
fi
143-
144-
145-
echo "Modified or new .py files in tests folder:"
146-
echo "$files" | while read line; do
147-
file=$(echo "$line" | cut -c 3-)
148-
echo $file
149-
done
173+
source $GITHUB_ENV
174+
files=$(echo "$CHANGED_TEST_FILES" | tr ',' '\n')
150175
151176
# fill new tests
152177
# using `|| true` here because if no tests found, pyspec fill returns error code
153178
mkdir -p fixtures/state_tests
154179
mkdir -p fixtures/eof_tests
155-
echo "$files" | while read line; do
156-
file=$(echo "$line" | cut -c 3-)
157-
uv run fill $file --until=Cancun --evm-bin evmone-t8n --solc-version=0.8.25 || true >> filloutput.log 2>&1
158-
(uv run fill $file --fork=CancunEIP7692 --evm-bin evmone-t8n --solc-version=0.8.25 -k eof_test || true) > >(tee -a filloutput.log filloutputEOF.log) 2>&1
159-
done
180+
181+
echo "uv run fill $files --until=Cancun --evm-bin evmone-t8n >> filloutput.log 2>&1"
182+
uv run fill $files --until=Cancun --evm-bin evmone-t8n >> filloutput.log 2>&1
183+
cat filloutput.log
160184
161185
if grep -q "FAILURES" filloutput.log; then
162186
echo "Error: failed to generate .py tests."
163187
exit 1
164188
fi
165-
if [ "${{ matrix.driver }}" = "retesteth" ] && grep -q "passed" filloutputEOF.log; then
166-
echo "Disabling retesteth coverage check as EOF tests detected!"
167-
echo "retesteth_skip=true" >> $GITHUB_ENV
168-
exit 0
169-
else
170-
echo "retesteth_skip=false" >> $GITHUB_ENV
171-
fi
172-
173189
174190
filesState=$(find fixtures/state_tests -type f -name "*.json")
175191
filesEOF=$(find fixtures/eof_tests -type f -name "*.json")
@@ -178,13 +194,78 @@ jobs:
178194
exit 1
179195
fi
180196
197+
# Include basic evm operations into coverage by default
198+
# As when we translate from yul/solidity some dup/push opcodes could become untouched
199+
uv run fill tests/homestead/coverage/test_coverage.py --until=Cancun --evm-bin evmone-t8n
200+
181201
PATCH_TEST_PATH=${{ github.workspace }}/evmtest_coverage/coverage/PATCH_TESTS
182202
mkdir -p $PATCH_TEST_PATH
183203
find fixtures/state_tests -type f -name "*.json" -exec cp {} $PATCH_TEST_PATH \;
184204
find fixtures/eof_tests -type f -name "*.json" -exec cp {} $PATCH_TEST_PATH \;
185205
206+
- name: Parse and fill introduced test sources from before the PR
207+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' && env.converted_skip == 'true' }}
208+
env:
209+
CHANGED_TEST_FILES: ${{ steps.changed-tests.outputs.tests_all_modified_files }}
210+
run: |
211+
echo "--------------------"
212+
echo "converted-ethereum-tests.txt seem untouched, try to fill pre-patched version of .py files:"
213+
214+
source $GITHUB_ENV
215+
files=$(echo "$CHANGED_TEST_FILES" | tr ',' '\n')
216+
217+
git checkout main
218+
PREV_COMMIT=$(git rev-parse HEAD)
219+
echo "Checkout head $PREV_COMMIT"
220+
221+
# Take only those files that exist in the filesystem (ignore newly created files)
222+
files_fixed=$(echo "$files" | tr ' ' '\n' | while read file; do
223+
if [ -f "$file" ]; then
224+
echo "$file"
225+
fi
226+
done | tr '\n' ' ')
227+
228+
echo "Select files that were changed and exist on the main branch:"
229+
echo $files_fixed
230+
231+
rm -r fixtures
232+
rm filloutput.log
233+
mkdir -p fixtures/state_tests
234+
mkdir -p fixtures/eof_tests
235+
236+
if [ -n "$files_fixed" ]; then
237+
echo "uv run fill $files_fixed --until=Cancun --evm-bin evmone-t8n >> filloutput.log 2>&1"
238+
uv run fill $files_fixed --until=Cancun --evm-bin evmone-t8n >> filloutput.log 2>&1
239+
cat filloutput.log
240+
241+
if grep -q "FAILURES" filloutput.log; then
242+
echo "Error: failed to generate .py tests from before the PR."
243+
exit 1
244+
fi
245+
246+
if grep -q "ERROR collecting test session" filloutput.log; then
247+
echo "Error: failed to generate .py tests from before the PR."
248+
exit 1
249+
fi
250+
else
251+
echo "No tests affected from before patch!"
252+
fi
253+
254+
filesState=$(find fixtures/state_tests -type f -name "*.json")
255+
filesEOF=$(find fixtures/eof_tests -type f -name "*.json")
256+
257+
BASE_TEST_PATH=${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS
258+
mkdir -p $BASE_TEST_PATH
259+
find fixtures/state_tests -type f -name "*.json" -exec cp {} $BASE_TEST_PATH \;
260+
find fixtures/eof_tests -type f -name "*.json" -exec cp {} $BASE_TEST_PATH \;
261+
for file in $BASE_TEST_PATH/*.json; do
262+
if [ -e "$file" ]; then
263+
mv "$file" "${file%.json}_$PREV_COMMIT.json"
264+
fi
265+
done
266+
186267
- name: Print tests that will be covered
187-
if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }}
268+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' }}
188269
run: |
189270
echo "Original BASE tests:"
190271
ls ${{ github.workspace }}/evmtest_coverage/coverage/BASE_TESTS
@@ -194,44 +275,44 @@ jobs:
194275
195276
- name: Run coverage of the BASE tests
196277
uses: addnab/docker-run-action@v3
197-
if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }}
278+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' }}
198279
with:
199280
image: winsvega/evmone-coverage-script:latest
200281
options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests
201-
run: /entrypoint.sh --mode=cover --driver=${{ matrix.driver }} --testpath=/tests/BASE_TESTS --outputname=BASE
282+
run: /entrypoint.sh --mode=cover --driver=native --testpath=/tests/BASE_TESTS --outputname=BASE
202283

203284
- name: Run coverage of the PATCH tests
204285
uses: addnab/docker-run-action@v3
205-
if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }}
286+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' }}
206287
with:
207288
image: winsvega/evmone-coverage-script:latest
208289
options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests
209-
run: /entrypoint.sh --mode=cover --driver=${{ matrix.driver }} --testpath=/tests/PATCH_TESTS --outputname=PATCH
290+
run: /entrypoint.sh --mode=cover --driver=native --testpath=/tests/PATCH_TESTS --outputname=PATCH
210291

211292
- name: Run coverage DIFF of the PATCH tests compared to BASE tests
212293
uses: addnab/docker-run-action@v3
213-
if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }}
294+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' }}
214295
with:
215296
image: winsvega/evmone-coverage-script:latest
216297
options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests
217298
run: /entrypoint.sh --mode=diff --basefile=coverage_BASE.lcov --patchfile=coverage_PATCH.lcov
218299

219300
- name: Chmod coverage results
220-
if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }}
301+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' }}
221302
run: |
222303
user=$(whoami)
223304
sudo chown -R $user:$user ${{ github.workspace }}/evmtest_coverage/coverage
224305
225306
- name: Upload coverage results
226307
uses: actions/upload-artifact@v3
227-
if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }}
308+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' }}
228309
with:
229-
name: coverage-diff
310+
name: coverage-diff-native
230311
path: ${{ github.workspace }}/evmtest_coverage/coverage
231312

232313
- name: Verify coverage results
233314
uses: addnab/docker-run-action@v3
234-
if: ${{ env.retesteth_skip == 'false' || matrix.driver == 'native' }}
315+
if: ${{ steps.changed-tests.outputs.tests_any_changed == 'true' }}
235316
with:
236317
image: winsvega/evmone-coverage-script:latest
237318
options: -v ${{ github.workspace }}/evmtest_coverage/coverage:/tests

0 commit comments

Comments
 (0)