Beispiel #1
0
def get_fixversions(request):
    jira_loginname, jira_password = get_jira_loginname_and_password(request)

    request = cached_requests_get(settings.TASKBOARD_JIRA_SERVER_BASE_URL
                                  + '/rest/api/latest/project/'
                                  + settings.TASKBOARD_JIRA_PROJECTNAME
                                  + '/versions',
                           auth=(jira_loginname, jira_password),
                      verify=False)
    if not request.ok and request.reason == "Unauthorized":
        raise NotLoggedIntoJiraException()

    result = request.json()
    result.reverse()
    return result
Beispiel #2
0
def get_jira_sprints(request):
    jira_loginname = request.COOKIES.get("jira_loginname", getpass.getuser())
    jira_password = keyring.get_password(settings.TASKBOARD_KEYRING_SERVICENAME, jira_loginname)
    if not jira_loginname or not jira_password:
        response = HttpResponseRedirect(reverse("jiralogin"))
        return response

    request = cached_requests_get(settings.TASKBOARD_JIRA_SERVER_BASE_URL + '/rest/api/latest/project/' + settings.TASKBOARD_JIRA_PROJECTNAME + '/versions',
                           auth=(jira_loginname, jira_password),
                      verify=False)
    if not request.ok and request.reason == "Unauthorized":
        response = HttpResponseRedirect(reverse("jiralogin"))
        return response

    result = request.json()
    result.reverse()
    return HttpResponse(json.dumps(result))
Beispiel #3
0
def handle_jiraissuelookup(request, **kwargs):
    issuenumber = kwargs["issuenumber"]

    jira_loginname = request.COOKIES.get("jira_loginname", getpass.getuser())
    jira_password = keyring.get_password(settings.TASKBOARD_KEYRING_SERVICENAME, jira_loginname)

    issueResponse = cached_requests_get(settings.TASKBOARD_JIRA_SERVER_BASE_URL + '/rest/api/2/issue/' + issuenumber,
                           auth=(jira_loginname, jira_password),
                           verify=False)
    if not issueResponse.ok and issueResponse.reason == "Unauthorized":
        response = HttpResponseRedirect(reverse("jiralogin"))
        return response

    result = issueResponse.json()


    response = result
    print(response)
    return HttpResponse(json.dumps(response), content_type="application/json")

    
Beispiel #4
0
def get_searchresults(request, fixversion, jirausername, issuetype):
    jira_loginname, jira_password = get_jira_loginname_and_password(request)

    url = (settings.TASKBOARD_JIRA_SERVER_BASE_URL
                                  + '/rest/api/latest/search?jql='
                                  + 'project%20%3D%20%22' + urllib.parse.quote(settings.TASKBOARD_JIRA_PROJECTNAME) + "%22%20")
    if fixversion:
        url += 'AND%20fixVersion%20%3D%20%22' + urllib.parse.quote(fixversion) + "%22%20"
    if issuetype:
        url += 'AND%20issuetype%20%3D%20%22' + urllib.parse.quote(issuetype) + "%22%20"

    url += ( 'ORDER%20BY%20%22' + urllib.parse.quote(settings.TASKBOARD_JIRA_ORDERBY) + '%22%20ASC'
            + '&maxResults=1000000&fields=*all&expand=changelog')

    request = cached_requests_get(url,
                           auth=(jira_loginname, jira_password),
                      verify=False)
    if not request.ok and request.reason == "Unauthorized":
        raise NotLoggedIntoJiraException()

    result = request.json()
    return result
Beispiel #5
0
def get_issues(jira_loginname, jira_password):
    # Create dummy-issues from any failed jenkins-builds
    issues = collections.OrderedDict()
    jenkins_base_url = settings.TASKBOARD_JENKINS_SERVER_BASE_URL + settings.TASKBOARD_JENKINS_URL
    jenkinsresponse = cached_requests_get(jenkins_base_url,
                                       auth=(jira_loginname, jira_password),
                                       verify=False)
    if not jenkinsresponse.ok:
        raise AssertionError("""Failed to retrieve the jenkins json-info from the url '%s':\n%s""" % (jenkins_base_url, jenkinsresponse,))

    issue_url_count = {} # If there is more than one error on a testcase, we need to append "_2", "_3", etc to the normal issue-url.
    jenkinsresult = jenkinsresponse.json()
    for jenkinsjob in jenkinsresult["jobs"]:
        jenkinsjob_base_url = jenkinsjob["url"]
        jenkinsjob_name = jenkinsjob["name"]
        jenkinsjob_color = jenkinsjob["color"]

        if jenkinsjob_color == "notbuilt":
            # This job hasn't been built (or all builds have been deleted, so we know nothing about the current
            # status.
            jenkinsbuildstatus = "NOTBUILT"
        else:
            jenkinsbuildurl = "%slastCompletedBuild/api/json" % (jenkinsjob_base_url,)
            jenkinsbuildresponse = cached_requests_get(jenkinsbuildurl,
                                           auth=(jira_loginname, jira_password),
                                           verify=False)

            if not jenkinsbuildresponse.ok:
                raise AssertionError("""Failed to retrieve the jenkinsjob json-info from the url '%s':\n%s""" % (jenkinsbuildurl, jenkinsbuildresponse,))
            jenkinsbuildresult = jenkinsbuildresponse.json()
            jenkinsbuildstatus = jenkinsbuildresult["result"]

            jenkinsbuild_number = jenkinsbuildresult["number"]
        jenkinsissues = []


        has_testreport = False
        update_stored_seleniumerrors = False

        if jenkinsbuildstatus == "NOTBUILT":
            # This job has no builds, so we shouldn't change anything in the database
            pass
        elif jenkinsbuildstatus == "ABORTED":
            # This build was aborted, so we shouldn't change anything in the database
            pass
        elif jenkinsbuildstatus == "SUCCESS":
            # Nothing wrong with this build
            update_stored_seleniumerrors = True
        else:
            for action in jenkinsbuildresult["actions"]:
                if not action is None:
                    if action.get("urlName", None) == "testReport":
                        has_testreport = True
                        update_stored_seleniumerrors = True
                        break
                    
            
        if has_testreport:
            jenkinsrapporturl = "%slastCompletedBuild/testReport/api/json" % (jenkinsjob_base_url,)
            jenkinsjobresponse = cached_requests_get(jenkinsrapporturl,
                                           auth=(jira_loginname, jira_password),
                                           verify=False)

            if not jenkinsjobresponse.ok:
                raise AssertionError("""Failed to retrieve the jenkinsjobrapport json-info from the url '%s':\n%s""" % (jenkinsrapporturl, jenkinsjobresponse,))
            jenkinsjobresult = jenkinsjobresponse.json()
            expectedfailcount = jenkinsjobresult["failCount"]
            
            for childReport in jenkinsjobresult["childReports"]:
                childInfo = childReport["child"]
                childurl = childInfo["url"]
                childReportResult = childReport["result"]
                for suite in childReportResult["suites"]:
                    for testcase in suite["cases"]:
                        status =  testcase["status"]
                        if status in ("FAILED", "REGRESSION"):
        
                            key = jenkinsjob_name + "." + testcase["className"] + "." + testcase["name"]
        
                            packageName, simpleClassName = testcase["className"].rsplit(".", 1)
                            issue_url = "%stestReport/junit/%s/%s/%s" % (childurl, packageName, simpleClassName, testcase["name"])
                            urlcount = issue_url_count.get(issue_url, 0) + 1
                            issue_url_count[issue_url] = urlcount
                            if urlcount > 1:
                                key = "%s_%d" % (key, urlcount)
                                issue_url = "%s_%d" % (issue_url, urlcount)
                            issue_info = dict(fields = {},
                                                      subtasks = [],
                                                      labels = [],
                                                      key = key,
                                                      status="Open",
                                                      issuetype="Bug",
                                                      summary = "%s.%s" % (simpleClassName, testcase["name"]),
                                                      url = issue_url,
                                                      )
                            jenkinsissues.append(issue_info)
            if len(jenkinsissues) != expectedfailcount:
                raise AssertionError("""Expected %s jenkinsissues from %s, but found only %d: %s""" % (expectedfailcount, jenkinsjob_base_url, jenkinsissues))

        jenkinsjob_model, was_created = JenkinsJob.objects.get_or_create(name=jenkinsjob_name)
        if update_stored_seleniumerrors:
            issuekey2issueinfo = dict((issueinfo["key"], issueinfo) for issueinfo in jenkinsissues)
            taskkeys_in_build = set(issuekey2issueinfo.keys())
            open_seleniumerror_models = SeleniumError.objects.filter(jenkinsjob=jenkinsjob_model).filter(fixed_in_build=None) # errors from this job that hasn't been fixed yet.
            open_taskkeys = set([error.taskkey for error in open_seleniumerror_models])
            
            # find seleniumerrors that were fixed by this build
            taskkeys_fixed_by_this_build = open_taskkeys - taskkeys_in_build
                                                              
            # find seleniumerrors that were introduced by this build
            taskkeys_introduced_by_this_build = taskkeys_in_build - open_taskkeys
            current_time = datetime.datetime.now()
            jenkinsbuild_model = None # This is created if it is needed
            if taskkeys_fixed_by_this_build or taskkeys_introduced_by_this_build:
                jenkinsbuild_model, was_created = JenkinsBuild.objects.get_or_create(jenkinsjob=jenkinsjob_model,
                                                                    buildnumber=jenkinsbuild_number)
            
            for seleniumerrormodel in open_seleniumerror_models:
                # Update SeleniumError-models that were fixed in this version
                if seleniumerrormodel.taskkey in taskkeys_fixed_by_this_build:
                    seleniumerrormodel.fixed_in_build = jenkinsbuild_model
                    seleniumerrormodel.fixed_datetime = current_time
                
                    # Update stored info for old tasks that are still present in this build
                elif seleniumerrormodel.taskkey in taskkeys_in_build:
                    issueinfo = issuekey2issueinfo[seleniumerrormodel.taskkey]
                    seleniumerrormodel.static_issueinfo=json.dumps(issueinfo)
                    
                seleniumerrormodel.save()
                    
            # Create SeleniumError for the errors that were introduced in this build
            for taskkey in taskkeys_introduced_by_this_build:
                issueinfo = issuekey2issueinfo[taskkey]
                SeleniumError.objects.create(taskkey=taskkey,
                                              static_issueinfo=json.dumps(issueinfo),
                                              jenkinsjob=jenkinsjob_model,
                                              introduced_in_build = jenkinsbuild_model
                                             )
        
        issuesforjob = collections.OrderedDict()
        for seleniumerror in SeleniumError.objects.filter(jenkinsjob=jenkinsjob_model,
                                                         fixed_in_build = None
                                                         ):
            issueinfo = json.loads(seleniumerror.static_issueinfo)

            errorform = SeleniumErrorForm(instance=seleniumerror)
            issueinfo["errorform"] = errorform
            issueinfo["errorid"] = seleniumerror.id
            issueinfo["formposturl"] = reverse("errorformposthandler")
            issueinfo["assigned_user_id"] = seleniumerror.assigned_user.id if not seleniumerror.assigned_user is None else 0
            
            if not seleniumerror.assigned_user is None:
                issueinfo["assignee"] = {"jirauser": seleniumerror.assigned_user,
                                         "name" : seleniumerror.assigned_user.jirausername,
                                         "displayName" : seleniumerror.assigned_user.jiradisplayname,
                                         }
                
            issuesforjob[issueinfo["key"]] = issueinfo
        if issuesforjob:
            issues.update(issuesforjob)
            jenkinsparentissue = dict(fields = {},
                                              subtasks = list(issuesforjob.values()),
                                              labels = [],
                                              key = jenkinsjob_name + "_parentissuedummy",
                                              status="Open",
                                              issuetype="User Story",
                                              issuecssclass = "Bug",
                                              summary="""Jenkins-jobben "%s" har %d feil!""" % (jenkinsjob_name, len(issuesforjob)),
                                              url=jenkinsjob_base_url,
                                              is_jenkins_job=True,
                                              )
            issues[jenkinsjob_base_url] = jenkinsparentissue
    return issues
Beispiel #6
0
def get_issues(fixVersion, jira_loginname, jira_password):
    issues = collections.OrderedDict()
    jirausername2userinfo = dict() # used to update the displaynames and avatarimages of our stored JiraUser models

    request = cached_requests_get(settings.TASKBOARD_JIRA_SERVER_BASE_URL
                                  + '/rest/api/latest/search?jql='
                                  + 'project%20%3D%20%22' + urllib.parse.quote(settings.TASKBOARD_JIRA_PROJECTNAME) + '%22%20AND%20'
                                  + 'fixVersion%20%3D%20%22' + urllib.parse.quote(fixVersion) + '%22%20'
                                  + 'ORDER%20BY%20%22' + urllib.parse.quote(settings.TASKBOARD_JIRA_ORDERBY) + '%22%20ASC'
                                  + '&maxResults=1000000&fields=*all&expand=changelog',
                           auth=(jira_loginname, jira_password),
                      verify=False)
    if not request.ok and request.reason == "Unauthorized":
        raise NotLoggedIntoJiraException()

    result = request.json()

    #print(result)

    for issue in result["issues"]:
        issue_info = {}
        fields = issue["fields"]
        key = issue["key"]
        assert key.startswith(settings.TASKBOARD_JIRA_PROJECTNAME + "-")

        issue_info["jiranummer"] = key.split("-")[1]
        issue_info["url"] = settings.TASKBOARD_JIRA_SERVER_BASE_URL + "/browse/%s" % (key, )
        assignee = fields["assignee"]
        issue_info["assignee"] = assignee
        if assignee:
            jirausername2userinfo[assignee["name"]] = assignee

        previous_assignees_oldest_first = []
        # TODO: we should use the issue's "changelog" to get the list of previous assignees, but there is a bug in jira that
        # prevents the "changelog"-field from appearing: https://jira.atlassian.com/browse/JRA-27731
        # (We could do a separate http-request for each issue, but that would probably take too long.)
        for worklog in fields["worklog"]["worklogs"]:
            workloginfo = worklog
            author = workloginfo["author"]
            if author !=  assignee:
                previous_assignees_oldest_first.append(author)
        # We need a z-index to make the avatar-images stack correctly
        issue_info["previous_assignees"] = previous_assignees = []
        previous_assignee_offset = 0
        previous_assignees_names = set()
        for previous_assignee_index, previous_assignee in enumerate(reversed(previous_assignees_oldest_first)):
            if not previous_assignee["name"] in previous_assignees_names:
                previous_assignees_names.add(previous_assignee["name"])
                previous_assignee["z_index"] = 998 - previous_assignee_index
                previous_assignee_offset += 30 * math.pow(0.9, previous_assignee_index)
                previous_assignee["left"] = previous_assignee_offset
                previous_assignee["bottom"] = 0 #previous_assignee_offset
                previous_assignees.append(previous_assignee)
                jirausername2userinfo[previous_assignee["name"]] = previous_assignee


        issue_info["description"] = fields["description"]
        issue_info["summary"] = fields["summary"]
        issue_info["issuetype"] = fields["issuetype"]["name"]
        issue_info["timeestimate"] = "%.0f" % (float(fields["timeestimate"]) / 3600.0,) if not fields["timeestimate"] is None else None
        issue_info["timeoriginalestimate"] = "%.0f" % (float(fields["timeoriginalestimate"]) / 3600.0,) if not fields["timeoriginalestimate"] is None else None
        issue_info["subtasks"] = fields["subtasks"]
        for fielddisplayname, fieldname in settings.TASKBOARD_INHERITABLE_TAG_FIELDNAMES:
            issue_info[fieldname] = fields[fieldname]

        priority = fields.get("priority", None)
        if priority and priority["name"] == 'NO PRIORITY SELECTED':
            priority = None
        issue_info["priority"] = priority

        issue_info["status"] = fields["status"]["name"]
        resolution = fields["resolution"]
        issue_info["resolution"] = resolution["name"] if resolution else None

        issue_info["labels"] = fields["labels"]
        issue_info["key"] = issue["key"]
        issues[key] = issue_info


    for jirausername, userinfo in list(jirausername2userinfo.items()):
        jirauser, was_created = JiraUser.objects.get_or_create(jirausername=jirausername)
        jiradisplayname = userinfo["displayName"]
        if jirauser.jiradisplayname != jiradisplayname:
            jirauser.jiradisplayname = jiradisplayname
            jirauser.save()

        if not jirauser.avatar_image:
            # Try to set the image from the jira avatar image
            avatarUrls = userinfo["avatarUrls"]
            if avatarUrls:
                # avatarUrls is a dict that maps from the imagesize ("16x16", "48x48", etc) to an url. We want to
                # use the largest image.
                widthXheights = list(avatarUrls.keys())
                if widthXheights:
                    widthXheights.sort(key=lambda widthXheight: int(widthXheight.split("x")[0]), reverse=True)
                    best_size = widthXheights[0]
                    imageurl = avatarUrls[best_size]
                    imageresponse = cached_requests_get(imageurl, auth=(jira_loginname, jira_password),
                                                        verify=False)
                    logging.info("Using the jiraavatar imageurl '%s' for the jirauser '%s'" % (imageurl, jirausername))
                    if imageresponse.ok:
                        imagedata = imageresponse.content
                        avatar_image_hash = md5sum_from_bytes(imagedata)
                        jira_default_avatar_image_path = os.path.join(os.path.dirname(__file__), "jira_default_avatar.png")
                        jira_default_avatar_image_hash = md5sum_from_filename(jira_default_avatar_image_path)
                        if avatar_image_hash != jira_default_avatar_image_hash:
                            jirauser.avatar_image.save("%s.png" % (jirauser.jirausername,), ContentFile(imagedata))
                            jirauser.save()

        if not jirauser.avatar_image:
            # Generate an image from the username

            #f = ImageFont.load_default()
            fontsize = 20
            font = ImageFont.truetype(os.path.join(os.path.dirname(__file__), "../../fonts/Courier.ttf"), size=fontsize)

            txt=Image.new('RGBA', (140, 60), (255,255,255,255))
            draw = ImageDraw.Draw(txt)

            import textwrap
            lines = textwrap.wrap(jiradisplayname, width = 12)
            y_text = 2
            for line in lines:
                width, height = font.getsize(line)
                draw.text((2, y_text), line, font = font, fill = (0,0,0, 255))
                y_text += height + 2

            imagedata = io.BytesIO()
            txt.save(imagedata, format="PNG")
            jirauser.avatar_image.save("%s.png" % (jirauser.jirausername,), File(imagedata))
            jirauser.save()



    return issues