-
Notifications
You must be signed in to change notification settings - Fork 89
351 lines (304 loc) · 13.2 KB
/
build_and_test.yml
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
name: Build and Test Configuration
on:
workflow_call:
inputs:
BUILD_AND_TEST_CLI_ARGS:
required: false
type: string
BUILD_SHARED_LIBS:
required: false
type: string
default: 'ON'
BUILD_TYPE:
required: false
type: string
default: build
DOCKER_CERTS_UPDATE_COMMAND:
required: false
type: string
CMAKE_BUILD_TYPE:
required: true
type: string
CODE_COVERAGE:
required: false
type: boolean
default: false
DOCKER_CERTS_DIR:
required: false
type: string
default: ''
DOCKER_IMAGE_TAG:
required: true
type: string
DOCKER_REPOSITORY:
required: true
type: string
DOCKER_RUN_ARGS:
required: false
type: string
ENABLE_HYPRE:
required: false
type: string
ENABLE_HYPRE_DEVICE:
required: false
type: string
ENABLE_TRILINOS:
required: false
type: string
GCP_BUCKET:
required: false
type: string
HOST_CONFIG:
required: false
type: string
NPROC:
required: false
type: string
default: ''
HOST_ARCH:
required: false
type: string
RUNS_ON:
required: true
type: string
USE_SCCACHE:
required: false
type: boolean
default: true
REQUIRED_LABEL:
required: false
type: string
LOCAL_BASELINE_DIR:
required: false
type: string
BUILD_GENERATOR:
required: false
type: string
default: '--ninja'
secrets:
GOOGLE_CLOUD_GCP:
required: false
jobs:
build_test_deploy:
runs-on: ${{ inputs.RUNS_ON }}
steps:
- name: does_pr_have_necessary_labels
if: ${{inputs.REQUIRED_LABEL && github.event_name == 'pull_request'}}
run: |
pr_json=$(curl -H "Accept: application/vnd.github+json" https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.number }})
LABELS=$(echo ${pr_json} | jq -crM '[.labels[].name]')
echo " the labels are ${LABELS}"
echo " the required label is ${{inputs.REQUIRED_LABEL}}"
if [[ "${LABELS}" != *"${{inputs.REQUIRED_LABEL}}"* ]]; then
exit 1
fi
- name: 'Cleanup build folder'
run: |
pwd
echo "cleaning ${GITHUB_WORKSPACE}"
ls -la ./
rm -rf ./* ./.*|| true
echo "expecting ${GITHUB_WORKSPACE} to be empty"
ls -la ./
- name: Checkout Repository
uses: actions/[email protected]
with:
submodules: true
lfs: ${{ inputs.BUILD_TYPE == 'integrated_tests' }}
fetch-depth: 1
- id: 'auth'
if: ${{ inputs.GCP_BUCKET || inputs.USE_SCCACHE }}
uses: 'google-github-actions/[email protected]'
with:
credentials_json: '${{ secrets.GOOGLE_CLOUD_GCP }}'
create_credentials_file: true
- name: 'Set up Cloud SDK'
if: inputs.GCP_BUCKET
uses: 'google-github-actions/[email protected]'
with:
version: '>= 363.0.0'
- name: Print environment
run: printenv
- name: Setup QEMU for ${{ inputs.HOST_ARCH }} emulation
if: ${{ inputs.HOST_ARCH }}
uses: docker/setup-qemu-action@v3
with:
platforms: ${{ inputs.HOST_ARCH }}
- name: Build, test, deploy.
run: |
# Those two bash arrays will be populated depending on the required options,
# and expended as CLI arguments for the docker and scripts calls.
docker_args=()
script_args=()
if [[ -n "${{ inputs.DOCKER_CERTS_DIR }}" ]]; then
DOCKER_CERTS_DIR=${{ inputs.DOCKER_CERTS_DIR }}
docker_args+=(-e DOCKER_CERTS_DIR=${DOCKER_CERTS_DIR})
fi
if [[ -n "${{ inputs.DOCKER_CERTS_UPDATE_COMMAND }}" ]]; then
DOCKER_CERTS_UPDATE_COMMAND=${{ inputs.DOCKER_CERTS_UPDATE_COMMAND }}
docker_args+=(-e DOCKER_CERTS_UPDATE_COMMAND=${DOCKER_CERTS_UPDATE_COMMAND})
fi
if [[ -n "${{ inputs.NPROC }}" ]]; then
NPROC=${{ inputs.NPROC }}
script_args+=(--nproc ${NPROC})
fi
if [[ -n "${{ inputs.BUILD_GENERATOR }}" ]]; then
script_args+=(${{ inputs.BUILD_GENERATOR }})
fi
docker_args+=(${{ inputs.DOCKER_RUN_ARGS }})
COMMIT=${{ github.event.pull_request.head.sha }}
SHORT_COMMIT=${COMMIT:0:7}
script_args+=(--install-dir-basename GEOS-${SHORT_COMMIT})
# All the data exchanged with the docker container is eventually meant to be sent to the cloud.
if [[ ! -z "${{ inputs.GCP_BUCKET }}" ]]; then
if [ "${{ inputs.BUILD_TYPE }}" = "build" ]; then
DATA_BASENAME=GEOS-and-TPL-${SHORT_COMMIT}.tar.gz
elif [ "${{ inputs.BUILD_TYPE }}" = "integrated_tests" ]; then
DATA_BASENAME=integratedTests-pr${{ github.event.number }}-${{ github.run_number }}-${SHORT_COMMIT}.tar.gz
script_args+=(--run-integrated-tests)
fi
script_args+=(--data-basename ${DATA_BASENAME})
DATA_EXCHANGE_DIR=${GITHUB_WORKSPACE}/geos-exchange # Exchange folder outside of the container
if [ ! -d "${DATA_EXCHANGE_DIR}" ]; then
mkdir -p ${DATA_EXCHANGE_DIR}
fi
DATA_EXCHANGE_MOUNT_POINT=/tmp/exchange # Exchange folder inside of the container
docker_args+=(--volume=${DATA_EXCHANGE_DIR}:${DATA_EXCHANGE_MOUNT_POINT})
script_args+=(--exchange-dir ${DATA_EXCHANGE_MOUNT_POINT})
fi
HOST_CONFIG=${{ inputs.HOST_CONFIG }}
script_args+=(${HOST_CONFIG:+"--host-config ${HOST_CONFIG}"})
if ${{ inputs.USE_SCCACHE }} == 'true'; then
script_args+=(--sccache-credentials $(basename ${GOOGLE_GHA_CREDS_PATH}))
fi
# We need to know where the code folder is mounted inside the container so we can run the script at the proper location!
# Since this information is repeated twice, we use a variable.
GITHUB_WORKSPACE_MOUNT_POINT=/tmp/geos
docker_args+=(--volume=${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE_MOUNT_POINT})
script_args+=(--repository ${GITHUB_WORKSPACE_MOUNT_POINT})
# The linear algebra environment variables (ENABLE_HYPRE, ENABLE_HYPRE_DEVICE & ENABLE_TRILINOS)
# could be passed as scripts parameters as well, but a specific care must be taken to be sure
# there's no conflict with the host-config files.
ENABLE_HYPRE=${{ inputs.ENABLE_HYPRE }}
ENABLE_HYPRE_DEVICE=${{ inputs.ENABLE_HYPRE_DEVICE }}
ENABLE_TRILINOS=${{ inputs.ENABLE_TRILINOS }}
docker_args+=(-e ENABLE_HYPRE=${ENABLE_HYPRE:-OFF})
docker_args+=(-e ENABLE_HYPRE_DEVICE=${ENABLE_HYPRE_DEVICE:-CPU})
docker_args+=(-e ENABLE_TRILINOS=${ENABLE_TRILINOS:-ON})
docker_args+=(-e GEOS_BUILD_SHARED_LIBS=${{ inputs.BUILD_SHARED_LIBS }})
docker_args+=(--cap-add=SYS_PTRACE --rm)
script_args+=(--cmake-build-type ${{ inputs.CMAKE_BUILD_TYPE }})
script_args+=(${{ inputs.BUILD_AND_TEST_CLI_ARGS }})
DOCKER_REPOSITORY=${{ inputs.DOCKER_REPOSITORY }}
SPLIT_DOCKER_REPOSITORY=(${DOCKER_REPOSITORY//// })
CONTAINER_NAME=geosx_build_${SPLIT_DOCKER_REPOSITORY[1]}_${GITHUB_SHA:0:7}
echo "CONTAINER_NAME: ${CONTAINER_NAME}"
if [ "$(docker ps -aq -f name=${CONTAINER_NAME})" ]; then
docker rm -f ${CONTAINER_NAME}
fi
docker_args+=(--name ${CONTAINER_NAME})
if ${{ inputs.CODE_COVERAGE }} == 'true'; then
script_args+=(--code-coverage)
fi
if [[ -n "${{ inputs.LOCAL_BASELINE_DIR }}" ]]; then
# Extract the 'baseline' value
# Define the path to the YAML file
YAML_FILE_PATH="${GITHUB_WORKSPACE}/.integrated_tests.yaml"
# Verify the YAML file path
if [[ ! -f "${YAML_FILE_PATH}" ]]; then
echo "Error: File $YAML_FILE_PATH does not exist."
else
echo "Found integratedTests file: $YAML_FILE_PATH."
fi
# Extract the baseline field
BASELINE_FULL_PATH=$(grep -A 2 'baselines:' "${YAML_FILE_PATH}" | grep 'baseline:' | awk '{print $2}')
# Remove the 'integratedTests/' prefix
BASELINE_TAG=${BASELINE_FULL_PATH#integratedTests/}
echo "Baseline: ${BASELINE_TAG}"
# Extract the folder name
PR_NUMBER=$(echo "$BASELINE_TAG" | grep -o 'pr[0-9]*')
PR_BASELINE_FOLDER_NAME=baselines_${PR_NUMBER}
echo "Baseline folder name: ${PR_BASELINE_FOLDER_NAME}"
CURRENT_BASELINE_DIR=${{ inputs.LOCAL_BASELINE_DIR }}/${PR_BASELINE_FOLDER_NAME}
echo "Current baseline dir: ${CURRENT_BASELINE_DIR}"
if [ -d ${CURRENT_BASELINE_DIR} ];then
echo "Current baseline dir found."
ls -l ${CURRENT_BASELINE_DIR}
# We defined a mount point and mount it read-only inside the container.
CURRENT_BASELINE_DIR_MOUNT=/tmp/geos/baselines
docker_args+=(--volume=${CURRENT_BASELINE_DIR}:${CURRENT_BASELINE_DIR_MOUNT}:ro)
else
echo "Current baselines directory (${CURRENT_BASELINE_DIR}) not found"
fi
fi
echo running "docker run \
${docker_args[@]} \
-h=`hostname` \
${{ inputs.DOCKER_REPOSITORY }}:${{ inputs.DOCKER_IMAGE_TAG }} \
${GITHUB_WORKSPACE_MOUNT_POINT}/scripts/ci_build_and_test_in_container.sh \
${script_args[@]}"
# In case of integrated tests run, we still want to send the results to the cloud for inspection.
# While for standard build (if even possible), pushing a failed build would be pointless.
# GHA set `-e` to bash scripts by default to fail asap,
# but for this precise call, we want to deal with it more precisely
set +e
docker run \
${docker_args[@]} \
-h=`hostname` \
${{ inputs.DOCKER_REPOSITORY }}:${{ inputs.DOCKER_IMAGE_TAG }} \
${GITHUB_WORKSPACE_MOUNT_POINT}/scripts/ci_build_and_test_in_container.sh \
${script_args[@]}
EXIT_STATUS=$?
echo "Received exit status ${EXIT_STATUS} from the build process."
set -e
# Send to the bucket and print the download link when it makes sense.
if [[ ! -z "${{ inputs.GCP_BUCKET }}" ]]; then
if [[ "${{ inputs.BUILD_TYPE }}" = "integrated_tests" || ${EXIT_STATUS} -eq 0 ]]; then
if [ -f ${DATA_EXCHANGE_DIR}/${DATA_BASENAME} ]; then
CLOUDSDK_PYTHON=python3 gsutil cp -a public-read ${DATA_EXCHANGE_DIR}/${DATA_BASENAME} gs://${{ inputs.GCP_BUCKET }}/
echo "Download the bundle at https://storage.googleapis.com/${{ inputs.GCP_BUCKET }}/${DATA_BASENAME}"
fi
if [ -f ${DATA_EXCHANGE_DIR}/test_logs_${DATA_BASENAME} ]; then
CLOUDSDK_PYTHON=python3 gsutil cp -a public-read ${DATA_EXCHANGE_DIR}/test_logs_${DATA_BASENAME} gs://${{ inputs.GCP_BUCKET }}/
echo "Download integrated test logs here: https://storage.googleapis.com/${{ inputs.GCP_BUCKET }}/test_logs_${DATA_BASENAME}"
fi
if [ -f ${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME} ];then
if [[ -n "${{ inputs.LOCAL_BASELINE_DIR }}" ]]; then
# 1. We copy the baselines to a local directory to store them
# 1.a Create the new target directory to store the new baselines
THIS_PR_NUMBER=pr${{ github.event.number }}
NEW_PR_BASELINE_FOLDER_NAME=baselines_${THIS_PR_NUMBER}
TARGET_DIR="${{ inputs.LOCAL_BASELINE_DIR }}/${NEW_PR_BASELINE_FOLDER_NAME}"
echo "Create folder ${TARGET_DIR}"
mkdir -p "${TARGET_DIR}"
# 1.b We copy the new baselines to the new target directory
SOURCE_FILE="${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME}"
echo "Copy ${SOURCE_FILE} to ${TARGET_DIR}"
cp "${SOURCE_FILE}" "${TARGET_DIR}"
fi
# 2. We push the baselines to the cloud
CLOUDSDK_PYTHON=python3 gsutil cp -a public-read ${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME} gs://${{ inputs.GCP_BUCKET }}/
echo "Download test baselines here: https://storage.googleapis.com/${{ inputs.GCP_BUCKET }}/baseline_${DATA_BASENAME}"
echo "New baseline ID: baseline_${DATA_BASENAME::-7}"
else
echo "Baselines ${DATA_EXCHANGE_DIR}/baseline_${DATA_BASENAME} were not uploaded. Likeyly because no rebaseline was necessary."
fi
fi
fi
exit ${EXIT_STATUS}
- name: Upload coverage to Codecov
if: inputs.CODE_COVERAGE
uses: codecov/[email protected]
with:
files: ${GITHUB_WORKSPACE}/geos_coverage.info.cleaned
fail_ci_if_error: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: 'Cleanup build folder'
run: |
pwd
echo "cleaning ${GITHUB_WORKSPACE}"
ls -la ./
rm -rf ./* ./.*|| true
echo "expecting ${GITHUB_WORKSPACE} to be empty"
ls -la ./