123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- # Copyright 2021-2025 Avaiga Private Limited
- #
- # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
- # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
- # specific language governing permissions and limitations under the License.
- import argparse
- import subprocess
- import sys
- import xmltodict
- def check_total_coverage(coverage_file, threshold=80):
- """Check the total project coverage."""
- with open(coverage_file) as f:
- data = xmltodict.parse(f.read())
- total_coverage = float(data["coverage"]["@line-rate"]) * 100
- print(f"Total Coverage: {total_coverage:.2f}%") # noqa: T201
- if total_coverage < threshold:
- print(f"Total project coverage is below {threshold}%: {total_coverage:.2f}%") # noqa: T201
- sys.exit(1)
- def check_changed_files_coverage(coverage_file, changed_files, threshold=80):
- """Check the coverage of changed files."""
- with open(coverage_file) as f:
- data = xmltodict.parse(f.read())
- # Handle multiple packages in the coverage report
- packages = data["coverage"]["packages"]["package"]
- if not isinstance(packages, list):
- packages = [packages]
- # Extract coverage data for all files
- files = {}
- for package in packages:
- classes = package["classes"]["class"]
- if not isinstance(classes, list):
- classes = [classes]
- for cls in classes:
- files[cls["@filename"]] = float(cls["@line-rate"]) * 100
- qty = 0
- sum_coverage = 0
- for file in changed_files:
- if file in files:
- coverage = files[file]
- print(f"Coverage for {file}: {coverage:.2f}%") # noqa: T201
- sum_coverage += coverage
- qty += 1
- else:
- print(f"No coverage data found for {file}") # noqa: T201
- if qty:
- if sum_coverage / qty < threshold:
- print(f"Coverage for changed files is below {threshold}%: {sum_coverage/qty:.2f}%") # noqa: T201
- sys.exit(1)
- print(f"Coverage for changed files: {sum_coverage/qty:.2f}%") # noqa: T201
- else:
- print("No file detected to run coverage for.") # noqa: T201
- def get_changed_files(base_branch):
- """Get the list of changed Python files in the pull request."""
- try:
- result = subprocess.run(
- ["git", "diff", "--name-only", f"origin/{base_branch}", "--", "*.py"],
- capture_output=True,
- text=True,
- check=True,
- )
- changed_files = [
- file.replace("taipy/", "")
- for file in result.stdout.strip().splitlines()
- if not file.startswith(("tests/", "tools/"))
- ]
- return changed_files
- except subprocess.CalledProcessError as e:
- print(f"Error fetching changed files: {e}") # noqa: T201
- sys.exit(1)
- if __name__ == "__main__":
- parser = argparse.ArgumentParser(description="Coverage check script.")
- parser.add_argument("command", choices=["check-total", "check-changed"], help="Command to execute")
- parser.add_argument("--coverage-file", default="coverage.xml", help="Path to the coverage XML file")
- parser.add_argument("--threshold", type=float, default=80, help="Coverage threshold percentage")
- parser.add_argument("--base-branch", help="Base branch for comparing changed files")
- args = parser.parse_args()
- if args.command == "check-total":
- check_total_coverage(args.coverage_file, args.threshold)
- elif args.command == "check-changed":
- if not args.base_branch:
- print("Error: --base-branch is required for check-changed") # noqa: T201
- sys.exit(1)
- changed_files = get_changed_files(args.base_branch)
- if not changed_files:
- print("No relevant Python files changed.") # noqa: T201
- sys.exit(0)
- check_changed_files_coverage(args.coverage_file, changed_files, args.threshold)
|