@@ -32,6 +32,7 @@ import (
3232 "github.com/devtron-labs/devtron/pkg/sql"
3333 "github.com/devtron-labs/devtron/pkg/user"
3434 bean3 "github.com/devtron-labs/devtron/pkg/user/bean"
35+ "github.com/devtron-labs/devtron/pkg/variables/utils"
3536 "github.com/devtron-labs/devtron/util/rbac"
3637 "github.com/go-pg/pg"
3738 "go.uber.org/zap"
@@ -741,7 +742,7 @@ func (impl AppWorkflowServiceImpl) FilterWorkflows(triggerViewConfig *TriggerVie
741742 continue
742743 }
743744
744- identifierToFilteredWorkflowMapping , leafPipelines := fetchLeafPipelinesAndPopulateChildrenIdsInWorkflowMapping (workflow .AppWorkflowMappingDto )
745+ identifierToFilteredWorkflowMapping , leafPipelines , _ := processWorkflowMappingTree (workflow .AppWorkflowMappingDto )
745746
746747 identifierToFilteredWorkflowMapping = filterMappingOnFilteredCdPipelineIds (identifierToFilteredWorkflowMapping , leafPipelines , cdPipelineIdsFiltered )
747748
@@ -766,24 +767,34 @@ func extractOutFilteredWorkflowMappings(appWorkflowMappings []AppWorkflowMapping
766767 return newAppWorkflowMappingDto
767768}
768769
769- // fetchLeafPipelinesAndPopulateChildrenIdsInWorkflowMapping function fetches all the leaf cd pipelines and append
770- // the children pipelineIds into ChildPipelinesIds object in AppWorkflowMappingDto and returns both object.
771- func fetchLeafPipelinesAndPopulateChildrenIdsInWorkflowMapping (appWorkflowMappings []AppWorkflowMappingDto ) (map [PipelineIdentifier ]* AppWorkflowMappingDto , []* AppWorkflowMappingDto ) {
770+ // processWorkflowMappingTree function processed the wf mapping array into a tree structure
771+ // returns a map of identifier to mapping, leaf nodes and the root node
772+ func processWorkflowMappingTree (appWorkflowMappings []AppWorkflowMappingDto ) (map [PipelineIdentifier ]* AppWorkflowMappingDto , []AppWorkflowMappingDto , * AppWorkflowMappingDto ) {
772773 identifierToFilteredWorkflowMapping := make (map [PipelineIdentifier ]* AppWorkflowMappingDto )
773- leafPipelines := make ([]* AppWorkflowMappingDto , 0 )
774+ leafPipelines := make ([]AppWorkflowMappingDto , 0 )
775+ var rootPipeline * AppWorkflowMappingDto
776+ //initializing the nodes with empty children and collecting leaf
774777 for i , appWorkflowMapping := range appWorkflowMappings {
775- if appWorkflowMapping .IsLast {
776- leafPipelines = append (leafPipelines , & appWorkflowMappings [i ])
777- }
778+ appWorkflowMappings [i ].ChildPipelinesIds = mapset .NewSet ()
778779 identifierToFilteredWorkflowMapping [appWorkflowMapping .getPipelineIdentifier ()] = & appWorkflowMappings [i ]
779- if appWorkflowMappings [i ].ChildPipelinesIds == nil {
780- appWorkflowMappings [i ].ChildPipelinesIds = mapset .NewSet ()
780+
781+ //collecting leaf pipelines
782+ if appWorkflowMapping .IsLast {
783+ leafPipelines = append (leafPipelines , appWorkflowMapping )
781784 }
782- if appWorkflow , ok := identifierToFilteredWorkflowMapping [appWorkflowMapping .getParentPipelineIdentifier ()]; ok {
783- appWorkflow .ChildPipelinesIds .Add (appWorkflowMapping .ComponentId )
785+ }
786+
787+ for _ , appWorkflowMapping := range identifierToFilteredWorkflowMapping {
788+ // populating children in parent nodes
789+ parentId := appWorkflowMapping .getParentPipelineIdentifier ()
790+ componentId := appWorkflowMapping .ComponentId
791+ if parentMapping , hasParent := identifierToFilteredWorkflowMapping [parentId ]; hasParent && ! parentMapping .ChildPipelinesIds .Contains (componentId ) {
792+ parentMapping .ChildPipelinesIds .Add (componentId )
793+ } else if ! hasParent {
794+ rootPipeline = appWorkflowMapping
784795 }
785796 }
786- return identifierToFilteredWorkflowMapping , leafPipelines
797+ return identifierToFilteredWorkflowMapping , leafPipelines , rootPipeline
787798}
788799
789800// filterMappingOnFilteredCdPipelineIds iterates over all leaf cd-pipelines, if that leaf cd-pipeline is present in the
@@ -792,7 +803,7 @@ func fetchLeafPipelinesAndPopulateChildrenIdsInWorkflowMapping(appWorkflowMappin
792803// cd-pipeline from componentIdWorkflowMapping's list of AppWorkflowMappingDto and also truncate the child
793804// cd-pipeline id present in the parent's ChildPipelinesIds object inside AppWorkflowMappingDto.
794805func filterMappingOnFilteredCdPipelineIds (identifierToFilteredWorkflowMapping map [PipelineIdentifier ]* AppWorkflowMappingDto ,
795- leafPipelines []* AppWorkflowMappingDto , cdPipelineIdsFiltered mapset.Set ) map [PipelineIdentifier ]* AppWorkflowMappingDto {
806+ leafPipelines []AppWorkflowMappingDto , cdPipelineIdsFiltered mapset.Set ) map [PipelineIdentifier ]* AppWorkflowMappingDto {
796807
797808 leafPipelineSize := len (leafPipelines )
798809 for i := 0 ; i < leafPipelineSize ; i ++ {
@@ -803,9 +814,11 @@ func filterMappingOnFilteredCdPipelineIds(identifierToFilteredWorkflowMapping ma
803814 parent := leafPipelines [i ].getParentPipelineIdentifier ()
804815 identifierToFilteredWorkflowMapping [parent ].ChildPipelinesIds .Remove (leafPipelines [i ].ComponentId )
805816 }
806- if identifierToFilteredWorkflowMapping [leafPipelines [i ].getParentPipelineIdentifier ()].ChildPipelinesIds .Cardinality () == 0 {
817+ parentPipelineIdentifier := leafPipelines [i ].getParentPipelineIdentifier ()
818+ childPipelineIds := identifierToFilteredWorkflowMapping [parentPipelineIdentifier ].ChildPipelinesIds
819+ if childPipelineIds .Cardinality () == 0 {
807820 //this means this pipeline has become leaf, so append this pipelineId in leafPipelines for further processing
808- leafPipelines = append (leafPipelines , identifierToFilteredWorkflowMapping [leafPipelines [i ].getParentPipelineIdentifier ()])
821+ leafPipelines = append (leafPipelines , * identifierToFilteredWorkflowMapping [leafPipelines [i ].getParentPipelineIdentifier ()])
809822 leafPipelineSize += 1
810823 }
811824
@@ -849,3 +862,40 @@ func (impl AppWorkflowServiceImpl) FindAppWorkflowByCiPipelineId(ciPipelineId in
849862 return appWorkflowMapping , nil
850863
851864}
865+
866+ // LevelWiseSort performs level wise sort for workflow mappings starting from leaves
867+ // This will break if ever the workflow mappings array break the assumption of being a DAG with one root node
868+ func LevelWiseSort (appWorkflowMappings []AppWorkflowMappingDto ) []AppWorkflowMappingDto {
869+
870+ if len (appWorkflowMappings ) < 2 {
871+ return appWorkflowMappings
872+ }
873+
874+ identifierToNodeMapping , _ , root := processWorkflowMappingTree (appWorkflowMappings )
875+
876+ result := make ([]AppWorkflowMappingDto , 0 )
877+ nodesInCurrentLevel := append (make ([]AppWorkflowMappingDto , 0 ), * root )
878+ for len (result ) != len (appWorkflowMappings ) {
879+ result = append (result , nodesInCurrentLevel ... )
880+ childrenOfCurrentLevel := make ([]AppWorkflowMappingDto , 0 )
881+ for _ , node := range nodesInCurrentLevel {
882+ childrenOfCurrentLevel = append (childrenOfCurrentLevel , getMappingsFromIds (identifierToNodeMapping , utils .ToIntArray (node .ChildPipelinesIds .ToSlice ()))... )
883+ }
884+ // cloning slice elements
885+ nodesInCurrentLevel = append (childrenOfCurrentLevel , []AppWorkflowMappingDto {}... )
886+ }
887+
888+ return result
889+ }
890+
891+ func getMappingsFromIds (identifierToNodeMapping map [PipelineIdentifier ]* AppWorkflowMappingDto , ids []int ) []AppWorkflowMappingDto {
892+ result := make ([]AppWorkflowMappingDto , 0 )
893+ for _ , id := range ids {
894+ identifier := PipelineIdentifier {
895+ PipelineType : CD_PIPELINE_TYPE ,
896+ PipelineId : id ,
897+ }
898+ result = append (result , * identifierToNodeMapping [identifier ])
899+ }
900+ return result
901+ }
0 commit comments