From 4747a71b02a019c0b27bc8e79d7d48ed2c7aa6d3 Mon Sep 17 00:00:00 2001 From: yahavi Date: Wed, 18 Oct 2023 15:00:05 +0300 Subject: [PATCH] Support running npm install without package.json --- build/npm.go | 2 +- build/utils/npm.go | 10 ++++- build/utils/npm_test.go | 83 +++++++++++++++++++++++++---------------- build/yarn.go | 7 ++-- 4 files changed, 63 insertions(+), 39 deletions(-) diff --git a/build/npm.go b/build/npm.go index 10d658f3..c26a9a4b 100644 --- a/build/npm.go +++ b/build/npm.go @@ -43,7 +43,7 @@ func newNpmModule(srcPath string, containingBuild *Build) (*NpmModule, error) { } // Read module name - packageInfo, err := buildutils.ReadPackageInfoFromPackageJson(srcPath, npmVersion) + packageInfo, err := buildutils.ReadPackageInfoFromPackageJsonIfExist(srcPath, npmVersion) if err != nil { return nil, err } diff --git a/build/utils/npm.go b/build/utils/npm.go index 9751bfb7..ffc95e77 100644 --- a/build/utils/npm.go +++ b/build/utils/npm.go @@ -442,10 +442,16 @@ type PackageInfo struct { Scope string } -func ReadPackageInfoFromPackageJson(packageJsonDirectory string, npmVersion *version.Version) (*PackageInfo, error) { +// Read and populate package name, version and scope from the package.json file in the provided directory. +// If package.json does not exist, return an empty PackageInfo object. +func ReadPackageInfoFromPackageJsonIfExist(packageJsonDirectory string, npmVersion *version.Version) (*PackageInfo, error) { packageJson, err := os.ReadFile(filepath.Join(packageJsonDirectory, "package.json")) if err != nil { - return nil, err + if os.IsNotExist(err) { + return &PackageInfo{}, nil + } else { + return nil, err + } } return ReadPackageInfo(packageJson, npmVersion) } diff --git a/build/utils/npm_test.go b/build/utils/npm_test.go index 23509790..9f34ca14 100644 --- a/build/utils/npm_test.go +++ b/build/utils/npm_test.go @@ -1,14 +1,15 @@ package utils import ( - "github.com/jfrog/build-info-go/entities" - "github.com/stretchr/testify/require" "os" "path/filepath" - "reflect" + "strings" "testing" "time" + "github.com/jfrog/build-info-go/entities" + "github.com/stretchr/testify/require" + testdatautils "github.com/jfrog/build-info-go/build/testdata" "github.com/jfrog/build-info-go/utils" "github.com/stretchr/testify/assert" @@ -16,7 +17,7 @@ import ( var logger = utils.NewDefaultLogger(utils.INFO) -func TestReadPackageInfoFromPackageJson(t *testing.T) { +func TestReadPackageInfo(t *testing.T) { npmVersion, _, err := GetNpmVersionAndExecPath(logger) if err != nil { assert.NoError(t, err) @@ -31,18 +32,48 @@ func TestReadPackageInfoFromPackageJson(t *testing.T) { &PackageInfo{Name: "build-info-go-tests", Version: "1.0.0", Scope: ""}}, {`{ "name": "@jfrog/build-info-go-tests", "version": "1.0.0", "description": "test package"}`, &PackageInfo{Name: "build-info-go-tests", Version: "1.0.0", Scope: "@jfrog"}}, + {`{}`, &PackageInfo{}}, } for _, test := range tests { t.Run(test.json, func(t *testing.T) { packInfo, err := ReadPackageInfo([]byte(test.json), npmVersion) - if err != nil { - t.Error("No error was expected in this test", err) - } + assert.NoError(t, err) + assert.Equal(t, test.pi, packInfo) + }) + } +} + +func TestReadPackageInfoFromPackageJsonIfExist(t *testing.T) { + // Prepare tests + npmVersion, _, err := GetNpmVersionAndExecPath(logger) + assert.NoError(t, err) + path, err := filepath.Abs(filepath.Join("..", "testdata")) + assert.NoError(t, err) + projectPath, cleanup := testdatautils.CreateNpmTest(t, path, "project1", false, npmVersion) + defer cleanup() - equals := reflect.DeepEqual(test.pi, packInfo) - if !equals { - t.Error("expected:", test.pi, "got:", packInfo) + testCases := []struct { + testName string + packageJsonDirectory string + expectedPackageInfo *PackageInfo + }{ + {"Happy flow", projectPath, &PackageInfo{Name: "build-info-go-tests", Version: "1.0.0"}}, + {"No package.json in path", path, &PackageInfo{Name: "", Version: ""}}, + {"Path to file", filepath.Join(projectPath, "package.json"), nil}, + } + + for _, testCase := range testCases { + t.Run(testCase.testName, func(t *testing.T) { + packageInfo, err := ReadPackageInfoFromPackageJsonIfExist(testCase.packageJsonDirectory, npmVersion) + if testCase.expectedPackageInfo == nil { + assert.Error(t, err) + return } + assert.NoError(t, err) + removeVersionPrefixes(packageInfo) + assert.Equal(t, testCase.expectedPackageInfo.Name, packageInfo.Name) + actualVersion, _ := strings.CutPrefix(packageInfo.Version, "v") + assert.Equal(t, testCase.expectedPackageInfo.Version, actualVersion) }) } } @@ -57,10 +88,7 @@ func TestGetDeployPath(t *testing.T) { } for _, test := range tests { t.Run(test.expectedPath, func(t *testing.T) { - actualPath := test.pi.GetDeployPath() - if actualPath != test.expectedPath { - t.Error("expected:", test.expectedPath, "got:", actualPath) - } + assert.Equal(t, test.expectedPath, test.pi.GetDeployPath()) }) } } @@ -93,15 +121,8 @@ func TestParseDependencies(t *testing.T) { } dependencies := make(map[string]*dependencyInfo) err = parseDependencies(dependenciesJsonList, []string{"root"}, dependencies, npmLsDependencyParser, utils.NewDefaultLogger(utils.INFO)) - if err != nil { - t.Error(err) - } - if len(expectedDependenciesList) != len(dependencies) { - t.Error("The expected dependencies list length is", len(expectedDependenciesList), "and should be:\n", expectedDependenciesList, - "\nthe actual dependencies list length is", len(dependencies), "and the list is:\n", dependencies) - t.Error("The expected dependencies list length is", len(expectedDependenciesList), "and should be:\n", expectedDependenciesList, - "\nthe actual dependencies list length is", len(dependencies), "and the list is:\n", dependencies) - } + assert.NoError(t, err) + assert.Equal(t, len(expectedDependenciesList), len(dependencies)) for _, eDependency := range expectedDependenciesList { found := false for aDependency, v := range dependencies { @@ -110,9 +131,7 @@ func TestParseDependencies(t *testing.T) { break } } - if !found { - t.Error("The expected dependency:", eDependency, "is missing from the actual dependencies list:\n", dependencies) - } + assert.True(t, found, "The expected dependency:", eDependency, "is missing from the actual dependencies list:\n", dependencies) } } @@ -136,9 +155,7 @@ func TestAppendScopes(t *testing.T) { } for _, v := range scopes { result := appendScopes(v.a, v.b) - if !assert.ElementsMatch(t, result, v.expected) { - t.Errorf("appendScopes(\"%s\",\"%s\") => '%s', want '%s'", v.a, v.b, result, v.expected) - } + assert.ElementsMatch(t, result, v.expected, "appendScopes(\"%s\",\"%s\") => '%s', want '%s'", v.a, v.b, result, v.expected) } } @@ -299,7 +316,7 @@ func TestDependenciesTreeDifferentBetweenOKs(t *testing.T) { dependencies, err := CalculateNpmDependenciesList("npm", projectPath, "bundle-dependencies", NpmTreeDepListParam{Args: npmArgs}, true, logger) assert.NoError(t, err) - assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!") + assert.Greater(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"))) @@ -308,7 +325,7 @@ func TestDependenciesTreeDifferentBetweenOKs(t *testing.T) { assert.NoError(t, err) // Asserting there is at least one dependency. - assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!") + assert.Greater(t, len(dependencies), 0, "Error: dependencies are not found!") } func TestNpmProdFlag(t *testing.T) { @@ -387,7 +404,7 @@ func validateDependencies(t *testing.T, projectPath string, npmArgs []string) { dependencies, err := CalculateNpmDependenciesList("npm", projectPath, "build-info-go-tests", NpmTreeDepListParam{Args: npmArgs}, true, logger) assert.NoError(t, err) - assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!") + assert.Greater(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"))) @@ -396,5 +413,5 @@ func validateDependencies(t *testing.T, projectPath string, npmArgs []string) { assert.NoError(t, err) // Asserting there is at least one dependency. - assert.Greaterf(t, len(dependencies), 0, "Error: dependencies are not found!") + assert.Greater(t, len(dependencies), 0, "Error: dependencies are not found!") } diff --git a/build/yarn.go b/build/yarn.go index 143dbd58..52f3e21a 100644 --- a/build/yarn.go +++ b/build/yarn.go @@ -3,13 +3,14 @@ package build import ( "errors" "fmt" + "os" + "os/exec" + buildutils "github.com/jfrog/build-info-go/build/utils" "github.com/jfrog/build-info-go/entities" "github.com/jfrog/build-info-go/utils" "github.com/jfrog/gofrog/version" "golang.org/x/exp/slices" - "os" - "os/exec" ) const minSupportedYarnVersion = "2.4.0" @@ -49,7 +50,7 @@ func newYarnModule(srcPath string, containingBuild *Build) (*YarnModule, error) } // Read module name - packageInfo, err := buildutils.ReadPackageInfoFromPackageJson(srcPath, nil) + packageInfo, err := buildutils.ReadPackageInfoFromPackageJsonIfExist(srcPath, nil) if err != nil { return nil, err }