Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FlattenGraph for GraphNode #719

Merged
merged 12 commits into from
Apr 5, 2023
20 changes: 20 additions & 0 deletions xray/services/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package services
import (
"encoding/json"
"github.com/jfrog/jfrog-client-go/utils/log"
"golang.org/x/exp/maps"
"net/http"
"strings"
"time"
Expand Down Expand Up @@ -189,6 +190,25 @@ type GraphNode struct {
Parent *GraphNode `json:"-"`
}

// FlattenGraph creates a map of dependencies from the given graph, and returns a flat graph of dependencies with one level.
func FlattenGraph(graph []*GraphNode) []*GraphNode {
allDependencies := map[string]*GraphNode{}
for _, node := range graph {
populateUniqueDependencies(node, allDependencies)
}
return []*GraphNode{{Id: "root", Nodes: maps.Values(allDependencies)}}
}

func populateUniqueDependencies(node *GraphNode, allDependencies map[string]*GraphNode) {
if _, exist := allDependencies[node.Id]; exist {
return
}
allDependencies[node.Id] = &GraphNode{Id: node.Id}
for _, dependency := range node.Nodes {
populateUniqueDependencies(dependency, allDependencies)
}
}

type OtherComponentIds struct {
Id string `json:"component_id,omitempty"`
Origin int `json:"origin,omitempty"`
Expand Down
31 changes: 31 additions & 0 deletions xray/services/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package services

import (
"fmt"
"github.com/jfrog/gofrog/datastructures"
"github.com/stretchr/testify/assert"
"testing"
)

Expand Down Expand Up @@ -47,3 +49,32 @@ func TestCreateScanGraphQueryParams(t *testing.T) {
})
}
}

func TestFlattenGraph(t *testing.T) {
omerzi marked this conversation as resolved.
Show resolved Hide resolved
nodeA := &GraphNode{Id: "A"}
nodeB := &GraphNode{Id: "B"}
nodeC := &GraphNode{Id: "C"}
nodeD := &GraphNode{Id: "D"}
nodeE := &GraphNode{Id: "E"}
nodeF := &GraphNode{Id: "F"}

// Set dependencies
nodeA.Nodes = []*GraphNode{nodeB, nodeC}
nodeB.Nodes = []*GraphNode{nodeC, nodeD}
nodeC.Nodes = []*GraphNode{nodeD}
nodeD.Nodes = []*GraphNode{nodeE, nodeF}
nodeF.Nodes = []*GraphNode{nodeA, nodeB, nodeC}

// Create graph
graph := []*GraphNode{nodeA, nodeB, nodeC}
flatGraph := FlattenGraph(graph)

// Check that the graph has been flattened correctly
assert.Equal(t, len(flatGraph[0].Nodes), 6)
set := datastructures.MakeSet[string]()
for _, node := range flatGraph[0].Nodes {
assert.Len(t, node.Nodes, 0)
assert.False(t, set.Exists(node.Id))
set.Add(node.Id)
}
}