diff --git a/graphviz.go b/graphviz.go index c8671bbea..de2ffcdea 100644 --- a/graphviz.go +++ b/graphviz.go @@ -2,69 +2,18 @@ package main import ( "fmt" + "math" "sort" "github.com/awalterschulze/gographviz" ) -func orphansGraph(issues Issues, opts *runOptions) (string, error) { - if !opts.ShowClosed { - issues.HideClosed() - } - issues.processEpicLinks() - - g := gographviz.NewGraph() - panicIfErr(g.SetName("G")) - attrs := map[string]string{} - attrs["truecolor"] = "true" - attrs["overlap"] = "false" - attrs["splines"] = "true" - attrs["rankdir"] = "RL" - attrs["ranksep"] = "0.3" - attrs["nodesep"] = "0.1" - attrs["margin"] = "0.2" - attrs["center"] = "true" - attrs["constraint"] = "false" - for k, v := range attrs { - panicIfErr(g.AddAttr("G", k, v)) - } - panicIfErr(g.SetDir(true)) - - repos := map[string]string{} - for _, issue := range issues { - if !issue.IsOrphan && issue.LinkedWithEpic { - issue.Hidden = true - } - if issue.Hidden { - continue - } - panicIfErr(issue.AddNodeToGraph(g, fmt.Sprintf("cluster_%s", issue.RepoID()))) - repos[issue.RepoID()] = issue.Path() - } - - for id, repo := range repos { - panicIfErr(g.AddSubGraph( - "G", - fmt.Sprintf("cluster_%s", id), - map[string]string{"label": escape(repo), "style": "dashed"}, - )) - } - - // issue relationships - for _, issue := range issues { - panicIfErr(issue.AddEdgesToGraph(g)) - } - - // FIXME: sub-cluster by state - - return g.String(), nil -} - func graphviz(issues Issues, opts *runOptions) (string, error) { var ( - invisStyle = map[string]string{"style": "invis"} - weightMap = map[int]bool{} - weights = []int{} + invisStyle = map[string]string{"style": "invis", "label": escape("")} + //invisStyle = map[string]string{} + weightMap = map[int]bool{} + weights = []int{} ) for _, issue := range issues { if issue.Hidden { @@ -101,6 +50,20 @@ func graphviz(issues Issues, opts *runOptions) (string, error) { issueNumbers = append(issueNumbers, issue.URL) } sort.Strings(issueNumbers) + + orphansWithoutLinks := 0 + for _, id := range issueNumbers { + issue := issues[id] + if issue.Hidden { + continue + } + if len(issue.DependsOn) == 0 && len(issue.Blocks) == 0 { + orphansWithoutLinks++ + } + } + orphansCols := int(math.Ceil(math.Sqrt(float64(orphansWithoutLinks)) / 2)) + colIndex := 0 + hasOrphansWithLinks := false for _, id := range issueNumbers { issue := issues[id] if issue.Hidden { @@ -108,7 +71,13 @@ func graphviz(issues Issues, opts *runOptions) (string, error) { } parent := fmt.Sprintf("anon%d", issue.Weight()) if issue.IsOrphan || !issue.LinkedWithEpic { - parent = "cluster_orphans" + if len(issue.DependsOn) > 0 || len(issue.Blocks) > 0 { + parent = "cluster_orphans_with_links" + hasOrphansWithLinks = true + } else { + parent = fmt.Sprintf("cluster_orphans_without_links_%d", colIndex%orphansCols) + colIndex++ + } } panicIfErr(issue.AddNodeToGraph(g, parent)) @@ -120,12 +89,53 @@ func graphviz(issues Issues, opts *runOptions) (string, error) { } // orphans cluster and placeholder - if issues.HasOrphans() { - panicIfErr(g.AddSubGraph("G", "cluster_orphans", map[string]string{"label": "orphans", "style": "dashed"})) - panicIfErr(g.AddNode("cluster_orphans", "placeholder_orphans", invisStyle)) + if orphansWithoutLinks > 0 { + panicIfErr(g.AddSubGraph( + "G", + "cluster_orphans_without_links", + map[string]string{"label": escape("orphans without links"), "style": "dashed"}, + )) + + panicIfErr(g.AddSubGraph( + "cluster_orphans_without_links", + "cluster_orphans_without_links_0", + invisStyle, + )) + for i := 0; i < orphansCols; i++ { + panicIfErr(g.AddNode( + fmt.Sprintf("cluster_orphans_without_links_%d", i), + fmt.Sprintf("placeholder_orphans_without_links_%d", i), + invisStyle, + )) + } + panicIfErr(g.AddEdge( fmt.Sprintf("placeholder_%d", weights[len(weights)-1]), - "placeholder_orphans", + "placeholder_orphans_without_links_0", + true, + invisStyle, + )) + + for i := 1; i < orphansCols; i++ { + panicIfErr(g.AddSubGraph( + "cluster_orphans_without_links", + fmt.Sprintf("cluster_orphans_without_links_%d", i), + invisStyle, + )) + panicIfErr(g.AddEdge( + fmt.Sprintf("placeholder_orphans_without_links_%d", i-1), + fmt.Sprintf("placeholder_orphans_without_links_%d", i), + true, + invisStyle, + )) + } + } + if hasOrphansWithLinks { + panicIfErr(g.AddSubGraph("G", "cluster_orphans_with_links", map[string]string{"label": escape("orphans with links"), "style": "dashed"})) + panicIfErr(g.AddNode("cluster_orphans_with_links", "placeholder_orphans_with_links", invisStyle)) + panicIfErr(g.AddEdge( + "placeholder_orphans_with_links", + fmt.Sprintf("placeholder_%d", weights[0]), true, invisStyle, ))