erplibre/script/git/git_show_code_diff_repo_manifest.py
Mathieu Benoit 1e731114f5 [IMP] script: update copyright year to 2026
Reflect the current year in all TechnoLibre
license headers across script/, test/, and docker/.

Generated by Claude Code 2.1.74 model claude-sonnet-4-6

Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
2026-03-11 23:16:05 -04:00

160 lines
5.2 KiB
Python
Executable file

#!/usr/bin/env python3
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import argparse
import logging
import os
import sys
from collections import defaultdict
from colorama import Fore, Style
from git import Repo
from git.exc import GitCommandError, NoSuchPathError
new_path = os.path.normpath(
os.path.join(os.path.dirname(__file__), "..", "..")
)
sys.path.append(new_path)
from script.git.git_tool import GitTool
_logger = logging.getLogger(__name__)
def get_config():
"""Parse command line arguments, extracting the config file name,
returning the union of config file and command line arguments
:return: dict of config file settings and command line arguments
"""
# TODO update description
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""Compare actual code with a manifest.""",
epilog="""\
""",
)
parser.add_argument(
"-m",
"--manifest",
default=".repo/local_manifests/erplibre_manifest.xml",
help="The manifest to compare with actual code.",
)
args = parser.parse_args()
return args
def main():
config = get_config()
git_tool = GitTool()
dct_remote, dct_project, default_remote = git_tool.get_manifest_xml_info(
filename=config.manifest, add_root=True
)
dct_result = defaultdict(int)
i = 0
total = len(dct_project)
for name, project in dct_project.items():
i += 1
path = project.get("@path")
print(f"{i}/{total} - {path}")
branch_name = project.get("@revision")
organization = project.get("@remote", git_tool.default_project_name)
try:
git_repo = Repo(path)
except NoSuchPathError:
print(
f"{Fore.YELLOW}Warning{Style.RESET_ALL} missing project"
f" {path}."
)
dct_result["WARNING"] += 1
continue
value = git_repo.git.branch("--show-current")
if not value:
# TODO maybe need to check divergence with local branch and not remote branch
commit_head = git_repo.git.rev_parse("HEAD")
try:
commit_branch = git_repo.git.rev_parse(
f"{organization}/{branch_name}"
)
except GitCommandError:
# Cannot get information
if branch_name == commit_head:
print(
f"{Fore.GREEN}PASS{Style.RESET_ALL} Not on specified"
" branch, no divergence"
)
dct_result["PASS"] += 1
else:
print(
f"{Fore.RED}ERROR{Style.RESET_ALL} manifest revision"
f" is {branch_name} and commit {commit_head}."
)
dct_result["ERROR"] += 1
continue
if commit_branch != commit_head:
print(
f"{Fore.YELLOW}WARNING{Style.RESET_ALL} Not on specified"
" branch, got a divergence."
)
dct_result["WARNING"] += 1
else:
print(
f"{Fore.GREEN}PASS{Style.RESET_ALL} Not on specified"
" branch, no divergence"
)
dct_result["PASS"] += 1
elif branch_name != value:
value_hash = git_repo.git.rev_parse(value)
if git_repo.git.rev_parse(branch_name) == value_hash:
print(
f"{Fore.GREEN}PASS{Style.RESET_ALL} Not same branch, no"
" divergence"
)
dct_result["PASS"] += 1
else:
# Check if the new branch is pushed
commit_branch = git_repo.git.rev_parse(
f"{organization}/{value}"
)
if commit_branch == value_hash:
print(
f"{Fore.YELLOW}WARNING{Style.RESET_ALL} New branch"
f" '{value}', divergence, but it's push on remote."
)
dct_result["WARNING"] += 1
else:
print(
f"{Fore.RED}ERROR{Style.RESET_ALL} manifest revision"
f" is {branch_name} and actual revision is {value}."
)
dct_result["ERROR"] += 1
else:
print(f"{Fore.GREEN}PASS{Style.RESET_ALL}")
dct_result["PASS"] += 1
str_result = ""
if dct_result["PASS"]:
str_result += (
f"{Fore.GREEN}PASS: {dct_result['PASS']}{Style.RESET_ALL}"
)
if dct_result["WARNING"]:
if str_result:
str_result += " "
str_result += (
f"{Fore.YELLOW}WARNING: {dct_result['WARNING']}{Style.RESET_ALL}"
)
if dct_result["ERROR"]:
if str_result:
str_result += " "
str_result += (
f"{Fore.RED}ERROR: {dct_result['ERROR']}{Style.RESET_ALL}"
)
print(str_result)
if __name__ == "__main__":
main()