Пример #1
0
    def search(self,
               jql_query: str = None,
               field_list: list = None,
               paginated: bool = True):
        assert isinstance(jql_query, str), "jql_query must be a string"
        assert isinstance(field_list, list), "field_list must be a list"
        assert all([isinstance(field, str) for field in field_list]), \
            "all fields in the field_list must be a string"
        assert isinstance(paginated,
                          bool), "paginated is a boolean True or False"

        if paginated:
            return JiraIssue.search(url=self.url,
                                    headers=self.header(),
                                    search_request={
                                        'jql': jql_query,
                                        'fields': field_list
                                    })
        else:
            return JiraIssue.search_issues(url=self.url,
                                           headers=self.header(),
                                           search_request={
                                               'jql': jql_query,
                                               'fields': field_list
                                           })
Пример #2
0
    def add_test(url: str = None,
                 headers: dict = None,
                 project_id: str = None,
                 story_key: str = None,
                 test_description: str = None,
                 test_name: str = None,
                 test_type: str = None):
        """
        Create a Jira "test" entry related to a project and story
        TODO work on the customfield as it may vary with the jira setting
        :param url: the jira server url without endpoint
        :param headers: the request headers
        :param project_id: the project id not the project key
        :param story_key: the story key the test is related to
        :param test_description: the test description
        :param test_name: the test name
        :param test_type: the test type (Manual, Cucumber, Generic)
        :return: the create link response and the test key
        """
        data = {
            "fields": {
                "project": {
                    "id": str(project_id)
                },
                "summary": test_name,
                "description": "",
                "issuetype": {
                    "id":
                    str(
                        JiraIssue.get_issue_identifier(
                            url=url,
                            headers=headers,
                            issue_type=JiraTests.TEST))
                },
                "customfield_10202": {
                    "value": "Cucumber"
                },
                "customfield_10203": {
                    "value": str(test_type)
                },
                "customfield_10204": test_description
            }
        }

        response = JiraIssue.create_issue(url=url,
                                          headers=headers,
                                          issue_data=data)
        key = response.json()["key"]

        response = JiraIssue.create_link(url=url,
                                         headers=headers,
                                         from_key=key,
                                         to_key=story_key,
                                         link_type="Tests")
        return response, key
Пример #3
0
 def get_issue_meta(self):
     """
     Get the issues' project meta data
     :return:
     """
     return JiraIssue.get_issue_meta(url=self.url,
                                     headers=self.header(),
                                     project_id=self.project_id)
Пример #4
0
 def create_story(url=None,
                  headers=None,
                  project_id=None,
                  title=None,
                  description=None,
                  epic_key=None,
                  actor=None,
                  action=None,
                  benefit=None):
     """
     Request the creation of a story
     :param project_id:
     :param headers:
     :param url:
     :param action:
     :param benefit:
     :param actor:
     :param epic_key:
     :param title:
     :param description:
     :return: request response
     """
     data = {
         "fields": {
             "project": {
                 "id": str(project_id)
             },
             "summary": title,
             "issuetype": {
                 "id":
                 str(
                     JiraIssue.get_issue_identifier(
                         url=url,
                         headers=headers,
                         issue_type=JiraStories.STORY))
             },
             "description": description,
             "customfield_10002": epic_key,
             JiraStories.ROLE_JIRA_KEY: actor,
             JiraStories.ACTION_JIRA_KEY: action,
             JiraStories.BENEFIT_JIRA_KEY: benefit
         }
     }
     return JiraIssue.create_issue(url=url,
                                   headers=headers,
                                   issue_data=data)
Пример #5
0
 def create_issue(self, issue_data: dict = None):
     """
     Create a new issue in the project.
     :param issue_data:
     :return: a request response
     """
     return JiraIssue.create_issue(url=self.url,
                                   headers=self.header(),
                                   issue_data=issue_data)
Пример #6
0
 def update_issue(self, issue_key: str = None, issue_data: dict = None):
     """
     Update the issue with the given data
     :param issue_key: the jira issue key
     :param issue_data: the issue update
     :return: a request Response
     """
     return JiraIssue.update_issue(url=self.url,
                                   headers=self.header(),
                                   issue_key=issue_key,
                                   issue_data=issue_data)
Пример #7
0
    def get_issue_status(self, issue_key: str = None):
        """
        Retrieve the issue status
        :param issue_key: a jira issue key
        :return: a string as the status
        """
        assert isinstance(issue_key, str), "issue_key must be a string"

        return JiraIssue.get_issue_status(url=self.url,
                                          headers=self.header(),
                                          issue_key=issue_key)
Пример #8
0
    def get_issue(self, issue_key: str = None):
        """
        Retrieve a Jira issue by its key.
        :param issue_key: a string as a Jira Key
        :return: a requests response
        """
        assert isinstance(issue_key, str), "issue_key must be a string"

        return JiraIssue.get_issue(url=self.url,
                                   headers=self.header(),
                                   issue_key=issue_key)
Пример #9
0
    def get_issue_identifier(self, issue_type: str = None):
        """
        Retrieve the issue id of a specific issue type.

        :param issue_type: the issue name
        :return: a string as a Jira id
        """
        assert isinstance(issue_type, str), "issue_type must be a string"

        return JiraIssue.get_issue_identifier(url=self.url,
                                              headers=self.header(),
                                              issue_type=issue_type)
Пример #10
0
    def add_attachments_to_issue(self, issue_key=None, file_name=None):
        """

        :param issue_key:
        :param file_name:
        :return:
        """
        assert isinstance(issue_key, str), "issue_key must be a string"

        return JiraIssue.add_attachments_to_issue(url=self.url,
                                                  headers=self.header(),
                                                  issue_key=issue_key,
                                                  file_name=file_name)
Пример #11
0
 def get_epics(url=None, headers=None, project_id=None):
     """
     Get all epics related to a project
     :return: a list of key-epic name sets
     """
     data = {"jql": "project = {} AND type = Epic".format(project_id),
             "fields": ["key", "customfield_10004"]}
     list_rep = []
     response = JiraIssue.search_issues(url=url, headers=headers, search_request=data)
     issues = response.json()["issues"]
     for item in issues:
         list_rep.append((item["key"], item["fields"]["customfield_10004"]))
     return list_rep
Пример #12
0
    def update_issue_description(self,
                                 issue_key: str = None,
                                 description: str = None):
        """
        Update the given issue with the new description
        :param issue_key: a jira issue key
        :param description: the new description
        :return: a requests response
        """
        assert isinstance(issue_key, str), "issue_key must be a string"
        assert isinstance(description, str), "description must be a string"

        return JiraIssue.update_issue_description(url=self.url,
                                                  headers=self.header(),
                                                  issue_key=issue_key,
                                                  description=description)
Пример #13
0
 def get_project(self):
     """
     Get all the Project issues held in Jira.
     :raise Exception: Response status code is not 200 ok
     :return: a Request response.
     """
     response = requests.get("{}/rest/api/2/project".format(self.url),
                             headers=self.header())
     if response.status_code != 200:
         log.error("Getting project cast an error {}".format(response.text))
         raise Exception("Getting project cast an error {}".format(
             response.text))
     else:
         return {
             "status_code": response.status_code,
             "content": JiraIssue.sanitize(content=response.content)
         }
Пример #14
0
 def delete_attachments(url=None,
                        headers=None,
                        issue_key=None,
                        attachment_id=None):
     """"
     Delete all issue attachments or only one attachment depending on the input
     """
     if issue_key is not None and attachment_id is None:
         attachments_id_list = JiraIssue.get_issue_attachments_id(
             url=url, headers=headers, issue_key=issue_key)
         for attachment_id in attachments_id_list:
             JiraAttachments.delete_attachments(url=url,
                                                headers=headers,
                                                attachment_id=attachment_id)
     elif issue_key is None and attachment_id is not None:
         return requests.delete("{}/rest/api/2/attachment/{}".format(
             url, attachment_id),
                                headers=headers)
     else:
         print("Error")
Пример #15
0
 def get_jira_test(self, jira_id=None):
     # get the test case from JIRA from a jira_id (ex: PFWES-5336)
     assert jira_id is not None, "Impossible to get jira issue: {}".format(
         jira_id)
     log.debug("## Get jira: {}".format(jira_id))
     jira_test_json = self.__connection.get_issue(jira_id)
     jira_test = 0
     if jira_test_json.status_code != 200:  # if we can't get the test
         log.error(
             "Connection to JIRA impossible. Check url, login/password - HTTP: {}"
             .format(jira_test_json.status_code))
         log.debug(jira_test_json.content)
         quit(1)
     else:
         jira_test = JiraIssue.sanitize(jira_test_json.content)
         log.debug('jira {}\n{}'.format(jira_id, jira_test))
         # check if jira's ID is a test case
         if jira_test["fields"]["issuetype"]['name'] != 'Test':
             log.error("{} is not a test case!".format(jira_id))
             quit(2)
     return jira_test
Пример #16
0
    def get_test_plan_in_release(url: str = None,
                                 headers: dict = None,
                                 release_name: str = None):
        """

        :param url: the jira server url without endpoint
        :param headers: the request headers
        :param release_name: the release name
        :return: a dictionary containing the key "issues" which value is a list of test plan key
        in a dictionary i.e.
        can be acceded with return_var["issues"][position]["key"]
        """
        data = {
            "jql":
            'fixVersion="{}" AND issueType = "Test Plan"'.format(release_name),
            "fields": [
                "key",
            ]
        }

        return JiraIssue.search_issues(url=url,
                                       headers=headers,
                                       search_request=data)
Пример #17
0
 def update_test(url=None,
                 headers=None,
                 test_key=None,
                 test_description=None,
                 test_name=None,
                 test_type=None):
     data = {
         "fields": {
             "summary": test_name,
             "description": "",
             "customfield_10202": {
                 "value": "Cucumber"
             },
             "customfield_10203": {
                 "value": str(test_type)
             },
             "customfield_10204": test_description
         }
     }
     return JiraIssue.update_issue(url=url,
                                   headers=headers,
                                   issue_key=test_key,
                                   issue_data=data)
Пример #18
0
 def update_story(url=None,
                  headers=None,
                  issue_key=None,
                  title=None,
                  description=None,
                  epic_key=None,
                  actor=None,
                  action=None,
                  benefit=None):
     data = {
         "fields": {
             "summary": title,
             "description": description,
             "customfield_10002": epic_key,
             JiraStories.ROLE_JIRA_KEY: actor,
             JiraStories.ACTION_JIRA_KEY: action,
             JiraStories.BENEFIT_JIRA_KEY: benefit
         }
     }
     return JiraIssue.update_issue(url=url,
                                   headers=headers,
                                   issue_key=issue_key,
                                   issue_data=data)  # noqa
Пример #19
0
 def retrieve_attachments(url=None,
                          headers=None,
                          issue_key=None,
                          attachment_id=None,
                          folder=None):
     logging.info("Retrieve attachment with issue_key='{}',"
                  " attachment_id='{}' and folder='{}'".format(
                      issue_key, attachment_id, folder))
     attachments = JiraIssue.get_issue_attachments_links(
         url=url, headers=headers, issue_key=issue_key)
     logging.info("attachments are '{}'".format(repr(attachments)))
     if attachment_id is not None and attachment_id in attachments.keys():
         JiraAttachments.download_file(
             url=attachments[attachment_id]["url"],
             headers=headers,
             file_absolute_path=join(
                 folder, attachments[attachment_id]["filename"]))  # noqa
     else:
         for key in attachments.keys():
             JiraAttachments.download_file(
                 url=attachments[key]["url"],
                 headers=headers,
                 file_absolute_path=join(
                     folder, attachments[key]["filename"]))  # noqa
Пример #20
0
    def __add_execution_to_report(url=None,
                                  headers=None,
                                  test_execution_key=None,
                                  new_report_sheet=None,
                                  folder=None,
                                  relative_folder=None):
        # this function add lines in test execution's sheet

        test_execution = JiraIssue.search(
            url=url,
            headers=headers,
            search_request={
                "jql": 'issuekey="{}"'.format(test_execution_key),  # noqa
                "fields": ["key", "summary", "description"]
            })  # noqa

        # header definition
        new_report_sheet.merge_range(
            1, 1, 1, 5,
            test_execution.json()["issues"][0]["fields"]["summary"])
        new_report_sheet.write_string('A2', 'Test execution:')

        # get test data
        tests = XRayIssues.get_tests_in_execution(
            url=url, headers=headers, test_execution_key=test_execution_key)
        evidences = JiraIssue.sanitize(content=tests.content)
        evidences = {item["key"]: item for item in evidences}

        current_row = 4
        log.debug("{} data: \n{}".format(test_execution_key, tests.json()))
        log.debug("Evidences {} data: \n{}".format(test_execution_key,
                                                   evidences))

        for index, test in enumerate(tests.json()):
            #  Create the download folder
            os.makedirs(os.path.join(folder, test["key"]))
            #  Get steps or scenarios
            steps = JiraIssue.search(url=url,
                                     headers=headers,
                                     search_request={
                                         "jql":
                                         'issuekey="{}"'.format(test["key"]),
                                         "fields": [
                                             "key", "customfield_10204",
                                             "customfield_10206", "summary",
                                             "issuelinks"
                                         ]
                                     })
            steps = JiraIssue.sanitize(content=steps.content)
            # log.info("step {} data:\n[{}".format(test["key"], steps))

            story_key = ''
            story_name = ''
            # try to catch story attached to the test
            try:
                # these fields doesn't exist for Release level, only for test plan / exec level
                short_link = steps["issues"][0]["fields"]["issuelinks"][
                    0]  # to ease readability
                story_key = short_link["inwardIssue"]["key"]
                story_name = short_link["inwardIssue"]["fields"]["summary"]
            except (KeyError, IndexError):
                try:
                    # on old version, field use outward instead of inward
                    short_link = steps["issues"][0]["fields"]["issuelinks"][
                        0]  # ease readability

                    log.debug("step {} data:\n{}".format(
                        test["key"], short_link["outwardIssue"]["key"]))
                    story_key = short_link["outwardIssue"]["key"]
                    story_name = short_link["outwardIssue"]["fields"][
                        "summary"]
                except (KeyError, IndexError):
                    log.warning("There is no story / improvement attached to"
                                " test {}".format(test["key"]))

            if steps["issues"][0]["fields"]["customfield_10204"] is not None:
                steps_list = [
                    steps["issues"][0]["fields"]["customfield_10204"]
                ]
            else:
                steps_list = [
                    item["step"] for item in steps["issues"][0]["fields"]
                    ["customfield_10206"]["steps"]
                ]

            file_list = evidences[test["key"]]["evidences"]
            defect_list = evidences[test["key"]]["defects"]

            lines_to_write = max(
                (len(steps_list), len(file_list), len(defect_list)))
            for step_index, step in enumerate(steps_list):
                new_report_sheet.write_string(current_row + step_index, 6,
                                              step)
            for evidence_index, evidence in enumerate(file_list):
                file_name = evidence["fileName"]
                JiraAttachments.download_file(url=evidence["fileURL"],
                                              headers=headers,
                                              file_absolute_path=os.path.join(
                                                  folder, test["key"],
                                                  file_name))
                new_report_sheet.write_url(current_row + evidence_index,
                                           7,
                                           os.path.join(
                                               relative_folder, test["key"],
                                               file_name),
                                           string=file_name)
            # set jira's ID url
            new_report_sheet.write_url(current_row,
                                       3,
                                       "{}/browse/{}".format(url, test["key"]),
                                       string=test["key"])  # Test ID
            if story_key != '':
                new_report_sheet.write_url(current_row,
                                           1,
                                           "{}/browse/{}".format(
                                               url, story_key),
                                           string=story_key)  # US ID
            new_report_sheet.write_string(current_row, 2,
                                          story_name)  # US name

            # merge rows when result is on multi lines
            if lines_to_write > 1:
                # set values and merge rows
                new_report_sheet.merge_range(
                    current_row, 4, current_row + lines_to_write - 1, 4,
                    steps["issues"][0]["fields"]["summary"])
                new_report_sheet.merge_range(current_row, 5,
                                             current_row + lines_to_write - 1,
                                             5, test["status"])
                # value already set, only merge rows
                new_report_sheet.merge_range(
                    current_row, 1, current_row + lines_to_write - 1, 1,
                    story_key)  # US ID field  # todo improve format
                new_report_sheet.merge_range(current_row, 2,
                                             current_row + lines_to_write - 1,
                                             2, None)  # US title field
                new_report_sheet.merge_range(
                    current_row, 3, current_row + lines_to_write - 1, 3,
                    test["key"])  # Test ID   # todo improve format
                new_report_sheet.merge_range(current_row, 6,
                                             current_row + lines_to_write - 1,
                                             6, None)  # Step field
            else:
                new_report_sheet.write_string(current_row, 1,
                                              story_key)  # todo improve format
                new_report_sheet.write_string(
                    current_row, 3, test["key"])  # todo improve format
                new_report_sheet.write_string(
                    current_row, 4, steps["issues"][0]["fields"]["summary"])
                new_report_sheet.write_string(current_row, 5, test["status"])

            current_row = current_row + lines_to_write
Пример #21
0
    def __from_test_plan_report(url=None,
                                headers=None,
                                test_plan_key=None,
                                folder=None):
        # Retrieve the summary and description
        test_plan = JiraIssue.search(url=url,
                                     headers=headers,
                                     search_request={
                                         "jql":
                                         'issuekey="{}"'.format(test_plan_key),
                                         "fields":
                                         ["key", "summary", "description"]
                                     })

        #  Create a xlsx file per test plan
        report = JiraReporter.__create_xlsx_file(folder=folder,
                                                 name=test_plan_key)

        #  Prepare the summary page and fill with Test plan data
        report["sheets"]["summary"] = report["workbook"].add_worksheet(
            "Summary")
        report["sheets"]["summary"].write_string(
            'A1', "This page is a summary of the test"
            " execution(s) for test"
            " plan {}".format(test_plan_key))
        report["sheets"]["summary"].set_column(3, 5, 15)
        report["sheets"]["summary"].merge_range(
            1, 1, 1, 5,
            test_plan.json()["issues"][0]["fields"]["summary"],
            report["format"]["main_title"])
        report["sheets"]["summary"].merge_range(3, 3, 3, 5, "Description",
                                                report["format"]["header"])
        report["sheets"]["summary"].write_string(3, 1, "Key",
                                                 report["format"]["header"])
        report["sheets"]["summary"].write_string(3, 3, "Description",
                                                 report["format"]["header"])

        test_executions = XRayIssues.get_tests_execution_of_test_plan(
            url=url, headers=headers, test_plan_key=test_plan_key)
        log.info("test_plan_key: {}".format(test_plan_key))

        for index, test_execution in enumerate(test_executions.json()):
            log.debug("Line: {}".format(4 + index))
            #  Creating the sheet for the execution
            report["sheets"][
                test_execution["key"]] = report["workbook"].add_worksheet(
                    test_execution["key"])  # noqa

            #  Updating the summary's sheet
            #  TODO: check the wrap format as it seems not to work
            report["sheets"]["summary"].merge_range(4 + index, 3, 4 + index, 5,
                                                    test_execution["summary"],
                                                    report["format"]["wrap"])
            report["sheets"]["summary"].write_url(
                4 + index, 1, "internal:'{}'!A1".format(test_execution["key"]))
            report["sheets"]["summary"].write_string(4 + index, 1,
                                                     test_execution["key"],
                                                     report["format"]["wrap"])

            # data
            JiraReporter.__from_test_execution_report(
                url=url,
                headers=headers,
                test_execution_key=test_execution["key"],
                new_report_sheet=report["sheets"][
                    test_execution["key"]],  # noqa
                folder=os.path.join(folder, test_plan_key,
                                    test_execution["key"]),
                relative_folder='{}/{}/'.format(test_plan_key,
                                                test_execution["key"]))  # noqa
            # set format
            JiraReporter.__format_test_report_sheet(
                report=report, sheet_key=test_execution["key"])

        report["workbook"].close()
Пример #22
0
    def update_jira_test(self, jira_id=None, jira_changes=None):
        # Update the test case from Jira with feature file data
        # jira_id = jira's id who will be updated
        # jira_changes = list of all changes
        assert jira_id is not None, "There is no jira_id to change"
        assert jira_changes is not None, "There is no change for jira_id{}".format(
            jira_id)

        results = {
            jira_id: {}
        }  # build a json for results = { jira_id: {"field1": "204 OK"}}

        # Split jira_changes to manage each field individually
        for field in jira_changes:
            log.debug("{} - jira_change[field]: {}".format(
                type(jira_changes[field]), jira_changes[field]))
            value = str(jira_changes[field])
            if field == mapping_feature_jira['story_tags']:
                # manage linked issue field
                my_result = self.__connection.create_link(from_key=jira_id,
                                                          to_key=value,
                                                          link_type='Tests')
            else:
                log.debug("field ---> {}".format(field))
                if field == mapping_feature_jira['labels']:
                    # Manage labels field
                    change = []
                    # update labels and remove unexpected labels
                    for action, data in jira_changes[field].items():
                        for tag in data:
                            change.append({action: tag})
                        value = change
                elif field == mapping_feature_jira['type']:
                    # manage case for field = type (scenario type)
                    value = [{"set": {"value": value}}]
                else:
                    # manage other fields than "label" "type" & "story tags"
                    value = [{"set": value}]

                field = field.replace('fields/', 'update/')
                log.debug('field: {} - value: \n\t{}\n'.format(field, value))
                json_data = {}
                dpath.util.new(json_data, field, value)
                log.debug("json_data: {}".format(json_data))
                # Update jira issue change by change
                my_result = self.__connection.update_issue(jira_id, json_data)

            # Manage return message of the issue's update
            if not (my_result.status_code == 204
                    or my_result.status_code == 201):
                # when error return ERROR messages
                log.warning("HTTP:{} - Error to update field: {}\n\t{}".format(
                    my_result.status_code,
                    field,  # noqa
                    JiraIssue.sanitize(my_result.content)))  # noqa
            else:
                # when not error return INFO messages
                log.info("HTTP:{} - Field: {} updated successfully".format(
                    my_result.status_code, field))

            results[jira_id][field] = my_result  # save result for this field
        # loop end
        return results
Пример #23
0
 def add_epic(url=None, headers=None, project_id=None, epic_name=None, epic_summary=None):
     data = {"fields": {"project": {"id": str(project_id)},
                        "summary": epic_summary,
                        "issuetype": {"id": str(JiraIssue.get_issue_identifier(issue_type=JiraEpics.EPIC))},  # noqa
                        "customfield_10004": epic_name}}
     return JiraIssue.create_issue(url=url, headers=headers, issue_data=data)
Пример #24
0
 def create_link(self, from_key=None, to_key=None, link_type=None):
     return JiraIssue.create_link(url=self.url,
                                  headers=self.header(),
                                  from_key=from_key,
                                  to_key=to_key,
                                  link_type=link_type)
Пример #25
0
    def get_issue_attachments_id(self, issue_key=None):
        assert isinstance(issue_key, str), "issue_key must be a string"

        return JiraIssue.get_issue_attachments_id(url=self.url,
                                                  headers=self.header(),
                                                  issue_key=issue_key)