Example #1
0
 def __init__(self, project_name):
     self.mongo_db = mongodb_class.mongoDB(project_name)
     self.jira = JIRA('http://172.16.60.13:8080', basic_auth=('shenwei','sw64419'))
     self.gh = GreenHopper({'server': 'http://172.16.60.13:8080'}, basic_auth=('shenwei', 'sw64419'))
     self.name = project_name
     self.project = self.jira.project(self.name)
     self.pj_name = u"%s" % self.project.name
     self.pj_manager = u"%s" % self.project.lead.displayName
     """获取项目版本信息
     """
     _versions = self.jira.project_versions(self.name)
     self.version = {}
     self.sprints = self._get_sprints()
     for _v in _versions:
         _key = (u"%s" % _v).replace('.', '^')
         if not self.version.has_key(_key):
             self.version[_key] = {}
         self.version[_key][u"id"] = _v.id
         self.version[_key]['startDate'] = ""
         self.version[_key]['releaseDate'] = ""
         if 'startDate' in dir(_v):
             self.version[_key]['startDate'] = _v.startDate
         if 'releaseDate' in dir(_v):
             self.version[_key]['releaseDate'] = _v.releaseDate
         self.mongo_db.handler("project", "update",
                               {"version": _key}, dict({"version": _key}, **self.version[_key]))
     self.issue = None
Example #2
0
 def __init__(self, project_name):
     global config
     self.mongo_db = mongodb_class.mongoDB(project_name)
     """将工作日志独立记录"""
     self.mongo_db_worklogs = mongodb_class.mongoDB("WORK_LOGS")
     self.jira = JIRA(config.get('JIRA', 'url'),
                      basic_auth=(config.get('JIRA', 'user'),
                                  config.get('JIRA', 'password')))
     self.gh = GreenHopper({'server': config.get('JIRA', 'url')},
                           basic_auth=(config.get('JIRA', 'user'),
                                       config.get('JIRA', 'password')))
     self.name = project_name
     self.project = self.jira.project(self.name)
     self.pj_name = u"%s" % self.project.name
     self.pj_manager = u"%s" % self.project.lead.displayName
     """获取项目版本信息
     """
     _versions = self.jira.project_versions(self.name)
     self.version = {}
     self.sprints = self._get_sprints()
     for _v in _versions:
         _key = (u"%s" % _v).replace('.', '^')
         if not self.version.has_key(_key):
             self.version[_key] = {}
         self.version[_key][u"id"] = _v.id
         self.version[_key]['startDate'] = ""
         self.version[_key]['releaseDate'] = ""
         if 'startDate' in dir(_v):
             self.version[_key]['startDate'] = _v.startDate
         if 'releaseDate' in dir(_v):
             self.version[_key]['releaseDate'] = _v.releaseDate
         self.mongo_db.handler("project", "update",
                               {"version": _key}, dict({"version": _key}, **self.version[_key]))
     self.issue = None
Example #3
0
 def update_task_effort_left(self, user, password, key, effort_left_d):
     # TODO: See if we need to log in each time
     gh = GreenHopper(
         basic_auth=(user, password), options={"server": "https://jira01.corp.linkedin.com:8443", "verify": False}
     )
     issue = gh.issue(key)
     gh.add_worklog(issue, adjustEstimate="new", timeSpent="1h", newEstimate="%.1fd" % effort_left_d)
     return
Example #4
0
 def startSession(self):
     #now make the connection
     options = {'server': self.__jiraURL, 'verify': False}
     self.__jira = JIRA(options,
                        basic_auth=(self.__jiraUser, self.__jiraPassword))
     self.__greenhopper = GreenHopper(options,
                                      basic_auth=(self.__jiraUser,
                                                  self.__jiraPassword))
Example #5
0
def getJiraClient():
    jira=GreenHopper(options={'server': JIRA_SERVER}, oauth={
               'access_token': con_credentials.get('ACCESS_TOKEN'),
               'access_token_secret': con_credentials.get('ACCESS_TOKEN_SECRET'),
               'consumer_key': CONSUMER_KEY,
               'key_cert': RSA_KEY
               })
    return jira
Example #6
0
 def startSession(self):
     #now make the connection
     options = {
         'server':self.__jiraURL,
         'verify':False
     }
     self.__jira = JIRA(options, basic_auth=(self.__jiraUser, self.__jiraPassword))
     self.__greenhopper = GreenHopper(options, basic_auth=(self.__jiraUser, self.__jiraPassword))
Example #7
0
def jira_login():
	username = raw_input("Jira username: "******"Jira password: "******"Company (as used in Jira URL): ")
	jira_url = "https://" + company + ".jira.com"
	options = {'server': jira_url}
	gh = GreenHopper(options, basic_auth=(username, password))
	return gh
Example #8
0
 def _jira_login(self, endpoint: str, user: str, password: str) -> GreenHopper:
     try:
         basic_auth = (user, password)
         jira = GreenHopper({'server': endpoint}, basic_auth=basic_auth)
         # pylint: disable=protected-access
         if "JSESSIONID" in jira._session.cookies:
             # drop basic auth if we have a cookie (for performance)
             jira._session.auth = None
         return jira
     except JIRAError as e:
         raise e
Example #9
0
def jira_login(endpoint, user=None):
    try:
        basic_auth = None
        if user:
            if sys.stdin.isatty():
                password = getpass.getpass(stream=sys.stderr)
            else:
                password = sys.stdin.readline().rstrip()
            basic_auth = (user, password)
        try:
            jira = GreenHopper({'server': endpoint}, basic_auth=basic_auth)
        except JIRAError:
            sys.stderr.write("warn: Autentication to JIRA failed," +
                             " continuing unauthenticated\n")
            jira = GreenHopper({'server': endpoint})
        # pylint: disable=protected-access
        if "JSESSIONID" in jira._session.cookies:
            # drop basic auth if we have a cookie (for performance)
            jira._session.auth = None
        return jira
    except JIRAError as exn:
        sys.stderr.write("Connection to JIRA failed: %s: %s\n" %
                         (exn.response.status_code, exn.response.reason))
        exit(4)
Example #10
0
 def greenhopper(self):
     return GreenHopper(options={
         'server': self.get('root'),
         'verify': False
     },
                        oauth={
                            'access_token':
                            self.get('access_token'),
                            'access_token_secret':
                            self.get('access_token_secret'),
                            'consumer_key':
                            self.get('consumer_key'),
                            'key_cert':
                            self.rsa_key
                        })
Example #11
0
class IssueManager:

    ## The constructor
    # @param self The object pointer
    # @param jiraURL The url of the JIRA instance
    # @param jiraUser The user name to use
    # @param jiraPassword The user password to use
    def __init__(self, jiraURL, jiraUser, jiraPassword):
        self.__jiraUser = jiraUser
        self.__jiraPassword = jiraPassword
        self.__jiraURL = jiraURL
        self.startSession()

    ## Create the connection
    # @param self Teh object pointer
    def startSession(self):
        #now make the connection
        options = {'server': self.__jiraURL, 'verify': False}
        self.__jira = JIRA(options,
                           basic_auth=(self.__jiraUser, self.__jiraPassword))
        self.__greenhopper = GreenHopper(options,
                                         basic_auth=(self.__jiraUser,
                                                     self.__jiraPassword))

    ## Kill the jira connection
    # @param self The object pointer
    def killSession(self):
        self.__jira.kill_session()
        self.__greenhopper.kill_session()

    ## Add the epic link to an issue
    # @param self The object pointer
    # @param issue The issue ID
    # @param epic The epic ID
    def attachEpic(self, issue, epic):
        #attach the epic
        self.__greenhopper.add_issues_to_epic(epic, [issue])

    ## Create an issue set by calling the createIssue and createSubtask methods
    # @param self The object pointer
    # @param project The project to add the issue to
    # @param name The summary of the issue
    # @param priority The priority of the issue
    # @param product The software product the requirement belongs to (e.g. Device, Apollo, Cloud)
    # @param components The components to add to the issues
    # @returns A dictionary of issues that were created
    def createIssueSet(self, project, name, priority, product, components):
        #dictionary to store jira issues
        issues = {}

        #set up the description
        description = '<h3>User Experience</h3><h3>Acceptance Criteria</h3><ul><li></li></ul>'

        #if we list more than one product that set the product flag to multiple
        productLabel = product

        if (';' in product):
            productLabel = 'Multiple'

        #create the parent issue
        parentID = self.createIssue(project, name, description, 'Story',
                                    priority, productLabel, components)
        issues[parentID] = '%s\t%s\t%s' % (parentID, 'Story', name)

        #create the tasks for development and testing depending on the product
        for specificProduct in product.split(';'):
            issue1 = self.createIssue(
                project, 'Implementation (%s): %s' % (specificProduct, name),
                '', 'Implement', priority, productLabel, components)
            issues[issue1] = '%s\t%s\t%s' % (issue1, 'Implement', name)
            issue2 = self.createIssue(
                project,
                'Create Unit Tests (%s): %s' % (specificProduct, name), '',
                'Unit Test', priority, productLabel, components)
            issues[issue2] = '%s\t%s\t%s' % (issue2, 'Unit Test', name)
            issue3 = self.createIssue(
                project, 'Verification (%s): %s' % (specificProduct, name), '',
                'Verification Test', priority, productLabel, components)
            issues[issue3] = '%s\t%s\t%s' % (issue3, 'Verification Test', name)

            #create the links
            self.linkIssues(parentID, issue1, 'Develop')
            self.linkIssues(parentID, issue2, 'Verify')
            self.linkIssues(parentID, issue3, 'Verify')

        #print the ids
        return (parentID, issues)

    ## Create a new issue
    # @param self The object pointer
    # @param project The project to add the issue to
    # @param summary The summary of the issue
    # @param description The description of the issue
    # @param issueType The type of the issue
    # @param priority The priority of the issue
    # @param product The software product the requirement belongs to (e.g. Device, Apollo, Cloud)
    # @param components The components to add to the issue
    # @returns The JIRA issue identifier
    def createIssue(self, project, summary, description, issueType, priority,
                    product, components):
        #create an issue by setting up the dictionary
        issueDict = {
            'project': {
                'key': project
            },
            'priority': {
                'name': priority
            },
            'summary': summary,
            'description': description,
            'issuetype': {
                'name': issueType
            },
            'labels': ['AddedViaAPI'],
            'customfield_11100': {
                'value': product
            }
        }

        #add the components if there are any
        if (not components == ''):
            issueDict['components'] = self.addComponents(components)

        #now create the issue
        print issueDict
        newIssue = self.__jira.create_issue(fields=issueDict)

        #return the id
        return (newIssue.key)

    ## Create a new epic
    # @param self The object pointer
    # @param project The project to add the issue to
    # @param summary The summary of the issue
    # @param description The description of the issue
    # @param issueType The type of the issue
    # @param priority The priority of the issue
    # @param product The software product the requirement belongs to (e.g. Device, Apollo, Cloud)
    # @param components The components to add to the issue
    # @returns The JIRA issue identifier
    def createEpic(self, project, summary, description, issueType, priority,
                   product, components):
        #create an issue by setting up the dictionary
        issueDict = {
            'project': {
                'key': project
            },
            'priority': {
                'name': priority
            },
            'summary': summary,
            'description': description,
            'issuetype': {
                'name': issueType
            },
            'labels': ['AddedViaAPI'],
            'customfield_11100': {
                'value': product
            },
            'customfield_10401': summary
        }

        #add the components if there are any
        if (not components == ''):
            issueDict['components'] = self.addComponents(components)

        #now create the issue
        print issueDict
        newIssue = self.__greenhopper.create_issue(fields=issueDict)

        #return the id
        return (newIssue.key)

    ## Create a subtask issue
    # @param self The object pointer
    # @param project The project to add the issue to
    # @param summary The summary of the issue
    # @param description The description of the issue
    # @param issueType The type of the issue
    # @param priority The priority of the issue
    # @param product The software product the requirement belongs to (e.g. Device, Apollo, Cloud)
    # @param components The components to add to the task
    # @returns The JIRA issue identifier
    def createSubtask(self, project, parentID, summary, description, issueType,
                      priority, product, components):
        #create an issue by setting up the dictionary
        issueDict = {
            'parent': {
                'id': parentID
            },
            'project': {
                'key': project
            },
            'priority': {
                'name': priority
            },
            'summary': summary,
            'description': description,
            'issuetype': {
                'name': issueType
            },
            'labels': ['AddedViaAPI'],
            'customfield_11100': {
                'value': product
            }
        }

        #add the components if there are any
        if (not components == ''):
            issueDict['components'] = self.addComponents(components)

        #now create the issue
        print issueDict
        newIssue = self.__jira.create_issue(fields=issueDict)

        #return the id
        return (newIssue.key)

    ## Link two issues
    # @param self The object pointer
    # @param jiraID1 The JIRA id of the first issue
    # @param jiraID2 The JIRA id of the second issue
    # @param linkType The type of connect
    def linkIssues(self, jiraID1, jiraID2, linkType):
        #now link the two issues
        print "Linking %s and %s" % (jiraID1, jiraID2)
        self.__jira.create_issue_link(type=linkType,
                                      inwardIssue=jiraID2,
                                      outwardIssue=jiraID1)

    ## Create an array from a ";"-separated list, used for populating components
    # @param self The object pointer
    # @param componentString The string to be parsed
    # @returns The array of components
    def addComponents(self, componentString):
        tokens = componentString.split(';')
        components = []

        #populate the array
        for token in tokens:
            components.append({'name': token})

        return (components)
Example #12
0
class jira_handler:
    def __init__(self, project_name):
        self.mongo_db = mongodb_class.mongoDB()
        self.jira = JIRA('http://172.16.60.13:8080',
                         basic_auth=('shenwei', 'sw64419'))
        self.gh = GreenHopper({'server': 'http://172.16.60.13:8080'},
                              basic_auth=('shenwei', 'sw64419'))
        self.name = project_name
        self.project = self.jira.project(self.name)
        self.pj_name = u"%s" % self.project.name
        self.pj_manager = u"%s" % self.project.lead.displayName
        """获取项目版本信息
        """
        _versions = self.jira.project_versions(self.name)
        self.version = {}
        for _v in _versions:
            _key = (u"%s" % _v).replace('.', '^')
            if not self.version.has_key(_key):
                self.version[_key] = {}
            self.version[_key][u"id"] = _v.id
            self.version[_key]['startDate'] = ""
            self.version[_key]['releaseDate'] = ""
            if 'startDate' in dir(_v):
                self.version[_key]['startDate'] = _v.startDate
            if 'releaseDate' in dir(_v):
                self.version[_key]['releaseDate'] = _v.releaseDate
            if self.mongo_db.get_count("project", {"version": _key}) > 0:
                self.mongo_db.handler(
                    "project", "update", {"version": _key},
                    dict({"version": _key}, **self.version[_key]))
            else:
                _val = dict({"version": _key}, **self.version[_key])
                print _val
                self.mongo_db.handler("project", "insert", _val)
        self.issue = None

    def _get_board(self):
        _boards = self.jira.boards()
        for _b in _boards:
            if self.name in _b.name:
                return _b.id
        return None

    def get_current_sprint(self):
        """
        获取本阶段sprint名称
        :return: 返回状态为ACTIVE的sprint的名称
        """
        _b_id = self._get_board()
        if type(_b_id) is not types.NoneType:
            _sprints = self.jira.sprints(_b_id)
            for _s in _sprints:
                if _s.state == 'ACTIVE':
                    return _s.name
        return None

    def get_sprint(self):
        if "customfield_10501" in self.issue.raw['fields'] and \
                type(self.issue.fields.customfield_10501) is not types.NoneType:
            return u'%s' % self.issue.fields.customfield_10501[0].split(
                'name=')[1].split(',')[0]
        return None

    def get_versions(self):
        _v = {}
        for _k in self.version:
            _key = (u"%s" % _k).replace('^', '.')
            _v[_key] = self.version[_k]
        return _v

    def get_pj_info(self):
        return {'pj_name': self.pj_name, 'pj_manager': self.pj_manager}

    def set_issue_by_name(self, issue_id):
        self.issue = self.jira.issue(issue_id)

    def print_green_hopper(self):
        _f = self.gh.fields()
        for __f in _f:
            __cns = __f['clauseNames']
            print('-' * 8)
            for _n in __cns:
                print u"name: %s" % _n
            print "id: ", u"%s" % __f['id']
            print "name: ", u"%s" % __f['name']

    def get_story_point(self):
        """
        获取Issue(story)的预置成本, 1 point = 4 hours
        :return: 预置成本
        """
        if "customfield_10304" in self.issue.raw['fields'] and \
                type(self.issue.fields.customfield_10304) is not types.NoneType:
            return self.issue.fields.customfield_10304
        return None

    def get_task_time(self):
        return {
            "agg_time": self.issue.fields.aggregatetimeestimate,
            "org_time": self.issue.fields.timeoriginalestimate,
            "spent_time": self.issue.fields.timespent
        }

    def get_landmark(self):
        if len(self.issue.fields.fixVersions) > 0:
            return u"%s" % self.issue.fields.fixVersions[0]
        if len(self.issue.fields.versions) > 0:
            print self.show_name(
            ), " version: %s" % self.issue.fields.versions[0]
            return u"%s" % self.issue.fields.versions[0]
        return ""

    def get_desc(self):
        return u"%s" % self.issue.fields.summary

    def show_name(self):
        return u"%s" % str(self.issue)

    def get_type(self):
        return u"%s" % self.issue.fields.issuetype

    def get_status(self):
        return u"%s" % self.issue.fields.status

    def get_subtasks(self):
        """
        收集issue的相关子任务的issue
        :return: 相关issue字典
        """
        link = {}
        if not link.has_key(self.show_name()):
            link[self.show_name()] = []
        _task_issues = self.issue.fields.subtasks
        for _t in _task_issues:
            link[self.show_name()].append(u"%s" % _t)
        return link

    def get_child_requirement(self):

        link = []
        jql = "issue in  childrenOfParentRequirement('%s')" % self.show_name()
        # print jql
        tot = 0
        while True:
            issues = self.jira.search_issues(jql, maxResults=100, startAt=tot)
            for issue in issues:
                link.append(issue.key)
            if len(issues) == 100:
                tot += 100
            else:
                break
        return link

    def get_link(self):
        """
        收集issue的相关issue
        :return: 相关issue字典
        """
        link = {}
        if self.show_name() not in link:
            link[self.show_name()] = []
        """兼容以前: 与story相关的task是通过issulelinks关联的"""
        _task_issues = self.issue.fields.issuelinks
        for _t in _task_issues:
            if "outwardIssue" in dir(_t):
                """该story相关的任务"""
                link[self.show_name()].append(u"%s" % _t.outwardIssue)
            if "inwardIssue" in dir(_t):
                """该story相关的任务"""
                link[self.show_name()].append(u"%s" % _t.inwardIssue)
        """采用synapseRT插件后对需求的管理"""
        _task_issues = self.get_child_requirement()
        for _t in _task_issues:
            link[self.show_name()].append(_t)

        return link

    def show_issue(self):
        """
        显示issue信息
        :return:
        """
        print("[%s]-%s" % (self.show_name(), self.get_desc())),
        print u"类型:%s" % self.get_type(),
        print(u'状态:%s' % self.get_status()),

        print u"里程碑:%s" % self.get_landmark(),
        _time = self.get_task_time()
        """
        if type(_time['agg_time']) is types.NoneType:
            _time['agg_time'] = ""
        if type(_time['org_time']) is types.NoneType:
            _time['org_time'] = ""
        if type(_time["spent_time"]) is types.NoneType:
            _time["spent_time"] = ""
        """
        if "customfield_11300" in self.issue.raw['fields'] and \
                type(self.issue.fields.customfield_11300) is not types.NoneType:
            _epic_link = self.issue.raw['fields']["customfield_11300"]
        else:
            _epic_link = None
        _issue = {
            u"%s" % self.show_name(): {
                "issue_type": self.get_type(),
                "created": self.issue.fields.created,
                "updated": self.issue.fields.updated,
                "lastViewed": self.issue.fields.lastViewed,
                "users": self.get_users(),
                "status": self.get_status(),
                "landmark": self.get_landmark(),
                "point": self.get_story_point(),
                "agg_time": _time['agg_time'],
                "org_time": _time['org_time'],
                "summary": self.issue.fields.summary,
                "spent_time": _time['spent_time'],
                "sprint": self.get_sprint(),
                "epic_link": _epic_link
            }
        }
        _key = u"%s" % self.show_name()
        if self.mongo_db.get_count("issue", {"issue": _key}) > 0:
            self.mongo_db.handler("issue", "update", {"issue": _key},
                                  dict({"issue": _key}, **_issue[_key]))
        else:
            self.mongo_db.handler("issue", "insert",
                                  dict({"issue": _key}, **_issue[_key]))
        if self.mongo_db.get_count("issue_link", {"issue": _key}) > 0:
            self.mongo_db.handler("issue_link", "update", {"issue": _key},
                                  dict({"issue": _key}, **self.get_link()))
        else:
            self.mongo_db.handler("issue_link", "insert",
                                  dict({"issue": _key}, **self.get_link()))

        return _issue

    def get_users(self):
        """
        获取访问issue的用户
        2018.3.1:改为 经办人 assignee
        :return:
        watcher = self.jira.watchers(self.issue)
        _user = u"%s" % (', '.join(watcher.displayName for watcher in watcher.watchers))
        """
        if type(self.issue.raw['fields']["assignee"]) is types.NoneType:
            return None
        return (u"%s" %
                self.issue.raw['fields']["assignee"]['displayName']).replace(
                    ' ', '')

    def write_log(self, info):
        self.mongo_db.handler("log", "insert", info)

    def write_worklog(self, info):
        _search = {
            'issue': info['issue'],
            'author': info['author'],
            'updated': info['updated']
        }
        self.mongo_db.handler('worklog', 'update', _searchinfo)

    def sync_worklog(self):
        worklogs = self.jira.worklogs(self.show_name())
        wl = {}
        for worklog in worklogs:
            wl['issue'] = self.show_name()
            wl['author'] = u'%s' % worklog.author
            wl['comment'] = u'%s' % worklog.comment
            wl['timeSpent'] = worklog.timeSpent
            wl['timeSpentSeconds'] = worklog.timeSpentSeconds
            wl['updated'] = worklog.updated
            self.write_worklog(wl)

    def scan_issue(self, bg_date, keys, version):
        """
        扫描project收集相关版本的issue信息
        :param bg_date: 起始日期,如 2018-1-31
        :param keys: 关键字,[u'story', u'故事']
        :param version: 版本,里程碑
        :return: 按issue类型进行统计值kv_sum,issue链kv_link,相关任务链task_link
        """
        jql_sql = u'project=%s AND created >= %s ORDER BY created DESC' % (
            self.name, bg_date)
        total = 0
        kv_sum = {}
        kv_link = {}
        task_link = {}

        while True:
            issues = self.jira.search_issues(jql_sql,
                                             maxResults=100,
                                             startAt=total)
            for issue in issues:

                if (u"%s" % issue.fields.issuetype) not in keys:
                    continue

                self.issue = issue

                if ((u"%s" % issue.fields.issuetype) == 'story' and
                        (self.get_landmark() == version or u'入侵' in self.issue.fields.summary)) or \
                        (u"%s" % issue.fields.issuetype) in [u'epic', u'improvement',
                                                             u'New Feature', u'改进', u'新功能']:
                    """收集story相关的任务"""
                    task_link.update(self.get_link())

                    _type = self.get_type()
                    _status = self.get_status()
                    if not kv_sum.has_key(_type):
                        kv_sum[_type] = 0
                        kv_link[_type] = {}

                    kv_sum[_type] += 1
                    if not (kv_link[_type]).has_key(_status):
                        (kv_link[_type])[_status] = []
                    (kv_link[_type])[_status].append(self.show_name())

            if len(issues) == 100:
                total += 100
            else:
                break
        return kv_sum, kv_link, task_link
Example #13
0
# This script shows how to use the client in anonymous mode
# against jira.atlassian.com.
from six import print_ as print

from jira.client import GreenHopper

# By default, the client will connect to a JIRA instance started from the Atlassian Plugin SDK
# (see https://developer.atlassian.com/display/DOCS/Installing+the+Atlassian+Plugin+SDK for details).
# Override this with the options parameter.
# GreenHopper is a plugin in a JIRA instance
options = {
    'server': 'https://jira.atlassian.com'
}
gh = GreenHopper(options)

# Get all boards viewable by anonymous users.
boards = gh.boards()

# Get the sprints in a specific board
board_id = 441
print("GreenHopper board: %s (%s)" % (boards[0].name, board_id))
sprints = gh.sprints(board_id)

# List the incomplete issues in each sprint
for sprint in sprints:
    sprint_id = sprint.id
    print("Sprint: %s" % sprint.name)
    incompleted_issues = gh.incompleted_issues(board_id, sprint_id)
    print("Incomplete issues: %s" %
          ', '.join(issue.key for issue in incompleted_issues))
Example #14
0
                    filename=file_path)

jira_config = get_jira_config()
jira_pwd = (base64.b64decode(jira_config['pwd'])).decode('utf-8')
myjira = JIRA(
    jira_config['url'],
    basic_auth=(jira_config['user'], (base64.b64decode(jira_config['pwd'])).decode('utf-8')),
    logging=True,
    validate=True,
    async_=True,
    async_workers=20,
    options={'verify': False},
)

greenhopper = GreenHopper(
    options={'server': CI_JIRA_URL, 'verify': False},
    basic_auth=(jira_config['user'], jira_pwd)
)


class Testclient(object):
    """
    testrail client, send request, and get info and data
    """
    def __init__(self, base_url):
        self.user = xxxxxxxxx
        self.password = xxxxxxxxx
        if not base_url.endswith('/'):
            base_url += '/'
        self.__url = base_url + 'index.php?/api/v2/'

    def send_get(self, uri, filepath=None):
Example #15
0
                 issue.estimateStatistic.statFieldValue.value)
    if hasattr(issue, 'issue.trackingStatistic.statFieldValue.text'):
        fh.write("remainingtime: %s\n",
                 issue.trackingStatistic.statFieldValue.text)
    fh.write("\n#####################################\n")
    #print issue.assignee, ":", get_email_addr(issue.key), ","


# By default, the client will connect to a JIRA instance started from the Atlassian Plugin SDK
# (see https://developer.atlassian.com/display/DOCS/Installing+the+Atlassian+Plugin+SDK for details).
# Override this with the options parameter.
# GreenHopper is a plugin in a JIRA instance
options = {'server': 'https://issues.citrite.net'}

jira = JIRA(options)
gh = GreenHopper(options)

# Get all boards viewable by anonymous users.
# boards = gh.boards()
board_id = ""
board_name = ""
# for board in boards:
#     if 'scrum-hyd' in board.name.lower():
#         board_id = board.id
#         board_name = board.name
#         break
# Get the sprints in a specific board
board_id = 440
board_name = 'CCP QA Scrum'
sprint_id = 1578
print("GreenHopper board: %s (%s)" % (board_name, board_id))
Example #16
0
# This script shows how to use the client in anonymous mode
# against jira.atlassian.com.
from jira.client import GreenHopper

# By default, the client will connect to a Jira instance started from the Atlassian Plugin SDK
# (see https://developer.atlassian.com/display/DOCS/Installing+the+Atlassian+Plugin+SDK for details).
# Override this with the options parameter.
# GreenHopper is a plugin in a Jira instance
options = {"server": "https://jira.atlassian.com"}
gh = GreenHopper(options)

# Get all boards viewable by anonymous users.
boards = gh.boards()

# Get the sprints in a specific board
board_id = 441
print(f"GreenHopper board: {boards[0].name} ({board_id})")
sprints = gh.sprints(board_id)
Example #17
0
# This script shows how to use the client in anonymous mode
# against jira.atlassian.com.
from six import print_ as print

from jira.client import GreenHopper

# By default, the client will connect to a JIRA instance started from the Atlassian Plugin SDK
# (see https://developer.atlassian.com/display/DOCS/Installing+the+Atlassian+Plugin+SDK for details).
# Override this with the options parameter.
# GreenHopper is a plugin in a JIRA instance
options = {'server': 'https://jira.atlassian.com'}
gh = GreenHopper(options)

# Get all boards viewable by anonymous users.
boards = gh.boards()

# Get the sprints in a specific board
board_id = 441
print("GreenHopper board: %s (%s)" % (boards[0].name, board_id))
sprints = gh.sprints(board_id)

# List the incomplete issues in each sprint
for sprint in sprints:
    sprint_id = sprint.id
    print("Sprint: %s" % sprint.name)
    incompleted_issues = gh.incompleted_issues(board_id, sprint_id)
    print("Incomplete issues: %s" % ', '.join(issue.key
                                              for issue in incompleted_issues))
Example #18
0
# Gets velocity and related stuff

#import imp
import sys

sys.path.append('/Users/jmcbride/Code/jira-python')
#print sys.path

from jira.client import GreenHopper
from jira.exceptions import *

options = {
    'server': 'https://jira.rax.io'
}
gh = GreenHopper(options)
e = JIRAError()

# Get all boards available
boards = gh.boards

# Get the DNS board
board_id = 41
#print("Story board: %s (%s)" % (boards[0].name, board_id))
#print("Story board: %s" % (boards[0].name))
#print("Story board: %s" % (board_id), boards)

sprints = gh.sprints(board_id)


# List all sprints
print("%s Sprints for this board:") % (len(sprints))
Example #19
0
 def connect(self):
     self._jira_client = GreenHopper(basic_auth=(self._username,
                                                 self._password),
                                     options={'server': self._server_url})
    if hasattr(issue, 'issue.trackingStatistic.statFieldValue.text'):
        fh.write("remainingtime: %s\n", issue.trackingStatistic.statFieldValue.text)
    fh.write("\n#####################################\n")
    #print issue.assignee, ":", get_email_addr(issue.key), ","


# By default, the client will connect to a JIRA instance started from the Atlassian Plugin SDK
# (see https://developer.atlassian.com/display/DOCS/Installing+the+Atlassian+Plugin+SDK for details).
# Override this with the options parameter.
# GreenHopper is a plugin in a JIRA instance
options = {
    'server': 'https://issues.citrite.net'
}

jira = JIRA(options)
gh = GreenHopper(options)

# Get all boards viewable by anonymous users.
# boards = gh.boards()
board_id = ""
board_name = ""
# for board in boards:
#     if 'scrum-hyd' in board.name.lower():
#         board_id = board.id
#         board_name = board.name
#         break
# Get the sprints in a specific board
board_id = 440
board_name = 'CCP QA Scrum'
sprint_id = 1578
print("GreenHopper board: %s (%s)" % (board_name, board_id))
Example #21
0
class IssueManager:

    ## The constructor
    # @param self The object pointer
    # @param options The option hash
    def __init__(self, options):
        self.__jiraUser = options.user
        self.__jiraPassword = options.password
        self.__jiraURL = options.site
        self.startSession()

    ## Create the connection
    # @param self Teh object pointer
    def startSession(self):
        #now make the connection
        options = {
            'server':self.__jiraURL,
            'verify':False
        }
        self.__jira = JIRA(options, basic_auth=(self.__jiraUser, self.__jiraPassword))
        self.__greenhopper = GreenHopper(options, basic_auth=(self.__jiraUser, self.__jiraPassword))

    ## Kill the jira connection
    # @param self The object pointer
    def killSession(self):
        self.__jira.kill_session()
        self.__greenhopper.kill_session()

    ## Create a new epic
    # @param self The object pointer
    # @param options The option dictionary
    # @returns The JIRA issue identifier
    def createEpic(self, options):
        #create an epic by setting up the dictionary
        issueDict = {
            #'assignee': {'name':'Unassigned'},
            'project': {'key':options.project},
            'priority' : {'name':options.priority},
            'summary': options.epic,
            'customfield_10401': options.epic,
            'description': options.description,
            'issuetype' : {'name':'Epic'},
            'labels':[
                   'AddedViaAPI',
                   'APISetFixVersion'
            ],
        }

        #set up software / hardware product type
        #if we list more than one product that set the product flag to multiple
        productLabel = options.product

        if(';' in options.product):
             productLabel = 'Multiple'

        #see if we are hardware of software
        if options.type == 'Hardware':
            #hardware product
            issueDict['customfield_11200'] = {'value':productLabel}
        else:
            #software product
            issueDict['customfield_11100'] = {'value':productLabel}

        #add the components if there are any
        if(not options.components == ''):
            issueDict['components'] = self.addComponents(options.components)

        #now create the issue
        #print issueDict
        newIssue = self.__greenhopper.create_issue(fields=issueDict)

        #return the id
        return(newIssue.key)

    ## Link two issues
    # @param self The object pointer
    # @param jiraID1 The JIRA id of the first issue
    # @param jiraID2 The JIRA id of the second issue
    # @param linkType The type of connect
    def linkIssues(self, jiraID1, jiraID2, linkType):
        #now link the two issues
        print "Linking %s and %s" % (jiraID1, jiraID2)
        self.__jira.create_issue_link(type=linkType, inwardIssue=jiraID2, outwardIssue=jiraID1)

    ## Create an array from a ";"-separated list, used for populating components
    # @param self The object pointer
    # @param componentString The string to be parsed
    # @returns The array of components
    def addComponents(self, componentString):
        tokens = componentString.split(';')
        components = []

        #populate the array
        for token in tokens:
            components.append( {'name':token} )

        return(components)
def jgreencon(jira_param):
    """ This is the methos used as jira connector """
    jcon = GreenHopper(options={'server': jira_param[0]},
                       basic_auth=(jira_param[1], jira_param[2]))
    return jcon
Example #23
0
#   ===============================
#

from jira import JIRA
from jira.client import GreenHopper
import io

import types, json
import sys

options = {
    'server': 'http://jira.chinacloud.com.cn',
}

jira = JIRA('http://jira.chinacloud.com.cn', basic_auth=('shenwei', 'sw64419'))
gh = GreenHopper(options, basic_auth=('shenwei', 'sw64419'))
fd = io.open('date_desc.txt', 'w+', encoding='utf-8')


def _print(s):
    global fd

    fd.write(u"%s" % s)
    fd.write(u"\n")
    print(s)


def test(custom_name):
    # Fetch all fields
    allfields = jira.fields()
    # Make a map from field name -> field id
Example #24
0
	def GreenHopper_connect(self, username, password, options):
		print('authenticating with JIRA Greenhopper...')
		gh = GreenHopper(basic_auth=(username, password), options = options)
		print('authenticated with GreenHopper. ')
		return gh
Example #25
0
class jira_handler:
    """
    Jira处理类。
    【备注】:目前存在Jira方法与Issue对象混合在一起的不足。
    【改进】:将Jira方法与Issue对象实体分离,各自进行类定义。
    """

    def __init__(self, project_name):
        self.mongo_db = mongodb_class.mongoDB(project_name)
        self.jira = JIRA('http://172.16.60.13:8080', basic_auth=('shenwei','sw64419'))
        self.gh = GreenHopper({'server': 'http://172.16.60.13:8080'}, basic_auth=('shenwei', 'sw64419'))
        self.name = project_name
        self.project = self.jira.project(self.name)
        self.pj_name = u"%s" % self.project.name
        self.pj_manager = u"%s" % self.project.lead.displayName
        """获取项目版本信息
        """
        _versions = self.jira.project_versions(self.name)
        self.version = {}
        self.sprints = self._get_sprints()
        for _v in _versions:
            _key = (u"%s" % _v).replace('.', '^')
            if not self.version.has_key(_key):
                self.version[_key] = {}
            self.version[_key][u"id"] = _v.id
            self.version[_key]['startDate'] = ""
            self.version[_key]['releaseDate'] = ""
            if 'startDate' in dir(_v):
                self.version[_key]['startDate'] = _v.startDate
            if 'releaseDate' in dir(_v):
                self.version[_key]['releaseDate'] = _v.releaseDate
            self.mongo_db.handler("project", "update",
                                  {"version": _key}, dict({"version": _key}, **self.version[_key]))
        self.issue = None

    def _get_board(self):
        _boards = self.jira.boards()
        for _b in _boards:
            if self.name.upper() in _b.name.upper():
                return _b.id
        return None

    def transDate(self, str):
        print("---> transDate [%s] <---" % str)
        if str != None and str != u'无':
            _s = str.\
                replace(u'十一月', '11').\
                replace(u'十二月', '12').\
                replace(u'一月', '1').\
                replace(u'二月', '2').\
                replace(u'三月', '3').\
                replace(u'四月', '4').\
                replace(u'五月', '5').\
                replace(u'六月', '6').\
                replace(u'七月', '7').\
                replace(u'八月', '8').\
                replace(u'九月', '9').\
                replace(u'十月', '10')
            _time = time.strptime(_s, '%d/%m/%y')
            return time.strftime('%Y-%m-%d', _time)
        else:
            return ""

    def _get_sprints(self):
        """
        获取看板内sprint列表
        :return: sprint列表 [ name, startDate, endDate, state ]
        """
        _list = []
        _b_id = self._get_board()
        if type(_b_id) is not types.NoneType:
            _sprints = self.jira.sprints(_b_id)
            for _s in _sprints:
                _sprint = self.jira.sprint(_s.id)
                _data = {'name': _s.name,
                         'startDate': self.transDate(_sprint.startDate.split(' ')[0]),
                         'endDate': self.transDate(_sprint.endDate.split(' ')[0]),
                         'state': _s.state
                         }
                _list.append(_data)
            return _list
        return None

    def get_sprints(self):
        return self.sprints

    def get_current_sprint(self):
        """
        获取本阶段sprint名称
        :return: 返回状态为ACTIVE的sprint的名称
        """
        if type(self.sprints) is not types.NoneType:
            for _s in self.sprints:
                if _s['state'] == 'ACTIVE':
                    return (_s['name'], _s['startDate'], _s['endDate']), _next
                _next = (_s['name'], _s['startDate'], _s['endDate'])
        return None

    def get_sprint(self):
        """
        获取当前Issue的sprint定义
        :return: sprint定义
        """
        if "customfield_10501" in self.issue.raw['fields'] and \
                type(self.issue.fields.customfield_10501) is not types.NoneType:
            return u'%s' % (",".join(item.split('name=')[1].split(',')[0]
                                      for item in self.issue.fields.customfield_10501))
            # return u'%s' % self.issue.fields.customfield_10501[0].split('name=')[1].split(',')[0]
        return None

    def get_versions(self):
        _v = {}
        for _k in self.version:
            _key = (u"%s" % _k).replace('^', '.')
            _v[_key] = self.version[_k]
        return _v

    def get_pj_info(self):
        return {'pj_name': self.pj_name, 'pj_manager': self.pj_manager}

    def set_issue_by_name(self, issue_id):
        self.issue = self.jira.issue(issue_id)

    def print_green_hopper(self):
        _f = self.gh.fields()
        for __f in _f:
            __cns = __f['clauseNames']
            print('-' * 8)
            for _n in __cns:
                print u"name: %s" % _n
            print "id: ", u"%s" % __f['id']
            print "name: ", u"%s" % __f['name']

    def get_story_point(self):
        """
        获取Issue(story)的预置成本, 1 point = 4 hours
        :return: 预置成本
        """
        if "customfield_10304" in self.issue.raw['fields'] and \
                type(self.issue.fields.customfield_10304) is not types.NoneType:
            return self.issue.fields.customfield_10304
        return None

    def get_task_time(self):
        return {"agg_time": self.issue.fields.aggregatetimeestimate,
                "org_time": self.issue.fields.timeoriginalestimate,
                "spent_time": self.issue.fields.timespent}

    def get_landmark(self):
        if len(self.issue.fields.fixVersions) > 0:
            return u"%s" % self.issue.fields.fixVersions[0]
        if len(self.issue.fields.versions) > 0:
            # print self.show_name(), " version: %s" % self.issue.fields.versions[0]
            return u"%s" % self.issue.fields.versions[0]
        return ""

    def get_desc(self):
        return self.issue.fields.summary

    def show_name(self):
        return str(self.issue)

    def get_type(self):
        return u"%s" % self.issue.fields.issuetype

    def get_status(self):
        """
        获取Issue的状态,待办、处理中、待测试、测试中、完成
        :return:
        """
        return u"%s" % self.issue.fields.status

    def get_subtasks(self):
        """
        收集issue的相关子任务的issue
        :return: 相关issue字典
        """
        link = {}
        if not link.has_key(self.show_name()):
            link[self.show_name()] = []
        _task_issues = self.issue.fields.subtasks
        for _t in _task_issues:
            link[self.show_name()].append(u"%s" % _t)
        return link

    def get_child_requirement(self):

        link = []
        jql = "issue in  childrenOfParentRequirement('%s')" % self.show_name()
        # print jql
        tot = 0
        while True:
            issues = self.jira.search_issues(jql, maxResults=100, startAt=tot)
            for issue in issues:
                link.append(issue.key)
            if len(issues) == 100:
                tot += 100
            else:
                break
        return link

    def get_epic_link(self, jql):

        print(">>> get_epic_link<%s>" % jql)
        total = 0
        _issue_name = self.show_name()
        task_link = {_issue_name: []}
        while True:
            issues = self.jira.search_issues(jql, maxResults=100, startAt=total)
            for issue in issues:
                self.issue = issue
                self.sync_issue()
                """收集epic相关的story和任务"""
                task_link[_issue_name].append(self.show_name())
            if len(issues) == 100:
                total += 100
            else:
                break
        print task_link
        self.set_issue_by_name(_issue_name)
        return task_link

    def get_link(self):
        """
        收集issue的相关issue
        :return: 相关issue字典
        """
        link = {self.show_name(): []}

        """兼容以前: 与story相关的task是通过issulelinks关联的"""
        _task_issues = self.issue.fields.issuelinks
        for _t in _task_issues:
            if "outwardIssue" in dir(_t):
                """该story相关的任务"""
                link[self.show_name()].append(u"%s" % _t.outwardIssue)
            if "inwardIssue" in dir(_t):
                """该story相关的任务"""
                link[self.show_name()].append(u"%s" % _t.inwardIssue)

        """采用synapseRT插件后对需求的管理"""
        _task_issues = self.get_child_requirement()
        for _t in _task_issues:
            link[self.show_name()].append(_t)

        return link

    def sync_issue(self):
        """
        同步issue数据,同时完成重要参量的变更日志。
        :return:
        """
        _components = u"%s" % (', '.join(comp.name for comp in self.issue.fields.components))
        _key = u"%s" % self.show_name()
        _time = self.get_task_time()
        _epic_link = None
        if "customfield_11300" in self.issue.raw['fields'] and \
                type(self.issue.fields.customfield_11300) is not types.NoneType:
            _epic_link = self.issue.raw['fields']["customfield_11300"]
        _issue = {u"%s" % self.show_name(): {
                "issue_type": self.get_type(),
                "created": self.issue.fields.created,
                "updated": self.issue.fields.updated,
                "lastViewed": self.issue.fields.lastViewed,
                "users": self.get_users(),
                "status": self.get_status(),
                "landmark": self.get_landmark(),
                "point": self.get_story_point(),
                "agg_time": _time['agg_time'],
                "org_time": _time['org_time'],
                "summary": self.issue.fields.summary,
                "spent_time": _time['spent_time'],
                "sprint": self.get_sprint(),
                "epic_link": _epic_link,
                "components": _components
            }}
        _old_issue = self.mongo_db.handler("issue", "find_one", {"issue": _key})
        if _old_issue is None:
            self.mongo_db.handler("issue", "update",
                                  {"issue": _key}, dict({"issue": _key}, **_issue[_key]))
        else:
            _change = False
            for _item in ['issue_type','created','updated','users','status',
                          'landmark','point','agg_time','org_time',
                          'summary','spent_time','sprint','epic_link']:
                if _old_issue[_item] != _issue[_key][_item]:
                    _log = {"issue_id": _key, "key": _item,
                            "old": _old_issue[_item], "new": _issue[_key][_item]}
                    self.write_log(_log)
                    _change = True
            _change = True
            if _change:
                self.mongo_db.handler("issue", "update",
                                      {"issue": _key}, dict({"issue": _key}, **_issue[_key]))

    def get_issue_link(self):
        _link = self.get_link()
        print "---> get_issue_link: ", _link
        return _link

    def sync_issue_link(self):
        _key = u"%s" % self.show_name()
        _link = self.get_link()

        print "sync_issue_link: ", _link

        self.mongo_db.handler("issue_link", "update",
                              {"issue": _key}, dict({"issue": _key}, **_link))
        return _link

    def show_issue(self):
        """
        显示issue信息
        :return:
        """
        print(u"[%s]" % self.show_name()),
        print u"类型:%s" % self.get_type(),
        print(u'状态:%s' % self.get_status()),
        print u"里程碑:%s" % self.get_landmark()

    def get_users(self):
        """
        获取访问issue的用户
        2018.3.1:改为 经办人 assignee
        :return:
        watcher = self.jira.watchers(self.issue)
        _user = u"%s" % (', '.join(watcher.displayName for watcher in watcher.watchers))
        """
        if type(self.issue.raw['fields']["assignee"]) is types.NoneType:
            return None
        return (u"%s" % self.issue.raw['fields']["assignee"]['displayName']).replace(' ', '')

    def write_log(self, info):
        print "---<write_log>---: ",info
        self.mongo_db.handler("log", "insert", info)

    def write_worklog(self, info):
        """
        写入或更新 工作日志记录。
        :param info: 新的日志数据
        :return:
        """
        if not info.has_key("comment"):
            return

        _search = {'issue': info['issue'],
                   'id': info['id']}
        self.mongo_db.handler('worklog', 'update', _search, info)

    def clear_worklog(self, worklog_id):
        """
        清除"不存在"的记录!
        :param worklog_id: 存在的worklog_id
        :return:
        """
        _set = {'timeSpentSeconds': 0}
        if len(worklog_id) > 0:
            _search = {"issue": self.show_name(), "id": {"$not": {"$in": worklog_id}}}
        else:
            _search = {"issue": self.show_name()}
        _one = self.mongo_db.handler('worklog', 'find_one', _search)
        if _one is None:
            return
        # self.mongo_db.handler('worklog', 'remove', _search)
        """保留原记录,将其用时值设置为0,以便事后跟踪
        """
        self.mongo_db.handler('worklog', 'update', _search, _set)

    def sync_worklog(self):
        """
        获取指定 issue 的工作日志记录。
        - 2018.4.2:针对以前有的,但现在没有的 日志记录 的处理?!清除其spent时间
        :return:
        """
        worklogs = self.jira.worklogs(self.show_name())
        wl = {}
        _id = []
        for worklog in worklogs:
            wl['issue'] = self.show_name()
            wl['author'] = u'%s' % worklog.author
            wl['comment'] = u'%s' % worklog.comment
            wl['timeSpent'] = worklog.timeSpent
            wl['timeSpentSeconds'] = worklog.timeSpentSeconds
            wl['updated'] = worklog.updated
            wl['created'] = worklog.created
            wl['started'] = worklog.started
            wl['id'] = worklog.id
            _id.append(worklog.id)
            self.write_worklog(wl)
        """同时同步Issue的变动日志"""
        """ 因worklog可随意更改或删除, 有必要实时清除多余的记录!"""
        self.clear_worklog(_id)

        self.sync_changelog()

    def scan_task_by_sprint(self, sprint):
        """
        通过sprint获取Issue,以便获取它们的 工作日志
        :param sprint: 当前的sprint名称
        :return: Issue列表
        """
        jql_sql = u'project=%s AND Sprint = "%s" ORDER BY created DESC' %\
                  (self.name, sprint)
        total = 0
        tasks = []
        while True:
            issues = self.jira.search_issues(jql_sql, maxResults=100, startAt=total)
            for issue in issues:
                self.issue = issue
                """同步issue"""
                self.sync_issue()
                self.sync_worklog()
                self.sync_issue_link()
                tasks.append(self.show_name())
            if len(issues) == 100:
                total += 100
            else:
                break
        return tasks

    def scan_epic(self, bg_date):
        """
        扫描project收集epic信息
        :param bg_date: 起始日期,如 2018-1-31
        :param issue_type:指定issue类型
        :return: 按issue类型进行统计值kv_sum,issue链kv_link,相关任务链task_link
        """
        jql_sql = u'project=%s AND issuetype=epic AND created >= %s ORDER BY created DESC' % (
            self.name, bg_date)
        total = 0
        story_link = []

        while True:
            issues = self.jira.search_issues(jql_sql, maxResults=100, startAt=total)
            for issue in issues:
                self.issue = issue
                """同步issue"""
                # self.show_issue()
                self.sync_issue()
                """收集epic相关的story和任务"""
                _jql = u'project=%s AND "Epic Link"=%s AND created >= %s ORDER BY created DESC' % \
                       (self.name, self.show_name(), bg_date)
                _link = self.get_epic_link(_jql)
                """同步epic的link"""
                # print "--> epic link: ", dict({"issue": self.show_name()}, **_link)
                self.mongo_db.handler("issue_link", "update",
                                      {"issue": self.show_name()},
                                      dict({"issue": self.show_name()}, **_link))
                story_link += _link[self.show_name()]

            if len(issues) == 100:
                total += 100
            else:
                break
        return story_link

    def scan_story(self, bg_date):
        """
        按 project 获取其下所有 story 数据。
        :param bg_date: 开始搜索的日期
        :return:
        """
        jql_sql = u'project=%s AND issuetype=story AND created >= %s ORDER BY created DESC' % (
            self.name, bg_date)
        total = 0
        task_link = []

        while True:
            issues = self.jira.search_issues(jql_sql, maxResults=100, startAt=total)
            for issue in issues:
                self.issue = issue
                """同步issue"""
                # self.show_issue()
                self.sync_issue()
                """收集story相关的任务"""
                _link = self.sync_issue_link()
                """同步epic的link"""
                self.mongo_db.handler("issue_link", "update",
                                      {"issue": self.show_name()},
                                      dict({"issue": self.show_name()}, **_link))
                task_link += _link[self.show_name()]

            if len(issues) == 100:
                total += 100
            else:
                break
        return task_link

    def scan_task(self, bg_date):
        """
        按 project 获取其下所有与执行相关的 issue 数据。
        :param bg_date: 开始搜索的日期
        :return:
        """
        jql_sql = u'project=%s AND ( issuetype=task OR' \
                  u' issuetype=任务 OR' \
                  u' issuetype=故障 OR' \
                  u' issuetype=Bug OR' \
                  u' issuetype=Sub-task OR' \
                  u' issuetype=子任务 ) AND' \
                  u' created >= %s ORDER BY created DESC' % (self.name, bg_date)
        print jql_sql
        total = 0
        task_link = []

        while True:
            issues = self.jira.search_issues(jql_sql, maxResults=100, startAt=total)
            for issue in issues:
                self.issue = issue
                """同步issue"""
                self.show_issue()
                self.sync_issue()
                # self.sync_changelog()
                self.sync_worklog()
                task_link.append(self.show_name())
            if len(issues) == 100:
                total += 100
            else:
                break
        return task_link

    def sync_changelog(self):
        """
        获取指定 issue 的 变更日志记录
        :return:
        """
        issue = self.jira.issue(self.show_name(), expand='changelog')
        changelog = issue.changelog
        for history in changelog.histories:
            for item in history.items:
                _data = {'issue': self.show_name(),
                         'field': item.field,
                         'author': u"%s" % history.author,
                         'date': history.created,
                         'old': getattr(item, 'fromString'),
                         'new': getattr(item, 'toString')
                         }
                if self.mongo_db.handler('changelog', 'find_one', _data) is None:
                    self.mongo_db.handler('changelog', 'insert', _data)
Example #26
0
class IssueManager:

    ## The constructor
    # @param self The object pointer
    # @param jiraURL The url of the JIRA instance
    # @param jiraUser The user name to use
    # @param jiraPassword The user password to use
    def __init__(self, jiraURL, jiraUser, jiraPassword):
        self.__jiraUser = jiraUser
        self.__jiraPassword = jiraPassword
        self.__jiraURL = jiraURL
        self.startSession()

    ## Create the connection
    # @param self Teh object pointer
    def startSession(self):
        #now make the connection
        options = {
            'server':self.__jiraURL,
            'verify':False
        }
        self.__jira = JIRA(options, basic_auth=(self.__jiraUser, self.__jiraPassword))
        self.__greenhopper = GreenHopper(options, basic_auth=(self.__jiraUser, self.__jiraPassword))

    ## Kill the jira connection
    # @param self The object pointer
    def killSession(self):
        self.__jira.kill_session()
        self.__greenhopper.kill_session()

    ## Add the epic link to an issue
    # @param self The object pointer
    # @param issue The issue ID
    # @param epic The epic ID
    def attachEpic(self, issue, epic):
        #attach the epic
        self.__greenhopper.add_issues_to_epic(epic, [issue])

    ## Create an issue set by calling the createIssue and createSubtask methods
    # @param self The object pointer
    # @param project The project to add the issue to
    # @param name The summary of the issue
    # @param priority The priority of the issue
    # @param product The software product the requirement belongs to (e.g. Device, Apollo, Cloud)
    # @param components The components to add to the issues
    # @param version The fix version
    # @returns A dictionary of issues that were created
    def createIssueSet(self, project, name, priority, product, components, version):
        #dictionary to store jira issues
        issues = {}

        #set up the description
        description = '<h3>User Experience</h3><h3>Acceptance Criteria</h3><ul><li></li></ul>'

        #if we list more than one product that set the product flag to multiple
        productLabel = product

        if(';' in product):
             productLabel = 'Multiple'

        #create the parent issue
        parentID = self.createIssue(project, name, description, 'Story', priority, productLabel, components, version)
        issues[parentID] = '%s\t%s\t%s' % (parentID, 'Story', name)

        #create the tasks for development and testing depending on the product
        for specificProduct in product.split(';'):
            issue1 = self.createIssue(project, 'Implementation (%s): %s' % (specificProduct, name), '', 'Implement', priority, productLabel, components, version)
            issues[issue1] = '%s\t%s\t%s' % (issue1, 'Implement', name)
            issue2 = self.createIssue(project, 'Create Unit Tests (%s): %s' % (specificProduct, name), '', 'Unit Test', priority, productLabel, components, version)
            issues[issue2] = '%s\t%s\t%s' % (issue2, 'Unit Test', name)
            issue3 = self.createIssue(project, 'Verification (%s): %s' % (specificProduct, name), '', 'Verification Test', priority, productLabel, components, version)
            issues[issue3] = '%s\t%s\t%s' % (issue3, 'Verification Test', name)

            #create the links
            self.linkIssues(parentID, issue1, 'Develop')
            self.linkIssues(parentID, issue2, 'Verify')
            self.linkIssues(parentID, issue3, 'Verify')

        #print the ids
        return(parentID, issues)

    ## Create a new issue
    # @param self The object pointer
    # @param project The project to add the issue to
    # @param summary The summary of the issue
    # @param description The description of the issue
    # @param issueType The type of the issue
    # @param priority The priority of the issue
    # @param product The software product the requirement belongs to (e.g. Device, Apollo, Cloud)
    # @param components The components to add to the issue
    # @param version The fix version
    # @returns The JIRA issue identifier
    def createIssue(self, project, summary, description, issueType, priority, product, components, version):
        #create an issue by setting up the dictionary
        issueDict = {
            #'assignee': {'name':'Unassigned'},
            'project': {'key':project},
            'priority' : {'name':priority},
            'summary': summary,
            'description': description,
            'issuetype' : {'name':issueType},
            'labels':[
                   'AddedViaAPI',
                   'APISetFixVersion'
            ],
            'customfield_11100': {'value':product}
        }

        #if it is a story type then we want ot add a label for acceptance criteria too
        if issueType == 'Story':
            issueDict['labels'].append('NeedAcceptanceCriteria')

        #add the components if there are any
        if(not components == ''):
            issueDict['components'] = self.addComponents(components)

        #now create the issue
        print issueDict
        newIssue = self.__jira.create_issue(fields=issueDict)

        #return the id
        return(newIssue.key)

    ## Create a new epic
    # @param self The object pointer
    # @param project The project to add the issue to
    # @param summary The summary of the issue
    # @param description The description of the issue
    # @param issueType The type of the issue
    # @param priority The priority of the issue
    # @param product The software product the requirement belongs to (e.g. Device, Apollo, Cloud)
    # @param components The components to add to the issue
    # @param version The fix version
    # @returns The JIRA issue identifier
    def createEpic(self, project, summary, description, issueType, priority, product, components, version):
        #create an issue by setting up the dictionary
        issueDict = {
            #'project': {'key':project},
            'priority' : {'name':priority},
            'summary': summary,
            'description': description,
            'issuetype' : {'name':issueType},
            'labels':[
                   'AddedViaAPI',
                   'APISetFixVersion'
            ],
            'customfield_11100': {'value':product},
            'customfield_10401': summary
        }

        #add the components if there are any
        if(not components == ''):
            issueDict['components'] = self.addComponents(components)

        #now create the issue
        print issueDict
        newIssue = self.__greenhopper.create_issue(fields=issueDict)

        #return the id
        return(newIssue.key)

    ## Create a subtask issue
    # @param self The object pointer
    # @param project The project to add the issue to
    # @param summary The summary of the issue
    # @param description The description of the issue
    # @param issueType The type of the issue
    # @param priority The priority of the issue
    # @param product The software product the requirement belongs to (e.g. Device, Apollo, Cloud)
    # @param components The components to add to the task
    # @param version The fixVersion
    # @returns The JIRA issue identifier
    def createSubtask(self, project, parentID, summary, description, issueType, priority, product, components):
        #create an issue by setting up the dictionary
        issueDict = {
            'parent':{'id':parentID},
            'project': {'key':project},
            'priority' : {'name':priority},
            'summary': summary,
            'description': description,
            'issuetype' : {'name':issueType},
            'labels':[
                   'AddedViaAPI',
                   'APISetFixVersion'
            ],
            'customfield_11100': {'value':product}
        }

        #add the components if there are any
        if(not components == ''):
            issueDict['components'] = self.addComponents(components)

        #now create the issue
        print issueDict
        newIssue = self.__jira.create_issue(fields=issueDict)

        #return the id
        return(newIssue.key)

    ## Link two issues
    # @param self The object pointer
    # @param jiraID1 The JIRA id of the first issue
    # @param jiraID2 The JIRA id of the second issue
    # @param linkType The type of connect
    def linkIssues(self, jiraID1, jiraID2, linkType):
        #now link the two issues
        print "Linking %s and %s" % (jiraID1, jiraID2)
        self.__jira.create_issue_link(type=linkType, inwardIssue=jiraID2, outwardIssue=jiraID1)

    ## Create an array from a ";"-separated list, used for populating components
    # @param self The object pointer
    # @param componentString The string to be parsed
    # @returns The array of components
    def addComponents(self, componentString):
        tokens = componentString.split(';')
        components = []

        #populate the array
        for token in tokens:
            components.append( {'name':token} )

        return(components)
Example #27
0
class JiraAgent:
    def __init__(self, server_url, username, password):
        self._server_url = server_url
        self._username = username
        self._password = password

        self._jira_client = None

    def connect(self):
        self._jira_client = GreenHopper(basic_auth=(self._username,
                                                    self._password),
                                        options={'server': self._server_url})

    def retrieve_sprint_id(self, board_id, sprint_name):
        sprints_dto = self._jira_client.sprints(board_id)
        for sprint_dto in sprints_dto:
            if sprint_dto.name.strip() == sprint_name:
                return sprint_dto.id

        return ''

    def retrieve_sprint_info(self, sprint_id):
        response = requests.get(
            F'{self._server_url}/rest/agile/1.0/sprint/{sprint_id}',
            auth=(self._username, self._password))
        response_json = response.json()

        start_date = response_json['startDate'][:10]
        end_date = response_json['completeDate'][:10]

        return SprintInfo(start_date, end_date)

    def download_work_log_of_sprint(self, sprint_id):
        query = F'sprint={sprint_id} AND (type="Task" OR type="Sub-task" OR type="Bug") AND status="Done"'
        issues_dto = self._jira_client.search_issues(query, maxResults=160)

        return self._download_details_of_issues(issues_dto)

    def _download_details_of_issues(self, issues_dto):
        issues = []
        progress_bar = tqdm(total=issues_dto.total)

        for issue_dto in issues_dto:
            detailed_issue_dto = self._jira_client.issue(issue_dto.key)

            work_log = self._collect_work_log(
                detailed_issue_dto.fields.worklog.worklogs)
            time_data = IssueTimeData(
                issue_dto.fields.timeoriginalestimate or 0,
                issue_dto.fields.aggregatetimespent or 0, work_log)
            issue = Issue(issue_dto.key, issue_dto.fields.summary,
                          issue_dto.permalink(), time_data)
            issues.append(issue)

            progress_bar.update(1)

        progress_bar.close()

        return issues

    def _collect_work_log(self, work_logs_dto):
        work_log_items = []

        for work_log_dto in work_logs_dto:
            author = work_log_dto.author.displayName
            comment = work_log_dto.comment
            creation_date = work_log_dto.created
            spent_time = work_log_dto.timeSpentSeconds

            work_log_item = WorkLogItem(author, creation_date, spent_time,
                                        comment)

            work_log_items.append(work_log_item)

        return work_log_items