CI: remove no longer needed shippable scripts; modernize and harmonize AZP scripts (#1286)

* Remove no longer needed shippable scripts.

* Modernize and harmonize AZP scripts.
This commit is contained in:
Felix Fontein 2026-06-22 08:05:45 +02:00 committed by GitHub
parent 925eb15ded
commit d59c8d9345
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 50 additions and 450 deletions

View File

@ -1,10 +1,10 @@
#!/usr/bin/env bash
# Aggregate code coverage results for later processing.
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# Aggregate code coverage results for later processing.
set -o pipefail -eu
agent_temp_directory="$1"
@ -13,10 +13,6 @@ PATH="${PWD}/bin:${PATH}"
mkdir "${agent_temp_directory}/coverage/"
if [[ "$(ansible --version)" =~ \ 2\.9\. ]]; then
exit
fi
options=(--venv --venv-system-site-packages --color -v)
ansible-test coverage combine --group-by command --export "${agent_temp_directory}/coverage/" "${options[@]}"

View File

@ -11,8 +11,7 @@ Keep in mind that Azure Pipelines does not enforce unique job display names (onl
It is up to pipeline authors to avoid name collisions when deviating from the recommended format.
"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from __future__ import annotations
import os
import re
@ -24,12 +23,12 @@ def main():
"""Main program entry point."""
source_directory = sys.argv[1]
if '/ansible_collections/' in os.getcwd():
if "/ansible_collections/" in os.getcwd():
output_path = "tests/output"
else:
output_path = "test/results"
destination_directory = os.path.join(output_path, 'coverage')
destination_directory = os.path.join(output_path, "coverage")
if not os.path.exists(destination_directory):
os.makedirs(destination_directory)
@ -38,27 +37,27 @@ def main():
count = 0
for name in os.listdir(source_directory):
match = re.search('^Coverage (?P<attempt>[0-9]+) (?P<label>.+)$', name)
label = match.group('label')
attempt = int(match.group('attempt'))
match = re.search("^Coverage (?P<attempt>[0-9]+) (?P<label>.+)$", name)
label = match.group("label")
attempt = int(match.group("attempt"))
jobs[label] = max(attempt, jobs.get(label, 0))
for label, attempt in jobs.items():
name = 'Coverage {attempt} {label}'.format(label=label, attempt=attempt)
name = f"Coverage {attempt} {label}"
source = os.path.join(source_directory, name)
source_files = os.listdir(source)
for source_file in source_files:
source_path = os.path.join(source, source_file)
destination_path = os.path.join(destination_directory, source_file + '.' + label)
print('"%s" -> "%s"' % (source_path, destination_path))
destination_path = os.path.join(destination_directory, source_file + "." + label)
print(f'"{source_path}" -> "{destination_path}"')
shutil.copyfile(source_path, destination_path)
count += 1
print('Coverage file count: %d' % count)
print('##vso[task.setVariable variable=coverageFileCount]%d' % count)
print('##vso[task.setVariable variable=outputPath]%s' % output_path)
print(f"Coverage file count: {count}")
print(f"##vso[task.setVariable variable=coverageFileCount]{count}")
print(f"##vso[task.setVariable variable=outputPath]{output_path}")
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@ -1,10 +1,10 @@
#!/usr/bin/env bash
# Check the test results and set variables for use in later steps.
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# Check the test results and set variables for use in later steps.
set -o pipefail -eu
if [[ "$PWD" =~ /ansible_collections/ ]]; then

View File

@ -15,7 +15,6 @@ import pathlib
import shutil
import subprocess
import tempfile
import typing as t
import urllib.request
@ -23,7 +22,7 @@ import urllib.request
class CoverageFile:
name: str
path: pathlib.Path
flags: t.List[str]
flags: list[str]
@dataclasses.dataclass(frozen=True)
@ -34,8 +33,8 @@ class Args:
def parse_args() -> Args:
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--dry-run', action='store_true')
parser.add_argument('path', type=pathlib.Path)
parser.add_argument("-n", "--dry-run", action="store_true")
parser.add_argument("path", type=pathlib.Path)
args = parser.parse_args()
@ -46,32 +45,36 @@ def parse_args() -> Args:
return Args(**kwargs)
def process_files(directory: pathlib.Path) -> t.Tuple[CoverageFile, ...]:
def process_files(directory: pathlib.Path) -> tuple[CoverageFile, ...]:
processed = []
for file in directory.joinpath('reports').glob('coverage*.xml'):
name = file.stem.replace('coverage=', '')
for file in directory.joinpath("reports").glob("coverage*.xml"):
name = file.stem.replace("coverage=", "")
# Get flags from name
flags = name.replace('-powershell', '').split('=') # Drop '-powershell' suffix
flags = [flag if not flag.startswith('stub') else flag.split('-')[0] for flag in flags] # Remove "-01" from stub files
flags = name.replace("-powershell", "").split("=") # Drop '-powershell' suffix
flags = [
flag if not flag.startswith("stub") else flag.split("-")[0] for flag in flags
] # Remove "-01" from stub files
processed.append(CoverageFile(name, file, flags))
return tuple(processed)
def upload_files(codecov_bin: pathlib.Path, files: t.Tuple[CoverageFile, ...], dry_run: bool = False) -> None:
def upload_files(codecov_bin: pathlib.Path, files: tuple[CoverageFile, ...], dry_run: bool = False) -> None:
for file in files:
cmd = [
str(codecov_bin),
'--name', file.name,
'--file', str(file.path),
"--name",
file.name,
"--file",
str(file.path),
]
for flag in file.flags:
cmd.extend(['--flags', flag])
cmd.extend(["--flags", flag])
if dry_run:
print(f'DRY-RUN: Would run command: {cmd}')
print(f"DRY-RUN: Would run command: {cmd}")
continue
subprocess.run(cmd, check=True)
@ -79,11 +82,11 @@ def upload_files(codecov_bin: pathlib.Path, files: t.Tuple[CoverageFile, ...], d
def download_file(url: str, dest: pathlib.Path, flags: int, dry_run: bool = False) -> None:
if dry_run:
print(f'DRY-RUN: Would download {url} to {dest} and set mode to {flags:o}')
print(f"DRY-RUN: Would download {url} to {dest} and set mode to {flags:o}")
return
with urllib.request.urlopen(url) as resp:
with dest.open('w+b') as f:
with dest.open("w+b") as f:
# Read data in chunks rather than all at once
shutil.copyfileobj(resp, f, 64 * 1024)
@ -92,14 +95,14 @@ def download_file(url: str, dest: pathlib.Path, flags: int, dry_run: bool = Fals
def main():
args = parse_args()
url = 'https://ansible-ci-files.s3.amazonaws.com/codecov/linux/codecov'
with tempfile.TemporaryDirectory(prefix='codecov-') as tmpdir:
codecov_bin = pathlib.Path(tmpdir) / 'codecov'
url = "https://ansible-ci-files.s3.amazonaws.com/codecov/linux/codecov"
with tempfile.TemporaryDirectory(prefix="codecov-") as tmpdir:
codecov_bin = pathlib.Path(tmpdir) / "codecov"
download_file(url, codecov_bin, 0o755, args.dry_run)
files = process_files(args.path)
upload_files(codecov_bin, files, args.dry_run)
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@ -1,18 +1,14 @@
#!/usr/bin/env bash
# Generate code coverage reports for uploading to Azure Pipelines and codecov.io.
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# Generate code coverage reports for uploading to Azure Pipelines and codecov.io.
set -o pipefail -eu
PATH="${PWD}/bin:${PATH}"
if [[ "$(ansible --version)" =~ \ 2\.9\. ]]; then
exit
fi
if ! ansible-test --help >/dev/null 2>&1; then
# Install the devel version of ansible-test for generating code coverage reports.
# This is only used by Ansible Collections, which are typically tested against multiple Ansible versions (in separate jobs).

View File

@ -1,10 +1,10 @@
#!/usr/bin/env bash
# Configure the test environment and run the tests.
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
# Configure the test environment and run the tests.
set -o pipefail -eu
entry_point="$1"

View File

@ -5,8 +5,7 @@
"""Prepends a relative timestamp to each input line from stdin and writes it to stdout."""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from __future__ import annotations
import sys
import time
@ -16,14 +15,14 @@ def main():
"""Main program entry point."""
start = time.time()
sys.stdin.reconfigure(errors='surrogateescape')
sys.stdout.reconfigure(errors='surrogateescape')
sys.stdin.reconfigure(errors="surrogateescape")
sys.stdout.reconfigure(errors="surrogateescape")
for line in sys.stdin:
seconds = time.time() - start
sys.stdout.write('%02d:%02d %s' % (seconds // 60, seconds % 60, line))
seconds = int(time.time() - start)
sys.stdout.write(f"{seconds // 60:02}:{seconds % 60:02} {line}")
sys.stdout.flush()
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@ -1 +0,0 @@
remote.sh

View File

@ -1 +0,0 @@
remote.sh

View File

@ -1,31 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -o pipefail -eux
declare -a args
IFS='/:' read -ra args <<< "$1"
image="${args[1]}"
python="${args[2]}"
if [ "${#args[@]}" -gt 3 ]; then
target="azp/${args[3]}/"
else
target="azp/"
fi
if [[ "${python}" =~ -pypi-latest$ ]]; then
python="${python/-pypi-latest}"
echo 'force_docker_sdk_for_python_pypi: true' >> tests/integration/integration_config.yml
fi
if [[ "${python}" =~ -dev-latest$ ]]; then
python="${python/-dev-latest}"
echo 'force_docker_sdk_for_python_dev: true' >> tests/integration/integration_config.yml
fi
# shellcheck disable=SC2086
ansible-test integration --color -v --retry-on-error "${target}" ${COVERAGE:+"$COVERAGE"} ${CHANGED:+"$CHANGED"} ${UNSTABLE:+"$UNSTABLE"} \
--docker "quay.io/ansible-community/test-image:${image}" --python "${python}"

View File

@ -1,30 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -o pipefail -eux
declare -a args
IFS='/:' read -ra args <<< "$1"
image="${args[1]}"
if [ "${#args[@]}" -gt 2 ]; then
target="azp/${args[2]}/"
else
target="azp/"
fi
if [[ "${image}" =~ -pypi-latest$ ]]; then
image="${image/-pypi-latest}"
echo 'force_docker_sdk_for_python_pypi: true' >> tests/integration/integration_config.yml
fi
if [[ "${image}" =~ -dev-latest$ ]]; then
image="${image/-dev-latest}"
echo 'force_docker_sdk_for_python_dev: true' >> tests/integration/integration_config.yml
fi
# shellcheck disable=SC2086
ansible-test integration --color -v --retry-on-error "${target}" ${COVERAGE:+"$COVERAGE"} ${CHANGED:+"$CHANGED"} ${UNSTABLE:+"$UNSTABLE"} \
--docker "${image}"

View File

@ -1,48 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -o pipefail -eux
declare -a args
IFS='/:' read -ra args <<< "$1"
platform="${args[0]}"
version="${args[1]}"
pyver=default
# check for explicit python version like 8.3@3.8
declare -a splitversion
IFS='@' read -ra splitversion <<< "$version"
if [ "${#splitversion[@]}" -gt 1 ]; then
version="${splitversion[0]}"
pyver="${splitversion[1]}"
fi
if [ "${#args[@]}" -gt 2 ]; then
target="azp/${args[2]}/"
else
target="azp/"
fi
if [[ "${version}" =~ -pypi-latest$ ]]; then
version="${version/-pypi-latest}"
echo 'force_docker_sdk_for_python_pypi: true' >> tests/integration/integration_config.yml
fi
if [[ "${version}" =~ -dev-latest$ ]]; then
version="${version/-dev-latest}"
echo 'force_docker_sdk_for_python_dev: true' >> tests/integration/integration_config.yml
fi
stage="${S:-prod}"
provider="${P:-default}"
if [ "${platform}" == "rhel" ] && [[ "${version}" =~ ^8\. ]]; then
echo "pynacl >= 1.4.0, < 1.5.0; python_version == '3.6'" >> tests/utils/constraints.txt
fi
# shellcheck disable=SC2086
ansible-test integration --color -v --retry-on-error "${target}" ${COVERAGE:+"$COVERAGE"} ${CHANGED:+"$CHANGED"} ${UNSTABLE:+"$UNSTABLE"} \
--python "${pyver}" --remote "${platform}/${version}" --remote-terminate always --remote-stage "${stage}" --remote-provider "${provider}"

View File

@ -1 +0,0 @@
remote.sh

View File

@ -1,17 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -o pipefail -eux
if [ "${BASE_BRANCH:-}" ]; then
base_branch="origin/${BASE_BRANCH}"
else
base_branch=""
fi
# shellcheck disable=SC2086
ansible-test sanity --color -v --junit ${COVERAGE:+"$COVERAGE"} ${CHANGED:+"$CHANGED"} \
--docker --base-branch "${base_branch}" \
--allow-disabled

View File

@ -1,234 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -o pipefail -eux
declare -a args
IFS='/:' read -ra args <<< "$1"
ansible_version="${args[0]}"
script="${args[1]}"
after_script="${args[2]}"
function join {
local IFS="$1";
shift;
echo "$*";
}
# Ensure we can write other collections to this dir
sudo chown -R "$(whoami)" "${PWD}/../../../"
test="$(join / "${args[@]:1}")"
docker images ansible/ansible
docker images quay.io/ansible/*
docker ps
for container in $(docker ps --format '{{.Image}} {{.ID}}' | grep -v -e '^drydock/' -e '^quay.io/ansible/azure-pipelines-test-container:' | sed 's/^.* //'); do
docker rm -f "${container}" || true # ignore errors
done
docker ps
if [ -d /home/shippable/cache/ ]; then
ls -la /home/shippable/cache/
fi
command -v python
python -V
function retry
{
# shellcheck disable=SC2034
for repetition in 1 2 3; do
set +e
"$@"
result=$?
set -e
if [ ${result} == 0 ]; then
return ${result}
fi
echo "@* -> ${result}"
done
echo "Command '@*' failed 3 times!"
exit 255
}
command -v pip
pip --version
pip list --disable-pip-version-check
if [ "${ansible_version}" == "devel" ]; then
retry pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
else
retry pip install "https://github.com/ansible/ansible/archive/stable-${ansible_version}.tar.gz" --disable-pip-version-check
fi
export ANSIBLE_COLLECTIONS_PATHS="${PWD}/../../../"
# START: HACK
COMMUNITY_CRYPTO_BRANCH=main
if [ "${ansible_version}" == "2.16" ]; then
COMMUNITY_CRYPTO_BRANCH=stable-2
fi
if [ "${script}" == "linux" ] && [ "$after_script" == "ubuntu2004" ]; then
COMMUNITY_CRYPTO_BRANCH=stable-2
fi
retry git clone --depth=1 --single-branch --branch stable-1 https://github.com/ansible-collections/community.library_inventory_filtering.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/library_inventory_filtering_v1"
# NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
# retry ansible-galaxy -vvv collection install community.library_inventory_filtering_v1
if [ "${test}" == "units/1" ]; then
# Nothing further should be added to this list.
# This is to prevent modules or plugins in this collection having a runtime dependency on other collections.
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"
# NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
# retry ansible-galaxy -vvv collection install community.internal_test_tools
fi
if [ "${script}" != "sanity/1" ] && [ "${script}" != "units/1" ]; then
# To prevent Python dependencies on other collections only install other collections for integration tests
retry git clone --depth=1 --single-branch https://github.com/ansible-collections/ansible.posix.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/ansible/posix"
retry git clone --depth=1 --single-branch --branch "${COMMUNITY_CRYPTO_BRANCH}" https://github.com/ansible-collections/community.crypto.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/crypto"
retry git clone --depth=1 --single-branch https://github.com/ansible-collections/community.general.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/general"
# NOTE: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
# retry ansible-galaxy -vvv collection install ansible.posix
# retry ansible-galaxy -vvv collection install community.crypto
# retry ansible-galaxy -vvv collection install community.general
fi
# END: HACK
export PYTHONIOENCODING='utf-8'
if [ "${JOB_TRIGGERED_BY_NAME:-}" == "nightly-trigger" ]; then
COVERAGE=yes
COMPLETE=yes
fi
if [ -n "${COVERAGE:-}" ]; then
# on-demand coverage reporting triggered by setting the COVERAGE environment variable to a non-empty value
export COVERAGE="--coverage"
elif [[ "${COMMIT_MESSAGE}" =~ ci_coverage ]]; then
# on-demand coverage reporting triggered by having 'ci_coverage' in the latest commit message
export COVERAGE="--coverage"
else
# on-demand coverage reporting disabled (default behavior, always-on coverage reporting remains enabled)
export COVERAGE="--coverage-check"
fi
if [ -n "${COMPLETE:-}" ]; then
# disable change detection triggered by setting the COMPLETE environment variable to a non-empty value
export CHANGED=""
elif [[ "${COMMIT_MESSAGE}" =~ ci_complete ]]; then
# disable change detection triggered by having 'ci_complete' in the latest commit message
export CHANGED=""
else
# enable change detection (default behavior)
export CHANGED="--changed"
fi
if [ "${IS_PULL_REQUEST:-}" == "true" ]; then
# run unstable tests which are targeted by focused changes on PRs
export UNSTABLE="--allow-unstable-changed"
else
# do not run unstable tests outside PRs
export UNSTABLE=""
fi
# remove empty core/extras module directories from PRs created prior to the repo-merge
find plugins -type d -empty -print -delete
function cleanup
{
# 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
if [ "${COVERAGE}" == "--coverage" ] && [ "${CHANGED}" == "" ] && [ "${test}" == "sanity/5" ]; then
stub="--stub"
# trigger coverage reporting for stubs even if no other coverage data exists
mkdir -p tests/output/coverage/
else
stub=""
fi
if [ -d tests/output/coverage/ ]; then
if find tests/output/coverage/ -mindepth 1 -name '.*' -prune -o -print -quit | grep -q .; then
process_coverage='yes' # process existing coverage files
elif [ "${stub}" ]; then
process_coverage='yes' # process coverage when stubs are enabled
else
process_coverage=''
fi
if [ "${process_coverage}" ]; then
# use python 3.7 for coverage to avoid running out of memory during coverage xml processing
# only use it for coverage to avoid the additional overhead of setting up a virtual environment for a potential no-op job
virtualenv --python /usr/bin/python3.7 ~/ansible-venv
set +ux
. ~/ansible-venv/bin/activate
set -ux
# shellcheck disable=SC2086
ansible-test coverage xml --color -v --requirements --group-by command --group-by version ${stub:+"$stub"}
cp -a tests/output/reports/coverage=*.xml "$SHIPPABLE_RESULT_DIR/codecoverage/"
if [ "${ansible_version}" != "2.9" ]; then
# analyze and capture code coverage aggregated by integration test target
ansible-test coverage analyze targets generate -v "$SHIPPABLE_RESULT_DIR/testresults/coverage-analyze-targets.json"
fi
# upload coverage report to codecov.io only when using complete on-demand coverage
if [ "${COVERAGE}" == "--coverage" ] && [ "${CHANGED}" == "" ]; then
for file in tests/output/reports/coverage=*.xml; do
flags="${file##*/coverage=}"
flags="${flags%-powershell.xml}"
flags="${flags%.xml}"
# remove numbered component from stub files when converting to tags
flags="${flags//stub-[0-9]*/stub}"
flags="${flags//=/,}"
flags="${flags//[^a-zA-Z0-9_,]/_}"
bash <(curl -s https://ansible-ci-files.s3.us-east-1.amazonaws.com/codecov/codecov.sh) \
-f "${file}" \
-F "${flags}" \
-n "${test}" \
-t 8450ed26-4e94-4d07-8831-d2023d6d20a3 \
-X coveragepy \
-X gcov \
-X fix \
-X search \
-X xcode \
|| echo "Failed to upload code coverage report to codecov.io: ${file}"
done
fi
fi
fi
if [ -d tests/output/junit/ ]; then
cp -aT tests/output/junit/ "$SHIPPABLE_RESULT_DIR/testresults/"
fi
if [ -d tests/output/data/ ]; then
cp -a tests/output/data/ "$SHIPPABLE_RESULT_DIR/testresults/"
fi
if [ -d tests/output/bot/ ]; then
cp -aT tests/output/bot/ "$SHIPPABLE_RESULT_DIR/testresults/"
fi
}
if [ "${SHIPPABLE_BUILD_ID:-}" ]; then trap cleanup EXIT; fi
if [[ "${COVERAGE:-}" == "--coverage" ]]; then
timeout=60
else
timeout=50
fi
ansible-test env --dump --show --timeout "${timeout}" --color -v
if [ "${SHIPPABLE_BUILD_ID:-}" ]; then "tests/utils/shippable/check_matrix.py"; fi
"tests/utils/shippable/${script}.sh" "${test}"

View File

@ -1 +0,0 @@
remote.sh

View File

@ -1,29 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
set -o pipefail -eux
declare -a args
IFS='/:' read -ra args <<< "$1"
group="${args[1]}"
if [[ "${COVERAGE:-}" == "--coverage" ]]; then
timeout=90
else
timeout=30
fi
group1=()
case "${group}" in
1) options=("${group1[@]:+${group1[@]}}") ;;
esac
ansible-test env --timeout "${timeout}" --color -v
# shellcheck disable=SC2086
ansible-test units --color -v --docker default ${COVERAGE:+"$COVERAGE"} ${CHANGED:+"$CHANGED"} \
"${options[@]:+${options[@]}}" \