-
-
Notifications
You must be signed in to change notification settings - Fork 1k
244 lines (228 loc) · 11.2 KB
/
Copy pathpr-emulator-wtf.yml
File metadata and controls
244 lines (228 loc) · 11.2 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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
name: PR Emulator.wtf
on: # yamllint disable-line rule:truthy
workflow_run:
workflows: ['Pull Request']
types: [completed]
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
permissions: {}
jobs:
emulator_wtf:
name: "Instrumentation Test app"
runs-on: ubuntu-latest
environment: ui-test
if: >
github.event.workflow_run.event == 'pull_request'
&& github.event.workflow_run.conclusion == 'success'
permissions:
id-token: write # Needed for OIDC authentication
actions: read # Needed for retrieving artifacts
checks: write # Needed to publish this job's status as a PR check
steps:
# Surface this job's own success/failure as a check on the PR commit.
# workflow_run jobs are detached from the PR, so the status is not shown
# otherwise. A check run created via the API for a PR-head SHA gets grouped
# under an arbitrary existing check suite on that commit (here CodeQL's, so
# it renders as "CodeQL / Instrumentation Test app (dynamic)"); the suite
# cannot be chosen via the API. We accept that prefix to stay consistent
# with the publish-unit-test-result-action check below, which has the same
# limitation. Every input here comes from the trusted workflow_run context
# (no fork-controlled data is consumed).
- name: Create PR check (in progress)
id: create_check
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
# On PR-context check_suites GitHub absorbs API-created check_runs into
# the triggering "Pull Request" workflow's suite and silently rewrites
# details_url to the legacy `runs/{check_run_id}` form, which lands on
# an empty synthetic-job page in the parent run. We can't prevent that,
# but a Markdown link in output.summary renders on whichever page the
# Details button ends up showing, so the real emulator.wtf job logs
# are always one click away.
run: |
# Identify this job by its runner, not by display name. GitHub does
# not expose the current job's database id directly (no GITHUB_JOB_ID,
# no /actions/jobs/current endpoint — confirmed against the REST API
# docs), and $GITHUB_JOB is the YAML key, not the id we need for the
# URL. The jobs API returns a `runner_name` field on every job, and
# the runner exports its name as $RUNNER_NAME, so matching the two
# uniquely identifies this job regardless of how many siblings exist.
# `env.RUNNER_NAME` is jq's safe way to read the env var (no shell
# interpolation of the value into the filter string).
JOB_ID=$(gh api "repos/$REPO/actions/runs/$GITHUB_RUN_ID/jobs?per_page=100" \
--jq '[.jobs[] | select(.runner_name == env.RUNNER_NAME) | .id][0]' || true)
# Defence-in-depth: only use JOB_ID in a URL if it looks like an id.
# gh returns integers here, but validating keeps the URL safe even if
# GitHub's response format ever changes, and guards against the
# selector ever matching zero or multiple jobs.
if [[ "$JOB_ID" =~ ^[0-9]+$ ]]; then
JOB_URL="$RUN_URL/job/$JOB_ID"
else
JOB_URL="$RUN_URL"
fi
SUMMARY="Full logs: [open this emulator.wtf job →]($JOB_URL)"
check_id=$(jq -n \
--arg sha "$HEAD_SHA" \
--arg url "$JOB_URL" \
--arg summary "$SUMMARY" \
'{
name: "Instrumentation Test app",
head_sha: $sha,
status: "in_progress",
details_url: $url,
output: {title: "Running on emulator.wtf", summary: $summary}
}' \
| gh api --method POST "repos/$REPO/check-runs" --input - --jq '.id')
{
echo "check_id=$check_id"
echo "job_url=$JOB_URL"
} >> "$GITHUB_OUTPUT"
- name: Download emulator.wtf inputs
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: emulator-wtf-inputs
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: emulator-wtf-inputs
- name: Load device list
id: devices
# The artifact comes from a PR build that may originate from a fork; validate
# every line strictly before piping the contents into GITHUB_OUTPUT to prevent
# heredoc-terminator injection.
run: |
if [ ! -s emulator-wtf-inputs/devices.txt ]; then
echo "::error::devices.txt is empty or missing"
exit 1
fi
while IFS= read -r line; do
if [[ ! "$line" =~ ^model=Pixel7,version=(2[3-9]|3[0-9]|40)$ ]]; then
echo "::error::Invalid line in devices.txt"
exit 1
fi
done < emulator-wtf-inputs/devices.txt
{
echo 'list<<DEVICES_EOF'
cat emulator-wtf-inputs/devices.txt
echo 'DEVICES_EOF'
} >> "$GITHUB_OUTPUT"
- uses: emulator-wtf/actions/configure-credentials@1a96fbe11f971a7f9da7d5e80eda476909224c78 # v1.0.1
with:
oidc-configuration-id: ${{ vars.EMULATOR_WTF_OIDC_CONFIGURATION_ID }}
- name: Run tests full
uses: emulator-wtf/actions/run-tests@1a96fbe11f971a7f9da7d5e80eda476909224c78 # v1.0.1
with:
devices: ${{ steps.devices.outputs.list }}
app: emulator-wtf-inputs/app/build/outputs/apk/full/debug/app-full-debug.apk
test: emulator-wtf-inputs/app/build/outputs/apk/androidTest/full/debug/app-full-debug-androidTest.apk
outputs-dir: build/test-results/full
- name: Run tests minimal
uses: emulator-wtf/actions/run-tests@1a96fbe11f971a7f9da7d5e80eda476909224c78 # v1.0.1
with:
devices: ${{ steps.devices.outputs.list }}
app: emulator-wtf-inputs/app/build/outputs/apk/minimal/debug/app-minimal-debug.apk
test: emulator-wtf-inputs/app/build/outputs/apk/androidTest/minimal/debug/app-minimal-debug-androidTest.apk
outputs-dir: build/test-results/minimal
- name: Upload test results
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: Instrumentation Test app results
path: |
**/build/test-results/**/TEST-*.xml
**/build/test-results/**/results.xml
- name: Upload test reports
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: Instrumentation Test app reports
path: build/test-results/**
# job.status reflects everything above (check creation, downloads, test runs) and is
# one of success/failure/cancelled, all valid check-run conclusions.
# We re-send the same output.summary link so the completed check page
# keeps the deep-link to the emulator.wtf job logs (see the Create step
# for why this matters on PR-context check_suites).
- name: Finalize PR check
if: always() && steps.create_check.outputs.check_id != ''
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
CHECK_ID: ${{ steps.create_check.outputs.check_id }}
CONCLUSION: ${{ job.status }}
JOB_URL: ${{ steps.create_check.outputs.job_url }}
run: |
SUMMARY="Full logs: [open this emulator.wtf job →]($JOB_URL)"
jq -n \
--arg conclusion "$CONCLUSION" \
--arg summary "$SUMMARY" \
'{
status: "completed",
conclusion: $conclusion,
output: {title: "Completed on emulator.wtf", summary: $summary}
}' \
| gh api --method PATCH "repos/$REPO/check-runs/$CHECK_ID" --input -
publish_test_results:
name: "Publish Tests Results"
needs: [emulator_wtf]
if: always()
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write
actions: read
contents: read
steps:
- name: Download artifacts from pr.yml run
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
path: pr-artifacts
# If emulator_wtf was skipped (non-PR trigger or triggering workflow did not succeed) or
# cancelled/failed before running tests, it uploads no results artifact, and
# downloading it by name errors. Tolerate that so we still publish the
# pr.yml results below. We cannot gate on needs.emulator_wtf.result because
# a real test failure also fails the job yet does produce this artifact,
# which we must still publish.
- name: Download emulator.wtf results from this run
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: Instrumentation Test app results
path: pr-artifacts/Instrumentation Test app results
# Build a minimal event payload from the trusted workflow_run context.
# Supplying any event_file flips the is_fork check to false in the
# publish-unit-test-result-action source
# (publish_test_results.py: `is_fork = event_file is None and ...`), so it
# publishes the check run instead of disabling it for fork PRs. We build
# the payload here from trusted context rather than forwarding the real
# pull_request payload, which on a fork PR could be forged.
# The PR for the failures comment is resolved from the commit SHA via the
# API (the action's publisher.py get_pulls_from_commit), so no PR number
# is needed here.
#
# This payload is intentionally minimal: it was verified sufficient against
# publish-unit-test-result-action (the pinned SHA below). Every
# other event field the action reads degrades gracefully when absent (it
# only drops the cosmetic "vs base"/"vs earlier" deltas). If you bump the
# action version, re-check which event fields it reads and update this.
- name: Build minimal event payload
env:
HEAD_REPO: ${{ github.event.workflow_run.head_repository.full_name }}
run: |
jq -n --arg head "$HEAD_REPO" \
'{pull_request: {head: {repo: {full_name: $head}}}}' > event.json
- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@d0a4676d0e0b938bc201470d88276b7c74c712b3 # v2.24.0
with:
commit: ${{ github.event.workflow_run.head_sha }}
event_name: ${{ github.event.workflow_run.event }}
event_file: "event.json"
comment_mode: "failures"
action_fail: true
files: |
pr-artifacts/**/TEST-*.xml
pr-artifacts/**/results.xml