-
Notifications
You must be signed in to change notification settings - Fork 154
235 lines (228 loc) · 10.6 KB
/
Copy pathquicktest.yaml
File metadata and controls
235 lines (228 loc) · 10.6 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
name: quicktest
# File: quicktest.yaml
# Author: David Kügler
# Reworked on: 2024-12-01
# Created on: 2023-07-10 by Taha Abdullah
# Functionality: This workflow runs FastSurfer on MRI data and runs pytest to check if the results are acceptable. It
# also checks if the FastSurfer environment and output already exist, and if not, it creates them.
# Usage: This workflow is triggered on a pull request to the dev and main branch. It can also be triggered manually
# with workflow-dispatch.
# Expected Secrets:
# - QUICKTEST_IMAGE_HREF_08mm: URL to a sample 0.8mm image
# - QUICKTEST_IMAGE_HREF_1mm: URL to a sample 1mm image
# - QUICKTEST_TARGET_HREF_08mm: URL to the reference processing of the sample 0.8mm image
# - QUICKTEST_TARGET_HREF_1mm: URL to the reference processing of the sample 1mm image
# - QUICKTEST_LICENSE: content of a FreeSurfer license file
concurrency:
# maybe the group here should actually not depend on the ref (only number would mean there are
# not concurrent runs of the same pr) -- but then we should probably add the branch name (for
# manually triggered workflows)
group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }}
cancel-in-progress: true
on:
pull_request:
types: [labeled]
workflow_dispatch:
inputs:
docker-image:
description: 'Which docker image should be used to run this test (build-cached => build from git, also pr/<#no>)'
default: build-cached
type: string
freesurfer-build-image:
description: 'FreeSurfer build image to build with ("" (default) => deepmi/fastsurfer-build:freesurferXXX; extract version from pyproject.toml)'
type: string
permissions:
actions: read
attestations: read
checks: write
contents: read
deployments: read
issues: read
discussions: read
packages: read
pages: read
pull-requests: write
repository-projects: read
security-events: read
statuses: read
env:
SUBJECTS_DIR: /tmp/subjects
REFERENCE_DIR: /tmp/reference
jobs:
build-docker:
name: 'Check and build the current docker image'
runs-on: ubuntu-latest
timeout-minutes: 180
outputs:
continue: ${{ steps.parse.outputs.CONTINUE }}
docker-image: ${{ steps.parse.outputs.DOCKER_IMAGE }}
extra-args: ${{ steps.parse.outputs.EXTRA_ARGS }}
fs-build-image: ${{ steps.parse-version.outputs.FS_BUILD_IMAGE }}
fs-version: ${{ steps.parse-version.outputs.FS_VERSION }}
fs-version-short: ${{ steps.parse-version.outputs.FS_VERSION_SHORT }}
fastsurfer-home: ${{ steps.parse-version.outputs.FASTSURFER_HOME }}
steps:
- name: 'Check whether the tests should run'
id: parse
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
# Debug information
# Workflow: ${{ github.workflow }}
# Event Name: ${{ github.event_name }}
# Action: ${{ github.event.action }}
# pull_request-Event
# PR: ${{ github.event.number }}
# Event Triggered by: ${{ github.event.sender.login }}
# workflow_dispatch-Event
# Inputs:
cat > /dev/null <<ENDOFINPUTS
${{ toJSON(inputs) }}
ENDOFINPUTS
gh_header=(-H "Accept: application/vnd.github+json"
-H "X-GitHub-Api-Version: 2022-11-28")
if [[ "${{ github.event_name }}" == "pull_request" ]]
then
if [[ "${{ github.event.action }}" != "labeled" ]] && [[ "${{ github.event.action }}" != "unlabeled" ]]
then
# not a label-related action, should not be triggered
echo "The Workflow '${{ github.workflow }}' was triggered by 'pull_request' of type"
echo " '${{ github.event.action }}' but should only be triggered by 'labeled' or 'unlabeled' actions."
echo "CONTINUE=false" > $GITHUB_OUTPUT
elif [[ "${{ github.event.label.name }}" == "quicktest" ]]
then
echo "CONTINUE=true" > $GITHUB_OUTPUT
else
echo "This is a different label that was attached."
echo "CONTINUE=false" > $GITHUB_OUTPUT
fi
echo "DOCKER_IMAGE=build-cached" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]
then
# the inputs context is only useful/set in the workflow dispatch event case
if [[ "${{ inputs.docker-image }}" == "" ]] ; then
echo "DOCKER_IMAGE=build-cached" > $GITHUB_OUTPUT
else
echo "DOCKER_IMAGE=${{ inputs.docker-image }}" > $GITHUB_OUTPUT
fi
echo "CONTINUE=true" >> $GITHUB_OUTPUT
else # this event has no specific rules (invalid)
echo "This workflow is not defined for the event ${{ github.event_name }}!"
exit 1
fi
if ! gh api "${gh_header[@]}" /repos/${{ github.repository }}/collaborators/${{ github.event.sender.login }}
then
echo "Only collaborators explicitly listed as collaborators can trigger this workflow!"
echo "CONTINUE=false" >> $GITHUB_OUTPUT
fi
# later, we might want to extract additional run options from the pr text or issue comments
# these should just be added here
# https://api.github.com/repos/${{ github.repository }}/issues/${{ github.number }}
# https://api.github.com/repos/${{ github.repository }}/issues/${{ github.number }}/comments
# this may also need adaptations in the test script at the bottom
echo "EXTRA_ARGS=" >> $GITHUB_OUTPUT
- name: Checkout repository
# DOCKER_IMAGE is build-cached => we want to build, check this repository out to build the docker image
if: steps.parse.outputs.CONTINUE == 'true' && steps.parse.outputs.DOCKER_IMAGE == 'build-cached'
uses: actions/checkout@v7
- name: Checkout repository
# DOCKER_IMAGE starts with pr/*** => we want to build, check the PR out to build the docker image
if: steps.parse.outputs.CONTINUE == 'true' && startsWith(steps.parse.outputs.DOCKER_IMAGE, 'pr/')
uses: actions/checkout@v7
with:
ref: ${{ steps.parse.outputs.DOCKER_IMAGE }}
- name: Setup uv and Python 3.11
uses: astral-sh/setup-uv@v7
with:
python-version: '3.11'
# python 3.11 is needed to read pyproject.toml (tomllib)
- name: Get the FreeSurfer version
# we want to build the docker image, get what we want to do for freesurfer (read fslink from install_pruned.sh,
if: steps.parse.outputs.CONTINUE == 'true' && (steps.parse.outputs.DOCKER_IMAGE == 'build-cached' || startsWith(steps.parse.outputs.DOCKER_IMAGE, 'pr/'))
shell: bash
id: parse-version
run: |
# get the FreeSurfer version from pyproject.toml
{
fs_version="$(uv run python ./tools/read_toml.py --file ./pyproject.toml --key tool.freesurfer.version)"
fs_version_short="${fs_version//\./}"
echo "FS_VERSION=$fs_version"
echo "FS_VERSION_SHORT=$fs_version_short"
if [[ -n "${{ inputs.freesurfer-build-image }}" ]] ; then
echo "FS_BUILD_IMAGE=${{ inputs.freesurfer-build-image }}"
else
echo "FS_BUILD_IMAGE=deepmi/fastsurfer-build:freesurfer$fs_version_short"
fi
echo "FASTSURFER_HOME=$(pwd)"
} > $GITHUB_OUTPUT
- uses: Deep-MI/FastSurfer/.github/actions/build-docker@dev
if: steps.parse.outputs.CONTINUE == 'true' && steps.parse.outputs.DOCKER_IMAGE == 'build-cached'
# This action needs the "full" checkout (located at ${{ inputs.fastsurfer-home }})
with:
fastsurfer-home: ${{ steps.parse-version.outputs.FASTSURFER_HOME }}
# currently, this image has to be updated and used to circumvent storage limitations in github actions
# and it is also faster to use this prebuilt, reduced-size freesurfer distribution
freesurfer-build-image: "${{ steps.parse-version.outputs.FS_BUILD_IMAGE }}"
fastsurfer-test:
name: 'Run FastSurfer on sample images and perform tests'
needs: build-docker
runs-on: ubuntu-latest
timeout-minutes: 180
if: needs.build-docker.outputs.continue == 'true'
strategy:
# the following matrix strategy will result in one run per subject as matrix is "one-dimensional".
# Additional parameters under "include" are then added as additional (dependent) information
matrix:
subject-id: [0.8mm, 1.0mm]
include:
- subject-id: 1.0mm
file-extension: ".mgz"
image-key: QUICKTEST_IMAGE_HREF_1mm
case-key: QUICKTEST_TARGET_HREF_1mm
extra-args: ""
- subject-id: 0.8mm
file-extension: ".nii.gz"
image-key: QUICKTEST_IMAGE_HREF_08mm
case-key: QUICKTEST_TARGET_HREF_08mm
extra-args: "--3T"
steps:
- name: Check out the repository that is to be tested
uses: actions/checkout@v7
- name: Run FastSurfer for ${{ matrix.subject-id }} with the previously created docker container
uses: Deep-MI/FastSurfer/.github/actions/run-fastsurfer@dev
with:
subject-id: ${{ matrix.subject-id }}
file-extension: ${{ matrix.file-extension }}
image-href: ${{ secrets[matrix.image-key] }}
license: ${{ secrets.QUICKTEST_LICENSE }}
docker-image: ${{ needs.build-docker.outputs.docker-image }}
extra-args: ${{ matrix.extra-args }} ${{ needs.build-docker.outputs.extra-args }}
cleanup: 'false'
- name: Run tests
uses: Deep-MI/FastSurfer/.github/actions/run-tests@dev
with:
subject-id: ${{ matrix.subject-id }}
subjects-dir: ${{ env.SUBJECTS_DIR }}
reference-dir: ${{ env.REFERENCE_DIR }}
case-href: ${{ secrets[matrix.case-key] }}
junit-file: /tmp/fastsurfer-quicktest-${{ matrix.subject-id }}.junit.xml
annotation:
name: Annotate test results as checks
runs-on: ubuntu-latest
needs: [fastsurfer-test, build-docker]
if: always() && needs.build-docker.outputs.continue == 'true'
steps:
- name: Retrieve test JUnit files
uses: actions/download-artifact@v8
with:
pattern: fastsurfer-${{ github.sha }}-junit-*
merge-multiple: 'true'
path: /tmp
- name: Write the results into the check
uses: mikepenz/action-junit-report@v6
with:
report_paths: /tmp/fastsurfer-quicktest-*.junit.xml
check_name: Annotate the test results as checks
fail_on_failure: 'true'
fail_on_parse_error: 'true'