Skip to content

Commit

Permalink
Replace Bash codecov uploader by new Python codecov uploader. (#235) (#…
Browse files Browse the repository at this point in the history
…236)

ci_coverage

(cherry picked from commit 3961ad3)

Co-authored-by: Felix Fontein <[email protected]>
  • Loading branch information
patchback[bot] and felixfontein authored Nov 13, 2021
1 parent f8c04cb commit 3029ad3
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .azure-pipelines/scripts/aggregate-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mkdir "${agent_temp_directory}/coverage/"

options=(--venv --venv-system-site-packages --color -v)

ansible-test coverage combine --export "${agent_temp_directory}/coverage/" "${options[@]}"
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.
Expand Down
101 changes: 101 additions & 0 deletions .azure-pipelines/scripts/publish-codecov.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env python
"""
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()
27 changes: 0 additions & 27 deletions .azure-pipelines/scripts/publish-codecov.sh

This file was deleted.

2 changes: 1 addition & 1 deletion .azure-pipelines/scripts/report-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ if ! ansible-test --help >/dev/null 2>&1; then
pip install https://github.com/ansible/ansible/archive/devel.tar.gz --disable-pip-version-check
fi

ansible-test coverage xml --stub --venv --venv-system-site-packages --color -v
ansible-test coverage xml --group-by command --stub --venv --venv-system-site-packages --color -v
2 changes: 1 addition & 1 deletion .azure-pipelines/templates/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
summaryFileLocation: "$(outputPath)/reports/$(pipelinesCoverage).xml"
displayName: Publish to Azure Pipelines
condition: gt(variables.coverageFileCount, 0)
- bash: .azure-pipelines/scripts/publish-codecov.sh "$(outputPath)"
- bash: .azure-pipelines/scripts/publish-codecov.py "$(outputPath)"
displayName: Publish to codecov.io
condition: gt(variables.coverageFileCount, 0)
continueOnError: true
6 changes: 6 additions & 0 deletions tests/sanity/ignore-2.10.txt
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
.azure-pipelines/scripts/publish-codecov.py compile-2.6!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py compile-2.7!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
plugins/modules/docker_container.py use-argspec-type-path # uses colon-separated paths, can't use type=path
6 changes: 6 additions & 0 deletions tests/sanity/ignore-2.11.txt
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
.azure-pipelines/scripts/publish-codecov.py compile-2.6!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py compile-2.7!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
plugins/modules/docker_container.py use-argspec-type-path # uses colon-separated paths, can't use type=path
1 change: 1 addition & 0 deletions tests/sanity/ignore-2.12.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
plugins/modules/docker_container.py use-argspec-type-path # uses colon-separated paths, can't use type=path
1 change: 1 addition & 0 deletions tests/sanity/ignore-2.13.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
plugins/modules/docker_container.py use-argspec-type-path # uses colon-separated paths, can't use type=path
6 changes: 6 additions & 0 deletions tests/sanity/ignore-2.9.txt
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
.azure-pipelines/scripts/publish-codecov.py compile-2.6!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py compile-2.7!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
plugins/modules/docker_container.py use-argspec-type-path # uses colon-separated paths, can't use type=path

0 comments on commit 3029ad3

Please sign in to comment.