diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 4467cea..fc35ace 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -21,6 +21,12 @@ jobs: with: go-version: '1.22.3' + - name: Lint + uses: golangci/golangci-lint-action@v6 + with: + version: v1.59.0 + args: --config=./.golangci.yml + - name: Build run: make build diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..6df6414 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,27 @@ +run: + go: "1.22.3" + concurrency: 8 + timeout: 5m + build-tags: + - make + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 + +linters-settings: + misspell: + locale: US + +linters: + disable-all: true + enable: + - errcheck + - goimports + - gosimple + - govet + - ineffassign + - misspell + - staticcheck + - typecheck + - unused diff --git a/Makefile b/Makefile index 7012c9c..84ee6e2 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,10 @@ build: $(GO) build -o $(OUTPUT) @echo "Binary at: $(OUTPUT)" +lint: + @echo "==> Running golangci-lint" + @golangci-lint run --config .golangci.yml + test: $(GO) test -v ./... diff --git a/main.go b/main.go index 50fa57a..c88a0b4 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "io" "log" "os" @@ -24,7 +23,7 @@ func main() { var err error // Read YAML input - yamlBytes, err = readYAML(inputFile) + yamlBytes, err = readInput(inputFile) if err != nil { log.Fatalf("Failed to read YAML: %v", err) } @@ -36,12 +35,17 @@ func main() { } // Process the graph - graph := graph.ProcessGraph(t) + graph, err := graph.ProcessGraph(t) + if err != nil { + log.Fatal(err) + } // Write the graph to the output file if err := os.WriteFile(outputFile, []byte(graph.String()), 0o755); err != nil { log.Fatalf("Failed to write output file: %v", err) } + + log.Println("Generated graph:", outputFile) }, } @@ -49,15 +53,16 @@ func main() { rootCmd.Flags().StringVarP(&outputFile, "output", "o", "graph.dot", "Specify output file") if err := rootCmd.Execute(); err != nil { - fmt.Println(err) - os.Exit(1) + log.Fatal(err) } } -// readYAML reads the YAML input from a file or stdin -func readYAML(inputFile string) ([]byte, error) { +// readInput reads the YAML input from a file or stdin +func readInput(inputFile string) ([]byte, error) { if inputFile != "" { + log.Println("Reading from file:", inputFile) return os.ReadFile(inputFile) } + log.Println("Reading from STDIN...") return io.ReadAll(os.Stdin) } diff --git a/pkg/graph/graph.go b/pkg/graph/graph.go index 661fbde..bfc48ab 100644 --- a/pkg/graph/graph.go +++ b/pkg/graph/graph.go @@ -10,44 +10,62 @@ import ( ) // ProcessGraph creates a Graphviz graph from the given ResourceTree -func ProcessGraph(t *resource.ResourceTree) *gographviz.Graph { +func ProcessGraph(t *resource.ResourceTree) (*gographviz.Graph, error) { + log.Println("Processing tree...") + graphName := "fluxgraph" g := gographviz.NewGraph() - g.SetDir(true) - g.SetName(graphName) - g.AddAttr(graphName, string(gographviz.RankDir), "LR") - g.AddAttr(graphName, string(gographviz.RankSep), "5.0") + g.SetDir(true) //nolint errcheck 'always returns nil' + g.SetName(graphName) //nolint errcheck 'always returns nil' + if err := g.Attrs.Add(string(gographviz.RankDir), "LR"); err != nil { + log.Fatal(err) + } + if err := g.Attrs.Add(string(gographviz.RankSep), "5.0"); err != nil { + log.Fatal(err) + } // Initialize stack and process the root nodes s := stack.New() - processRootNodes(g, t, s) + if err := processRootNodes(g, t, s); err != nil { + return nil, err + } // Process the graph nodes - processOtherNodes(g, s) + if err := processOtherNodes(g, s); err != nil { + return nil, err + } - return g + return g, nil } // processRootNodes processes the root nodes of the resource tree -func processRootNodes(g *gographviz.Graph, root *resource.ResourceTree, s *stack.Stack) { +func processRootNodes(g *gographviz.Graph, root *resource.ResourceTree, s *stack.Stack) error { // Add root node to graph - g.AddNode(g.Name, getName(root.Resource), getNodeAttrs(root.Resource, root.Resource)) + if err := g.AddNode(g.Name, getName(root.Resource), getNodeAttrs(root.Resource, root.Resource)); err != nil { + return err + } for _, child := range root.Resources { // Add child nodes of root node to graph - g.AddNode(g.Name, getName(child.Resource), getNodeAttrs(child.Resource, root.Resource)) + if err := g.AddNode(g.Name, getName(child.Resource), getNodeAttrs(child.Resource, root.Resource)); err != nil { + return err + } // Add edge from root node to child node - g.AddEdge(getName(root.Resource), getName(child.Resource), true, setAttrsColorAndStyle(make(map[string]string), root.Resource.GetKind())) + if err := g.AddEdge(getName(root.Resource), getName(child.Resource), true, setAttrsColorAndStyle(make(map[string]string), root.Resource.GetKind())); err != nil { + return err + } s.Push(child) } + + return nil } // processOtherNodes processes the nodes in the graph using a stack -func processOtherNodes(g *gographviz.Graph, s *stack.Stack) { +func processOtherNodes(g *gographviz.Graph, s *stack.Stack) error { for { poppedResource := s.Pop() if poppedResource == nil { - log.Println("Done!") + log.Println("Done processing!") break } @@ -58,13 +76,19 @@ func processOtherNodes(g *gographviz.Graph, s *stack.Stack) { for _, child := range parent.Resources { // Add child node of parent node to graph - g.AddNode(g.Name, getName(child.Resource), getNodeAttrs(child.Resource, parent.Resource)) + if err := g.AddNode(g.Name, getName(child.Resource), getNodeAttrs(child.Resource, parent.Resource)); err != nil { + return err + } // Add edge from parent node to child node - g.AddEdge(getName(parent.Resource), getName(child.Resource), true, setAttrsColorAndStyle(make(map[string]string), parent.Resource.GetKind())) + if err := g.AddEdge(getName(parent.Resource), getName(child.Resource), true, setAttrsColorAndStyle(make(map[string]string), parent.Resource.GetKind())); err != nil { + return err + } s.Push(child) } } + + return nil } // getName returns the formatted name for a resource