Source code for woob.capabilities.bugtracker

# Copyright(C) 2011 Romain Bignon
#
# This file is part of woob.
#
# woob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# woob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with woob. If not, see <http://www.gnu.org/licenses/>.

from .base import BaseObject, Capability, Enum, Field, IntField, StringField, UserError
from .date import DateField, DeltaField


__all__ = [
    "IssueError",
    "Project",
    "User",
    "Version",
    "Status",
    "Attachment",
    "Change",
    "Update",
    "Issue",
    "Query",
    "CapBugTracker",
]


[docs]class IssueError(UserError): """ Raised when there is an error with an issue. """
[docs]class Project(BaseObject): """ Represents a project. """ name = StringField("Name of the project") members = Field("Members of projects", list) versions = Field("List of versions available for this project", list) trackers = Field("All trackers", list) categories = Field("All categories", list) statuses = Field("Available statuses for issues", list) priorities = Field("Available priorities for issues", list) tags = Field("All tags", tuple, list) fields = Field("Custom fields names", list) def __init__(self, id, name, url=None): super().__init__(id, url) self.name = str(name) def __repr__(self): return "<Project %r>" % self.name
[docs] def find_user(self, id, name): """ Find a user from its ID. If not found, create a :class:`User` with the specified name. :param id: ID of user :type id: str :param name: Name of user :type name: str :rtype: :class:`User` """ for user in self.members: if user.id == id: return user if name is None: return None return User(id, name)
[docs] def find_version(self, id, name): """ Find a version from an ID. If not found, create a :class:`Version` with the specified name. :param id: ID of version :type id: str :param name: Name of version :type name: str :rtype: :class:`Version` """ for version in self.versions: if version.id == id: return version if name is None: return None return Version(id, name)
[docs] def find_status(self, name): """ Find a status from a name. :param name: Name of status :type name: str :rtype: :class:`Status` """ for status in self.statuses: if status.name == name: return status if name is None: return None return None
[docs]class User(BaseObject): """ User. """ name = StringField("Name of user") def __init__(self, id, name, url=None): super().__init__(id, url) self.name = str(name) def __repr__(self): return "<User %r>" % self.name
[docs]class Version(BaseObject): """ Version of a project. """ name = StringField("Name of version") def __init__(self, id, name, url=None): super().__init__(id, url) self.name = str(name) def __repr__(self): return "<Version %r>" % self.name
class StatusType(Enum): NEW = 0 PROGRESS = 1 RESOLVED = 2 REJECTED = 3
[docs]class Status(BaseObject): """ Status of an issue. **VALUE_** constants are the primary status types. """ VALUE_NEW = StatusType.NEW VALUE_PROGRESS = StatusType.PROGRESS VALUE_RESOLVED = StatusType.RESOLVED VALUE_REJECTED = StatusType.REJECTED name = StringField("Name of status") value = IntField("Value of status (constants VALUE_*)") def __init__(self, id, name, value, url=None): super().__init__(id, url) self.name = str(name) self.value = value def __repr__(self): return "<Status %r>" % self.name
[docs]class Attachment(BaseObject): """ Attachment of an issue. """ filename = StringField("Filename") def __repr__(self): return "<Attachment %r>" % self.filename
[docs]class Change(BaseObject): """ A change of an update. """ field = StringField("What field has been changed") last = StringField("Last value of field") new = StringField("New value of field") def __repr__(self): return f"<{type(self).__name__} {self.field!r}: {self.new!r} (old: {self.last!r})>"
[docs]class Update(BaseObject): """ Represents an update of an issue. """ author = Field("Author of update", User) date = DateField("Date of update") hours = DeltaField("Time activity") message = StringField("Log message") attachments = Field("Files attached to update", list, tuple) changes = Field("List of changes", list, tuple) def __repr__(self): return "<Update %r>" % self.id
[docs]class Issue(BaseObject): """ Represents an issue. """ project = Field("Project of this issue", Project) title = StringField("Title of issue") body = StringField("Text of issue") creation = DateField("Date when this issue has been created") updated = DateField("Date when this issue has been updated for the last time") start = DateField("Date when this issue starts") due = DateField("Date when this issue is due for") attachments = Field("List of attached files", list, tuple) history = Field("History of updates", list, tuple) author = Field("Author of this issue", User) assignee = Field("User assigned to this issue", User) tracker = StringField("Name of the tracker") category = StringField("Name of the category") version = Field("Target version of this issue", Version) status = Field("Status of this issue", Status) fields = Field("Custom fields (key,value)", dict) priority = StringField("Priority of the issue") # XXX tags = Field("Categories/Tags of the issue", tuple, list) related_issues = Field("Related issues", list)
[docs]class Query(BaseObject): """ Query to find an issue. """ project = Field("Filter on projects", str, str, Project) title = StringField("Filter on titles") author = Field("Filter on authors", str, User) assignee = Field("Filter on assignees", str, User) version = Field("Filter on versions", str, Version) category = StringField("Filter on categories") status = Field("Filter on statuses", str, Status) tags = Field("Filter on tags", tuple, list) fields = Field("Filter on custom fields", dict) def __init__(self, id="", url=None): super().__init__(id, url)
[docs]class CapBugTracker(Capability): """ Bug trackers websites. """ (SORT_RELEVANCE, SORT_RATING, SORT_PRIORITY, SORT_DATE) = range(4)
[docs] def iter_issues(self, query, sortby=SORT_RELEVANCE, ascending=False): """ Iter issues with optionnal patterns. :param query: query :type query: :class:`Query` :rtype: iter[:class:`Issue`] """ raise NotImplementedError()
[docs] def get_issue(self, id): """ Get an issue from its ID. :param id: ID of issue :rtype: :class:`Issue` """ raise NotImplementedError()
[docs] def create_issue(self, project): """ Create an empty issue on the given project. :param project: project :type project: :class:`Project` :returns: the created issue :rtype: :class:`Issue` """ raise NotImplementedError()
[docs] def post_issue(self, issue): """ Post an issue to create or update it. :param issue: issue to create or update :type issue: :class:`Issue` """ raise NotImplementedError()
[docs] def update_issue(self, issue, update): """ Add an update to an issue. :param issue: issue or id of issue :type issue: :class:`Issue` :param update: an Update object :type update: :class:`Update` """ raise NotImplementedError()
[docs] def remove_issue(self, issue): """ Remove an issue. :param issue: issue :type issue: :class:`Issue` """ raise NotImplementedError()
[docs] def iter_projects(self): """ Iter projects. :rtype: iter[:class:`Project`] """ raise NotImplementedError()
[docs] def get_project(self, id): """ Get a project from its ID. :rtype: :class:`Project` """ raise NotImplementedError()