-
Notifications
You must be signed in to change notification settings - Fork 64
/
presubmit-tests.sh
executable file
·372 lines (335 loc) · 12.5 KB
/
presubmit-tests.sh
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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
#!/usr/bin/env bash
# Copyright 2018 The Knative Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This is a helper script for Knative presubmit test scripts.
# See README.md for instructions on how to use it.
source "$(dirname "${BASH_SOURCE[0]}")"/library.sh
# Custom configuration of presubmit tests
readonly PRESUBMIT_TEST_FAIL_FAST=${PRESUBMIT_TEST_FAIL_FAST:-0}
# Extensions or file patterns that don't require presubmit tests.
readonly NO_PRESUBMIT_FILES=(\.png \.gitignore \.gitattributes ^OWNERS ^OWNERS_ALIASES ^AUTHORS \.github/.*)
# Flag if this is a presubmit run or not.
(( IS_PROW )) && [[ ${JOB_TYPE} == "presubmit" ]] && IS_PRESUBMIT=1 || IS_PRESUBMIT=0
readonly IS_PRESUBMIT
# List of changed files on presubmit, LF separated.
CHANGED_FILES=""
# Flags that this PR is exempt of presubmit tests.
IS_PRESUBMIT_EXEMPT_PR=0
# Flags that this PR contains only changes to documentation.
IS_DOCUMENTATION_PR=0
# Returns true if PR only contains the given file regexes.
# Parameters: $1 - file regexes, space separated.
function pr_only_contains() {
[[ -z "$(echo "${CHANGED_FILES}" | grep -v "\(${1// /\\|}\)$")" ]]
}
# Initialize flags and context for presubmit tests:
# CHANGED_FILES, IS_PRESUBMIT_EXEMPT_PR and IS_DOCUMENTATION_PR.
function initialize_environment() {
CHANGED_FILES=""
IS_PRESUBMIT_EXEMPT_PR=0
IS_DOCUMENTATION_PR=0
(( ! IS_PRESUBMIT )) && return
CHANGED_FILES="$(list_changed_files)"
if [[ -n "${CHANGED_FILES}" ]]; then
echo -e "Changed files in commit ${PULL_PULL_SHA}:\n${CHANGED_FILES}"
local no_presubmit_files="${NO_PRESUBMIT_FILES[*]}"
pr_only_contains "${no_presubmit_files}" && IS_PRESUBMIT_EXEMPT_PR=1
# A documentation PR must contain markdown files
if pr_only_contains "\.md ${no_presubmit_files}"; then
[[ -n "$(echo "${CHANGED_FILES}" | grep '\.md')" ]] && IS_DOCUMENTATION_PR=1
fi
else
header "NO CHANGED FILES REPORTED, ASSUMING IT'S AN ERROR AND RUNNING TESTS ANYWAY"
fi
readonly CHANGED_FILES
readonly IS_DOCUMENTATION_PR
readonly IS_PRESUBMIT_EXEMPT_PR
}
# Display a pass/fail banner for a test group.
# Parameters: $1 - test group name (e.g., build)
# $2 - result (0=passed, 1=failed)
function results_banner() {
if [[ $2 -eq 0 ]]; then
header "$1 tests PASSED"
else
error "$1 tests FAILED"
fi
}
# Run build tests. If there's no `build_tests` function, run the default
# build test runner.
function run_build_tests() {
(( ! RUN_BUILD_TESTS )) && return 0
header "Running build tests"
local failed=0
# Run pre-build tests, if any
if function_exists pre_build_tests; then
pre_build_tests || { failed=1; step_failed "pre_build_tests"; }
fi
# Don't run build tests if pre-build tests failed
if (( ! failed )); then
if function_exists build_tests; then
build_tests || { failed=1; step_failed "build_tests"; }
else
default_build_test_runner || { failed=1; step_failed "default_build_test_runner"; }
fi
fi
# Don't run post-build tests if pre/build tests failed
if (( ! failed )) && function_exists post_build_tests; then
post_build_tests || { failed=1; step_failed "post_build_tests"; }
fi
results_banner "Build" ${failed}
return ${failed}
}
# Run a build test and report its output as the failure if it fails.
# Parameters: $1 - report name.
# $2... - command (test) to run.
function report_build_test() {
local report
report="$(mktemp)"
local report_name="$1"
shift
local errors=""
capture_output "${report}" "$@" || errors="$(cat "${report}")"
create_junit_xml _build_tests "${report_name}" "${errors}"
[[ -z "${errors}" ]]
}
# Default build test runner that:
# * run `/hack/verify-codegen.sh` (if it exists)
# * `go build` on the entire repo
# * check licenses in all go packages
function default_build_test_runner() {
foreach_go_module __build_test_runner_for_module
}
function __build_test_runner_for_module() {
local failed=0
subheader "Build tests for $(go_mod_module_name)"
# Run verify-codegen check
if [[ -f ./hack/verify-codegen.sh ]]; then
subheader "Checking autogenerated code is up-to-date"
report_build_test Verify_CodeGen ./hack/verify-codegen.sh || failed=1
fi
# For documentation PRs, just check the md files and run
# verify-codegen (as md files can be auto-generated in some repos).
(( IS_DOCUMENTATION_PR )) && return ${failed}
# Don't merge these two lines, or return code will always be 0.
# Get all build tags in go code (ignore /vendor, /hack and /third_party)
local tags
tags="$(go run knative.dev/toolbox/go-ls-tags@latest --joiner=,)"
local go_pkg_dirs
go_pkg_dirs="$(go list -tags "${tags}" ./...)" || return $?
if [[ -z "${go_pkg_dirs}" ]]; then
subheader "No golang code found, skipping build tests"
return 0
fi
# Ensure all the code builds
subheader "Checking that go code builds"
report_build_test Build_Go \
go test -vet=off -tags "${tags}" -exec echo ./... || failed=2
# Check that we don't have any forbidden licenses in our images.
subheader "Checking for forbidden licenses"
report_build_test Check_Licenses check_licenses || failed=3
return ${failed}
}
# Run unit tests. If there's no `unit_tests` function, run the default
# unit test runner.
function run_unit_tests() {
(( ! RUN_UNIT_TESTS )) && return 0
if (( IS_DOCUMENTATION_PR )); then
header "Documentation only PR, skipping unit tests"
return 0
fi
header "Running unit tests"
local failed=0
# Run pre-unit tests, if any
if function_exists pre_unit_tests; then
pre_unit_tests || { failed=1; step_failed "pre_unit_tests"; }
fi
# Don't run unit tests if pre-unit tests failed
if (( ! failed )); then
if function_exists unit_tests; then
unit_tests || { failed=1; step_failed "unit_tests"; }
else
default_unit_test_runner || { failed=1; step_failed "default_unit_test_runner"; }
fi
fi
# Don't run post-unit tests if pre/unit tests failed
if (( ! failed )) && function_exists post_unit_tests; then
post_unit_tests || { failed=1; step_failed "post_unit_tests"; }
fi
results_banner "Unit" ${failed}
return ${failed}
}
# Default unit test runner that runs all go tests in the repo.
function default_unit_test_runner() {
foreach_go_module __unit_test_runner_for_module
}
function __unit_test_runner_for_module() {
subheader "Unit tests for $(go_mod_module_name)"
report_go_test -short -race -count 1 ./...
}
# Run integration tests. If there's no `integration_tests` function, run the
# default integration test runner.
function run_integration_tests() {
# Don't run integration tests if not requested OR on documentation PRs
(( ! RUN_INTEGRATION_TESTS )) && return 0
if (( IS_DOCUMENTATION_PR )); then
header "Documentation only PR, skipping integration tests"
return 0
fi
header "Running integration tests"
local failed=0
# Run pre-integration tests, if any
if function_exists pre_integration_tests; then
pre_integration_tests || { failed=1; step_failed "pre_integration_tests"; }
fi
# Don't run integration tests if pre-integration tests failed
if (( ! failed )); then
if function_exists integration_tests; then
integration_tests || { failed=1; step_failed "integration_tests"; }
else
default_integration_test_runner || { failed=1; step_failed "default_integration_test_runner"; }
fi
fi
# Don't run integration tests if pre/integration tests failed
if (( ! failed )) && function_exists post_integration_tests; then
post_integration_tests || { failed=1; step_failed "post_integration_tests"; }
fi
results_banner "Integration" ${failed}
return ${failed}
}
# Default integration test runner that runs all `test/e2e-*tests.sh`.
function default_integration_test_runner() {
local failed=0
while read -r e2e_test; do
subheader "Running integration test ${e2e_test}"
"${e2e_test}" || failed=$?
if (( failed )); then
echo "${e2e_test} failed: $failed" >&2
return $failed
fi
done < <(find test/ -maxdepth 1 ! -name "$(printf "*\n*")" -name "e2e-*tests.sh")
return ${failed}
}
# Options set by command-line flags.
RUN_BUILD_TESTS=0
RUN_UNIT_TESTS=0
RUN_INTEGRATION_TESTS=0
# Process flags and run tests accordingly.
function main() {
initialize_environment
if (( IS_PRESUBMIT_EXEMPT_PR )) && (( ! IS_DOCUMENTATION_PR )); then
header "Commit only contains changes that don't require tests, skipping"
exit 0
fi
# Show the version of the tools we're using
if (( IS_PROW )); then
# Disable gcloud update notifications
gcloud config set component_manager/disable_update_check true
header "Current test setup"
echo ">> gcloud SDK version"
gcloud version
echo ">> kubectl version"
kubectl version --client
echo ">> go version"
go version
echo ">> go env"
go env
echo ">> python3 version"
python3 --version
echo ">> git version"
git version
echo ">> ko version"
[[ -f /ko_version ]] && cat /ko_version || echo "unknown"
if [[ "${DOCKER_IN_DOCKER_ENABLED:-}" == "true" ]]; then
echo ">> docker version"
docker version
fi
if type java > /dev/null; then
echo ">> java version"
java -version
echo "JAVA_HOME: ${JAVA_HOME:-}"
fi
if command -v mvn > /dev/null; then
echo ">> maven version"
mvn --version
fi
if command -v cosign > /dev/null; then
echo ">> cosign version"
cosign version
fi
echo ">> prow-tests image version"
[[ -f /commit_hash ]] && echo "Prow test image was built from $(cat /commit_hash) commit which is viewable at https://github.com/knative/test-infra/tree/$(cat /commit_hash) " || echo "unknown"
fi
[[ -z ${1:-} ]] && set -- "--all-tests"
local TESTS_TO_RUN=()
while [[ $# -ne 0 ]]; do
local parameter=$1
case ${parameter} in
--help|-h)
echo "Usage: ./presubmit-tests.sh [options...]"
echo " --build-tests: run build tests."
echo " --unit-tests: run unit tests."
echo " --integration-tests: run integration tests, basically all the e2e-*tests.sh."
echo " --all-tests: run build tests, unit tests and integration tests in sequence."
echo " --run-test: run custom tests. Can be used to run multiple tests that need different args."
echo " For example, ./presubmit-tests.sh --run-test \"e2e-tests1.sh arg1\" \"e2e-tests2.sh arg2\"."
;;
--build-tests) RUN_BUILD_TESTS=1 ;;
--unit-tests) RUN_UNIT_TESTS=1 ;;
--integration-tests) RUN_INTEGRATION_TESTS=1 ;;
--all-tests)
RUN_BUILD_TESTS=1
RUN_UNIT_TESTS=1
RUN_INTEGRATION_TESTS=1
;;
--run-test)
shift
[[ $# -ge 1 ]] || abort "missing executable after --run-test"
TESTS_TO_RUN+=("$1")
;;
*) abort "error: unknown option ${parameter}" ;;
esac
shift
done
readonly RUN_BUILD_TESTS
readonly RUN_UNIT_TESTS
readonly RUN_INTEGRATION_TESTS
readonly TESTS_TO_RUN
cd "${REPO_ROOT_DIR}" || exit
# Tests to be performed, in the right order if --all-tests is passed.
local failed=0
if [[ ${#TESTS_TO_RUN[@]} -gt 0 ]]; then
if (( RUN_BUILD_TESTS || RUN_UNIT_TESTS || RUN_INTEGRATION_TESTS )); then
abort "--run-test must be used alone"
fi
# If this is a presubmit run, but a documentation-only PR, don't run the test
if (( IS_PRESUBMIT && IS_DOCUMENTATION_PR )); then
header "Documentation only PR, skipping running custom test"
exit 0
fi
for test_to_run in "${TESTS_TO_RUN[@]}"; do
${test_to_run} || { failed=$?; step_failed "${test_to_run}"; }
done
fi
run_build_tests || { failed=$?; step_failed "run_build_tests"; }
# If PRESUBMIT_TEST_FAIL_FAST is set to true, don't run unit tests if build tests failed
if (( ! PRESUBMIT_TEST_FAIL_FAST )) || (( ! failed )); then
run_unit_tests || { failed=$?; step_failed "run_unit_tests"; }
fi
# If PRESUBMIT_TEST_FAIL_FAST is set to true, don't run integration tests if build/unit tests failed
if (( ! PRESUBMIT_TEST_FAIL_FAST )) || (( ! failed )); then
run_integration_tests || { failed=$?; step_failed "run_integration_tests"; }
fi
exit ${failed}
}