예제 #1
0
    def _add_project(self, project_configuration, skip_project_validation, perfrom_update_call):
        """Adds a project to Teamscale. The parameter `skip_project_validation` specifies, whether to skip the validation of the project.
        The parameter `perfrom_update_call` specifies, whether an update call should be
        made:
        - If `perfrom_update_call` is set to `True`, re-adding a project with an existing id will update the original
        project.
        - If `perfrom_update_call` is set to `False`, re-adding a project with an existing id will result in an error.
        - Further, if `perfrom_update_call` is set to `True`, but no project with the specified id exists, an error is
        thrown as well.

        Args:
            project_configuration (data.ProjectConfiguration): The project that is to be created (or updated).
            skip_project_validation (bool): Whether to skip validation of the project.
            perfrom_update_call (bool): Whether to perform an update call.
        Returns:
            requests.Response: object generated by the upload request.

        Raises:
            ServiceError: If anything goes wrong.
        """
        service_url = self.get_global_service_url("create-project")
        parameters = {
            "skip-project-validation": skip_project_validation,
            "only-config-update": perfrom_update_call
        }
        response = self.put(service_url, parameters=parameters, data=to_json(project_configuration))

        response_message = TeamscaleClient._get_response_message(response)
        if response_message != 'success':
            raise ServiceError(
                "ERROR: GET {url}: {status_code}:{message}".format(url=service_url, status_code=response.status_code,
                                                                   message=response_message))
        return response
예제 #2
0
    def upload_coverage_data(self, coverage_files, coverage_format, timestamp, message, partition):
        """Upload coverage reports to Teamscale. It is expected that the given coverage report files can be read from the filesystem.

        Args:
            coverage_files (list): list of coverage filenames (strings!) that should be uploaded. Files must be readable.
            coverage_format  (constants.CoverageFormats): the format to use
            timestamp (datetime.datetime): timestamp (unix format) for which to upload the data
            message (str): The message to use for the generated upload commit
            partition (str): The partition's id into which the data should be added (See also: :ref:`FAQ - Partitions<faq-partition>`).

        Returns:
            requests.Response: object generated by the request

        Raises:
            ServiceError: If anything goes wrong
        """
        service_url = self.get_project_service_url("external-report")
        parameters = {
            "t": self._get_timestamp_ms(timestamp),
            "message": message,
            "partition": partition,
            "format": coverage_format,
            "adjusttimestamp": "true"
        }
        multiple_files = [('report', open(filename, 'rb')) for filename in coverage_files]
        response = requests.post(service_url, params=parameters, auth=self.auth_header, verify=self.sslverify, files=multiple_files)
        if response.status_code != 200:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return response
예제 #3
0
    def get_tasks(self, status="OPEN", details=True, start=0, max=300):
        """Retrieves the tasks for the client's project from the server.

        Args:
            status (constants.TaskStatus): The status to retrieve tickets for
            details (bool): Whether to retrieve details together with the tasks
            start (number): From which task number to start listing tasks
            max (number): Maximum number of tasks to return

        Returns:
            List[:class:`data.Task`]): The list of tasks.

        Raises:
            ServiceError: If anything goes wrong
            """
        service_url = self.get_project_service_url("tasks")
        parameters = {
            "status": status,
            "details": details,
            "start": start,
            "max": max,
            "with-count": False
        }
        response = self.get(service_url, parameters=parameters)
        if not response.ok:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return TeamscaleClient._tasks_from_json(response.json())
예제 #4
0
    def get_findings(self, uniform_path, timestamp, recursive=True):
        """Retrieves the list of findings in the currently active project for the given uniform path
        at the provided timestamp on the given branch.

        Args:
            uniform_path (str): The uniform path to get findings for.
            timestamp (datetime.datetime): timestamp (unix format) for which to upload the data
            recursive (bool): Whether to query findings recursively, i.e. also get findings for files under the given
                path.

        Returns:
            List[:class:`data.Finding`]): The list of findings.

        Raises:
            ServiceError: If anything goes wrong
        """
        service_url = self.get_project_service_url("findings") + uniform_path
        parameters = {
            "t": self._get_timestamp_parameter(timestamp=timestamp),
            "recursive": recursive,
            "all": True
        }
        response = self.get(service_url, parameters=parameters)
        if not response.ok:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return self._findings_from_json(response.json())
예제 #5
0
    def upload_architectures(self, architectures, timestamp, message):
        """Upload architectures to Teamscale. It is expected that the given architectures can be be read from the filesystem.

        Args:
            architectures (dict): mappping of teamscale paths to architecture files that should be uploaded. Files must be readable.
            timestamp (datetime.datetime): timestamp for which to upload the data
            message (str): The message to use for the generated upload commit

        Returns:
            requests.Response: object generated by the request

        Raises:
            ServiceError: If anything goes wrong
        """
        service_url = self.get_project_service_url("architecture-upload")
        parameters = {
            "t": self._get_timestamp_parameter(timestamp),
            "adjusttimestamp": "true",
            "message": message
        }
        architecture_files = [(path, open(filename, 'rb')) for path, filename in architectures.items()]
        response = requests.post(service_url, params=parameters, auth=self.auth_header, verify=self.sslverify,
                                 files=architecture_files, timeout=self.timeout)
        if not response.ok:
            raise ServiceError("ERROR: POST {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return response
예제 #6
0
    def upload_report(self, report_files, report_format, timestamp, message, partition, move_to_last_commit=True):
        """Upload reports from external tools to Teamscale. It is expected that the given report files can be read from
           the filesystem.

        Args:
            report_files (list): list of filenames (strings!) that should be uploaded. Files must be readable.
            report_format  (constants.ReportFormats): the format to use
            timestamp (datetime.datetime): timestamp (unix format) for which to upload the data
            message (str): The message to use for the generated upload commit
            partition (str): The partition's id into which the data should be added
                            (See also: :ref:`FAQ - Partitions<faq-partition>`).
            move_to_last_commit (bool): True to automatically adjust this commit to be the latest otherwise False.
                                        Default is True
        Returns:
            requests.Response: object generated by the request

        Raises:
            ServiceError: If anything goes wrong
        """
        service_url = self.get_project_service_url("external-report")
        parameters = {
            "t": self._get_timestamp_parameter(timestamp),
            "message": message,
            "partition": partition,
            "format": report_format,
            "adjusttimestamp": "true",
            "movetolastcommit": str(move_to_last_commit).lower()
        }
        multiple_files = [('report', open(filename, 'rb')) for filename in report_files]
        response = requests.post(service_url, params=parameters, auth=self.auth_header, verify=self.sslverify,
                                 files=multiple_files, timeout=self.timeout)
        if not response.ok:
            raise ServiceError("ERROR: POST {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return response
예제 #7
0
    def upload_files_for_precommit_analysis(self, timestamp, precommit_data):
        """Uploads the provided files for precommit analysis.

        Args:
            timestamp (datetime.datetime): The timestamp of the parent commit.
            precommit_data (data.PreCommitUploadData): The precommit data to upload.
        """
        service_url = self.get_project_service_url("pre-commit") + self._get_timestamp_parameter(timestamp)

        response = self.put(service_url, data=to_json(precommit_data))
        if not response.ok:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
예제 #8
0
    def check_api_version(self):
        """Verifies the server's api version and connectivity.

        Raises:
            ServiceError: If the version does not match or the server cannot be found.
        """
        url = self.get_global_service_url('service-api-info')
        response = self.get(url)
        json_response = response.json()
        api_version = json_response['apiVersion']
        if api_version < 6:
            raise ServiceError("Server api version " + str(
                api_version) + " too low and not compatible. This client requires Teamscale 4.1 or newer.")
예제 #9
0
    def get_architectures(self):
        """Returns the paths of all architecture in the project.

            Returns:
                List[str] The architecture names.
        """
        service_url = self.get_project_service_url("arch-assessment")
        parameters = {
            "list": True,

        }
        response = self.get(service_url, parameters=parameters)
        if not response.ok:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return [architecture_overview['uniformPath'] for architecture_overview in response.json()]
예제 #10
0
    def delete(self, url, parameters=None):
        """Sends a DELETE request to the given service url.

        Args:
            url (str):  The URL for which to execute a DELETE request
            parameters (dict): parameters to attach to the url

        Returns:
            requests.Response: request's response

        Raises:
            ServiceError: If anything goes wrong
        """
        response = requests.delete(url, params=parameters, auth=self.auth_header, verify=self.sslverify)
        if response.status_code != 200:
            raise ServiceError("ERROR: PUT {url}: {r.status_code}:{r.text}".format(url=url, r=response))
        return response
예제 #11
0
    def get_baselines(self):
        """Retrieves a list of baselines from the server for the currently active project.

        Returns:
            List[:class:`data.Basenline`]): The list of baselines.

        Raises:
            ServiceError: If anything goes wrong
        """
        service_url = self.get_project_service_url("baselines")
        parameters = {
            "detail": True
        }
        headers = {'Accept' : 'application/json'}
        response = requests.get(service_url, params=parameters, auth=self.auth_header, verify=self.sslverify, headers=headers)
        if response.status_code != 200:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return [ Baseline(x['name'], x['description'], timestamp=x['timestamp']) for x in response.json() ]
예제 #12
0
    def add_task_comment(self, task_id, comment):
        """Adds a comment to a task.

        Args:
            task_id (number): the task id to which to add the comment
            comment (str): the comment to add

        Returns:
            requests.Response: object generated by the request

        Raises:
            ServiceError: If anything goes wrong
        """
        service_url = self.get_project_service_url("comment-task") + str(task_id)
        response = self.put(service_url, data=to_json(comment))
        if not response.ok:
            raise ServiceError("ERROR: PUT {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return response
예제 #13
0
    def put(self, url, json=None, parameters=None, data=None):
        """Sends a PUT request to the given service url with the json payload as content.

        Args:
            url (str):  The URL for which to execute a PUT request
            json: The Object to attach as content, will be serialized to json (only for object that can be serialized by default)
            parameters (dict): parameters to attach to the url
            data: The data object to be attached to the request

        Returns:
            requests.Response: request's response

        Raises:
            ServiceError: If anything goes wrong
        """
        response = requests.put(url, params=parameters, json=json, data=data, headers={'Content-Type': 'application/json'}, auth=self.auth_header, verify=self.sslverify)
        if response.status_code != 200:
            raise ServiceError("ERROR: PUT {url}: {r.status_code}:{r.text}".format(url=url, r=response))
        return response
예제 #14
0
    def get(self, url, parameters=None):
        """Sends a GET request to the given service url.

        Args:
            url (str):  The URL for which to execute a PUT request
            parameters (dict): parameters to attach to the url

        Returns:
            requests.Response: request's response

        Raises:
            ServiceError: If anything goes wrong
        """
        headers = {'Accept': 'application/json'}
        response = requests.get(url, params=parameters, auth=self.auth_header, verify=self.sslverify, headers=headers,
                                timeout=self.timeout)
        if not response.ok:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=url, r=response))
        return response
예제 #15
0
    def _parse_findings_response(self, service_url, response):
        """Parses findings retrieved from Teamscale.

        Args:
            service_url (str): The service url. Used for logging.
            response (requests.Response): The response to parse for findings.

        Returns:
            A tuple consisting of three lists: added findings, findings in changed code, and removed findings.

        Raises:
            ServiceError: If anything goes wrong.
        """
        if not response.ok:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))

        added_findings = self._findings_from_json(response.json()['addedFindings'])
        findings_in_changed_code = self._findings_from_json(response.json()['findingsInChangedCode'])
        removed_findings = self._findings_from_json(response.json()['removedFindings'])

        return added_findings, removed_findings, findings_in_changed_code
예제 #16
0
    def get_finding_by_id(self, finding_id, branch=None, timestamp=None):
        """Retrieves the finding with the given id.

        Args:
            finding_id (str): The id of the finding to retrieve.
            branch (str): The branch from which the finding should be retrieved.
            timestamp (datetime.datetime): The timestamp (unix format) for which to receive the finding.

        Returns:
             data.Finding: The retrieved finding.

        Raises:
            ServiceError: If anything goes wrong
        """
        service_url = self.get_project_service_url("findings-by-id") + finding_id

        parameters = {
            "t": self._get_timestamp_parameter(timestamp=timestamp, branch=branch),
        }
        response = self.get(service_url, parameters=parameters)
        if not response.ok:
            raise ServiceError("ERROR: GET {url}: {r.status_code}:{r.text}".format(url=service_url, r=response))
        return self._finding_from_json(response.json())