Skip to content

Commit

Permalink
Merge pull request canonical#13 from canonical/lp-to-jira-tests
Browse files Browse the repository at this point in the history
Added initial tests and argument parsing with argparse
  • Loading branch information
mclemenceau authored Sep 30, 2021
2 parents 6e06ae5 + 6a0f686 commit 5d8c0a6
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 99 deletions.
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Ignore CPython artefacts
__pycache__/
*.pyc

# Ignore test artefacts
.coverage
.pytest_cache/

# Ignore pip artefacts
*.egg-info/
144 changes: 78 additions & 66 deletions LpToJira/lp_to_jira.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
# create a new Entry in JIRA in a given project


import sys
import os
import argparse
import textwrap

from optparse import OptionParser
from datetime import datetime, timedelta

from launchpadlib.launchpad import Launchpad
Expand Down Expand Up @@ -42,24 +42,34 @@ def get_lp_bug(lp, bug_number):
"""Make sure the bug ID exists, return bug"""

bug = None

if lp is None:
return bug

try:
bug = lp.bugs[bug_number]

except KeyError:
print("Couldn't find the Launchpad bug {}".format(bug_number))

return bug


def get_lp_bug_pkg(lp, bug):
"""From a LP bug, get its package"""
def get_lp_bug_pkg(bug):
"""
From a LP bug, get its package
a Launchpad bug may impact multiple packages,
this function is pretty unprecise as it returns only the latest package
TODO: probably do something about this, return a list or fail if multiple
packages.
"""

bug_pkg = None
if len(bug.bug_tasks) == 1:
bug_pkg = bug.bug_tasks[0].bug_target_name.split()[0]
else:
for task in bug.bug_tasks:
if "(Ubuntu)" in task.bug_target_name:
bug_pkg = task.bug_target_name.split()[0]

# Only return bug from Ubuntu (will return the last one if multiple pkgs
for task in bug.bug_tasks:
if "(Ubuntu" in task.bug_target_name:
bug_pkg = task.bug_target_name.split()[0]

return bug_pkg

Expand Down Expand Up @@ -117,7 +127,7 @@ def build_jira_issue(lp, bug, project_id):
"""Builds and return a dict to create a Jira Issue from"""

# Get bug info from LP
bug_pkg = get_lp_bug_pkg(lp, bug)
bug_pkg = get_lp_bug_pkg(bug)

# Build the Jira Issue from the LP info
issue_dict = {
Expand Down Expand Up @@ -169,107 +179,109 @@ def lp_to_jira_bug(lp, jira, bug, project_id, opts):
bug.lp_save()


def main():
usage = """\
usage: lp-to-jira [options] bug-id project-id
Create JIRA entry for a given Launchpad bug ID
options:
-e, --exists"
Look if the Launchpad Bug has alreaady been imported
print the JIRA issue ID if found
-l, --label LABEL
Add LABEL to the JIRA issue after creation
-s SYNC_PROJECT_BUGS, --sync_project_bugs=SYNC_PROJECT_BUGS
The name of the LP Project. This will bring in every
bug from your project if you do not also specify days
-d DAYS, --days=DAYS
Only look for LP Bugs in the past n days
--no-lp-tag
Examples:
lp-to-jira 3215487 FR
lp-to-jira -e 3215487 FR
lp-to-jira -l ubuntu-meeting 3215487 PR
lp-to-jira -s ubuntu -d 3 IQA
"""

opt_parser = OptionParser(usage)
opt_parser.add_option(
'-l', '--label',
dest='label',
def main(args=None):
opt_parser = argparse.ArgumentParser(
description="A script create JIRA issue from Launchpad bugs",
formatter_class=argparse.RawTextHelpFormatter,
epilog=textwrap.dedent('''\
Examples:
lp-to-jira 3215487 FR
lp-to-jira -e 3215487 FR
lp-to-jira -l ubuntu-meeting 3215487 PR
lp-to-jira -s ubuntu -d 3 IQA
''')
)
opt_parser.add_option(
opt_parser.add_argument(
'bug', type=int,
# Somewhat hacky way to allow -s option to not require bug id
# -s (sync) is an optional parameter that doesn't require bug id
default=0,
nargs='?',
help="The Launchpad numeric bug ID")
opt_parser.add_argument(
'project', type=str,
help="The JIRA project string key")
opt_parser.add_argument(
'-l',
'--label',
dest='label',
help='Add LABEL to the JIRA issue after creation')
opt_parser.add_argument(
'-e', '--exists',
dest='exists',
action='store_true'
action='store_true',
help=textwrap.dedent('''
Look if the Launchpad Bug has alreaady been imported
print the JIRA issue ID if found
''')
)

opt_parser.add_option(
opt_parser.add_argument(
'-s', '--sync_project_bugs',
dest='sync_project_bugs',
action='store',
type=str,
help='Adds all bugs from a specified LP Project to specified Jira board'
' if they are not already on the Jira board.'
' Use --days to narrow down bugs'
help=textwrap.dedent('''
Adds all bugs from a specified LP Project to specified Jira board
if they are not already on the Jira board.
Use --days to narrow down bugs
''')
)

opt_parser.add_option(
opt_parser.add_argument(
'-d', '--days',
dest='days',
action='store',
type=int,
help='Only look for LP Bugs in the past n days'
)

opt_parser.add_option(
opt_parser.add_argument(
'--no-lp-tag',
dest='no_lp_tag',
action='store_true',
help='Do not add tag to LP Bug'
)

opts, args = opt_parser.parse_args()
opts = opt_parser.parse_args(args)

if (opts.bug == 0 and not opts.sync_project_bugs):
opt_parser.print_usage()
print('lp-to-jira: error: the follow argument is required: bug')
return 1

# Connect to Launchpad API
# TODO: catch exception if the Launchpad API isn't open
snap_home = os.getenv("SNAP_USER_COMMON")
if snap_home:
credential_store = UnencryptedFileCredentialStore("{}/.lp_creds".format(snap_home))
credential_store = UnencryptedFileCredentialStore(
"{}/.lp_creds".format(snap_home))
else:
credential_store = UnencryptedFileCredentialStore(os.path.expanduser("~/.lp_creds"))
credential_store = UnencryptedFileCredentialStore(
os.path.expanduser("~/.lp_creds"))
lp = Launchpad.login_with(
'foundations',
'production',
version='devel',credential_store=credential_store)
version='devel', credential_store=credential_store)

# Connect to the JIRA API
try:
api = jira_api()
except ValueError as exc:
except ValueError:
return "ERROR: Cannot initialize JIRA API."

jira = JIRA(api.server, basic_auth=(api.login, api.token))

if opts.sync_project_bugs:
tasks_list = get_all_lp_project_bug_tasks(lp, opts.sync_project_bugs, opts.days)
tasks_list = get_all_lp_project_bug_tasks(
lp, opts.sync_project_bugs, opts.days)
if tasks_list is None:
return 1

for bug_task in tasks_list:
bug = bug_task.bug
lp_to_jira_bug(lp, jira, bug, args[0], opts)
lp_to_jira_bug(lp, jira, bug, opts.project, opts)
return 0

# Make sure there's 2 arguments
if len(args) < 2:
opt_parser.print_usage()
return 1

bug_number = args[0]
project_id = args[1]
bug_number = opts.bug
project_id = opts.project

bug = get_lp_bug(lp, bug_number)
if bug is None:
Expand Down
38 changes: 38 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest

from unittest.mock import Mock

@pytest.fixture
def empty_bug():
bug = Mock()
bug.title = ""
bug.description = ""
bug.id = 0
bug.tags = []
bug.web_link = "https://"
bug.bug_tasks = []

return bug

@pytest.fixture
def lp():
bug = Mock()
bug.title = "test bug"
bug.id = 123456
bug.bug_tasks = [
Mock(bug_target_name=n, status=s)
for n, s in zip(['systemd (Ubuntu)',
'vim (Debian)',
'glibc (Ubuntu)'],
['New',
'Confirmed',
'New'])
]

project1 = Mock()
project1.searchTasks = Mock(return_value=None)

project2 = Mock()
project2.searchTasks = Mock(return_value=bug)

return Mock(bugs={123456: bug}, projects={"subiquity": project1, "curtin": project2})
45 changes: 45 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
[metadata]
name = LpToJira
version = 0.6
description = A Command Line helper to import launchpad bug in JIRA.
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/canonical/lp-to-jira
project_urls =
Bug Reports = https://github.com/canonical/lp-to-jira/issues
Source Code = https://github.com/mclemenceau/lp-to-jira
classifiers =
Development Status :: 3 - Alpha
License :: OSI Approved :: GNU General Public License v2 (GPLv2)
Operating System :: OS Independent
Programming Language :: Python :: 3

[options]
packages = find:
install_requires =
launchpadlib
jira

[options.extras_require]
test =
pytest
pytest-cov

[options.entry_points]
console_scripts =
lp-to-jira = LpToJira.lp_to_jira:main
lp-to-jira-report = LpToJira.lp_to_jira_report:main

[tool:pytest]
addopts = --cov
testpaths = tests

[coverage:run]
source = LpToJira
branch = true

[coverage:report]
show_missing = true
exclude_lines =
raise NotImplementedError
assert False
34 changes: 1 addition & 33 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,3 @@
import setuptools

from setuptools import setup

with open("README.md", "r") as fh:
long_description = fh.read()

setup(
name="LpToJira",
version="0.6",
author="Matthieu Clemenceau",
author_email="[email protected]",
description=("A Command Line helper to import launchpad bug in JIRA."),
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/canonical/lp-to-jira",
project_urls={
'Bug Reports': 'https://github.com/canonical/lp-to-jira/issues',
'Source': 'https://github.com/canonical/lp-to-jira',
},
packages=setuptools.find_packages(),
keywords='lp to jira',
entry_points={
'console_scripts': [
'lp-to-jira=LpToJira.lp_to_jira:main',
'lp-to-jira-report=LpToJira.lp_to_jira_report:main',
],
},
install_requires=['jira','launchpadlib'],
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
],
)
setup()
Empty file added tests/__init__.py
Empty file.
Loading

0 comments on commit 5d8c0a6

Please sign in to comment.