Skip to content

Commit

Permalink
first draft of the work. still need ordering, switching all GetYarnDe…
Browse files Browse the repository at this point in the history
…pendencies to use the function GetYarnDependencies2 (and then switch the names) and last- fix all calls in tests.
  • Loading branch information
eranturgeman committed Jul 23, 2023
1 parent 75ffd8b commit 5b9cca7
Show file tree
Hide file tree
Showing 4 changed files with 693 additions and 110 deletions.
116 changes: 15 additions & 101 deletions build/utils/yarn.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/jfrog/build-info-go/entities"
"github.com/jfrog/build-info-go/utils"
"github.com/jfrog/gofrog/parallel"
"github.com/jfrog/jfrog-cli-core/v2/xray/audit"
"github.com/pkg/errors"
"os/exec"
"strings"
Expand Down Expand Up @@ -93,62 +94,16 @@ func GetYarnExecutable() (string, error) {
return yarnExecPath, nil
}

// TODO DELETE
// GetYarnDependencies this function is intended for yarn 2.0.0 and above!
// returns a map of the dependencies of a Yarn project and the root package of the project.
// The keys are the packages' values (Yarn's full identifiers of the packages), for example: '@scope/package-name@npm:1.0.0'.
// GetYarnDependencies returns a map of the dependencies of a Yarn project and the root package of the project.
// The keys are the packages' values (Yarn's full identifiers of the packages), for example: '@scope/[email protected]'.
// Pay attention that a package's value won't necessarily contain its version. Use the version in package's details instead.
// Note that in some versions of Yarn, the version of the root package is '0.0.0-use.local', instead of the version in the package.json file.

func GetYarnDependencies(executablePath, srcPath string, packageInfo *PackageInfo, log utils.Log) (dependenciesMap map[string]*YarnDependency, root *YarnDependency, err error) {
// Run 'yarn info or list'
responseStr, errStr, err := runYarnInfoOrList(executablePath, srcPath, true)
// Some warnings and messages of Yarn are printed to stderr. They don't necessarily cause the command to fail, but we'd want to show them to the user.
if len(errStr) > 0 {
log.Warn("An error occurred while collecting dependencies info:\n" + errStr)
}
executableVersion, err := audit.GetExecutableVersion(executablePath)
if err != nil {
log.Warn("An error was thrown while collecting dependencies info: " + err.Error() + "\nCommand output:\n" + responseStr)

// A returned error doesn't necessarily mean that the operation totally failed. If, in addition, the response is empty, then it probably failed.
if responseStr == "" {
return
}
err = nil
}

dependenciesMap = make(map[string]*YarnDependency)
scanner := bufio.NewScanner(strings.NewReader(responseStr))

for scanner.Scan() {
var currDependency YarnDependency
currDepBytes := scanner.Bytes()
err = json.Unmarshal(currDepBytes, &currDependency)
if err != nil {
return
}

// Check whether this dependency's name starts with the package name (which means this is the root)
if strings.HasPrefix(currDependency.Value, packageInfo.FullName()+"@") {
// In some versions of Yarn, the version of the root project returned from the 'yarn info' command is '0.0.0-use.local', instead of the version mentioned in the package.json.
// It was fixed in later versions of Yarn.
if currDependency.Details.Version == "0.0.0-use.local" {
currDependency.Details.Version = packageInfo.Version
}

root = &currDependency
}

dependenciesMap[currDependency.Value] = &currDependency
return
}
return
}

// GetYarnDependencies returns a map of the dependencies of a Yarn project and the root package of the project.
// The keys are the packages' values (Yarn's full identifiers of the packages), for example: '@scope/[email protected]'.
// Pay attention that a package's value won't necessarily contain its version. Use the version in package's details instead.
func GetYarnDependencies2(executablePath, srcPath string, packageInfo *PackageInfo, log utils.Log, execVersion string) (dependenciesMap map[string]*YarnDependency, root *YarnDependency, err error) {
isV2AndAbove := strings.Compare(execVersion, YarnV2Version) >= 0
isV2AndAbove := strings.Compare(executableVersion, YarnV2Version) >= 0
// Run 'yarn info or list'
responseStr, errStr, err := runYarnInfoOrList(executablePath, srcPath, isV2AndAbove)
// Some warnings and messages of Yarn are printed to stderr. They don't necessarily cause the command to fail, but we'd want to show them to the user.
Expand All @@ -165,7 +120,6 @@ func GetYarnDependencies2(executablePath, srcPath string, packageInfo *PackageIn
err = nil
}

//dependenciesMap = make(map[string]*YarnDependency)
if isV2AndAbove {
dependenciesMap, root, err = BuildYarnV2DependencyMap(packageInfo, responseStr)
} else {
Expand All @@ -174,26 +128,26 @@ func GetYarnDependencies2(executablePath, srcPath string, packageInfo *PackageIn
return
}

// BuildYarnV1DependencyMap builds a map of dependencies
// BuildYarnV1DependencyMap builds a map of dependencies for Yarn versions < 2.0.0
// Pay attention that in Yarn < 2.0.0 the project itself with its direct dependencies is not presented when running the
// command 'yarn list' therefore the root is built manually.
func BuildYarnV1DependencyMap(packageInfo *PackageInfo, responseStr string) (dependenciesMap map[string]*YarnDependency, root *YarnDependency, err error) {
dependenciesMap = make(map[string]*YarnDependency)
var depTree Yarn1JsonTop
var depTree Yarn1Data
err = json.Unmarshal([]byte(responseStr), &depTree)
if err != nil {
return
}

locatorsMap := make(map[string]string) //TODO del
locatorsMap := make(map[string]string)
for _, curDependency := range depTree.Data.DepTree {
locatorsMap[curDependency.Name[:strings.Index(curDependency.Name[1:], "@")+1]] = curDependency.Name
}

for _, curDependency := range depTree.Data.DepTree {
var dependency YarnDependency
dependency.Value = curDependency.Name
version := curDependency.Name[strings.Index(curDependency.Name[1:], "@")+2:] //TODO make sure the +2 is ok, suppose to cover a package that starts with @
version := curDependency.Name[strings.Index(curDependency.Name[1:], "@")+2:] // TODO make sure the +2 is ok, suppose to cover a package that starts with @
packageCleanName := curDependency.Name[:strings.Index(curDependency.Name[1:], "@")+1]
locatorsMap[packageCleanName] = curDependency.Name

Expand All @@ -206,12 +160,12 @@ func BuildYarnV1DependencyMap(packageInfo *PackageInfo, responseStr string) (dep
dependenciesMap[curDependency.Name] = &dependency
}

root = BuildYarn1Root(&depTree, packageInfo, &locatorsMap)
root = BuildYarn1Root(packageInfo, &locatorsMap)
dependenciesMap[root.Value] = root
return
}

// BuildYarnV2DependencyMap builds a map of dependencies
// BuildYarnV2DependencyMap builds a map of dependencies for Yarn version >= 2.0.0
// Note that in some versions of Yarn, the version of the root package is '0.0.0-use.local', instead of the version in the package.json file.
func BuildYarnV2DependencyMap(packageInfo *PackageInfo, responseStr string) (dependenciesMap map[string]*YarnDependency, root *YarnDependency, err error) {
dependenciesMap = make(map[string]*YarnDependency)
Expand Down Expand Up @@ -278,48 +232,8 @@ func GetYarnDependencyKeyFromLocator(yarnDepLocator string) string {
return yarnDepLocator[:virtualIndex+1] + yarnDepLocator[hashSignIndex+1:]
}

/*
TODO delete when done
// THIS IS THE VERSION WITHOUT USING PACKAGE.JSON
func BuildYarn1RootTest(depTree *Yarn1JsonTop, packageInfo *PackageInfo) (root *YarnDependency) {
// getting all dependencies and sub-dependencies
allDependencies := make(map[string][2]string)
subDependencies := make(map[string]string)
for idx, dependency := range depTree.Data.DepTree {
depName := dependency.Name[:strings.Index(dependency.Name[1:], "@")+1]
allDependencies[depName] = [2]string{dependency.Name, dependency.Color}
if len(depTree.Data.DepTree[idx].Dependencies) > 0 {
subDeps := depTree.Data.DepTree[idx].Dependencies
for _, dep := range subDeps {
subDependencies[dep.DependencyName[:strings.Index(dep.DependencyName[1:], "@")+1]] = ""
}
}
}
// filtering out all dependencies which are not direct
for dependencyName, _ := range subDependencies {
if _, exists := allDependencies[dependencyName]; exists && allDependencies[dependencyName][1] != "bold" {
delete(allDependencies, dependencyName)
}
}
// build root dependency
var rootDependency YarnDependency
rootDependency.Value = packageInfo.Name
version := packageInfo.Version
rootDependency.Details = YarnDepDetails{version, nil}
for _, info := range allDependencies {
directDependencyName := info[0]
rootDependency.Details.Dependencies = append(rootDependency.Details.Dependencies, YarnDependencyPointer{"", directDependencyName})
}
root = &rootDependency
return
}
*/

// BuildYarn1Root finds the direct dependencies of the project and builds
func BuildYarn1Root(depTree *Yarn1JsonTop, packageInfo *PackageInfo, locatorsMap *map[string]string) (root *YarnDependency) {
// BuildYarn1Root builds the root of the project's dependency tree (from direct dependencies in package.json)
func BuildYarn1Root(packageInfo *PackageInfo, locatorsMap *map[string]string) (root *YarnDependency) {
var rootDependency YarnDependency
rootDependency.Value = packageInfo.Name
version := packageInfo.Version
Expand All @@ -331,7 +245,7 @@ func BuildYarn1Root(depTree *Yarn1JsonTop, packageInfo *PackageInfo, locatorsMap
return
}

type Yarn1JsonTop struct {
type Yarn1Data struct {
Data YarnDependencyTree `json:"data,omitempty"`
}

Expand Down
10 changes: 10 additions & 0 deletions build/utils/yarn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,13 @@ func TestGetYarnDependencies(t *testing.T) {
assert.Equal(t, "v1.0.0", root.Details.Version)
assert.Len(t, dependenciesMap, 3)
}

/*
TESTS TO ADD:
1) conversion from v1 unmarshall to v2 struct
2) correct build of v1 root
*/

func TestBuildYarnV1DependencyMap(t *testing.T) {

}
59 changes: 56 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,77 @@ require (
github.com/CycloneDX/cyclonedx-go v0.7.1
github.com/buger/jsonparser v1.1.1
github.com/jfrog/gofrog v1.3.0
github.com/jfrog/jfrog-cli-core/v2 v2.39.2
github.com/minio/sha256-simd v1.0.1-0.20230222114820-6096f891a77b
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.8.2
github.com/stretchr/testify v1.8.4
github.com/urfave/cli/v2 v2.25.1
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/exp v0.0.0-20230418202329-0354be287a23
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1

)

require (
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/forPelevin/gomoji v1.1.8 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/go-git/go-git/v5 v5.7.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.2 // indirect
github.com/gookit/color v1.5.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/imdario/mergo v0.3.15 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jedib0t/go-pretty/v6 v6.4.6 // indirect
github.com/jfrog/jfrog-client-go v1.31.2 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.11.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.3 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mholt/archiver/v3 v3.5.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/owenrumney/go-sarif/v2 v2.1.3 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pierrec/lz4/v4 v4.1.2 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/skeema/knownhosts v1.1.1 // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.15.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/ulikunitz/xz v0.5.9 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/term v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit 5b9cca7

Please sign in to comment.