コード例 #1
0
ファイル: jira_access.py プロジェクト: GripQA/client-tools
def get_sprint_list(api, proj_name2key_map, authenticate):
    """Retrieves the projects sprints

    Sprint data "may" be available through another REST API. We use this
    API to retrieve information about the project's sprints

    Args:
        api - string containing the URL component for the desired API
        proj_name2key_map - maps from poject names to project keys
        authenticate - tuple containing username & password to log into JIRA

    Returns:
        List containing sprint dictionaries
    """
    sprint_list = []
    view_id_rest = get_rest(api+"rapidviews/list", authenticate)
    for v in view_id_rest['views']:
        v_id = v['id']
        url = api + "sprintquery/{0}?includeHistoricSprints=true".format(v_id)
        sprint_id_rest = get_rest(url, authenticate)
        proj = get_proj_from_view(v, proj_name2key_map)
        for s in sprint_id_rest['sprints']:
            sprint_list.append((v_id, s['id'], proj))
            
    return sprint_list
コード例 #2
0
ファイル: jira_access.py プロジェクト: GripQA/client-tools
def proc_sprints(api, proj_name2key_map, authenticate, counters):
    """Retrieves and processes the sprint information

    Retrieves the list of sprints associated with the current project, then
    scans the list to extract sprint endTime dates.  These represent the 
    sprint_closed measurement

    Args:
        api - string containing the URL component for the desired API
        proj_name2key_map - maps from project names to project keys
        authenticate - tuple containing username & password to log into JIRA
        counters - object containing occurrence counters

    Returns:
        No return value
    """
    sprint_list = get_sprint_list(api, proj_name2key_map, authenticate)
    url_str = ("rapid/charts/scopechangeburndownchart.json?"
               "rapidViewId={0}&sprintId={1}")
    for sp in sprint_list:
        url = api + url_str.format(sp[0], sp[1])
        sprint_rest = get_rest(url, authenticate)
        log_sprint_closed(sprint_rest['endTime']
                          ,sp[2]
                          ,counters.sprints
                          ,counters.measurements)
コード例 #3
0
ファイル: sonar_access.py プロジェクト: GripQA/client-tools
def sonar_main(config):
    """Main function to retrieve and process results of the SonarQube analysis

    Args:
        config - Fully Populated GripConfig object

    Returns:
        No returned value
    """
    global GLOBALS
    # Hardcoded to use default local SonarQube installation
    # You will likely need to change this for your specific situation
    authenticate = ("admin", "admin")
    url_str = ("http://localhost:9000/api/resources?scopes=PRJ&resource={0}"
               "&metrics=lines,ncloc,duplicated_lines,complexity,"
               "class_complexity,function_complexity,file_complexity,tests"
               "&format=json")
                                         
    url = url_str.format(config.sonarqube_project)
    print("Making Request for: '{0}'".format(url))
    sonar_data = get_rest(url, authenticate)

    if sonar_data is not None:
        print("Got back {} results...".format(len(sonar_data[0]['msr'])))
        # Define the look-up table that will map keys from the SonarQube
        # results to functions that will generate the corresponging
        # GripMeasurements
        lut = {"class_complexity":class_complexity
               ,"complexity":complexity
               ,"duplicated_lines":duplicate_lines
               ,"file_complexity":file_complexity
               ,"function_complexity":function_complexity
               ,"lines":lines_comments
               ,"ncloc":loc
               }
        GLOBALS['TIMESTAMP'] = gen_timestamp(sonar_data[0]['date'])
        measurements = []
        for v in sonar_data[0]['msr']:
            lut[v['key']](v, measurements)

        if measurements:
            for i in measurements:
                print(i)
            gen_json(measurements, config.json_basename + "-sq")
    else:
        err_str = "{0}Unable to retrieve issues for {1}.\n"
        sys.stderr.write(err_str.format(ERR_LABEL, ACCOUNT_NAME))
コード例 #4
0
ファイル: jira_access.py プロジェクト: GripQA/client-tools
 def handle_name_field(issue, name_field, auth, contributors):
     # Adapts the name/email address data to a modern
     # format.  Also adds the name/email addr tuple to the
     # collection of contributors
     #
     # name_field - specifies which field we'll be transfering
     #
     # Need to make an API call to get the details of the name
     tmp_n = issue['fields'][name_field]
     url = tmp_n['value']['self']
     name_info = get_rest(url, auth)
     name = name_info['displayName']
     email = name_info['emailAddress']
     # adapt the specified issue
     tmp_n['displayName'] = name
     tmp_n['emailAddress'] = email
     # update the contributors collection
     contributors[email] = name
コード例 #5
0
ファイル: jira_descr.py プロジェクト: GripQA/client-tools
def descr_main(config):
    """Main function for retrieving and displaying Java issue information

    Uses REST APIs to GET a project's names for various issue types, states and
    priorities.  Formats the output for easier reading.

    Args:
        config - configuration object

    Returns:
        No return value
    """
    labels = ["issuetype"
              ,"status"
              ,"resolution"
              ,"priority"
              ]
    api = config.jira_rest_api
    auth = (config.username, config.password)
    for l in labels:
        print("\n\n{0}:".format(l))
        url = "{0}{1}{2}".format(config.server, api, l)
        jsn = get_rest(url, auth)
        dump_data(jsn)
コード例 #6
0
ファイル: jira_access.py プロジェクト: GripQA/client-tools
def jira_main(config):
    """Main function for processing JIRA information

    Uses REST APIs to GET a project's issues and sprint information.
    Analyzes both to gather measurements that are interesting to Grip then
    produces a file containing a JSON representation of the extracted
    measurements

    Args:
        config - configuration object

    Returns:
        No return value
    """
    # set up the counters
    counters = Counters()
    # prepare for getting issues
    authenticate = (config.username, config.password)
    server = config.server
    api = config.jira_rest_api
    #
    # Get the list of projects.  We'll process issues for each project
    proj_url = "{0}{1}project".format(server, api)
    projects = get_rest(proj_url, authenticate)
    print("{0}Found {1} projects.".format(NOTE_LABEL, len(projects)))
    proj_name2key_map = build_proj_name2key_map(projects)
    # flag will be set to True if we find any issues in the projects
    found_issues = False
    for proj in projects:
        if proj['key'] in config.projects_to_analyze:
            query_str = ("search?jql=project={0}+order+by+created+asc"
                         "&startAt=0&expand=changelog&maxResults=-1")
            query = query_str.format(proj['key'])
            url = "{0}{1}{2}".format(server, api, query)
            print("\nProcessing project: {0}".format(proj['key']))
            print("Making Request for: {0}".format(url))    
            issues_rest = get_rest(url, authenticate)
            if issues_rest is not None:
                found_issues = True
                fstr = "{0}Retrieved {1} issues..."
                print(fstr.format(NOTE_LABEL, len(issues_rest['issues'])))
                for i in issues_rest['issues']:
                    # There should be a more elegant way of doing this, but the
                    # REST API apparently doesn't have a way to query for its
                    # own version
                    if api == "rest/api/2.0.alpha1/":
                        # obsolete version of the API, we'll need to adapt the
                        # issue for processing by these functions
                        i = adapt_2alpha1_issue(i
                                                ,config
                                                ,authenticate
                                                ,counters
                                                )
                    # Current version of the API
                    if i is not None:
                        if MEASUREMENTS_OUT:
                            proc_issue(i, config, counters)
                        else:
                            dump_issue(i, config, counters)
                    else:
                        err_str = "{0}Bad Issue Reference\n"
                        sys.stderr.write(err_str.format(ERR_LABEL))

    if found_issues:
        # Take care of the sprints
        sprint_api = config.sprint_api
        # "rest/greenhopper/1.0/"
        # If sprint_api isn't set in the configuration file, we'll skip
        # this step
        if sprint_api is not None:
            proc_sprints(server+sprint_api
                         ,proj_name2key_map
                         ,authenticate
                         ,counters
                         )
        # and the contributors
        handle_contributors(counters.contributors)

        # if we have measurements to pass along
        if counters.measurements:
            # Measurements were placed on the list in order of issue
            # processing.  Re-order by sorting on timestamp
            counters.measurements.sort(key=itemgetter(3))
            if GLOBALS['VERBOSE']:
                for i in counters.measurements:
                    print(i)

            gen_json(counters.measurements, config.json_basename + "-jira")
            
            # Dump the summary results
            fstr = ("\n\nCounter Class Summary:\n"
                    "  ISSUES OPEN   = {0}\n"
                    "  ISSUES CLOSED = {1}\n"
                    "  ISSUES TOTAL  = {2}\n\n"
                    "  REQUIREMENTS OPEN: {3}\n"
                    "  REQUIREMENTS CLOSED: {4}\n"
                    "  REQUIREMENTS TOTAL:  {5}\n\n"
                    "  DEFECTS CREATED = {6}\n"
                    "  DEFECTS CLOSED  = {7}\n"
                    "  DEFECTS TOTAL   = {8}\n\n"
                    "  SPRINTS TOTAL   = {9}\n\n"
                   )
            print(fstr.format(counters.issues.open
                              ,counters.issues.closed
                              ,counters.issues.total
                              ,counters.requirements.open
                              ,counters.requirements.closed
                              ,counters.requirements.total
                              ,counters.defects.created
                              ,counters.defects.closed
                              ,counters.defects.total
                              ,counters.sprints.total))

    else:
        err_str = "ERROR: Unable to retrieve issues for {0}.\n"
        sys.stderr.write(err_str.format(ACCOUNT_NAME))
コード例 #7
0
ファイル: jira_access.py プロジェクト: GripQA/client-tools
def adapt_2alpha1_issue(issue_ref, config, auth, counters):
    """Adapts an issue from the old version of the API into a structure
    that can be processed by code expecting to work on current data

    Transforms the structure of the issue to conform to that of an issue
    from the current version of the API.  All differences in data of
    interest will be handled in this function.  Due to information missing
    from the older version, we're forced to make some assumptions to fill
    in the gaps

    Args:
        issue_ref - dictionary representing the issue to be checked
        config - configuration object
        auth - tuple with username / password for basic authentication
        counters - object containing occurrence counters

    Returns:
        An issue compatible with the current vesion of the API
    """
    def progress_counter():
        # Since this function needs to make several REST requests for each
        # issue, it can be quite slow.  This progress count periodically
        # indicates the progress on stdout, so the user knows that we're
        # still going
        try:
            adapt_2alpha1_issue.iter_counter += 1
        except AttributeError:
            reset_progress_counter()

        if (adapt_2alpha1_issue.iter_counter % 10) == 0:
            f_str = "{0}Processing {1}th issue"
            print(f_str.format(NOTE_LABEL, adapt_2alpha1_issue.iter_counter))

    def reset_progress_counter():
        # Resets the iter_counter variable to 1, can also be used to initialize
        # the counter
        adapt_2alpha1_issue.iter_counter = 1
            
    def handle_issuetype(issue):
        # Adapts the issue type to the modern format
        tmp_i = issue['fields']['issuetype']
        tmp_i['name'] = tmp_i['value']['name']

    def handle_project(issue):
        # Adapts the project data to the modern format
        tmp_p = issue['fields']['project']
        tmp_p['key'] =  tmp_p['value']['key']

    def handle_name_field(issue, name_field, auth, contributors):
        # Adapts the name/email address data to a modern
        # format.  Also adds the name/email addr tuple to the
        # collection of contributors
        #
        # name_field - specifies which field we'll be transfering
        #
        # Need to make an API call to get the details of the name
        tmp_n = issue['fields'][name_field]
        url = tmp_n['value']['self']
        name_info = get_rest(url, auth)
        name = name_info['displayName']
        email = name_info['emailAddress']
        # adapt the specified issue
        tmp_n['displayName'] = name
        tmp_n['emailAddress'] = email
        # update the contributors collection
        contributors[email] = name

    def handle_description(issue):
        # Some customer issues don't seem to have any text in their
        # description fields, so I'm not sure what the description is
        # supposed to look like in an alpha API issue.  I'm kind of
        # guessing here.
        #
        # Cache the current info in a new key, since we'll be replacing
        # the value of the description key
        descr = issue['fields']['description']
        issue['fields']['description-alpha'] = descr
        # use the "['fields']['description']['value'] field to populate
        # the new format description
        issue['fields']['description'] = descr.get("value")

    def handle_status(issue):
        # Adapt the status field to the current format
        #
        # Cache the current info in a new key, since we'll be replacing
        # the value of the status key
        descr = issue['fields']['status']
        issue['fields']['status-alpha'] = descr
        # use the "['fields']['status']['value'] field to populate
        # the new format status
        issue['fields']['status'] = descr.get("value")['name']

    def handle_datetime(issue, field):
        # Adapts a datetime field to the new format, preserves the old
        # field values in a new field named <field_name>-alpha.
        #
        # field - the name of the datetime field to handle.
        #
        tmp_datetime_field = issue['fields'].get(field, None)
        if tmp_datetime_field is not None:
            tmp_datetime = issue['fields'][field]['value']
            stash_field = field + "-alpha"
            issue['fields'][stash_field] = issue['fields'][field]
            # use the "['fields'][field]['value'] field to populate
            # the new format description
            issue['fields'][field] = tmp_datetime
        elif GLOBALS['VERBOSE']:
            fstr = "{0}Issue '{1}' does not have a/an '{2}' field"
            print(fstr.format(NOTE_LABEL, issue['key'], field))

    def handle_all_datetimes(issue):
        # Adapts all datetime fields of interest to the new format
        for dtm in ["created", "updated", "resolutiondate"]:
            handle_datetime(issue, dtm)

    def make_creator_field(issue):
        # transfers data from the reporter field to the issue's creator field
        # MUST be run after the reporter field has been populated correctly
        reporter = get_name(issue['fields']['reporter'])
        issue['fields']['creator'] = {"displayName":reporter[0]
                                      ,"emailAddress":reporter[1]
                                      }

    def make_history(issue):
        # Although issues obtained through the alpha REST API don't have
        # changelogs & histories, we need dummy values for later processing
        issue['changelog'] = {"histories":[]}

    alpha_issue = get_rest(issue_ref['self'], auth)
    if alpha_issue is not None:
        progress_counter()
        handle_issuetype(alpha_issue)
        handle_project(alpha_issue)
        handle_name_field(alpha_issue, "reporter", auth, counters.contributors)
        make_creator_field(alpha_issue)
        handle_all_datetimes(alpha_issue)
        # Since we won't have a history to process for the alpha issues:
        handle_name_field(alpha_issue, "assignee", auth, counters.contributors)
        handle_description(alpha_issue)
        handle_status(alpha_issue)
        make_history(alpha_issue)
        
    return alpha_issue