Files
Кокос Артем Николаевич 06cd57e2c4 Blacked
2026-02-05 15:31:31 +07:00

121 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import sys
import argparse
from typing import List, Optional
from redminelib.resources import Issue
from .config import Config
from .client import fetch_issues_with_spent_time
from .report_builder import build_grouped_report
from .formatters.factory import get_formatter_by_extension, get_console_formatter
def parse_date_range(date_arg: str) -> tuple[str, str]:
if "--" not in date_arg:
raise ValueError("Date range must be in format YYYY-MM-DD--YYYY-MM-DD")
parts = date_arg.split("--", 1)
if len(parts) != 2:
raise ValueError("Invalid date range format")
return parts[0].strip(), parts[1].strip()
def main(argv: Optional[List[str]] = None) -> int:
parser = argparse.ArgumentParser(
prog="redmine-reporter",
description="Generate Redmine issue report based on your time entries.",
)
parser.add_argument(
"--date",
default=Config.get_default_date_range(),
# help="Date range in format YYYY-MM-DD--YYYY-MM-DD (default: %(default)s)"
help="Date range in format YYYY-MM-DD--YYYY-MM-DD (default from .env or %(default)s)",
)
parser.add_argument(
"--compact", action="store_true", help="Use compact plain-text output instead of table"
)
parser.add_argument(
"--output",
help="Path to output .odt file (e.g., report.odt). If omitted, prints to stdout.",
)
parser.add_argument(
"--author", default="", help="Override author name from .env (REDMINE_AUTHOR)"
)
parser.add_argument(
"--no-time", action="store_true", help="Do not include spent time into table"
)
args = parser.parse_args(argv)
try:
Config.validate()
except ValueError as e:
print(f"❌ Configuration error: {e}", file=sys.stderr)
return 1
try:
from_date, to_date = parse_date_range(args.date)
except ValueError as e:
print(f"❌ Date error: {e}", file=sys.stderr)
return 1
try:
issue_hours = fetch_issues_with_spent_time(from_date, to_date)
except Exception as e:
print(f"❌ Redmine API error: {e}", file=sys.stderr)
return 1
if issue_hours is None:
print(" No time entries found in the given period.", file=sys.stderr)
return 0
print(f"✅ Total issues: {len(issue_hours)} [{args.date}]")
rows = build_grouped_report(issue_hours, fill_time=not args.no_time)
if args.output:
output_ext = os.path.splitext(args.output)[1].lower()
formatter = get_formatter_by_extension(
output_ext, author=Config.get_author(args.author), from_date=from_date, to_date=to_date
)
if not formatter:
print(f"❌ Неизвестный формат файла: {output_ext}", file=sys.stderr)
return 1
try:
formatter.save(rows, args.output)
print(f"✅ Report saved to {args.output}")
except ImportError as e:
if output_ext == ".odt":
print("❌ odfpy is not installed. Install with: pip install odfpy", file=sys.stderr)
else:
print(f"❌ Import error: {e}", file=sys.stderr)
return 1
except Exception as e:
fmt = "ODT" if output_ext == ".odt" else ("CSV" if output_ext == ".csv" else "Markdown")
print(f"{fmt} export error: {e}", file=sys.stderr)
return 1
else:
if args.compact:
formatter = get_console_formatter("compact")
else:
formatter = get_console_formatter("table")
if not formatter:
print("❌ Неизвестный тип консольного форматтера.", file=sys.stderr)
return 1
try:
output = formatter.format(rows)
print(output)
except Exception as e:
print(f"❌ Formatting error: {e}", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
sys.exit(main())