blob: 3e1af1e05a7b6a5ff4e75663062ad275604fd924 [file] [log] [blame]
#!/usr/bin/env python3
"""Update JIRA from a CVS file.
New users that appear in the CSV can be added if needed.
New components can be added or existing components updated.
example.csv
Project,Group,Component Name,Owner,Email,Note
FPII,arima,Music,Foo Bar,foobar@fairphone.com,
FPII,arima,OOBE,Andrew Appleby,andrewa@fairphone.com,
CSV fields:
* 'Component name' - Name of component to change or add
* 'Group' - Group to add users to
* 'Note' - Description to be used for the component
* 'Owner' - JIRA user name responsible for a component
* 'Project' - Project to add components to
* 'Email' - Email address for the JIRA user
"""
import argparse
import csv
import os
import sys
import logging
from jira.exceptions import JIRAError
from jira_fairphone import JiraFairphone
import log
__log__ = logging.getLogger(__name__)
FIELD_COMPONENT = "Component Name"
FIELD_EMAIL = "Email"
FIELD_GROUP = "Group"
FIELD_NOTE = "Note"
FIELD_PROJECT = "Project"
FIELD_USER_NAME = "Owner"
def cmdline_args():
"""Add and parse command line arguments.
:returns Namespace:
Populated namespace for the command line arguments.
"""
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument(
"--user",
type=str,
dest="jira_user",
default=os.environ.get("JIRA_USER", None),
help="JIRA username to log into JIRA with.\nDefault: env JIRA_USER",
)
parser.add_argument(
"--password",
type=str,
dest="jira_password",
default=os.environ.get("JIRA_PASSWORD", None),
help="JIRA password.\nDefault: env JIRA_PASSWORD",
)
parser.add_argument(
"csvfile",
type=argparse.FileType("r"),
help="CSV file to import from.\n",
)
parser.add_argument(
"--update-groups",
action="store_true",
default=False,
dest="update_groups",
help="If a JIRA group is missing, create it.\n",
)
parser.add_argument(
"--update-users",
action="store_true",
dest="update_users",
help="Add or update JIRA users.\n"
"Required CSV fields:\n"
" * Owner\n"
" * Email\n"
"Optional CSV fields:\n"
" * Group\n",
)
parser.add_argument(
"--update-components",
action="store_true",
dest="update_components",
help="Add or update JIRA components.\n"
"Required CSV fields:\n"
" * Component name\n"
" * Project\n"
"Optional CSV fields:\n"
" * Owner\n"
" * Note\n",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Run script without modifying JIRA.",
)
parser.add_argument(
"-l",
"--log",
default=sys.stderr,
type=argparse.FileType("w"),
help="Log file. Default: stderr.",
)
parser.add_argument(
"-v",
"--verbose",
default=0,
action="count",
help="Increase log level. May be used several times.",
)
parser.add_argument(
"-q",
"--quiet",
default=0,
action="count",
help="Decrease log level. May be used several times.",
)
args = parser.parse_args()
log.configure_logger("", args.log, args.verbose, args.quiet)
__log__.info("JIRA username: %s", args.jira_user)
if args.update_groups:
__log__.info("Update JIRA groups")
if args.update_users:
__log__.info("Update JIRA users")
if args.update_components:
__log__.info("Update JIRA components")
if args.dry_run:
__log__.info("Dry run")
return args
def update_groups(jira, csv_list):
"""Add new JIRA groups from CVS list.
Args:
jira: Fairphone jira wrapper to interact with.
csv_list: A list of user information populated from the CSV file.
"""
for row in csv_list:
group = row.get(FIELD_GROUP, None)
if group and not jira.groups(query=group):
jira.add_group(group)
def update_users(jira, csv_list):
"""Update or add new JIRA users from CVS list.
Args:
jira: Fairphone jira wrapper to interact with.
csv_list: A list of user information populated from the CSV file.
"""
for row in csv_list:
username = row.get(FIELD_USER_NAME, None)
email = row.get(FIELD_EMAIL, None)
if not username:
__log__.warning("User name missing")
continue
if not email:
__log__.warning("Email missing for user %s", username)
continue
jira.add_user(username, email)
group = row.get(FIELD_GROUP, None)
if group:
jira.add_user_to_group(username, group)
def update_components(jira, csv_list):
"""Add and update JIRA components from a csv list.
Args:
jira: Fairphone jira wrapper to interact with.
csv_list: A list of user information populated from the CSV file.
"""
jira_component_dict = {}
def get_jira_component_info(project):
return {
jira_component.name: jira_component.id
for jira_component in jira.project_components(project)
}
for row in csv_list:
project = row.get(FIELD_PROJECT, None)
if not project:
__log__.warning("Missing project name")
continue
component_name = row.get(FIELD_COMPONENT, None)
if not component_name:
__log__.warning("Missing component name")
continue
if project not in jira_component_dict:
jira_component_dict[project] = get_jira_component_info(project)
jira_component_id = jira_component_dict[project].get(
component_name, None
)
if not jira_component_id:
jira.create_component(
component_name,
project,
description=row.get(FIELD_NOTE, None),
leadUserName=row.get(FIELD_USER_NAME, None),
)
else:
jira.update_component(
jira_component_id,
project,
description=row.get(FIELD_NOTE, None),
leadUserName=row.get(FIELD_USER_NAME, None),
)
if __name__ == "__main__":
ARGS = cmdline_args()
try:
JIRA = JiraFairphone(ARGS.jira_user, ARGS.jira_password, ARGS.dry_run)
CSV_READER = csv.DictReader(ARGS.csvfile)
CSV_LIST = list(CSV_READER)
if ARGS.update_groups:
update_groups(JIRA, CSV_LIST)
if ARGS.update_users:
update_users(JIRA, CSV_LIST)
if ARGS.update_components:
update_components(JIRA, CSV_LIST)
except JIRAError as error:
__log__.exception("Jira exception. Status: %d", error.status_code)