1#!/usr/local/bin/bash 2 3set -o pipefail -eux 4 5declare -a args 6IFS='/:' read -ra args <<< "$1" 7 8ansible_version="${args[0]}" 9script="${args[1]}" 10 11function join { 12 local IFS="$1"; 13 shift; 14 echo "$*"; 15} 16 17# Ensure we can write other collections to this dir 18sudo chown "$(whoami)" "${PWD}/../../" 19 20test="$(join / "${args[@]:1}")" 21 22docker images ansible/ansible 23docker images quay.io/ansible/* 24docker ps 25 26for container in $(docker ps --format '{{.Image}} {{.ID}}' | grep -v -e '^drydock/' -e '^quay.io/ansible/azure-pipelines-test-container:' | sed 's/^.* //'); do 27 docker rm -f "${container}" || true # ignore errors 28done 29 30docker ps 31 32if [ -d /home/shippable/cache/ ]; then 33 ls -la /home/shippable/cache/ 34fi 35 36command -v python 37python -V 38 39function retry 40{ 41 # shellcheck disable=SC2034 42 for repetition in 1 2 3; do 43 set +e 44 "$@" 45 result=$? 46 set -e 47 if [ ${result} == 0 ]; then 48 return ${result} 49 fi 50 echo "@* -> ${result}" 51 done 52 echo "Command '@*' failed 3 times!" 53 exit 255 54} 55 56command -v pip 57pip --version 58pip list --disable-pip-version-check 59if [ "${ansible_version}" == "devel" ]; then 60 retry pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check 61else 62 retry pip install "https://github.com/ansible/ansible/archive/stable-${ansible_version}.tar.gz" --disable-pip-version-check 63fi 64 65if [ "${SHIPPABLE_BUILD_ID:-}" ]; then 66 export ANSIBLE_COLLECTIONS_PATHS="${HOME}/.ansible" 67 SHIPPABLE_RESULT_DIR="$(pwd)/shippable" 68 TEST_DIR="${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/general" 69 mkdir -p "${TEST_DIR}" 70 cp -aT "${SHIPPABLE_BUILD_DIR}" "${TEST_DIR}" 71 cd "${TEST_DIR}" 72else 73 export ANSIBLE_COLLECTIONS_PATHS="${PWD}/../../../" 74fi 75 76if [ "${test}" == "sanity/extra" ]; then 77 retry pip install junit-xml --disable-pip-version-check 78fi 79 80# START: HACK install dependencies 81if [ "${script}" != "sanity" ] || [ "${test}" == "sanity/extra" ]; then 82 # Nothing further should be added to this list. 83 # This is to prevent modules or plugins in this collection having a runtime dependency on other collections. 84 retry git clone --depth=1 --single-branch https://github.com/ansible-collections/community.internal_test_tools.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/internal_test_tools" 85 # NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429) 86 # retry ansible-galaxy -vvv collection install community.internal_test_tools 87fi 88 89if [ "${script}" != "sanity" ] && [ "${script}" != "units" ]; then 90 CRYPTO_BRANCH=main 91 if [ "${script}" == "linux" ] && [[ "${test}" =~ "ubuntu1604/" ]]; then 92 CRYPTO_BRANCH=stable-1 93 fi 94 # To prevent Python dependencies on other collections only install other collections for integration tests 95 retry git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.posix.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/ansible/posix" 96 retry git clone --depth=1 --branch "${CRYPTO_BRANCH}" --single-branch https://github.com/ansible-collections/community.crypto.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/crypto" 97 # NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429) 98 # retry ansible-galaxy -vvv collection install ansible.posix 99 # retry ansible-galaxy -vvv collection install community.crypto 100fi 101 102# END: HACK 103 104if [ "${script}" != "sanity" ] && [ "${script}" != "units" ]; then 105 # Adds meta/runtime.yml redirects for all modules before running integration tests. 106 # This ensures that ansible-base and ansible-core will use the "real" modules instead of the 107 # symbolic links, which results in coverage to be reported correctly. 108 "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/internal_test_tools/tools/meta_runtime.py" redirect --target both --flatmap 109fi 110 111export PYTHONIOENCODING='utf-8' 112 113if [ "${JOB_TRIGGERED_BY_NAME:-}" == "nightly-trigger" ]; then 114 COVERAGE=yes 115 COMPLETE=yes 116fi 117 118if [ -n "${COVERAGE:-}" ]; then 119 # on-demand coverage reporting triggered by setting the COVERAGE environment variable to a non-empty value 120 export COVERAGE="--coverage" 121elif [[ "${COMMIT_MESSAGE}" =~ ci_coverage ]]; then 122 # on-demand coverage reporting triggered by having 'ci_coverage' in the latest commit message 123 export COVERAGE="--coverage" 124else 125 # on-demand coverage reporting disabled (default behavior, always-on coverage reporting remains enabled) 126 export COVERAGE="--coverage-check" 127fi 128 129if [ -n "${COMPLETE:-}" ]; then 130 # disable change detection triggered by setting the COMPLETE environment variable to a non-empty value 131 export CHANGED="" 132elif [[ "${COMMIT_MESSAGE}" =~ ci_complete ]]; then 133 # disable change detection triggered by having 'ci_complete' in the latest commit message 134 export CHANGED="" 135else 136 # enable change detection (default behavior) 137 export CHANGED="--changed" 138fi 139 140if [ "${IS_PULL_REQUEST:-}" == "true" ]; then 141 # run unstable tests which are targeted by focused changes on PRs 142 export UNSTABLE="--allow-unstable-changed" 143else 144 # do not run unstable tests outside PRs 145 export UNSTABLE="" 146fi 147 148# remove empty core/extras module directories from PRs created prior to the repo-merge 149find plugins -type d -empty -print -delete 150 151function cleanup 152{ 153 # for complete on-demand coverage generate a report for all files with no coverage on the "sanity/5" job so we only have one copy 154 if [ "${COVERAGE}" == "--coverage" ] && [ "${CHANGED}" == "" ] && [ "${test}" == "sanity/5" ]; then 155 stub="--stub" 156 # trigger coverage reporting for stubs even if no other coverage data exists 157 mkdir -p tests/output/coverage/ 158 else 159 stub="" 160 fi 161 162 if [ -d tests/output/coverage/ ]; then 163 if find tests/output/coverage/ -mindepth 1 -name '.*' -prune -o -print -quit | grep -q .; then 164 process_coverage='yes' # process existing coverage files 165 elif [ "${stub}" ]; then 166 process_coverage='yes' # process coverage when stubs are enabled 167 else 168 process_coverage='' 169 fi 170 171 if [ "${process_coverage}" ]; then 172 # use python 3.7 for coverage to avoid running out of memory during coverage xml processing 173 # only use it for coverage to avoid the additional overhead of setting up a virtual environment for a potential no-op job 174 virtualenv --python /usr/bin/python3.7 ~/ansible-venv 175 set +ux 176 . ~/ansible-venv/bin/activate 177 set -ux 178 179 # shellcheck disable=SC2086 180 ansible-test coverage xml --color -v --requirements --group-by command --group-by version ${stub:+"$stub"} 181 cp -a tests/output/reports/coverage=*.xml "$SHIPPABLE_RESULT_DIR/codecoverage/" 182 183 if [ "${ansible_version}" != "2.9" ]; then 184 # analyze and capture code coverage aggregated by integration test target 185 ansible-test coverage analyze targets generate -v "$SHIPPABLE_RESULT_DIR/testresults/coverage-analyze-targets.json" 186 fi 187 188 # upload coverage report to codecov.io only when using complete on-demand coverage 189 if [ "${COVERAGE}" == "--coverage" ] && [ "${CHANGED}" == "" ]; then 190 for file in tests/output/reports/coverage=*.xml; do 191 flags="${file##*/coverage=}" 192 flags="${flags%-powershell.xml}" 193 flags="${flags%.xml}" 194 # remove numbered component from stub files when converting to tags 195 flags="${flags//stub-[0-9]*/stub}" 196 flags="${flags//=/,}" 197 flags="${flags//[^a-zA-Z0-9_,]/_}" 198 199 bash <(curl -s https://ansible-ci-files.s3.us-east-1.amazonaws.com/codecov/codecov.sh) \ 200 -f "${file}" \ 201 -F "${flags}" \ 202 -n "${test}" \ 203 -t 20636cf5-4d6a-4b9a-8d2d-6f22ebbaa752 \ 204 -X coveragepy \ 205 -X gcov \ 206 -X fix \ 207 -X search \ 208 -X xcode \ 209 || echo "Failed to upload code coverage report to codecov.io: ${file}" 210 done 211 fi 212 fi 213 fi 214 215 if [ -d tests/output/junit/ ]; then 216 cp -aT tests/output/junit/ "$SHIPPABLE_RESULT_DIR/testresults/" 217 fi 218 219 if [ -d tests/output/data/ ]; then 220 cp -a tests/output/data/ "$SHIPPABLE_RESULT_DIR/testresults/" 221 fi 222 223 if [ -d tests/output/bot/ ]; then 224 cp -aT tests/output/bot/ "$SHIPPABLE_RESULT_DIR/testresults/" 225 fi 226} 227 228if [ "${SHIPPABLE_BUILD_ID:-}" ]; then trap cleanup EXIT; fi 229 230if [[ "${COVERAGE:-}" == "--coverage" ]]; then 231 timeout=60 232else 233 timeout=50 234fi 235 236ansible-test env --dump --show --timeout "${timeout}" --color -v 237 238if [ "${SHIPPABLE_BUILD_ID:-}" ]; then "tests/utils/shippable/check_matrix.py"; fi 239"tests/utils/shippable/${script}.sh" "${test}" "${ansible_version}" 240