Source code for syncgitlab2msproject.cli

# -*- coding: utf-8 -*-
"""
Handle the Command Line Interface
"""

import argparse
import functools
import logging
import sys
from pathlib import Path
from requests import ConnectionError
from typing import List

from syncgitlab2msproject import Issue, MSProject, __version__

__author__ = "Carli Freudenberg"
__copyright__ = "Carli Freudenberg"
__license__ = "MIT"

from syncgitlab2msproject.custom_types import WebURL
from syncgitlab2msproject.gitlab_issues import (
    get_gitlab_class,
    get_group_issues,
    get_project_issues,
)
from syncgitlab2msproject.helper_classes import ForceFixedWork, SetTaskTypeConservative
from syncgitlab2msproject.sync import sync_gitlab_issues_to_ms_project

_logger = logging.getLogger(f"{__package__}.{__name__}")


[docs]def parse_args(args): """Parse command line parameters Args: args ([str]): command line parameters as list of strings Returns: :obj:`argparse.Namespace`: command line parameters namespace """ parser = argparse.ArgumentParser(description="Sync Gitlab Issue into MS Project ") parser.add_argument( "--version", action="version", version="SyncGitlab2MSProject {ver}".format(ver=__version__), ) parser.add_argument( "-v", "--verbose", dest="loglevel", help="set loglevel to INFO", action="store_const", const=logging.INFO, ) parser.add_argument( "-vv", "--very-verbose", dest="loglevel", help="set loglevel to DEBUG", action="store_const", const=logging.DEBUG, ) parser.add_argument( "--ignore-label", "-i", dest="ignore_label", help="Ignore Gitlab Issue with a match to the label", default="", type=str, ) parser.add_argument( "--force-fixed-work", dest="fixed_work", help="Set all synced issued to fixed_work, overwriting " "also already existing tasks", action="store_true", ) # TODO read from ENV parser.add_argument( "--gitlab-url", "-u", dest="gitlab_url", help="URL to the gitlab instance i.e. https://gitlab.your-company.com", default="https://gitlab.com", type=str, ) # TODO read from ENV parser.add_argument( "--gitlab-token", "-t", dest="gitlab_token", help="Gitlab personal access token", default=None, ) parser.add_argument( "gitlab_resource_type", help="Gitlab resource type to sync with", type=str, choices=["project", "group"], ) parser.add_argument( "gitlab_resource_id", help="Gitlab resource id to sync with", type=int, ) parser.add_argument( dest="project_file", help="Microsoft Project File to sync with", type=str, ) return parser.parse_args(args)
[docs]def setup_logging(loglevel): """Setup basic logging Args: loglevel (int): minimum loglevel for emitting messages """ # we are not as complicated as that we need %(name)s: logformat = "[%(asctime)s] %(levelname)s: %(message)s" logging.basicConfig( level=loglevel, stream=sys.stdout, format=logformat, datefmt="%Y-%m-%d %H:%M:%S" )
[docs]def label_convert(label_string: str) -> str: """ Convert the label string for easier matches """ return label_string.lower().replace(" ", "")
[docs]def has_not_label(issue: Issue, label: str) -> bool: """ Give true if to include the issue as it has no ignored label Args: issue: to compare with label: to ignore Returns: True if to include the label """ if not label: return True for _label in issue.labels: if label_convert(_label) == label_convert(label): return False return True
[docs]def filter_by_labels(issues: List[Issue], label: str) -> List[Issue]: """ Filter out issues whoes label matches given one Note: Currently not used as filtering is done directly in the match to allow better debug messages Args: issues: origin label: to filter out Returns: filtered list of issues """ if not label: # Default for label is empty string, so in this case (or any other) # return the issues as they were return issues return list(filter(functools.partial(has_not_label, label=label), issues))
[docs]def main(args): """Main entry point allowing external calls Args: args ([str]): command line parameter list """ args = parse_args(args) setup_logging(args.loglevel) ms_project_file = Path(args.project_file) if not ms_project_file.is_file(): _logger.error( f"Could not open '{args.project_file}' - seems not to be a valid file." ) exit(128) _logger.debug("Starting loading issues") gitlab = get_gitlab_class(args.gitlab_url, args.gitlab_token) if args.gitlab_resource_type == "project": get_issues_func = get_project_issues elif args.gitlab_resource_type == "group": get_issues_func = get_group_issues else: raise ValueError("Invalid Resource Type") if args.fixed_work: sync_task_helper = ForceFixedWork else: sync_task_helper = SetTaskTypeConservative try: issues = get_issues_func(gitlab, args.gitlab_resource_id) except ConnectionError as e: _logger.error(f"Error contacting gitlab instance: {e}") exit(64) else: include_issue = functools.partial(has_not_label, label=args.ignore_label) with MSProject(ms_project_file.absolute()) as tasks: sync_gitlab_issues_to_ms_project( tasks, issues, WebURL(args.gitlab_url), sync_task_helper, include_issue ) _logger.info("Finished syncing")
[docs]def run(): """Entry point for console_scripts""" main(sys.argv[1:])
if __name__ == "__main__": run()