Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
JFrog Pipelines Step committed Mar 30, 2023
2 parents 9b6f2ec + 995c2d6 commit 40746ff
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 68 deletions.
2 changes: 1 addition & 1 deletion build/gradle.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const (
GradleExtractorFileName = "build-info-extractor-gradle-%s-uber.jar"
gradleInitScriptTemplate = "gradle.init"
GradleExtractorRemotePath = "org/jfrog/buildinfo/build-info-extractor-gradle/%s"
GradleExtractorDependencyVersion = "4.31.7"
GradleExtractorDependencyVersion = "4.31.8"
)

type GradleModule struct {
Expand Down
2 changes: 1 addition & 1 deletion build/maven.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const (
PropertiesTempfolderName = "properties"
MavenExtractorRemotePath = "org/jfrog/buildinfo/build-info-extractor-maven3/%s"
GeneratedBuildInfoTempPrefix = "generatedBuildInfo"
MavenExtractorDependencyVersion = "2.39.7"
MavenExtractorDependencyVersion = "2.39.8"

ClassworldsConf = `main is org.apache.maven.cli.MavenCli from plexus.core
Expand Down
82 changes: 63 additions & 19 deletions build/utils/npm.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,33 +86,29 @@ type dependencyInfo struct {
}

// Run 'npm list ...' command and parse the returned result to create a dependencies map of.
// The dependencies map looks like name:version -> entities.Dependency
// The dependencies map looks like name:version -> entities.Dependency.
func CalculateDependenciesMap(executablePath, srcPath, moduleId string, npmArgs []string, log utils.Log) (map[string]*dependencyInfo, error) {
dependenciesMap := make(map[string]*dependencyInfo)

// These arguments must be added at the end of the command, to override their other values (if existed in nm.npmArgs)
npmArgs = append(npmArgs, "--json", "--all", "--long")
data, errData, err := RunNpmCmd(executablePath, srcPath, Ls, npmArgs, log)
// Some warnings and messages of npm are printed to stderr. They don't cause the command to fail, but we'd want to show them to the user.
// These arguments must be added at the end of the command, to override their other values (if existed in nm.npmArgs).
npmVersion, err := GetNpmVersion(executablePath, log)
if err != nil {
found, isDirExistsErr := utils.IsDirExists(filepath.Join(srcPath, "node_modules"), false)
if isDirExistsErr != nil {
return nil, isDirExistsErr
}
if !found {
return nil, errors.New("node_modules isn't found in '" + srcPath + "'. Hint: Restore node_modules folder by running npm install or npm ci.")
}
log.Warn("npm list command failed with error:", err.Error())
}
if len(errData) > 0 {
log.Warn("Some errors occurred while collecting dependencies info:\n" + string(errData))
return nil, err
}
npmVersion, err := GetNpmVersion(executablePath, log)
nodeModulesExist, err := utils.IsDirExists(filepath.Join(srcPath, "node_modules"), false)
if err != nil {
return nil, err
}
var data []byte
// If we don't have node_modules, the function will use the package-lock dependencies.
if nodeModulesExist {
data = runNpmLsWithNodeModules(executablePath, srcPath, npmArgs, log)
} else {
data, err = runNpmLsWithoutNodeModules(executablePath, srcPath, npmArgs, log, npmVersion)
if err != nil {
return nil, err
}
}
parseFunc := parseNpmLsDependencyFunc(npmVersion)

// Parse the dependencies json object.
return dependenciesMap, jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) (err error) {
if string(key) == "dependencies" {
Expand All @@ -122,6 +118,54 @@ func CalculateDependenciesMap(executablePath, srcPath, moduleId string, npmArgs
})
}

func runNpmLsWithNodeModules(executablePath, srcPath string, npmArgs []string, log utils.Log) (data []byte) {
npmArgs = append(npmArgs, "--json", "--all", "--long")
data, errData, err := RunNpmCmd(executablePath, srcPath, Ls, npmArgs, log)
if err != nil {
// It is optional for the function to return this error.
log.Warn("npm list command failed with error:", err.Error())
}
if len(errData) > 0 {
log.Warn("Some errors occurred while collecting dependencies info:\n" + string(errData))
}
return
}

func runNpmLsWithoutNodeModules(executablePath, srcPath string, npmArgs []string, log utils.Log, npmVersion *version.Version) ([]byte, error) {
isPackageLockExist, isDirExistsErr := utils.IsFileExists(filepath.Join(srcPath, "package-lock.json"), false)
if isDirExistsErr != nil {
return nil, isDirExistsErr
}
if !isPackageLockExist {
err := installPackageLock(executablePath, srcPath, npmArgs, log, npmVersion)
if err != nil {
return nil, err
}
}
npmArgs = append(npmArgs, "--json", "--all", "--long", "--package-lock-only")
data, errData, err := RunNpmCmd(executablePath, srcPath, Ls, npmArgs, log)
if err != nil {
log.Warn("npm list command failed with error:", err.Error())
}
if len(errData) > 0 {
log.Warn("Some errors occurred while collecting dependencies info:\n" + string(errData))
}
return data, nil
}

func installPackageLock(executablePath, srcPath string, npmArgs []string, log utils.Log, npmVersion *version.Version) error {
if npmVersion.AtLeast("6.0.0") {
npmArgs = append(npmArgs, "--package-lock-only")
// Installing package-lock to generate the dependencies map.
_, errData, err := RunNpmCmd(executablePath, srcPath, Install, npmArgs, log)
if err != nil {
return errors.New("Some errors occurred while installing package-lock: " + string(errData))
}
return nil
}
return errors.New("it looks like you’re using version " + npmVersion.GetVersion() + " of the npm client. Versions below 6.0.0 require running `npm install` before running this command")
}

func GetNpmVersion(executablePath string, log utils.Log) (*version.Version, error) {
versionData, _, err := RunNpmCmd(executablePath, "", Version, nil, log)
if err != nil {
Expand Down
84 changes: 37 additions & 47 deletions build/utils/npm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"testing"

testdatautils "github.com/jfrog/build-info-go/build/testdata"
"github.com/jfrog/build-info-go/entities"
"github.com/jfrog/build-info-go/utils"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -151,22 +150,7 @@ func TestBundledDependenciesList(t *testing.T) {
cacachePath := filepath.Join(projectPath, "tmpcache")
npmArgs := []string{"--cache=" + cacachePath}

// Install dependencies in the npm project.
_, _, err = RunNpmCmd("npm", projectPath, Ci, npmArgs, logger)
assert.NoError(t, err)

// Calculate dependencies.
dependencies, err := CalculateNpmDependenciesList("npm", projectPath, "build-info-go-tests", npmArgs, true, logger)
assert.NoError(t, err)

// Check peer dependency is not found.
var excpected []entities.Dependency
assert.NoError(t, utils.Unmarshal(filepath.Join(projectPath, "excpected_dependencies_list.json"), &excpected))
match, err := entities.IsEqualDependencySlices(excpected, dependencies)
assert.NoError(t, err)
if !match {
testdatautils.PrintBuildInfoMismatch(t, []entities.Module{{Dependencies: excpected}}, []entities.Module{{Dependencies: dependencies}})
}
validateDependencies(t, projectPath, npmArgs)
}

// This test runs with npm v6. It collects build-info for npm project that has conflicts in peer dependencies.
Expand All @@ -185,21 +169,8 @@ func TestConflictsDependenciesList(t *testing.T) {
defer cleanup()
cacachePath := filepath.Join(projectPath, "tmpcache")
npmArgs := []string{"--cache=" + cacachePath}
// Install dependencies in the npm project.
_, _, err = RunNpmCmd("npm", projectPath, Ci, npmArgs, logger)
assert.NoError(t, err)

// Calculate dependencies.
dependencies, err := CalculateNpmDependenciesList("npm", projectPath, "build-info-go-tests", npmArgs, true, logger)
assert.NoError(t, err)

var excpected []entities.Dependency
assert.NoError(t, utils.Unmarshal(filepath.Join(projectPath, "excpected_dependencies_list.json"), &excpected))
match, err := entities.IsEqualDependencySlices(dependencies, excpected)
assert.NoError(t, err)
if !match {
testdatautils.PrintBuildInfoMismatch(t, []entities.Module{{Dependencies: excpected}}, []entities.Module{{Dependencies: dependencies}})
}
validateDependencies(t, projectPath, npmArgs)
}

// This case happens when the package-lock.json with property '"lockfileVersion": 1,' gets updated to version '"lockfileVersion": 2,' (from npm v6 to npm v7/v8).
Expand All @@ -224,14 +195,7 @@ func TestDependencyWithNoIntegrity(t *testing.T) {
dependencies, err := CalculateNpmDependenciesList("npm", projectPath, "jfrogtest", npmArgs, true, logger)
assert.NoError(t, err)

// Verify results.
var excpected []entities.Dependency
assert.NoError(t, utils.Unmarshal(filepath.Join(projectPath, "excpected_dependencies_list.json"), &excpected))
match, err := entities.IsEqualDependencySlices(excpected, dependencies)
assert.NoError(t, err)
if !match {
testdatautils.PrintBuildInfoMismatch(t, []entities.Module{{Dependencies: excpected}}, []entities.Module{{Dependencies: dependencies}})
}
assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!")
}

// A project built differently for each operating system.
Expand All @@ -244,7 +208,7 @@ func TestDependenciesTreeDiffrentBetweenOss(t *testing.T) {
defer cleanup()
cacachePath := filepath.Join(projectPath, "tmpcache")

// Install all of the project's dependencies.
// Install all the project's dependencies.
npmArgs := []string{"--cache=" + cacachePath}
_, _, err = RunNpmCmd("npm", projectPath, Ci, npmArgs, logger)
assert.NoError(t, err)
Expand All @@ -253,14 +217,16 @@ func TestDependenciesTreeDiffrentBetweenOss(t *testing.T) {
dependencies, err := CalculateNpmDependenciesList("npm", projectPath, "bundle-dependencies", npmArgs, true, logger)
assert.NoError(t, err)

// Verify results.
var excpected []entities.Dependency
assert.NoError(t, utils.Unmarshal(filepath.Join(projectPath, "excpected_dependencies_list.json"), &excpected))
match, err := entities.IsEqualDependencySlices(excpected, dependencies)
assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!")

// Remove node_modules directory, then calculate dependencies by package-lock.
assert.NoError(t, utils.RemoveTempDir(filepath.Join(projectPath, "node_modules")))

dependencies, err = CalculateNpmDependenciesList("npm", projectPath, "build-info-go-tests", npmArgs, true, logger)
assert.NoError(t, err)
if !match {
testdatautils.PrintBuildInfoMismatch(t, []entities.Module{{Dependencies: excpected}}, []entities.Module{{Dependencies: dependencies}})
}

// Asserting there is at least one dependency.
assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!")
}

func TestNpmProdFlag(t *testing.T) {
Expand Down Expand Up @@ -325,3 +291,27 @@ func TestGetConfigCacheNpmIntegration(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, filepath.Join(cachePath, "_cacache"), configCache)
}

// This function executes Ci, then validate generating dependencies in two possible scenarios:
// 1. node_module exists in the project.
// 2. node_module doesn't exist in the project and generating dependencies needs package-lock.
func validateDependencies(t *testing.T, projectPath string, npmArgs []string) {
// Install dependencies in the npm project.
_, _, err := RunNpmCmd("npm", projectPath, Ci, npmArgs, logger)
assert.NoError(t, err)

// Calculate dependencies.
dependencies, err := CalculateNpmDependenciesList("npm", projectPath, "build-info-go-tests", npmArgs, true, logger)
assert.NoError(t, err)

assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!")

// Remove node_modules directory, then calculate dependencies by package-lock.
assert.NoError(t, utils.RemoveTempDir(filepath.Join(projectPath, "node_modules")))

dependencies, err = CalculateNpmDependenciesList("npm", projectPath, "build-info-go-tests", npmArgs, true, logger)
assert.NoError(t, err)

// Asserting there is at least one dependency.
assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!")
}

0 comments on commit 40746ff

Please sign in to comment.