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
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))
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")
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
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
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