|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# The whole of what a cron job needs to run the e2e tests, so that a crontab |
| 4 | +# line is this script and nothing else: |
| 5 | +# |
| 6 | +# PATH=/usr/local/go/bin:/usr/local/bin:/usr/bin:/bin |
| 7 | +# */5 * * * * /path/to/nri-plugins/scripts/testing/nightly/e2e-cron-job |
| 8 | +# |
| 9 | +# Every setting comes from the environment, so a host is configured without |
| 10 | +# editing this file. Install the settings file next to it: |
| 11 | +# |
| 12 | +# install -m 644 scripts/testing/nightly/e2e-cron-job.env \ |
| 13 | +# /etc/sysconfig/nri-plugins-e2e-cron-job |
| 14 | +# |
| 15 | +# and edit that. What it leaves out defaults below. Anything given on our own |
| 16 | +# command line is passed on to the runner, so a one-off is |
| 17 | +# |
| 18 | +# e2e-cron-job --no-pack-results --runtime crio |
| 19 | +# |
| 20 | +# Every five minutes is not a typo: with E2E_RUN_IF_CHANGED the runner does |
| 21 | +# nothing unless the branch it tests has moved since it last tried, so polling |
| 22 | +# often is how a merged PR gets tested soon after it lands rather than the |
| 23 | +# following night. A run already going is left alone, and once E2E_FORCE_AFTER |
| 24 | +# has passed with nothing new, the tests run anyway. |
| 25 | + |
| 26 | +set -o pipefail |
| 27 | + |
| 28 | +SELF="$0" |
| 29 | +HERE="$(dirname "$(realpath "$SELF")")" |
| 30 | + |
| 31 | +# ENV_FILE: where a host says what it wants, and the only thing to edit |
| 32 | +ENV_FILE="${E2E_CRON_ENV:-/etc/sysconfig/nri-plugins-e2e-cron-job}" |
| 33 | + |
| 34 | +if [ -r "$ENV_FILE" ]; then |
| 35 | + # shellcheck disable=SC1090 |
| 36 | + if ! source "$ENV_FILE"; then |
| 37 | + echo "$SELF: failed to read $ENV_FILE" >&2 |
| 38 | + exit 1 |
| 39 | + fi |
| 40 | +fi |
| 41 | + |
| 42 | +# E2E_REMOTE: repository to test a branch of |
| 43 | +E2E_REMOTE="${E2E_REMOTE:-https://github.com/containers/nri-plugins}" |
| 44 | +# E2E_BRANCH: which branch of it |
| 45 | +E2E_BRANCH="${E2E_BRANCH:-main}" |
| 46 | +# E2E_CLONE: where to keep the clone of it. A clone belongs to one remote: the |
| 47 | +# runner refuses one whose origin is another, so a second remote wants a second |
| 48 | +# directory here. |
| 49 | +E2E_CLONE="${E2E_CLONE:-/opt/e2e-test/nri-plugins/nri-plugins}" |
| 50 | +# E2E_RESULTS: where to publish the results of each run |
| 51 | +E2E_RESULTS="${E2E_RESULTS:-/opt/e2e-test/nri-plugins/results}" |
| 52 | +# E2E_PROXIES: a file setting up proxies in the environment, if this host needs |
| 53 | +# one to reach the remote and pull images |
| 54 | +E2E_PROXIES="${E2E_PROXIES:-}" |
| 55 | +# E2E_RUN_IF_CHANGED: only test when the branch has moved, which is what makes |
| 56 | +# it sane to be triggered every few minutes. Empty, no or 0 to test on every |
| 57 | +# trigger. Defaulted with ${VAR-...} rather than ${VAR:-...}, so that a setting |
| 58 | +# emptied on purpose stays empty instead of coming back as the default. |
| 59 | +E2E_RUN_IF_CHANGED="${E2E_RUN_IF_CHANGED-1}" |
| 60 | +# E2E_FORCE_AFTER: test anyway once this long has passed with nothing new. |
| 61 | +# Defaulted with ${VAR-...} like the switches above, so that an empty value stays |
| 62 | +# empty: the runner reads that as never, and coming back as a day instead would be |
| 63 | +# the opposite of what emptying it asks for. |
| 64 | +E2E_FORCE_AFTER="${E2E_FORCE_AFTER-24h}" |
| 65 | +# E2E_PACK_RESULTS: publish a run as a single archive, keeping everything it |
| 66 | +# collected. Needs e2e-report serve to browse. |
| 67 | +E2E_PACK_RESULTS="${E2E_PACK_RESULTS-1}" |
| 68 | +# E2E_OPTIONS: anything else to pass the runner, as it would be on its command |
| 69 | +# line, for what this script has no setting of its own |
| 70 | +E2E_OPTIONS="${E2E_OPTIONS:-}" |
| 71 | +# E2E_UPDATE_CLONE: bring the clone up to the branch before running, so that the |
| 72 | +# copy of the runner which parses our options is the branch's too. Off by |
| 73 | +# default: it is a reset --hard of a directory which may be someone's tree. |
| 74 | +E2E_UPDATE_CLONE="${E2E_UPDATE_CLONE-}" |
| 75 | + |
| 76 | +update_clone() { |
| 77 | + # Bring the clone up to the branch we are to test. The runner re-execs itself |
| 78 | + # out of the worktree it makes, so everything it does after parsing its |
| 79 | + # options is the branch's code already -- but it cannot re-exec its way out |
| 80 | + # of not understanding an option the checked-out copy has never heard of. |
| 81 | + # This is what closes that gap, for whoever wants it closed. |
| 82 | + # |
| 83 | + # Safe to do although we may well be running out of this very clone: git |
| 84 | + # replaces a file rather than writing over it, and the copy of us the shell |
| 85 | + # is reading stays open and therefore intact. Checked, not assumed. |
| 86 | + local origin |
| 87 | + |
| 88 | + # Nothing to update yet. The runner clones it, at the branch, by itself. |
| 89 | + if [ ! -e "$E2E_CLONE/.git" ]; then |
| 90 | + return 0 |
| 91 | + fi |
| 92 | + |
| 93 | + # Fetching needs whatever proxies reach the remote. The runner sets those up |
| 94 | + # for itself, but we are ahead of it here. |
| 95 | + if [ -n "$E2E_PROXIES" ] && [ -r "$E2E_PROXIES" ]; then |
| 96 | + # shellcheck disable=SC1090 |
| 97 | + source "$E2E_PROXIES" || true |
| 98 | + export http_proxy https_proxy no_proxy HTTP_PROXY HTTPS_PROXY NO_PROXY |
| 99 | + fi |
| 100 | + |
| 101 | + # A clone belongs to one remote. Resetting it to some other remote's branch |
| 102 | + # would be worse than leaving it alone, and the runner says so properly. |
| 103 | + origin=$(git -C "$E2E_CLONE" remote get-url origin 2>/dev/null) |
| 104 | + if [ "$origin" != "$E2E_REMOTE" ]; then |
| 105 | + echo "$SELF: $E2E_CLONE is a clone of ${origin:-nothing} and not of" \ |
| 106 | + "$E2E_REMOTE, leaving it as it is" >&2 |
| 107 | + return 0 |
| 108 | + fi |
| 109 | + |
| 110 | + # A failure here is not ours to be fatal about: the checkout we have still |
| 111 | + # runs, and the runner fetches for itself and fails properly if it cannot. |
| 112 | + if ! git -C "$E2E_CLONE" fetch -q origin; then |
| 113 | + echo "$SELF: failed to fetch $E2E_REMOTE in $E2E_CLONE," \ |
| 114 | + "running with the clone as it is" >&2 |
| 115 | + return 0 |
| 116 | + fi |
| 117 | + if ! git -C "$E2E_CLONE" reset -q --hard "origin/$E2E_BRANCH"; then |
| 118 | + echo "$SELF: failed to put $E2E_CLONE on $E2E_BRANCH," \ |
| 119 | + "running with the clone as it is" >&2 |
| 120 | + return 0 |
| 121 | + fi |
| 122 | +} |
| 123 | + |
| 124 | +case "$E2E_UPDATE_CLONE" in |
| 125 | + 1|true|yes|y) |
| 126 | + update_clone |
| 127 | + ;; |
| 128 | +esac |
| 129 | + |
| 130 | +RUNNER="${E2E_RUNNER:-$HERE/e2e-runner}" |
| 131 | + |
| 132 | +if [ ! -x "$RUNNER" ]; then |
| 133 | + echo "$SELF: no e2e-runner to run at $RUNNER" >&2 |
| 134 | + exit 1 |
| 135 | +fi |
| 136 | + |
| 137 | +opts=(--remote "$E2E_REMOTE" |
| 138 | + --branch "$E2E_BRANCH" |
| 139 | + --local "$E2E_CLONE" |
| 140 | + --results "$E2E_RESULTS") |
| 141 | + |
| 142 | +case "$E2E_RUN_IF_CHANGED" in |
| 143 | + 1|true|yes|y) |
| 144 | + opts+=(--run-if-changed --force-after "$E2E_FORCE_AFTER") |
| 145 | + ;; |
| 146 | +esac |
| 147 | + |
| 148 | +case "$E2E_PACK_RESULTS" in |
| 149 | + 1|true|yes|y) |
| 150 | + opts+=(--pack-results) |
| 151 | + ;; |
| 152 | +esac |
| 153 | + |
| 154 | +if [ -n "$E2E_PROXIES" ]; then |
| 155 | + opts+=(--source-proxies "$E2E_PROXIES") |
| 156 | +fi |
| 157 | + |
| 158 | +# Unquoted on purpose: a setting of several flags in one value is the point of |
| 159 | +# it, and an empty one has to come to nothing rather than to an empty argument. |
| 160 | +# shellcheck disable=SC2206,SC2086 |
| 161 | +opts+=($E2E_OPTIONS) |
| 162 | + |
| 163 | +exec "$RUNNER" "${opts[@]}" "$@" |
0 commit comments