Esempio n. 1
0
    def test_graph(self, root, expected):
        graph = {'a': ['c'], 'b': ['a'], 'c': [], 'd': ['a'], 'e': ['b', 'a']}

        assert len(YagocdUtil.graph_depth_walk(
            root, lambda x: graph.get(x))) == len(expected)
        assert sorted(YagocdUtil.graph_depth_walk(
            root, lambda x: graph.get(x))) == sorted(expected)
Esempio n. 2
0
    def test_tie_descendants(self, session_fixture):
        child_a = pipeline.PipelineEntity(session=session_fixture,
                                          data={
                                              'name': 'child1',
                                              'materials': {}
                                          })

        parent_a = pipeline.PipelineEntity(session=session_fixture,
                                           data={
                                               'name':
                                               'parent1',
                                               'materials': [{
                                                   'description': 'child1',
                                                   'type': 'Pipeline'
                                               }]
                                           })

        pipelines = [child_a, parent_a]

        YagocdUtil.build_graph(
            nodes=pipelines,
            dependencies=lambda parent:
            [material for material in parent.data.materials],
            compare=lambda candidate, child: candidate.description == child.
            data.name)
        assert child_a.descendants == [parent_a]
Esempio n. 3
0
    def list(self):
        """
        List all available pipelines.

        :versionadded: 14.3.0.

        This method uses ``pipeline_groups`` API method call to list available pipelines.
        It also links them together, so later it's possible to refer to pipeline's descendants.
        :return: array of pipelines
        :rtype: list of yagocd.resources.pipeline.PipelineEntity
        """
        response = self._session.get(
            path=self.GROUPS_RESOURCE_PATH.format(base_api=self.base_api),
            headers={'Accept': 'application/json'},
        )

        pipelines = list()
        for group in response.json():
            for data in group['pipelines']:
                pipeline = PipelineEntity(
                    session=self._session,
                    data=data,
                    group=group['name']
                )
                pipelines.append(pipeline)

        # build pipeline graph to link related nodes
        return YagocdUtil.build_graph(
            nodes=pipelines,
            dependencies=lambda parent: [material for material in parent.data.materials],
            compare=lambda candidate, child: candidate.description == child.data.name
        )
Esempio n. 4
0
    def list(self):
        """
        List all available pipelines.

        :versionadded: 14.3.0.

        This method uses ``pipeline_groups`` API method call to list available pipelines.
        It also links them together, so later it's possible to refer to pipeline's descendants.
        :return: array of pipelines
        :rtype: list of yagocd.resources.pipeline.PipelineEntity
        """
        response = self._session.get(
            path=self.GROUPS_RESOURCE_PATH.format(base_api=self.base_api),
            headers={'Accept': 'application/json'},
        )

        pipelines = list()
        for group in response.json():
            for data in group['pipelines']:
                pipeline = PipelineEntity(session=self._session,
                                          data=data,
                                          group=group['name'])
                pipelines.append(pipeline)

        # build pipeline graph to link related nodes
        return YagocdUtil.build_graph(
            nodes=pipelines,
            dependencies=lambda parent:
            [material for material in parent.data.materials],
            compare=lambda candidate, child: candidate.description == child.
            data.name)
Esempio n. 5
0
    def _accept_header(self):
        """
        Method for determining correct `Accept` header.

        Different resources and different GoCD version servers prefer
        a diverse headers. In order to manage all of them, this method
        tries to help: if `VERSION_TO_ACCEPT_HEADER` is not provided,
        if would simply return default `ACCEPT_HEADER`.
        Though if some manager specifies `VERSION_TO_ACCEPT_HEADER`
        class variable, then it should be a dictionary: keys should be
        a versions and values should be desired accept headers.
        Choosing is pessimistic: if version of a server is less or
        equal to one of the dictionary, the value of that key would be
        used.

        :return: accept header to use in request.
        """
        if not self.VERSION_TO_ACCEPT_HEADER:
            return self.ACCEPT_HEADER

        return YagocdUtil.choose_option(
            version_to_options=self.VERSION_TO_ACCEPT_HEADER,
            default=self.ACCEPT_HEADER,
            server_version=self._session.server_version
        )
Esempio n. 6
0
    def test_tie_descendants(self, session_fixture):
        child_a = pipeline.PipelineEntity(
            session=session_fixture,
            data={'name': 'child1', 'materials': {}}
        )

        parent_a = pipeline.PipelineEntity(
            session=session_fixture,
            data={'name': 'parent1', 'materials': [{'description': 'child1', 'type': 'Pipeline'}]}
        )

        pipelines = [child_a, parent_a]

        YagocdUtil.build_graph(
            nodes=pipelines,
            dependencies=lambda parent: [material for material in parent.data.materials],
            compare=lambda candidate, child: candidate.description == child.data.name
        )
        assert child_a.descendants == [parent_a]
Esempio n. 7
0
    def get_predecessors(self, transitive=False):
        """
        Property for getting predecessors (parents) of current pipeline.
        This property automatically populates from API call

        :return: list of :class:`yagocd.resources.pipeline.PipelineEntity`.
        :rtype: list of yagocd.resources.pipeline.PipelineEntity
        """
        result = self._predecessors
        if transitive:
            return YagocdUtil.graph_depth_walk(result, lambda v: v.predecessors)
        return result
Esempio n. 8
0
    def get_descendants(self, transitive=False):
        """
        Property for getting descendants (children) of current pipeline.
        It's calculated by :meth:`yagocd.resources.pipeline.PipelineManager#tie_descendants` method during listing of
        all pipelines.

        :return: list of :class:`yagocd.resources.pipeline.PipelineEntity`.
        :rtype: list of yagocd.resources.pipeline.PipelineEntity
        """
        result = self._descendants
        if transitive:
            return YagocdUtil.graph_depth_walk(result, lambda v: v.descendants)
        return result
Esempio n. 9
0
    def get_predecessors(self, transitive=False):
        """
        Property for getting predecessors (parents) of current pipeline.
        This property automatically populates from API call

        :return: list of :class:`yagocd.resources.pipeline.PipelineEntity`.
        :rtype: list of yagocd.resources.pipeline.PipelineEntity
        """
        result = self._predecessors
        if transitive:
            return YagocdUtil.graph_depth_walk(result,
                                               lambda v: v.predecessors)
        return result
Esempio n. 10
0
    def get_descendants(self, transitive=False):
        """
        Property for getting descendants (children) of current pipeline.
        It's calculated by :meth:`yagocd.resources.pipeline.PipelineManager#tie_descendants` method during listing of
        all pipelines.

        :return: list of :class:`yagocd.resources.pipeline.PipelineEntity`.
        :rtype: list of yagocd.resources.pipeline.PipelineEntity
        """
        result = self._descendants
        if transitive:
            return YagocdUtil.graph_depth_walk(result, lambda v: v.descendants)
        return result
Esempio n. 11
0
    def _accept_header(self):
        """
        Method for determining correct `Accept` header.

        Different resources and different GoCD version servers prefer
        a diverse headers. In order to manage all of them, this method
        tries to help: if `VERSION_TO_ACCEPT_HEADER` is not provided,
        if would simply return default `ACCEPT_HEADER`.
        Though if some manager specifies `VERSION_TO_ACCEPT_HEADER`
        class variable, then it should be a dictionary: keys should be
        a versions and values should be desired accept headers.
        Choosing is pessimistic: if version of a server is less or
        equal to one of the dictionary, the value of that key would be
        used.

        :return: accept header to use in request.
        """
        if not self.VERSION_TO_ACCEPT_HEADER:
            return self.ACCEPT_HEADER

        return YagocdUtil.choose_option(
            version_to_options=self.VERSION_TO_ACCEPT_HEADER,
            default=self.ACCEPT_HEADER,
            server_version=self._session.server_version)
Esempio n. 12
0
    def value_stream_map(self, name, counter):
        """
        Method builds pipeline instance dependency graph.

        :param name: name of the pipeline.
        :param counter: pipeline counter.
        """
        response = self._session.get(
            path=self._session.urljoin(self.VSM_RESOURCE_PATH, '{}.json'.format(counter)).format(
                base_api=self._session.base_api(api_path=''), name=name),
            headers={'Accept': 'application/json'},
        )

        data = EasyDict(response.json())

        nodes = list()
        dependencies = dict()

        for level in data['levels']:
            for node_item in level.nodes:
                dependencies[node_item.id] = node_item.parents

                if node_item.node_type == 'DUMMY':  # WTF?!
                    continue
                elif node_item.node_type == 'PIPELINE':
                    for instance in node_item.instances:
                        pipeline_data = dict(
                            id=node_item.id,
                            name=node_item.name,
                            counter=instance.counter,
                            label=instance.label,
                            type=node_item.node_type.capitalize(),
                            stages=[]
                        )

                        for stage in instance.stages:
                            stage_data = dict(
                                pipeline_name=node_item.name,
                                pipeline_counter=instance.counter,
                                name=stage.name,
                                status=stage.status,
                                counter=stage.locator.split('/')[-1]
                            )
                            pipeline_data['stages'].append(stage_data)

                        nodes.append(PipelineInstance(session=self._session, data=pipeline_data))
                else:
                    if LooseVersion(self._session.server_version) <= LooseVersion('16.5.0'):
                        modifications = [m for m in node_item.instances]
                    else:
                        modifications = [m for sublist in node_item.material_revisions for m in sublist.modifications]

                    for modification in modifications:
                            modification['id'] = node_item.id
                            modification['type'] = node_item.node_type.capitalize()
                            nodes.append(ModificationEntity(session=self._session, data=modification))

        return YagocdUtil.build_graph(
            nodes=nodes,
            dependencies=lambda parent: dependencies[parent.data.id],
            compare=lambda candidate, child: candidate == child.data.id
        )
Esempio n. 13
0
    def value_stream_map(self, name, counter):
        """
        Method builds pipeline instance dependency graph.

        :param name: name of the pipeline.
        :param counter: pipeline counter.
        """
        response = self._session.get(
            path=self._session.urljoin(
                self.VSM_RESOURCE_PATH, '{}.json'.format(counter)).format(
                    base_api=self._session.base_api(api_path=''), name=name),
            headers={'Accept': 'application/json'},
        )

        data = EasyDict(response.json())

        nodes = list()
        dependencies = dict()

        for level in data['levels']:
            for node_item in level.nodes:
                dependencies[node_item.id] = node_item.parents

                if node_item.node_type == 'DUMMY':  # WTF?!
                    continue
                elif node_item.node_type == 'PIPELINE':
                    for instance in node_item.instances:
                        pipeline_data = dict(
                            id=node_item.id,
                            name=node_item.name,
                            counter=instance.counter,
                            label=instance.label,
                            type=node_item.node_type.capitalize(),
                            stages=[])

                        for stage in instance.stages:
                            stage_data = dict(
                                pipeline_name=node_item.name,
                                pipeline_counter=instance.counter,
                                name=stage.name,
                                status=stage.status,
                                counter=stage.locator.split('/')[-1])
                            pipeline_data['stages'].append(stage_data)

                        nodes.append(
                            PipelineInstance(session=self._session,
                                             data=pipeline_data))
                else:
                    if LooseVersion(self._session.server_version
                                    ) <= LooseVersion('16.5.0'):
                        modifications = [m for m in node_item.instances]
                    else:
                        modifications = [
                            m for sublist in node_item.material_revisions
                            for m in sublist.modifications
                        ]

                    for modification in modifications:
                        modification['id'] = node_item.id
                        modification['type'] = node_item.node_type.capitalize()
                        nodes.append(
                            ModificationEntity(session=self._session,
                                               data=modification))

        return YagocdUtil.build_graph(
            nodes=nodes,
            dependencies=lambda parent: dependencies[parent.data.id],
            compare=lambda candidate, child: candidate == child.data.id)
Esempio n. 14
0
    def test_graph(self, root, expected):
        graph = {'a': ['c'], 'b': ['a'], 'c': [], 'd': ['a'], 'e': ['b', 'a']}

        assert len(YagocdUtil.graph_depth_walk(root, lambda x: graph.get(x))) == len(expected)
        assert sorted(YagocdUtil.graph_depth_walk(root, lambda x: graph.get(x))) == sorted(expected)