import datetime
from .errors import BugException
VALID_STATUS = ["RESOLVED", "ASSIGNED", "NEW", "UNCONFIRMED"]
VALID_RESOLUTION = ["FIXED", "INCOMPLETE", "INVALID", "WORKSFORME",
"DUPLICATE", "WONTFIX"]
def str2datetime(s):
return datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%SZ')
[docs]class Bug(object):
"""This represents a Bugzilla Bug"""
[docs] def __init__(self, bugsy=None, **kwargs):
"""
Defaults are set if there are no kwargs passed in. To pass in
a dict create the Bug object like the following
:param bugsy: Bugsy instance to use to connect to Bugzilla.
>>> bug = Bug(**myDict)
"""
self._bugsy = bugsy
self._bug = dict(**kwargs)
self._bug['op_sys'] = kwargs.get('op_sys', 'All')
self._bug['product'] = kwargs.get('product', 'core')
self._bug['component'] = kwargs.get('component', 'general')
self._bug['platform'] = kwargs.get('platform', 'All')
self._bug['version'] = kwargs.get('version', 'unspecified')
@property
def id(self):
"""
Property for getting the ID of a bug.
>>> bug.id
123456
"""
return self._bug.get('id', None)
@property
def summary(self):
"""
Property for getting and setting the bug summary
>>> bug.summary
"I like cheese"
"""
return self._bug.get('summary', '')
@summary.setter
def summary(self, value):
"""
Property for getting and setting the bug summary
>>> bug.summary = "I like cheese"
"""
self._bug['summary'] = value
@property
def status(self):
"""
Property for getting or setting the bug status
>>> bug.status
"REOPENED"
"""
return self._bug.get('status', '')
@status.setter
def status(self, value):
"""
Property for getting or setting the bug status
>>> bug.status = "REOPENED"
"""
if self._bug.get('id', None):
if value in VALID_STATUS:
self._bug['status'] = value
else:
raise BugException("Invalid status type was used")
else:
raise BugException("Can not set status unless there is a bug id."
" Please call Update() before setting")
@property
def OS(self):
"""
Property for getting or setting the OS that the bug occured on
>>> bug.OS
"All"
"""
return self._bug['op_sys']
@OS.setter
def OS(self, value):
"""
Property for getting or setting the OS that the bug occured on
>>> bug.OS = "Linux"
"""
self._bug['op_sys']
@property
def resolution(self):
"""
Property for getting or setting the bug resolution
>>> bug.resolution
"FIXED"
"""
return self._bug['resolution']
@resolution.setter
def resolution(self, value):
"""
Property for getting or setting the bug resolution
>>> bug.resolution = "FIXED"
"""
if value in VALID_RESOLUTION:
self._bug['resolution'] = value
else:
raise BugException("Invalid resolution type was used")
@property
def product(self):
"""
Property for getting the bug product
>>> bug.product
Core
"""
return self._bug['product']
@product.setter
def product(self, value):
"""
Property for getting the bug product
>>> bug.product = "DOM"
"""
self._bug['product'] = value
@property
def component(self):
"""
Property for getting the bug component
>>> bug.component
General
"""
return self._bug['component']
@component.setter
def component(self, value):
"""
Property for getting the bug component
>>> bug.component = "Marionette"
"""
self._bug['component'] = value
@property
def platform(self):
"""
Property for getting the bug platform
>>> bug.platform
"ARM"
"""
return self._bug['platform']
@platform.setter
def platform(self, value):
"""
Property for getting the bug platform
>>> bug.platform = "OSX"
"""
self._bug['platform'] = value
@property
def version(self):
"""
Property for getting the bug platform
>>> bug.version
"TRUNK"
"""
return self._bug['version']
@version.setter
def version(self, value):
"""
Property for getting the bug platform
>>> bug.version = "0.3"
"""
self._bug['version'] = value
@property
def assigned_to(self):
"""
Property for getting the bug assignee
>>> bug.assigned_to
"automatedtester@mozilla.com"
"""
return self._bug['assigned_to']
@assigned_to.setter
def assigned_to(self, value):
"""
Property to set the bug assignee
>>> bug.assigned_to = "automatedtester@mozilla.com"
"""
self._bug['assigned_to'] = value
@property
def cc(self):
"""
Property to get the cc list for the bug. It returns emails for people
>>> bug.cc
[u'dburns@mozilla.com', u'automatedtester@mozilla.com']
"""
cc_list = [cc_detail['email'] for cc_detail in self._bug['cc_detail']]
return cc_list
@cc.setter
def cc(self, value):
"""
Property to add or remove people from the cc list.
To add people to the cc list
>>> bug.cc = "automatedtester@mozilla.com"
or
>>> bug.cc = ["automatedtester@mozilla.com", "dburns@mozilla.com"]
If you want to remove an email from the list, the last character of
the email address needs to be a `-`. For Example:
>>> bug.cc = "automatedtester@mozilla.com-"
# Removes an email.
You can mix adding and removing
>>> bug.cc = ["automatedtester@mozilla.com", "dburns@mozilla.com-"]
"""
self._bug['cc'] = self._process_setter(value)
@property
def keywords(self):
"""
Property to get the keywords list for the bug. It returns multiple
keywords in a list.
>>> bug.keywords
[u"ateam-marionette-runner", u"regression"]
"""
keywords = [keyword for keyword in self._bug['keywords']]
return keywords
@keywords.setter
def keywords(self, value):
"""
Property to add or remove keywords.
To add keywords
>>> bug.keywords = "ateam-marionette-runner"
or
>>> bug.keywords = ["intermittent", ateam-marionette-runner]
If you want to remove a keyword from the list, the last character of
the keyword needs to be a `-`. For Example:
>>> bug.keyword = "regression-"
# Removes a keyword.
You can mix adding and removing
>>> bug.keywords = ["intermittent", "regression-"]
"""
self._bug['keywords'] = self._process_setter(value)
@property
def depends_on(self):
"""
Property to get the bug numbers that depend on the current bug. It returns multiple
bug numbers in a list.
>>> bug.depends_on
[123456, 678901]
"""
depends_on = [dep for dep in self._bug['depends_on']]
return depends_on
@depends_on.setter
def depends_on(self, value):
"""
Property to add or remove dependent bugs.
To add dependent bugs
>>> bug.depends_on = 145678
or
>>> bug.depends_on = [145678, 999999]
If you want to remove a depends on from the list, the last character of
the keyword needs to be a `-`. For Example:
>>> bug.depends_on = "123456-"
# Removes a dependent bug.
You can mix adding and removing
>>> bug.depends_on = ["99999", "123456-"]
"""
self._bug['depends_on'] = self._process_setter(value)
@property
def blocks(self):
"""
Property to get the bug numbers that block on the current bug. It returns multiple
bug numbers in a list.
>>> bug.blocks
[123456, 678901]
"""
depends_on = [dep for dep in self._bug['blocks']]
return depends_on
@blocks.setter
def blocks(self, value):
"""
Property to add or remove blocking bugs.
To add blocking bugs
>>> bug.blocks = 145678
or
>>> bug.blocks = [145678, 999999]
If you want to remove a blocking bug on from the list, the last character of
the keyword needs to be a `-`. For Example:
>>> bug.blocks = "123456-"
# Removes a blocking bug.
You can mix adding and removing
"""
self._bug['blocks'] = self._process_setter(value)
[docs] def to_dict(self):
"""
Return the raw dict that is used inside this object
"""
return self._bug
[docs] def update(self):
"""
Update this object with the latest changes from Bugzilla
>>> bug.status
'NEW'
#Changes happen on Bugzilla
>>> bug.update()
>>> bug.status
'FIXED'
"""
if 'id' in self._bug:
result = self._bugsy.request('bug/%s' % self._bug['id'])
self._bug = dict(**result['bugs'][0])
else:
raise BugException("Unable to update bug that isn't in Bugzilla")
def _process_setter(self, value):
result = {}
if not isinstance(value, list):
if isinstance(value, int):
value = str(value)
if value[-1] == "-":
result = {"remove": [value[:-1]]}
else:
result = {"add": [value]}
else:
addin = []
removin = []
for val in value:
if isinstance(value, int):
value = str(value)
if val[-1] == "-":
removin.append(val[:-1])
else:
addin.append(val)
result = {"add": addin,
"remove": removin}
return result