// FindCircularBuilds checks all build configs for cycles func FindCircularBuilds(g osgraph.Graph) []osgraph.Marker { // Filter out all but ImageStreamTag and BuildConfig nodes nodeFn := osgraph.NodesOfKind(imagegraph.ImageStreamTagNodeKind, buildgraph.BuildConfigNodeKind) // Filter out all but BuildInputImage and BuildOutput edges edgeFn := osgraph.EdgesOfKind(buildedges.BuildInputImageEdgeKind, buildedges.BuildOutputEdgeKind) // Create desired subgraph sub := g.Subgraph(nodeFn, edgeFn) markers := []osgraph.Marker{} // Check for cycles for _, cycle := range topo.CyclesIn(sub) { nodeNames := []string{} for _, node := range cycle { if resourceStringer, ok := node.(osgraph.ResourceNode); ok { nodeNames = append(nodeNames, resourceStringer.ResourceString()) } } markers = append(markers, osgraph.Marker{ Node: cycle[0], RelatedNodes: cycle, Severity: osgraph.WarningSeverity, Key: CyclicBuildConfigWarning, Message: fmt.Sprintf("Cycle detected in build configurations: %s", strings.Join(nodeNames, " -> ")), }) } return markers }
func TestCyclesIn(t *testing.T) { for i, test := range cyclesInTests { g := concrete.NewDirectedGraph() g.AddNode(concrete.Node(-10)) // Make sure we test graphs with sparse IDs. for u, e := range test.g { // Add nodes that are not defined by an edge. if !g.Has(concrete.Node(u)) { g.AddNode(concrete.Node(u)) } for v := range e { g.SetEdge(concrete.Edge{F: concrete.Node(u), T: concrete.Node(v)}, 0) } } cycles := topo.CyclesIn(g) var got [][]int if cycles != nil { got = make([][]int, len(cycles)) } // johnson.circuit does range iteration over maps, // so sort to ensure consistent ordering. for j, c := range cycles { ids := make([]int, len(c)) for k, n := range c { ids[k] = n.ID() } got[j] = ids } sort.Sort(internal.BySliceValues(got)) if !reflect.DeepEqual(got, test.want) { t.Errorf("unexpected johnson result for %d:\n\tgot:%#v\n\twant:%#v", i, got, test.want) } } }