Skip to content

Commit 6f6d5d3

Browse files
authored
Move Java Dep Tree content from Core (#44)
1 parent e6de042 commit 6f6d5d3

File tree

13 files changed

+1381
-1
lines changed

13 files changed

+1381
-1
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# This test verifies that gradle-dep-tree.jar and maven-dep-tree.jar are kept up-to-date with the version specified in buildscripts/download-jars.js.
2+
# It accomplishes this by downloading the JARs and executing a "git diff" command.
3+
# In case there are any differences detected, the test will result in failure.
4+
name: Embedded Jars Tests
5+
on:
6+
push:
7+
branches:
8+
- '**'
9+
tags-ignore:
10+
- '**'
11+
pull_request:
12+
jobs:
13+
test:
14+
runs-on: ubuntu-latest
15+
env:
16+
GOPROXY: direct
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Download JARs
21+
run: buildscripts/download-jars.sh
22+
23+
- name: Check Diff
24+
run: git diff --exit-code
25+
26+
- name: Log if Failure
27+
run: echo "::warning::Please run ./buildscripts/download-jars to use compatible Maven and Gradle dependency tree JARs."
28+
if: ${{ failure() }}
29+

buildscripts/download-jars.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
3+
# Please use this script to download the JAR files for maven-dep-tree and gradle-dep-tree into the directory utils/java/.
4+
# These JARs allow us to build Maven and Gradle dependency trees efficiently and without compilation.
5+
# Learn more about them here:
6+
# https://github.com/jfrog/gradle-dep-tree
7+
# https://github.com/jfrog/maven-dep-tree
8+
9+
# Once you have updated the versions mentioned below, please execute this script from the root directory of the jfrog-cli-core to ensure the JAR files are updated.
10+
GRADLE_DEP_TREE_VERSION="3.0.2"
11+
# Changing this version also requires a change in mavenDepTreeVersion within utils/java/mvn.go.
12+
MAVEN_DEP_TREE_VERSION="1.1.0"
13+
14+
curl -fL https://releases.jfrog.io/artifactory/oss-release-local/com/jfrog/gradle-dep-tree/${GRADLE_DEP_TREE_VERSION}/gradle-dep-tree-${GRADLE_DEP_TREE_VERSION}.jar -o commands/audit/sca/java/resources/gradle-dep-tree.jar
15+
curl -fL https://releases.jfrog.io/artifactory/oss-release-local/com/jfrog/maven-dep-tree/${MAVEN_DEP_TREE_VERSION}/maven-dep-tree-${MAVEN_DEP_TREE_VERSION}.jar -o commands/audit/sca/java/resources/maven-dep-tree.jar
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package java
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"strings"
7+
8+
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
9+
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
10+
"github.com/jfrog/jfrog-cli-core/v2/utils/xray"
11+
"github.com/jfrog/jfrog-client-go/utils/errorutils"
12+
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
13+
)
14+
15+
const (
16+
GavPackageTypeIdentifier = "gav://"
17+
)
18+
19+
func BuildDependencyTree(depTreeParams DepTreeParams, tech coreutils.Technology) ([]*xrayUtils.GraphNode, map[string][]string, error) {
20+
if tech == coreutils.Maven {
21+
return buildMavenDependencyTree(&depTreeParams)
22+
}
23+
return buildGradleDependencyTree(&depTreeParams)
24+
}
25+
26+
type DepTreeParams struct {
27+
UseWrapper bool
28+
Server *config.ServerDetails
29+
DepsRepo string
30+
IsMavenDepTreeInstalled bool
31+
IsCurationCmd bool
32+
CurationCacheFolder string
33+
}
34+
35+
type DepTreeManager struct {
36+
server *config.ServerDetails
37+
depsRepo string
38+
useWrapper bool
39+
}
40+
41+
func NewDepTreeManager(params *DepTreeParams) DepTreeManager {
42+
return DepTreeManager{useWrapper: params.UseWrapper, depsRepo: params.DepsRepo, server: params.Server}
43+
}
44+
45+
// The structure of a dependency tree of a module in a Gradle/Maven project, as created by the gradle-dep-tree and maven-dep-tree plugins.
46+
type moduleDepTree struct {
47+
Root string `json:"root"`
48+
Nodes map[string]xray.DepTreeNode `json:"nodes"`
49+
}
50+
51+
// Reads the output files of the gradle-dep-tree and maven-dep-tree plugins and returns them as a slice of GraphNodes.
52+
// It takes the output of the plugin's run (which is a byte representation of a list of paths of the output files, separated by newlines) as input.
53+
func getGraphFromDepTree(outputFilePaths string) (depsGraph []*xrayUtils.GraphNode, uniqueDepsMap map[string][]string, err error) {
54+
modules, err := parseDepTreeFiles(outputFilePaths)
55+
if err != nil {
56+
return
57+
}
58+
uniqueDepsMap = map[string][]string{}
59+
for _, module := range modules {
60+
moduleTree, moduleUniqueDeps := GetModuleTreeAndDependencies(module)
61+
depsGraph = append(depsGraph, moduleTree)
62+
for depToAdd, depTypes := range moduleUniqueDeps {
63+
uniqueDepsMap[depToAdd] = depTypes
64+
}
65+
}
66+
return
67+
}
68+
69+
// Returns a dependency tree and a flat list of the module's dependencies for the given module
70+
func GetModuleTreeAndDependencies(module *moduleDepTree) (*xrayUtils.GraphNode, map[string][]string) {
71+
moduleTreeMap := make(map[string]xray.DepTreeNode)
72+
moduleDeps := module.Nodes
73+
for depName, dependency := range moduleDeps {
74+
dependencyId := GavPackageTypeIdentifier + depName
75+
var childrenList []string
76+
for _, childName := range dependency.Children {
77+
childId := GavPackageTypeIdentifier + childName
78+
childrenList = append(childrenList, childId)
79+
}
80+
moduleTreeMap[dependencyId] = xray.DepTreeNode{
81+
Types: dependency.Types,
82+
Children: childrenList,
83+
}
84+
}
85+
return xray.BuildXrayDependencyTree(moduleTreeMap, GavPackageTypeIdentifier+module.Root)
86+
}
87+
88+
func parseDepTreeFiles(jsonFilePaths string) ([]*moduleDepTree, error) {
89+
outputFilePaths := strings.Split(strings.TrimSpace(jsonFilePaths), "\n")
90+
var modules []*moduleDepTree
91+
for _, path := range outputFilePaths {
92+
results, err := parseDepTreeFile(path)
93+
if err != nil {
94+
return nil, err
95+
}
96+
modules = append(modules, results)
97+
}
98+
return modules, nil
99+
}
100+
101+
func parseDepTreeFile(path string) (results *moduleDepTree, err error) {
102+
depTreeJson, err := os.ReadFile(strings.TrimSpace(path))
103+
if errorutils.CheckError(err) != nil {
104+
return
105+
}
106+
results = &moduleDepTree{}
107+
err = errorutils.CheckError(json.Unmarshal(depTreeJson, &results))
108+
return
109+
}
110+
111+
func getArtifactoryAuthFromServer(server *config.ServerDetails) (string, string, error) {
112+
username, password, err := server.GetAuthenticationCredentials()
113+
if err != nil {
114+
return "", "", err
115+
}
116+
if username == "" {
117+
return "", "", errorutils.CheckErrorf("a username is required for authenticating with Artifactory")
118+
}
119+
return username, password, nil
120+
}
121+
122+
func (dtm *DepTreeManager) GetDepsRepo() string {
123+
return dtm.depsRepo
124+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package java
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"reflect"
7+
"strings"
8+
"testing"
9+
10+
"github.com/jfrog/jfrog-cli-core/v2/utils/tests"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func TestGetGradleGraphFromDepTree(t *testing.T) {
15+
// Create and change directory to test workspace
16+
tempDirPath, cleanUp := tests.CreateTestWorkspace(t, filepath.Join("..", "..", "..", "..", "tests", "testdata", "projects", "package-managers", "gradle", "gradle"))
17+
defer cleanUp()
18+
assert.NoError(t, os.Chmod(filepath.Join(tempDirPath, "gradlew"), 0700))
19+
expectedTree := map[string]map[string]string{
20+
"org.jfrog.example.gradle:shared:1.0": {},
21+
"org.jfrog.example.gradle:" + filepath.Base(tempDirPath) + ":1.0": {},
22+
"org.jfrog.example.gradle:services:1.0": {},
23+
"org.jfrog.example.gradle:webservice:1.0": {
24+
"junit:junit:4.11": "",
25+
"commons-io:commons-io:1.2": "",
26+
"org.apache.wicket:wicket:1.3.7": "",
27+
"org.jfrog.example.gradle:shared:1.0": "",
28+
"org.jfrog.example.gradle:api:1.0": "",
29+
"commons-lang:commons-lang:2.4": "",
30+
"commons-collections:commons-collections:3.2": "",
31+
},
32+
"org.jfrog.example.gradle:api:1.0": {
33+
"org.apache.wicket:wicket:1.3.7": "",
34+
"org.jfrog.example.gradle:shared:1.0": "",
35+
"commons-lang:commons-lang:2.4": "",
36+
},
37+
}
38+
expectedUniqueDeps := []string{
39+
"junit:junit:4.11",
40+
"org.jfrog.example.gradle:webservice:1.0",
41+
"org.jfrog.example.gradle:api:1.0",
42+
"org.jfrog.example.gradle:" + filepath.Base(tempDirPath) + ":1.0",
43+
"commons-io:commons-io:1.2",
44+
"org.apache.wicket:wicket:1.3.7",
45+
"org.jfrog.example.gradle:shared:1.0",
46+
"org.jfrog.example.gradle:api:1.0",
47+
"commons-collections:commons-collections:3.2",
48+
"commons-lang:commons-lang:2.4",
49+
"org.hamcrest:hamcrest-core:1.3",
50+
"org.slf4j:slf4j-api:1.4.2",
51+
}
52+
53+
manager := &gradleDepTreeManager{DepTreeManager{}}
54+
outputFileContent, err := manager.runGradleDepTree()
55+
assert.NoError(t, err)
56+
depTree, uniqueDeps, err := getGraphFromDepTree(outputFileContent)
57+
assert.NoError(t, err)
58+
reflect.DeepEqual(uniqueDeps, expectedUniqueDeps)
59+
60+
for _, dependency := range depTree {
61+
dependencyId := strings.TrimPrefix(dependency.Id, GavPackageTypeIdentifier)
62+
depChild, exists := expectedTree[dependencyId]
63+
assert.True(t, exists)
64+
assert.Equal(t, len(depChild), len(dependency.Nodes))
65+
}
66+
}

0 commit comments

Comments
 (0)