diff options
Diffstat (limited to 'ansible_collections/community/crypto/.azure-pipelines/scripts')
7 files changed, 315 insertions, 0 deletions
diff --git a/ansible_collections/community/crypto/.azure-pipelines/scripts/aggregate-coverage.sh b/ansible_collections/community/crypto/.azure-pipelines/scripts/aggregate-coverage.sh new file mode 100755 index 000000000..19f078f24 --- /dev/null +++ b/ansible_collections/community/crypto/.azure-pipelines/scripts/aggregate-coverage.sh @@ -0,0 +1,28 @@ +#!/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 + +# Aggregate code coverage results for later processing. + +set -o pipefail -eu + +agent_temp_directory="$1" + +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[@]}" + +if ansible-test coverage analyze targets generate --help >/dev/null 2>&1; then + # Only analyze coverage if the installed version of ansible-test supports it. + # Doing so allows this script to work unmodified for multiple Ansible versions. + ansible-test coverage analyze targets generate "${agent_temp_directory}/coverage/coverage-analyze-targets.json" "${options[@]}" +fi diff --git a/ansible_collections/community/crypto/.azure-pipelines/scripts/combine-coverage.py b/ansible_collections/community/crypto/.azure-pipelines/scripts/combine-coverage.py new file mode 100755 index 000000000..3b2fd993d --- /dev/null +++ b/ansible_collections/community/crypto/.azure-pipelines/scripts/combine-coverage.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# 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 + +""" +Combine coverage data from multiple jobs, keeping the data only from the most recent attempt from each job. +Coverage artifacts must be named using the format: "Coverage $(System.JobAttempt) {StableUniqueNameForEachJob}" +The recommended coverage artifact name format is: Coverage $(System.JobAttempt) $(System.StageDisplayName) $(System.JobDisplayName) +Keep in mind that Azure Pipelines does not enforce unique job display names (only names). +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 + +import os +import re +import shutil +import sys + + +def main(): + """Main program entry point.""" + source_directory = sys.argv[1] + + if '/ansible_collections/' in os.getcwd(): + output_path = "tests/output" + else: + output_path = "test/results" + + destination_directory = os.path.join(output_path, 'coverage') + + if not os.path.exists(destination_directory): + os.makedirs(destination_directory) + + jobs = {} + 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')) + jobs[label] = max(attempt, jobs.get(label, 0)) + + for label, attempt in jobs.items(): + name = 'Coverage {attempt} {label}'.format(label=label, attempt=attempt) + 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)) + 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) + + +if __name__ == '__main__': + main() diff --git a/ansible_collections/community/crypto/.azure-pipelines/scripts/process-results.sh b/ansible_collections/community/crypto/.azure-pipelines/scripts/process-results.sh new file mode 100755 index 000000000..1f4b8e4f1 --- /dev/null +++ b/ansible_collections/community/crypto/.azure-pipelines/scripts/process-results.sh @@ -0,0 +1,28 @@ +#!/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 + +# Check the test results and set variables for use in later steps. + +set -o pipefail -eu + +if [[ "$PWD" =~ /ansible_collections/ ]]; then + output_path="tests/output" +else + output_path="test/results" +fi + +echo "##vso[task.setVariable variable=outputPath]${output_path}" + +if compgen -G "${output_path}"'/junit/*.xml' > /dev/null; then + echo "##vso[task.setVariable variable=haveTestResults]true" +fi + +if compgen -G "${output_path}"'/bot/ansible-test-*' > /dev/null; then + echo "##vso[task.setVariable variable=haveBotResults]true" +fi + +if compgen -G "${output_path}"'/coverage/*' > /dev/null; then + echo "##vso[task.setVariable variable=haveCoverageData]true" +fi diff --git a/ansible_collections/community/crypto/.azure-pipelines/scripts/publish-codecov.py b/ansible_collections/community/crypto/.azure-pipelines/scripts/publish-codecov.py new file mode 100755 index 000000000..58e32f6d3 --- /dev/null +++ b/ansible_collections/community/crypto/.azure-pipelines/scripts/publish-codecov.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# 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 + +""" +Upload code coverage reports to codecov.io. +Multiple coverage files from multiple languages are accepted and aggregated after upload. +Python coverage, as well as PowerShell and Python stubs can all be uploaded. +""" + +import argparse +import dataclasses +import pathlib +import shutil +import subprocess +import tempfile +import typing as t +import urllib.request + + +@dataclasses.dataclass(frozen=True) +class CoverageFile: + name: str + path: pathlib.Path + flags: t.List[str] + + +@dataclasses.dataclass(frozen=True) +class Args: + dry_run: bool + path: pathlib.Path + + +def parse_args() -> Args: + parser = argparse.ArgumentParser() + parser.add_argument('-n', '--dry-run', action='store_true') + parser.add_argument('path', type=pathlib.Path) + + args = parser.parse_args() + + # Store arguments in a typed dataclass + fields = dataclasses.fields(Args) + kwargs = {field.name: getattr(args, field.name) for field in fields} + + return Args(**kwargs) + + +def process_files(directory: pathlib.Path) -> t.Tuple[CoverageFile, ...]: + processed = [] + 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 + + 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: + for file in files: + cmd = [ + str(codecov_bin), + '--name', file.name, + '--file', str(file.path), + ] + for flag in file.flags: + cmd.extend(['--flags', flag]) + + if dry_run: + print(f'DRY-RUN: Would run command: {cmd}') + continue + + subprocess.run(cmd, check=True) + + +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}') + return + + with urllib.request.urlopen(url) as resp: + with dest.open('w+b') as f: + # Read data in chunks rather than all at once + shutil.copyfileobj(resp, f, 64 * 1024) + + dest.chmod(flags) + + +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' + 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__': + main() diff --git a/ansible_collections/community/crypto/.azure-pipelines/scripts/report-coverage.sh b/ansible_collections/community/crypto/.azure-pipelines/scripts/report-coverage.sh new file mode 100755 index 000000000..63ac7f904 --- /dev/null +++ b/ansible_collections/community/crypto/.azure-pipelines/scripts/report-coverage.sh @@ -0,0 +1,23 @@ +#!/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 + +# 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). + # Since a version of ansible-test is required that can work the output from multiple older releases, the devel version is used. + pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check +fi + +ansible-test coverage xml --group-by command --stub --venv --venv-system-site-packages --color -v diff --git a/ansible_collections/community/crypto/.azure-pipelines/scripts/run-tests.sh b/ansible_collections/community/crypto/.azure-pipelines/scripts/run-tests.sh new file mode 100755 index 000000000..2cfdcf61e --- /dev/null +++ b/ansible_collections/community/crypto/.azure-pipelines/scripts/run-tests.sh @@ -0,0 +1,38 @@ +#!/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 + +# Configure the test environment and run the tests. + +set -o pipefail -eu + +entry_point="$1" +test="$2" +read -r -a coverage_branches <<< "$3" # space separated list of branches to run code coverage on for scheduled builds + +export COMMIT_MESSAGE +export COMPLETE +export COVERAGE +export IS_PULL_REQUEST + +if [ "${SYSTEM_PULLREQUEST_TARGETBRANCH:-}" ]; then + IS_PULL_REQUEST=true + COMMIT_MESSAGE=$(git log --format=%B -n 1 HEAD^2) +else + IS_PULL_REQUEST= + COMMIT_MESSAGE=$(git log --format=%B -n 1 HEAD) +fi + +COMPLETE= +COVERAGE= + +if [ "${BUILD_REASON}" = "Schedule" ]; then + COMPLETE=yes + + if printf '%s\n' "${coverage_branches[@]}" | grep -q "^${BUILD_SOURCEBRANCHNAME}$"; then + COVERAGE=yes + fi +fi + +"${entry_point}" "${test}" 2>&1 | "$(dirname "$0")/time-command.py" diff --git a/ansible_collections/community/crypto/.azure-pipelines/scripts/time-command.py b/ansible_collections/community/crypto/.azure-pipelines/scripts/time-command.py new file mode 100755 index 000000000..85a7c3c17 --- /dev/null +++ b/ansible_collections/community/crypto/.azure-pipelines/scripts/time-command.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# 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 + +"""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 + +import sys +import time + + +def main(): + """Main program entry point.""" + start = time.time() + + 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)) + sys.stdout.flush() + + +if __name__ == '__main__': + main() |