-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
199 lines (173 loc) · 7.3 KB
/
backend-with-coverage.yml
File metadata and controls
199 lines (173 loc) · 7.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
name: backend - with test coverage
on:
workflow_dispatch:
workflow_call:
# Every 30 minutes
schedule:
- cron: '0,30 * * * *'
env:
SENTRY_SKIP_SELENIUM_PLUGIN: '1'
jobs:
# Skip generating coverage if already exists in GCS
check-existing-coverage:
name: check for existing coverage
runs-on: ubuntu-24.04
timeout-minutes: 5
permissions:
contents: read
id-token: write
outputs:
has-coverage: ${{ steps.check-coverage.outputs.exists }}
commit-sha: ${{ steps.get-sha.outputs.sha }}
steps:
- name: Determine commit SHA
id: get-sha
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
COMMIT_SHA="${{ github.event.pull_request.head.sha }}"
else
COMMIT_SHA="${{ github.sha }}"
fi
echo "sha=${COMMIT_SHA}" >> "$GITHUB_OUTPUT"
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed # v2.1.3
with:
project_id: sentry-dev-tooling
workload_identity_provider: ${{ secrets.SENTRY_GCP_DEV_WORKLOAD_IDENTITY_POOL }}
service_account: ${{ secrets.COLLECT_TEST_DATA_SERVICE_ACCOUNT_EMAIL }}
- name: Check if coverage exists
id: check-coverage
env:
COMMIT_SHA: ${{ steps.get-sha.outputs.sha }}
run: |
if gcloud storage ls "gs://sentry-coverage-data/${COMMIT_SHA}/.coverage.combined" &>/dev/null; then
echo "Coverage already exists for commit ${COMMIT_SHA}, skipping test run"
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "No coverage found for commit ${COMMIT_SHA}, will run tests"
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
calculate-shards:
name: calculate test shards
if: needs.check-existing-coverage.outputs.has-coverage != 'true'
needs: [check-existing-coverage]
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
shard-count: ${{ steps.calculate-shards.outputs.shard-count }}
shard-indices: ${{ steps.calculate-shards.outputs.shard-indices }}
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Setup sentry env
uses: ./.github/actions/setup-sentry
id: setup
with:
mode: backend-ci
skip-devservices: true
- name: Calculate test shards
id: calculate-shards
run: python3 .github/workflows/scripts/calculate-backend-test-shards.py
backend-test-with-cov-context:
name: backend test
if: needs.check-existing-coverage.outputs.has-coverage != 'true'
runs-on: ubuntu-24.04
needs: [check-existing-coverage, calculate-shards]
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
instance: ${{ fromJSON(needs.calculate-shards.outputs.shard-indices) }}
env:
MATRIX_INSTANCE_TOTAL: ${{ needs.calculate-shards.outputs.shard-count }}
TEST_GROUP_STRATEGY: roundrobin
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Setup sentry env
uses: ./.github/actions/setup-sentry
id: setup
with:
mode: backend-ci
- name: Download odiff binary
run: |
curl -sL https://registry.npmjs.org/odiff-bin/-/odiff-bin-4.3.2.tgz \
| tar -xz --strip-components=2 package/raw_binaries/odiff-linux-x64
sudo install -m 755 odiff-linux-x64 /usr/local/bin/odiff
rm odiff-linux-x64
- name: Run backend test with coverage (${{ steps.setup.outputs.matrix-instance-number }} of ${{ steps.setup.outputs.matrix-instance-total }})
run: make test-backend-ci-with-coverage
- name: Validate coverage database
if: always()
run: |
set -euxo pipefail
if [[ ! -f .coverage ]]; then
echo "Error: No .coverage file found after tests"
exit 1
fi
python -c "import sqlite3; sqlite3.connect('.coverage').execute('SELECT COUNT(*) FROM file')"
- name: Upload raw coverage sqlite as artifact
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: pycoverage-sqlite-${{ github.run_id }}-${{ steps.setup.outputs.matrix-instance-number }}
path: .coverage
if-no-files-found: error
retention-days: 7
include-hidden-files: true
combine-coverage:
name: combine coverage
# Only upload coverage if all test shards pass - incomplete coverage could cause selective testing to skip tests incorrectly
if: needs.check-existing-coverage.outputs.has-coverage != 'true'
runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write
actions: read # used for DIM metadata
needs: [check-existing-coverage, backend-test-with-cov-context, calculate-shards]
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- uses: astral-sh/setup-uv@884ad927a57e558e7a70b92f2bccf9198a4be546 # v6
with:
version: '0.9.28'
enable-cache: false
- name: Download all coverage artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
pattern: pycoverage-sqlite-${{ github.run_id }}-*
path: .artifacts/all-coverage
- name: Verify all shards produced coverage
env:
EXPECTED_SHARD_COUNT: ${{ needs.calculate-shards.outputs.shard-count }}
run: |
set -euxo pipefail
echo "Downloaded coverage artifacts:"
ls -la .artifacts/all-coverage || true
COVERAGE_FILE_COUNT=$(find .artifacts/all-coverage -name ".coverage" -type f | wc -l)
echo "Found ${COVERAGE_FILE_COUNT} coverage files, expected ${EXPECTED_SHARD_COUNT}"
if [[ "$COVERAGE_FILE_COUNT" -ne "$EXPECTED_SHARD_COUNT" ]]; then
echo "Error: Missing coverage files. Expected ${EXPECTED_SHARD_COUNT}, found ${COVERAGE_FILE_COUNT}"
echo "This indicates some test shards failed to produce coverage."
find .artifacts/all-coverage -name ".coverage" -type f
exit 1
fi
- name: Combine all coverage databases
run: |
set -euxo pipefail
uvx --with covdefaults --with sentry-covdefaults-disable-branch-coverage \
coverage combine $(find .artifacts/all-coverage -name ".coverage" -type f)
if [[ ! -f .coverage ]]; then
echo "Error: Combined coverage file was not created"
exit 1
fi
mv .coverage ".coverage.combined"
- name: Authenticate to Google Cloud
id: gcloud-auth
uses: google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed # v2.1.3
with:
project_id: sentry-dev-tooling
workload_identity_provider: ${{ secrets.SENTRY_GCP_DEV_WORKLOAD_IDENTITY_POOL }}
service_account: ${{ secrets.COLLECT_TEST_DATA_SERVICE_ACCOUNT_EMAIL }}
- name: Upload coverage to GCS
uses: google-github-actions/upload-cloud-storage@c0f6160ff80057923ff50e5e567695cea181ec23 # v2.2.4
with:
path: .coverage.combined
destination: sentry-coverage-data/${{ needs.check-existing-coverage.outputs.commit-sha }}