summaryrefslogtreecommitdiff
path: root/buildscripts/jiraclient.py
blob: fd0a3fc43b603733e69d0cc7a9c214bab8d9b4cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"""Module to access a JIRA server."""

import jira


class JiraClient(object):
    """A client for JIRA."""

    CLOSE_TRANSITION_NAME = "Close Issue"
    RESOLVE_TRANSITION_NAME = "Resolve Issue"
    FIXED_RESOLUTION_NAME = "Fixed"
    WONT_FIX_RESOLUTION_NAME = "Won't Fix"

    def __init__(  # pylint: disable=too-many-arguments
            self, server, username=None, password=None, access_token=None, access_token_secret=None,
            consumer_key=None, key_cert=None):
        """Initialize the JiraClient with the server URL and user credentials."""
        opts = {"server": server, "verify": True}
        basic_auth = None
        oauth_dict = None
        if access_token and access_token_secret and consumer_key and key_cert:
            oauth_dict = {
                "access_token": access_token, "access_token_secret": access_token_secret,
                "consumer_key": consumer_key, "key_cert": key_cert
            }
        elif username and password:
            basic_auth = (username, password)
        else:
            raise TypeError("Must specify Basic Auth (using arguments username & password)"
                            " or OAuth (using arguments access_token, access_token_secret,"
                            " consumer_key & key_cert_file) credentials")
        self._jira = jira.JIRA(options=opts, basic_auth=basic_auth, oauth=oauth_dict, validate=True)

        self._transitions = {}
        self._resolutions = {}

    def create_issue(self, project, summary, description, labels=None):
        """Create an issue."""
        fields = {
            "project": project, "issuetype": {"name": "Task"}, "summary": summary,
            "description": description
        }
        new_issue = self._jira.create_issue(fields=fields)
        if labels:
            new_issue.update(fields={"labels": labels})
        return new_issue.key

    def close_issue(self, issue_key, resolution, fix_version=None):
        """Close an issue."""
        issue = self._jira.issue(issue_key)
        resolution_id = self._get_resolution_id(resolution)
        if resolution_id is None:
            raise ValueError("No resolution found for '{0}'. Leaving issue '{1}' open.".format(
                resolution, issue_key))
        close_transition_id = self._get_transition_id(issue, JiraClient.CLOSE_TRANSITION_NAME)
        if close_transition_id is None:
            raise ValueError("No transition found for '{0}'. Leaving issue '{1}' open.".format(
                JiraClient.CLOSE_TRANSITION_NAME, issue_key))
        fields = {"resolution": {"id": resolution_id}}
        if fix_version:
            fields["fixVersions"] = [{"name": fix_version}]
        self._jira.transition_issue(issue, close_transition_id, fields=fields)

    def _get_transition_id(self, issue, name):
        project_key = issue.fields.project.key
        project_transitions = self._transitions.setdefault(project_key, {})

        transition_id = project_transitions.get(name)
        if transition_id:
            return transition_id
        transitions = self._jira.transitions(issue)
        for transition in transitions:
            project_transitions[transition["name"]] = transition["id"]
            if transition["name"] == name:
                transition_id = transition["id"]
        return transition_id

    def _get_resolution_id(self, name):
        resolution_id = self._resolutions.get(name)
        if resolution_id is not None:
            return resolution_id
        resolutions = self._jira.resolutions()
        for resolution in resolutions:
            self._resolutions[resolution.name] = resolution.id
            if resolution.name == name:
                resolution_id = resolution.id
        return resolution_id