From 3f0de94011d768b6ba02fdfc0a4d4a6db8282687 Mon Sep 17 00:00:00 2001 From: Robi Nino Date: Mon, 18 Mar 2024 16:48:14 +0200 Subject: [PATCH 01/36] Promote version to 2.49.0 (#1157) --- go.mod | 8 ++++---- go.sum | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 6ae768550..5d9f3fc81 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,9 @@ require ( github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 github.com/jedib0t/go-pretty/v6 v6.5.4 - github.com/jfrog/build-info-go v1.9.23 + github.com/jfrog/build-info-go v1.9.24 github.com/jfrog/gofrog v1.6.3 - github.com/jfrog/jfrog-client-go v1.37.1 + github.com/jfrog/jfrog-client-go v1.38.0 github.com/magiconair/properties v1.8.7 github.com/manifoldco/promptui v0.9.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -96,8 +96,8 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240318124620-6267b7025659 +// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go dev -replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240311081927-91b472899d7d +// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc diff --git a/go.sum b/go.sum index a9fb9a01b..ee7d37364 100644 --- a/go.sum +++ b/go.sum @@ -83,12 +83,12 @@ github.com/jedib0t/go-pretty/v6 v6.5.4 h1:gOGo0613MoqUcf0xCj+h/V3sHDaZasfv152G6/ github.com/jedib0t/go-pretty/v6 v6.5.4/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= -github.com/jfrog/build-info-go v1.8.9-0.20240311081927-91b472899d7d h1:zYom4uvjHfO1ECk5aCTg6BTDKPVJZ/ddim9F+hzbmI8= -github.com/jfrog/build-info-go v1.8.9-0.20240311081927-91b472899d7d/go.mod h1:CaCKqcg3V2W9/ZysE4ZvXZMgsvunclhjrTTQQGp3CzM= +github.com/jfrog/build-info-go v1.9.24 h1:MjT+4bYecbNQ+dbLczg0lkE5DoLAhdyrF0cRXtnEJqI= +github.com/jfrog/build-info-go v1.9.24/go.mod h1:CaCKqcg3V2W9/ZysE4ZvXZMgsvunclhjrTTQQGp3CzM= github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc= github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240318124620-6267b7025659 h1:0tytbHFWEyDJrxu+PHN41nDQipUE8rDwldsl4kvC2qM= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240318124620-6267b7025659/go.mod h1:NB8tYFgkWtn+wHsKC+aYC75aLnS6yW81d8JAFTBxsi0= +github.com/jfrog/jfrog-client-go v1.38.0 h1:0QP4/dSmJe0oYUrAqzoPDpGdJHcrOeq9mycnb0pSxqQ= +github.com/jfrog/jfrog-client-go v1.38.0/go.mod h1:EHRLxpu0pIT7+ulYDNQ7IeieYBHMQeEPr8CoBHoJzQY= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= From 30cf248eadfbe3ad26b3072a485df0ea03d26184 Mon Sep 17 00:00:00 2001 From: Eran Turgeman <81029514+eranturgeman@users.noreply.github.com> Date: Tue, 19 Mar 2024 16:40:25 +0200 Subject: [PATCH 02/36] Additions to support Pnpm in frogbot (#1150) --- utils/coreutils/techutils.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/utils/coreutils/techutils.go b/utils/coreutils/techutils.go index ca63dc653..fa12fc2b2 100644 --- a/utils/coreutils/techutils.go +++ b/utils/coreutils/techutils.go @@ -87,11 +87,12 @@ var technologiesData = map[Technology]TechData{ applicabilityScannable: true, }, Pnpm: { - indicators: []string{"pnpm-lock.yaml"}, - exclude: []string{".yarnrc.yml", "yarn.lock", ".yarn"}, - packageDescriptors: []string{"package.json"}, - packageVersionOperator: "@", - applicabilityScannable: true, + indicators: []string{"pnpm-lock.yaml"}, + exclude: []string{".yarnrc.yml", "yarn.lock", ".yarn"}, + packageDescriptors: []string{"package.json"}, + packageVersionOperator: "@", + packageInstallationCommand: "update", + applicabilityScannable: true, }, Yarn: { indicators: []string{".yarnrc.yml", "yarn.lock", ".yarn", ".yarnrc"}, From bc5cbba1542b0c94f4ff0bf7fb90feb6404b27d8 Mon Sep 17 00:00:00 2001 From: Michael Sverdlov Date: Tue, 19 Mar 2024 16:59:27 +0200 Subject: [PATCH 03/36] Simplify file closer funcs (#1158) --- .github/workflows/analysis.yml | 10 +++--- .github/workflows/test.yml | 5 +-- artifactory/commands/generic/delete.go | 15 ++------ artifactory/commands/generic/upload.go | 13 +++---- artifactory/commands/golang/publish.go | 6 ++-- artifactory/commands/npm/publish.go | 8 ++--- .../commands/python/dependencies/cache.go | 15 ++------ .../python/dependencies/dependencies.go | 8 ++--- .../commands/terraform/terraformpublish.go | 8 ++--- .../commands/transferfiles/errorshandler.go | 11 ++---- .../commands/transferfiles/transfer.go | 10 ++---- artifactory/commands/utils/result_test.go | 8 ++--- artifactory/commands/utils/transfer.go | 8 ++--- artifactory/commands/utils/yarnutils.go | 8 ++--- artifactory/utils/container/buildinfo.go | 8 ++--- artifactory/utils/npm/config-list.go | 6 ++-- artifactory/utils/search.go | 15 ++------ artifactory/utils/transfersettings.go | 11 ++---- common/commands/config.go | 5 +-- go.mod | 18 +++++----- go.sum | 35 ++++++++++--------- utils/config/encryption.go | 8 ++--- utils/config/tokenrefresh.go | 11 ++---- utils/coreutils/tableutils.go | 6 ++-- utils/plugins/utils.go | 6 ++-- 25 files changed, 85 insertions(+), 177 deletions(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index 23a98a6e9..a8a77bee8 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -13,10 +13,11 @@ jobs: - name: Checkout Source uses: actions/checkout@v4 - - name: Install Go - uses: actions/setup-go@v3 + - name: Setup Go + uses: actions/setup-go@v5 with: go-version: 1.20.x + cache: false - name: Static Code Analysis uses: golangci/golangci-lint-action@v3 @@ -31,10 +32,11 @@ jobs: - name: Checkout Source uses: actions/checkout@v4 - - name: Install Go - uses: actions/setup-go@v3 + - name: Setup Go + uses: actions/setup-go@v5 with: go-version: 1.20.x + cache: false - name: Run Gosec Security Scanner # Temporarily set version 2.18.0 to workaround https://github.com/securego/gosec/issues/1046 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a3026f842..1693490dd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,10 +28,11 @@ jobs: - name: Install pipenv & poetry run: python -m pip install pipenv poetry - - name: Install Go - uses: actions/setup-go@v3 + - name: Setup Go + uses: actions/setup-go@v5 with: go-version: 1.20.x + cache: false - name: Install NuGet uses: nuget/setup-nuget@v1 diff --git a/artifactory/commands/generic/delete.go b/artifactory/commands/generic/delete.go index 38f93af67..ede3965c8 100644 --- a/artifactory/commands/generic/delete.go +++ b/artifactory/commands/generic/delete.go @@ -1,6 +1,7 @@ package generic import ( + ioutils "github.com/jfrog/gofrog/io" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-client-go/artifactory/services" @@ -36,12 +37,7 @@ func (dc *DeleteCommand) Run() (err error) { if err != nil { return } - defer func() { - e := reader.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(reader, &err) allowDelete := true if !dc.quiet { allowDelete, err = utils.ConfirmDelete(reader) @@ -95,12 +91,7 @@ func (dc *DeleteCommand) GetPathsToDelete() (contentReader *content.ContentReade if err != nil { return nil, err } - defer func() { - e := tempMergedReader.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(tempMergedReader, &err) // After merge, remove top chain dirs as we may encounter duplicates and collisions between files and directories to delete. // For example: // Reader1: {"a"} diff --git a/artifactory/commands/generic/upload.go b/artifactory/commands/generic/upload.go index 9fa2a0831..c89cd9f8b 100644 --- a/artifactory/commands/generic/upload.go +++ b/artifactory/commands/generic/upload.go @@ -5,9 +5,7 @@ import ( buildInfo "github.com/jfrog/build-info-go/entities" - "strconv" - "time" - + ioutils "github.com/jfrog/gofrog/io" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/common/build" "github.com/jfrog/jfrog-cli-core/v2/common/spec" @@ -18,6 +16,8 @@ import ( ioUtils "github.com/jfrog/jfrog-client-go/utils/io" "github.com/jfrog/jfrog-client-go/utils/io/content" "github.com/jfrog/jfrog-client-go/utils/log" + "strconv" + "time" ) type UploadCommand struct { @@ -263,12 +263,7 @@ func (uc *UploadCommand) handleSyncDeletes(syncDeletesProp string) (err error) { if err != nil { return err } - defer func() { - e := resultItems.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(resultItems, &err) _, err = servicesManager.DeleteFiles(resultItems) return err } diff --git a/artifactory/commands/golang/publish.go b/artifactory/commands/golang/publish.go index ba123c901..c9a73a3c8 100644 --- a/artifactory/commands/golang/publish.go +++ b/artifactory/commands/golang/publish.go @@ -4,6 +4,7 @@ import ( "archive/zip" "bytes" "encoding/json" + "errors" "fmt" buildinfo "github.com/jfrog/build-info-go/entities" biutils "github.com/jfrog/build-info-go/utils" @@ -57,10 +58,7 @@ func publishPackage(packageVersion, targetRepo, buildName, buildNumber, projectK return nil, nil, err } defer func() { - e := fileutils.RemoveTempDir(tempDirPath) - if err == nil { - err = e - } + err = errors.Join(err, fileutils.RemoveTempDir(tempDirPath)) }() var zipArtifact *buildinfo.Artifact diff --git a/artifactory/commands/npm/publish.go b/artifactory/commands/npm/publish.go index 764fc1b73..333655bba 100644 --- a/artifactory/commands/npm/publish.go +++ b/artifactory/commands/npm/publish.go @@ -5,6 +5,7 @@ import ( "compress/gzip" "errors" "fmt" + ioutils "github.com/jfrog/gofrog/io" "io" "os" "path/filepath" @@ -198,12 +199,7 @@ func (npc *NpmPublishCommand) Run() (err error) { if err != nil { return err } - defer func() { - e := npc.artifactsDetailsReader.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(npc.artifactsDetailsReader, &err) err = npmModule.AddArtifacts(buildArtifacts...) if err != nil { return errorutils.CheckError(err) diff --git a/artifactory/commands/python/dependencies/cache.go b/artifactory/commands/python/dependencies/cache.go index 3a15ad8df..71b5dd215 100644 --- a/artifactory/commands/python/dependencies/cache.go +++ b/artifactory/commands/python/dependencies/cache.go @@ -3,6 +3,7 @@ package dependencies import ( "encoding/json" buildinfo "github.com/jfrog/build-info-go/entities" + ioutils "github.com/jfrog/gofrog/io" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "io" @@ -31,12 +32,7 @@ func GetProjectDependenciesCache(cacheDir string) (cache *DependenciesCache, err if errorutils.CheckError(err) != nil { return nil, err } - defer func() { - e := jsonFile.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(jsonFile, &err) byteValue, err := io.ReadAll(jsonFile) if errorutils.CheckError(err) != nil { return nil, err @@ -66,12 +62,7 @@ func UpdateDependenciesCache(updatedMap map[string]buildinfo.Dependency, cacheDi if err != nil { return errorutils.CheckError(err) } - defer func() { - e := cacheFile.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(cacheFile, &err) _, err = cacheFile.Write(content) if err != nil { return errorutils.CheckError(err) diff --git a/artifactory/commands/python/dependencies/dependencies.go b/artifactory/commands/python/dependencies/dependencies.go index 8ab970851..142855d7c 100644 --- a/artifactory/commands/python/dependencies/dependencies.go +++ b/artifactory/commands/python/dependencies/dependencies.go @@ -3,6 +3,7 @@ package dependencies import ( "encoding/json" "fmt" + ioutils "github.com/jfrog/gofrog/io" "io" "strings" @@ -96,12 +97,7 @@ func getDependencyChecksumFromArtifactory(servicesManager artifactory.Artifactor if err != nil { return } - defer func() { - e := stream.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(stream, &err) result, err := io.ReadAll(stream) if err != nil { return diff --git a/artifactory/commands/terraform/terraformpublish.go b/artifactory/commands/terraform/terraformpublish.go index 6dbdefd36..517160a8e 100644 --- a/artifactory/commands/terraform/terraformpublish.go +++ b/artifactory/commands/terraform/terraformpublish.go @@ -2,6 +2,7 @@ package terraform import ( buildInfo "github.com/jfrog/build-info-go/entities" + ioutils "github.com/jfrog/gofrog/io" "github.com/jfrog/gofrog/parallel" commandsUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/utils" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" @@ -304,12 +305,7 @@ func readArtifactsFromSummary(summary *servicesUtils.OperationSummary) (artifact if artifactsDetailsReader == nil { return []buildInfo.Artifact{}, nil } - defer func() { - e := artifactsDetailsReader.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(artifactsDetailsReader, &err) return servicesUtils.ConvertArtifactsDetailsToBuildInfoArtifacts(artifactsDetailsReader) } diff --git a/artifactory/commands/transferfiles/errorshandler.go b/artifactory/commands/transferfiles/errorshandler.go index db9a8cb3e..b075d03b9 100644 --- a/artifactory/commands/transferfiles/errorshandler.go +++ b/artifactory/commands/transferfiles/errorshandler.go @@ -2,6 +2,7 @@ package transferfiles import ( "encoding/json" + "errors" "fmt" "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/transferfiles/api" "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/transferfiles/state" @@ -119,10 +120,7 @@ func (mng *TransferErrorsMng) start() (err error) { return err } defer func() { - e := mng.errorWriterMng.retryable.closeWriter() - if err == nil { - err = e - } + err = errors.Join(err, mng.errorWriterMng.retryable.closeWriter()) }() writerMng.retryable = errorWriter{writer: writerRetry, filePath: retryFilePath} // Init the content writer which is responsible for writing 'skipped errors' into files. @@ -136,10 +134,7 @@ func (mng *TransferErrorsMng) start() (err error) { return err } defer func() { - e := mng.errorWriterMng.skipped.closeWriter() - if err == nil { - err = e - } + err = errors.Join(err, mng.errorWriterMng.skipped.closeWriter()) }() writerMng.skipped = errorWriter{writer: writerSkip, filePath: skipFilePath} mng.errorWriterMng = writerMng diff --git a/artifactory/commands/transferfiles/transfer.go b/artifactory/commands/transferfiles/transfer.go index ed696c1d1..92840e75f 100644 --- a/artifactory/commands/transferfiles/transfer.go +++ b/artifactory/commands/transferfiles/transfer.go @@ -390,10 +390,7 @@ func (tdc *TransferFilesCommand) transferSingleRepo(sourceRepoKey string, target return } defer func() { - e := restoreFunc() - if err == nil { - err = e - } + err = errors.Join(err, restoreFunc()) }() if err = tdc.initCurThreads(buildInfoRepo); err != nil { @@ -643,10 +640,7 @@ func (tdc *TransferFilesCommand) cleanup(originalErr error, sourceRepos []string err = originalErr // Quit progress bar (before printing logs) if tdc.progressbar != nil { - e := tdc.progressbar.Quit() - if err == nil { - err = e - } + err = errors.Join(err, tdc.progressbar.Quit()) } // Transferring finished successfully if originalErr == nil { diff --git a/artifactory/commands/utils/result_test.go b/artifactory/commands/utils/result_test.go index 81423a2ff..380fdbe76 100644 --- a/artifactory/commands/utils/result_test.go +++ b/artifactory/commands/utils/result_test.go @@ -2,6 +2,7 @@ package utils import ( biutils "github.com/jfrog/build-info-go/utils" + ioutils "github.com/jfrog/gofrog/io" testsutils "github.com/jfrog/jfrog-client-go/utils/tests" "os" "path" @@ -43,12 +44,7 @@ func createTempDeployableArtifactFile() (filePath string, err error) { if errorutils.CheckError(err) != nil { return } - defer func() { - e := summary.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(summary, &err) tmpDir, err := fileutils.CreateTempDir() if err != nil { return diff --git a/artifactory/commands/utils/transfer.go b/artifactory/commands/utils/transfer.go index 71fabd4b1..ae9117b25 100644 --- a/artifactory/commands/utils/transfer.go +++ b/artifactory/commands/utils/transfer.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "github.com/gocarina/gocsv" + ioutils "github.com/jfrog/gofrog/io" logutils "github.com/jfrog/jfrog-cli-core/v2/utils/log" "github.com/jfrog/jfrog-client-go/http/jfroghttpclient" "github.com/jfrog/jfrog-client-go/utils/errorutils" @@ -54,12 +55,7 @@ func CreateCSVFile(filePrefix string, items interface{}, timeStarted time.Time) return } csvPath = summaryCsv.Name() - defer func() { - e := summaryCsv.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(summaryCsv, &err) // Marshal JSON typed items array to CSV file err = errorutils.CheckError(gocsv.MarshalFile(items, summaryCsv)) return diff --git a/artifactory/commands/utils/yarnutils.go b/artifactory/commands/utils/yarnutils.go index cde89b031..6d7880152 100644 --- a/artifactory/commands/utils/yarnutils.go +++ b/artifactory/commands/utils/yarnutils.go @@ -2,6 +2,7 @@ package utils import ( "encoding/json" + ioutils "github.com/jfrog/gofrog/io" "io" "strconv" "strings" @@ -54,12 +55,7 @@ func getDependencyInfo(name, ver string, previousBuildDependencies map[string]*e if err != nil { return } - defer func() { - e := stream.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(stream, &err) var result []byte result, err = io.ReadAll(stream) if err != nil { diff --git a/artifactory/utils/container/buildinfo.go b/artifactory/utils/container/buildinfo.go index 7a42f4ac4..89a543494 100644 --- a/artifactory/utils/container/buildinfo.go +++ b/artifactory/utils/container/buildinfo.go @@ -2,6 +2,7 @@ package container import ( "encoding/json" + ioutils "github.com/jfrog/gofrog/io" "os" "path" "strings" @@ -94,12 +95,7 @@ func setBuildProperties(buildName, buildNumber, project string, imageLayers []ut return } reader := content.NewContentReader(pathToFile, content.DefaultKey) - defer func() { - e := reader.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(reader, &err) _, err = serviceManager.SetProps(services.PropsParams{Reader: reader, Props: props}) return } diff --git a/artifactory/utils/npm/config-list.go b/artifactory/utils/npm/config-list.go index 477648dbf..d129ef53c 100644 --- a/artifactory/utils/npm/config-list.go +++ b/artifactory/utils/npm/config-list.go @@ -1,6 +1,7 @@ package npm import ( + "errors" gofrogcmd "github.com/jfrog/gofrog/io" npmutils "github.com/jfrog/jfrog-cli-core/v2/utils/npm" "github.com/jfrog/jfrog-client-go/utils/errorutils" @@ -12,10 +13,7 @@ import ( func GetConfigList(npmFlags []string, executablePath string) (data []byte, err error) { pipeReader, pipeWriter := io.Pipe() defer func(pipeReader *io.PipeReader) { - e := pipeReader.Close() - if err == nil { - err = e - } + err = errors.Join(err, pipeReader.Close()) }(pipeReader) npmFlags = append(npmFlags, "--json=false") diff --git a/artifactory/utils/search.go b/artifactory/utils/search.go index 1ed5823a5..c72d68d76 100644 --- a/artifactory/utils/search.go +++ b/artifactory/utils/search.go @@ -3,6 +3,7 @@ package utils import ( "encoding/json" "errors" + ioutils "github.com/jfrog/gofrog/io" "github.com/jfrog/jfrog-client-go/artifactory" "github.com/jfrog/jfrog-cli-core/v2/common/spec" @@ -70,12 +71,7 @@ func AqlResultToSearchResult(readers []*content.ContentReader) (contentReader *c if err != nil { return nil, err } - defer func() { - e := writer.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(writer, &err) for _, reader := range readers { for searchResult := new(utils.ResultItem); reader.NextRecord(searchResult) == nil; searchResult = new(utils.ResultItem) { if err != nil { @@ -149,12 +145,7 @@ func SearchResultNoDate(reader *content.ContentReader) (contentReader *content.C if err != nil { return nil, err } - defer func() { - e := writer.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(writer, &err) for resultItem := new(SearchResult); reader.NextRecord(resultItem) == nil; resultItem = new(SearchResult) { if err != nil { return nil, err diff --git a/artifactory/utils/transfersettings.go b/artifactory/utils/transfersettings.go index 1a3d36fd8..705743c31 100644 --- a/artifactory/utils/transfersettings.go +++ b/artifactory/utils/transfersettings.go @@ -3,6 +3,7 @@ package utils import ( "bytes" "encoding/json" + "errors" "os" "path/filepath" @@ -54,10 +55,7 @@ func LoadTransferSettings() (settings *TransferSettings, err error) { unlockFunc, err := lock.CreateLock(filepath.Join(locksDirPath, transferSettingsLockFile)) // Defer the lockFile.Unlock() function before throwing a possible error to avoid deadlock situations. defer func() { - e := unlockFunc() - if err == nil { - err = e - } + err = errors.Join(err, unlockFunc()) }() if err != nil { return @@ -99,10 +97,7 @@ func SaveTransferSettings(settings *TransferSettings) (err error) { unlockFunc, err := lock.CreateLock(filepath.Join(locksDirPath, transferSettingsLockFile)) // Defer the lockFile.Unlock() function before throwing a possible error to avoid deadlock situations. defer func() { - e := unlockFunc() - if err == nil { - err = e - } + err = errors.Join(err, unlockFunc()) }() if err != nil { return diff --git a/common/commands/config.go b/common/commands/config.go index a0802387c..53ce635e4 100644 --- a/common/commands/config.go +++ b/common/commands/config.go @@ -118,10 +118,7 @@ func (cc *ConfigCommand) Run() (err error) { unlockFunc, err := lock.CreateLock(lockDirPath) // Defer the lockFile.Unlock() function before throwing a possible error to avoid deadlock situations. defer func() { - e := unlockFunc() - if err == nil { - err = e - } + err = errors.Join(err, unlockFunc()) }() if err != nil { return diff --git a/go.mod b/go.mod index 5d9f3fc81..5114b033d 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 - github.com/jedib0t/go-pretty/v6 v6.5.4 + github.com/jedib0t/go-pretty/v6 v6.5.5 github.com/jfrog/build-info-go v1.9.24 github.com/jfrog/gofrog v1.6.3 github.com/jfrog/jfrog-client-go v1.38.0 @@ -19,13 +19,13 @@ require ( github.com/manifoldco/promptui v0.9.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/spf13/viper v1.18.2 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/urfave/cli v1.22.14 github.com/vbauerster/mpb/v7 v7.5.3 - golang.org/x/exp v0.0.0-20240213143201-ec583247a57a - golang.org/x/mod v0.15.0 + golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 + golang.org/x/mod v0.16.0 golang.org/x/sync v0.6.0 - golang.org/x/term v0.17.0 + golang.org/x/term v0.18.0 golang.org/x/text v0.14.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -88,10 +88,10 @@ require ( github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/tools v0.18.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/tools v0.19.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index ee7d37364..58ceb4446 100644 --- a/go.sum +++ b/go.sum @@ -79,8 +79,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jedib0t/go-pretty/v6 v6.5.4 h1:gOGo0613MoqUcf0xCj+h/V3sHDaZasfv152G6/5l91s= -github.com/jedib0t/go-pretty/v6 v6.5.4/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= +github.com/jedib0t/go-pretty/v6 v6.5.5 h1:PpIU8lOjxvVYGGKule0QxxJfNysUSbC9lggQU2cpZJc= +github.com/jedib0t/go-pretty/v6 v6.5.5/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= github.com/jfrog/build-info-go v1.9.24 h1:MjT+4bYecbNQ+dbLczg0lkE5DoLAhdyrF0cRXtnEJqI= @@ -180,8 +180,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= @@ -211,14 +212,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a h1:HinSgX1tJRX3KsL//Gxynpw5CTOAIPhgL4W8PNiIpVE= -golang.org/x/exp v0.0.0-20240213143201-ec583247a57a/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -226,8 +227,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -260,15 +261,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -282,8 +283,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/utils/config/encryption.go b/utils/config/encryption.go index 3e040c93d..eb4db4445 100644 --- a/utils/config/encryption.go +++ b/utils/config/encryption.go @@ -5,6 +5,7 @@ import ( "crypto/cipher" "crypto/rand" "encoding/base64" + ioutils "github.com/jfrog/gofrog/io" "io" "os" "strconv" @@ -115,12 +116,7 @@ func getEncryptionKeyFromSecurityConfFile() (key string, err error) { config := viper.New() config.SetConfigType("yaml") f, err := os.Open(secFile) - defer func() { - e := f.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(f, &err) if err != nil { return "", errorutils.CheckError(err) } diff --git a/utils/config/tokenrefresh.go b/utils/config/tokenrefresh.go index 298a3917d..e8f4da70b 100644 --- a/utils/config/tokenrefresh.go +++ b/utils/config/tokenrefresh.go @@ -1,6 +1,7 @@ package config import ( + "errors" "github.com/jfrog/jfrog-client-go/access" accessservices "github.com/jfrog/jfrog-client-go/access/services" "github.com/jfrog/jfrog-client-go/utils/errorutils" @@ -75,10 +76,7 @@ func tokenRefreshHandler(currentAccessToken string, tokenType TokenType) (newAcc unlockFunc, err := lock.CreateLock(lockDirPath) // Defer the lockFile.Unlock() function before throwing a possible error to avoid deadlock situations. defer func() { - e := unlockFunc() - if err == nil { - err = e - } + err = errors.Join(err, unlockFunc()) }() if err != nil { return @@ -211,10 +209,7 @@ func CreateInitialRefreshableTokensIfNeeded(serverDetails *ServerDetails) (err e unlockFunc, err := lock.CreateLock(lockDirPath) // Defer the lockFile.Unlock() function before throwing a possible error to avoid deadlock situations. defer func() { - e := unlockFunc() - if err == nil { - err = e - } + err = errors.Join(err, unlockFunc()) }() if err != nil { return diff --git a/utils/coreutils/tableutils.go b/utils/coreutils/tableutils.go index afe507016..cfa3a3eb1 100644 --- a/utils/coreutils/tableutils.go +++ b/utils/coreutils/tableutils.go @@ -2,6 +2,7 @@ package coreutils import ( "bufio" + "errors" "fmt" "math" "os" @@ -136,10 +137,7 @@ func PrintTable(rows interface{}, title string, emptyTableMessage string, printE tableWriter.Style().Options.SeparateRows = true stdoutWriter := bufio.NewWriter(os.Stdout) defer func() { - e := stdoutWriter.Flush() - if err == nil { - err = e - } + err = errors.Join(err, stdoutWriter.Flush()) }() tableWriter.SetOutputMirror(stdoutWriter) tableWriter.Render() diff --git a/utils/plugins/utils.go b/utils/plugins/utils.go index c436cb0e0..e678e17c5 100644 --- a/utils/plugins/utils.go +++ b/utils/plugins/utils.go @@ -2,6 +2,7 @@ package plugins import ( "encoding/json" + "errors" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/utils/lock" cliLog "github.com/jfrog/jfrog-cli-core/v2/utils/log" @@ -61,10 +62,7 @@ func readPluginsConfigAndConvertV0tToV1IfNeeded() (err error) { unlockFunc, err = lock.CreateLock(lockDirPath) // Defer the lockFile.Unlock() function before throwing a possible error to avoid deadlock situations. defer func() { - e := unlockFunc() - if err == nil { - err = e - } + err = errors.Join(err, unlockFunc()) }() if err != nil { return From b631e3df50dd44ae7f90127bb343c5c470d15401 Mon Sep 17 00:00:00 2001 From: Michael Sverdlov Date: Tue, 19 Mar 2024 19:05:25 +0200 Subject: [PATCH 04/36] Update deprecated setup-go action and improve close funcs (#1159) --- .../commands/buildinfo/adddependencies.go | 8 ++--- artifactory/commands/dotnet/dotnetcommand.go | 12 ++------ artifactory/commands/generic/delete.go | 5 +--- artifactory/commands/generic/download.go | 19 ++---------- artifactory/commands/generic/upload.go | 7 +---- artifactory/commands/golang/publish.go | 30 +++++++------------ artifactory/commands/npm/publish.go | 5 +--- artifactory/commands/python/poetry.go | 5 +--- artifactory/commands/python/python.go | 5 +--- .../commands/terraform/terraformpublish.go | 6 ++-- .../commands/transferconfig/transferconfig.go | 10 ++----- artifactory/commands/transferconfig/utils.go | 6 ++-- .../transferconfigmerge.go | 5 ++-- .../transferfiles/delayedartifactshandler.go | 5 ++-- .../transferfiles/longpropertycheck.go | 6 ++-- .../utils/precheckrunner/checkrunner.go | 5 ++-- artifactory/utils/container/buildinfo.go | 16 ++-------- artifactory/utils/utils.go | 7 ++--- common/build/buildutils.go | 10 ++----- common/progressbar/filesprogressbar.go | 6 ++-- go.mod | 4 +-- go.sum | 8 ++--- utils/dependencies/utils.go | 3 +- 23 files changed, 54 insertions(+), 139 deletions(-) diff --git a/artifactory/commands/buildinfo/adddependencies.go b/artifactory/commands/buildinfo/adddependencies.go index fc389aa2b..d35d3731e 100644 --- a/artifactory/commands/buildinfo/adddependencies.go +++ b/artifactory/commands/buildinfo/adddependencies.go @@ -2,6 +2,7 @@ package buildinfo import ( "errors" + ioutils "github.com/jfrog/gofrog/io" regxp "regexp" "strconv" @@ -316,15 +317,12 @@ func convertFileInfoToDependencies(files map[string]*fileutils.FileDetails) []bu func searchItems(spec *spec.SpecFiles, servicesManager artifactory.ArtifactoryServicesManager) (resultReader *content.ContentReader, err error) { temp := []*content.ContentReader{} var searchParams services.SearchParams - var reader *content.ContentReader defer func() { for _, reader := range temp { - e := reader.Close() - if err == nil { - err = e - } + ioutils.Close(reader, &err) } }() + var reader *content.ContentReader for i := 0; i < len(spec.Files); i++ { searchParams, err = utils.GetSearchParams(spec.Get(i)) if err != nil { diff --git a/artifactory/commands/dotnet/dotnetcommand.go b/artifactory/commands/dotnet/dotnetcommand.go index 60c79e4e0..54ddebe93 100644 --- a/artifactory/commands/dotnet/dotnetcommand.go +++ b/artifactory/commands/dotnet/dotnetcommand.go @@ -118,12 +118,7 @@ func (dc *DotnetCommand) Exec() (err error) { return err } defer func() { - if callbackFunc != nil { - e := callbackFunc() - if err == nil { - err = e - } - } + err = errors.Join(err, callbackFunc()) }() if err = buildInfoModule.CalcDependencies(); err != nil { if dc.isDotnetTestCommand() { @@ -272,10 +267,7 @@ func InitNewConfig(configDirPath, repoName string, server *config.ServerDetails, } log.Debug("Nuget config file created at:", configFile.Name()) defer func() { - e := configFile.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(configFile.Close())) }() // We would prefer to write the NuGet configuration using the `nuget add source` command, diff --git a/artifactory/commands/generic/delete.go b/artifactory/commands/generic/delete.go index ede3965c8..367965dc2 100644 --- a/artifactory/commands/generic/delete.go +++ b/artifactory/commands/generic/delete.go @@ -68,10 +68,7 @@ func (dc *DeleteCommand) GetPathsToDelete() (contentReader *content.ContentReade var temp []*content.ContentReader defer func() { for _, reader := range temp { - e := reader.Close() - if err == nil { - err = e - } + ioutils.Close(reader, &err) } }() for i := 0; i < len(dc.Spec().Files); i++ { diff --git a/artifactory/commands/generic/download.go b/artifactory/commands/generic/download.go index 293508572..ef5c7f5ab 100644 --- a/artifactory/commands/generic/download.go +++ b/artifactory/commands/generic/download.go @@ -119,23 +119,13 @@ func (dc *DownloadCommand) download() (err error) { log.Error(err) } if summary != nil { - defer func() { - e := summary.ArtifactsDetailsReader.Close() - if err == nil { - err = e - } - }() + defer gofrog.Close(summary.ArtifactsDetailsReader, &err) // If 'detailed summary' was requested, then the reader should not be closed here. // It will be closed after it will be used to generate the summary. if dc.DetailedSummary() { dc.result.SetReader(summary.TransferDetailsReader) } else { - defer func() { - e := summary.TransferDetailsReader.Close() - if err == nil { - err = e - } - }() + defer gofrog.Close(summary.TransferDetailsReader, &err) } totalDownloaded = summary.TotalSucceeded totalFailed = summary.TotalFailed @@ -168,10 +158,7 @@ func (dc *DownloadCommand) download() (err error) { var tmpRoot string tmpRoot, err = createDownloadResultEmptyTmpReflection(summary.TransferDetailsReader) defer func() { - e := fileutils.RemoveTempDir(tmpRoot) - if err == nil { - err = e - } + err = errors.Join(err, fileutils.RemoveTempDir(tmpRoot)) }() if err != nil { return err diff --git a/artifactory/commands/generic/upload.go b/artifactory/commands/generic/upload.go index c89cd9f8b..e346a9d53 100644 --- a/artifactory/commands/generic/upload.go +++ b/artifactory/commands/generic/upload.go @@ -139,12 +139,7 @@ func (uc *UploadCommand) upload() (err error) { } if summary != nil { artifactsDetailsReader = summary.ArtifactsDetailsReader - defer func() { - e := artifactsDetailsReader.Close() - if err == nil { - err = e - } - }() + defer ioutils.Close(artifactsDetailsReader, &err) // If 'detailed summary' was requested, then the reader should not be closed here. // It will be closed after it will be used to generate the summary. if uc.DetailedSummary() { diff --git a/artifactory/commands/golang/publish.go b/artifactory/commands/golang/publish.go index c9a73a3c8..4b042c64c 100644 --- a/artifactory/commands/golang/publish.go +++ b/artifactory/commands/golang/publish.go @@ -85,18 +85,17 @@ func publishPackage(packageVersion, targetRepo, buildName, buildNumber, projectK version := version.NewVersion(artifactoryVersion) if version.AtLeast(_go.ArtifactoryMinSupportedVersion) { log.Debug("Creating info file", projectPath) - pathToInfo, err := createInfoFile(packageVersion) + var pathToInfo string + pathToInfo, err = createInfoFile(packageVersion) if err != nil { return nil, nil, err } defer func() { - e := os.Remove(pathToInfo) - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(os.Remove(pathToInfo))) }() if collectBuildInfo { - infoArtifact, err := createInfoFileArtifact(pathToInfo, packageVersion) + var infoArtifact *buildinfo.Artifact + infoArtifact, err = createInfoFileArtifact(pathToInfo, packageVersion) if err != nil { return nil, nil, err } @@ -123,10 +122,7 @@ func createInfoFile(packageVersion string) (path string, err error) { return "", errorutils.CheckError(err) } defer func() { - e := file.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(file.Close())) }() _, err = file.Write(content) if err != nil { @@ -153,10 +149,7 @@ func readModFile(version, projectPath string, createArtifact bool) ([]byte, *bui return nil, nil, err } defer func() { - e := modFile.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(modFile.Close())) }() content, err := io.ReadAll(modFile) if err != nil { @@ -189,10 +182,7 @@ func archive(moduleName, version, projectPath, tempDir string, excludedPatterns openedFile = true defer func() { if openedFile { - e := tempFile.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(tempFile.Close())) } }() if err = archiveProject(tempFile, projectPath, moduleName, version, excludedPatterns); err != nil { @@ -214,10 +204,10 @@ func archive(moduleName, version, projectPath, tempDir string, excludedPatterns } } // Sync the file before renaming it - if err := tempFile.Sync(); err != nil { + if err = tempFile.Sync(); err != nil { return "", nil, err } - if err := tempFile.Close(); err != nil { + if err = tempFile.Close(); err != nil { return "", nil, err } openedFile = false diff --git a/artifactory/commands/npm/publish.go b/artifactory/commands/npm/publish.go index 333655bba..86b2056ce 100644 --- a/artifactory/commands/npm/publish.go +++ b/artifactory/commands/npm/publish.go @@ -428,10 +428,7 @@ func (npc *NpmPublishCommand) readPackageInfoFromTarball(packedFilePath string) return errorutils.CheckError(err) } defer func() { - e := tarball.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(tarball.Close())) }() gZipReader, err := gzip.NewReader(tarball) if err != nil { diff --git a/artifactory/commands/python/poetry.go b/artifactory/commands/python/poetry.go index b9367b71c..da91baa99 100644 --- a/artifactory/commands/python/poetry.go +++ b/artifactory/commands/python/poetry.go @@ -47,10 +47,7 @@ func (pc *PoetryCommand) Run() (err error) { } defer func() { if pythonBuildInfo != nil && err != nil { - e := pythonBuildInfo.Clean() - if e != nil { - err = errors.New(err.Error() + "\n" + e.Error()) - } + err = errors.Join(err, pythonBuildInfo.Clean()) } }() err = pc.SetPypiRepoUrlWithCredentials() diff --git a/artifactory/commands/python/python.go b/artifactory/commands/python/python.go index defac7960..8d2de8b3e 100644 --- a/artifactory/commands/python/python.go +++ b/artifactory/commands/python/python.go @@ -43,10 +43,7 @@ func (pc *PythonCommand) Run() (err error) { } defer func() { if pythonBuildInfo != nil && err != nil { - e := pythonBuildInfo.Clean() - if e != nil { - err = errors.New(err.Error() + "\n" + e.Error()) - } + err = errors.Join(err, pythonBuildInfo.Clean()) } }() err = pc.SetPypiRepoUrlWithCredentials() diff --git a/artifactory/commands/terraform/terraformpublish.go b/artifactory/commands/terraform/terraformpublish.go index 517160a8e..0a6e854e7 100644 --- a/artifactory/commands/terraform/terraformpublish.go +++ b/artifactory/commands/terraform/terraformpublish.go @@ -1,6 +1,7 @@ package terraform import ( + "errors" buildInfo "github.com/jfrog/build-info-go/entities" ioutils "github.com/jfrog/gofrog/io" "github.com/jfrog/gofrog/parallel" @@ -335,10 +336,7 @@ func checkIfTerraformModule(path string) (isModule bool, err error) { return false, errorutils.CheckError(err) } defer func() { - e := d.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, d.Close()) }() files, err := d.Readdir(-1) diff --git a/artifactory/commands/transferconfig/transferconfig.go b/artifactory/commands/transferconfig/transferconfig.go index ddc6ce01c..42af06f40 100644 --- a/artifactory/commands/transferconfig/transferconfig.go +++ b/artifactory/commands/transferconfig/transferconfig.go @@ -3,6 +3,7 @@ package transferconfig import ( "bytes" "context" + "errors" "fmt" "net/http" "os" @@ -105,10 +106,7 @@ func (tcc *TransferConfigCommand) Run() (err error) { tcc.LogTitle("Phase 2/5 - Export configuration from the source Artifactory") exportPath, cleanUp, err := tcc.exportSourceArtifactory() defer func() { - cleanUpErr := cleanUp() - if err == nil { - err = cleanUpErr - } + err = errors.Join(err, cleanUp()) }() if err != nil { return @@ -313,9 +311,7 @@ func (tcc *TransferConfigCommand) getEncryptedItems(selectedSourceRepos map[util return "", nil, err } defer func() { - if reactivationErr := reactivateKeyEncryption(); err == nil { - err = reactivationErr - } + err = errors.Join(err, reactivateKeyEncryption()) }() // Download artifactory.config.xml from the source Artifactory server. diff --git a/artifactory/commands/transferconfig/utils.go b/artifactory/commands/transferconfig/utils.go index 75d27310c..58c3b62c5 100644 --- a/artifactory/commands/transferconfig/utils.go +++ b/artifactory/commands/transferconfig/utils.go @@ -4,6 +4,7 @@ import ( "archive/zip" "bytes" "compress/flate" + "errors" "io" "os" "path/filepath" @@ -31,10 +32,7 @@ func archiveConfig(exportPath string, configXml string) (buffer *bytes.Buffer, r return flate.NewWriter(out, flate.BestCompression) }) defer func() { - closeErr := writer.Close() - if retErr == nil { - retErr = errorutils.CheckError(closeErr) - } + retErr = errors.Join(retErr, errorutils.CheckError(writer.Close())) }() err := handleTypoInAccessBootstrap(exportPath) diff --git a/artifactory/commands/transferconfigmerge/transferconfigmerge.go b/artifactory/commands/transferconfigmerge/transferconfigmerge.go index ea1c0d273..cf2b7a986 100644 --- a/artifactory/commands/transferconfigmerge/transferconfigmerge.go +++ b/artifactory/commands/transferconfigmerge/transferconfigmerge.go @@ -1,6 +1,7 @@ package transferconfigmerge import ( + "errors" "fmt" "reflect" "strings" @@ -358,9 +359,7 @@ func (tcmc *TransferConfigMergeCommand) decryptAndGetAllRemoteRepositories(remot return } defer func() { - if reactivationErr := reactivateKeyEncryption(); err == nil { - err = reactivationErr - } + err = errors.Join(err, reactivateKeyEncryption()) }() var remoteRepositoryKeys []string for _, remoteRepositoryDetails := range remoteRepositoriesDetails { diff --git a/artifactory/commands/transferfiles/delayedartifactshandler.go b/artifactory/commands/transferfiles/delayedartifactshandler.go index a5a20cfc9..caf80fcde 100644 --- a/artifactory/commands/transferfiles/delayedartifactshandler.go +++ b/artifactory/commands/transferfiles/delayedartifactshandler.go @@ -2,6 +2,7 @@ package transferfiles import ( "encoding/json" + "errors" "fmt" "os" "path" @@ -62,9 +63,7 @@ func getDelaysFilePrefix(repoKey string, phaseStartTime string) string { func (mng *TransferDelayedArtifactsMng) start() (err error) { defer func() { if mng.delayedWriter != nil { - if e := mng.delayedWriter.close(); err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(mng.delayedWriter.close())) } }() diff --git a/artifactory/commands/transferfiles/longpropertycheck.go b/artifactory/commands/transferfiles/longpropertycheck.go index 99c091a1a..5791c2fb8 100644 --- a/artifactory/commands/transferfiles/longpropertycheck.go +++ b/artifactory/commands/transferfiles/longpropertycheck.go @@ -2,6 +2,7 @@ package transferfiles import ( "encoding/json" + "errors" "fmt" "io" "sync" @@ -228,10 +229,7 @@ func runAqlService(serviceManager artifactory.ArtifactoryServicesManager, query } defer func() { if reader != nil { - e := reader.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(reader.Close())) } }() respBody, err := io.ReadAll(reader) diff --git a/artifactory/commands/utils/precheckrunner/checkrunner.go b/artifactory/commands/utils/precheckrunner/checkrunner.go index eca8a5e2e..62b435453 100644 --- a/artifactory/commands/utils/precheckrunner/checkrunner.go +++ b/artifactory/commands/utils/precheckrunner/checkrunner.go @@ -2,6 +2,7 @@ package precheckrunner import ( "context" + "errors" "fmt" "github.com/gookit/color" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -116,9 +117,7 @@ func (pcr *PreCheckRunner) Run(context context.Context, serverDetails *config.Se } // Execute checks defer func() { - if e := pcr.cleanup(); e != nil && err == nil { - err = e - } + err = errors.Join(err, pcr.cleanup()) }() var checkPassed bool for i, check := range pcr.checks { diff --git a/artifactory/utils/container/buildinfo.go b/artifactory/utils/container/buildinfo.go index 89a543494..412f2f4ab 100644 --- a/artifactory/utils/container/buildinfo.go +++ b/artifactory/utils/container/buildinfo.go @@ -114,9 +114,7 @@ func writeLayersToFile(layers []utils.ResultItem) (filePath string, err error) { if err != nil { return } - defer func() { - err = writer.Close() - }() + defer ioutils.Close(writer, &err) for _, layer := range layers { writer.Write(layer) } @@ -196,11 +194,7 @@ func performSearch(imagePathPattern string, serviceManager artifactory.Artifacto if err != nil { return nil, err } - defer func() { - if deferErr := reader.Close(); err == nil { - err = deferErr - } - }() + defer ioutils.Close(reader, &err) resultMap = make(map[string]*utils.ResultItem) for resultItem := new(utils.ResultItem); reader.NextRecord(resultItem) == nil; resultItem = new(utils.ResultItem) { resultMap[resultItem.Name] = resultItem @@ -220,11 +214,7 @@ func performMultiPlatformImageSearch(imagePathPattern string, serviceManager art if err != nil { return nil, err } - defer func() { - if deferErr := reader.Close(); err == nil { - err = deferErr - } - }() + defer ioutils.Close(reader, &err) pathToSha2 := make(map[string]string) pathToImageLayers := make(map[string][]*utils.ResultItem) resultMap = make(map[string][]*utils.ResultItem) diff --git a/artifactory/utils/utils.go b/artifactory/utils/utils.go index ab4c6a882..1699a4d43 100644 --- a/artifactory/utils/utils.go +++ b/artifactory/utils/utils.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + ioutils "github.com/jfrog/gofrog/io" "io" "net/http" "net/url" @@ -227,11 +228,7 @@ func RemoteUnmarshal(serviceManager artifactory.ArtifactoryServicesManager, remo if err != nil { return } - defer func() { - if localErr := ioReaderCloser.Close(); err == nil { - err = localErr - } - }() + defer ioutils.Close(ioReaderCloser, &err) content, err := io.ReadAll(ioReaderCloser) if err != nil { return errorutils.CheckError(err) diff --git a/common/build/buildutils.go b/common/build/buildutils.go index df222bd5c..4184403aa 100644 --- a/common/build/buildutils.go +++ b/common/build/buildutils.go @@ -120,10 +120,7 @@ func saveBuildData(action interface{}, buildName, buildNumber, projectKey string return err } defer func() { - e := tempFile.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(tempFile.Close())) }() _, err = tempFile.Write(content.Bytes()) return err @@ -149,10 +146,7 @@ func SaveBuildInfo(buildName, buildNumber, projectKey string, buildInfo *buildIn return err } defer func() { - e := tempFile.Close() - if err == nil { - err = errorutils.CheckError(e) - } + err = errors.Join(err, errorutils.CheckError(tempFile.Close())) }() _, err = tempFile.Write(content.Bytes()) return errorutils.CheckError(err) diff --git a/common/progressbar/filesprogressbar.go b/common/progressbar/filesprogressbar.go index 17de11da0..159f11af9 100644 --- a/common/progressbar/filesprogressbar.go +++ b/common/progressbar/filesprogressbar.go @@ -1,6 +1,7 @@ package progressbar import ( + "errors" "net/url" "os" "strings" @@ -323,10 +324,7 @@ func ExecWithProgress(cmd CommandWithProgress) (err error) { if progressBar != nil { cmd.SetProgress(progressBar) defer func() { - e := progressBar.Quit() - if err == nil { - err = e - } + err = errors.Join(err, progressBar.Quit()) }() } err = commands.Exec(cmd) diff --git a/go.mod b/go.mod index 5114b033d..0cd206a5b 100644 --- a/go.mod +++ b/go.mod @@ -96,8 +96,8 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go dev +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240319160327-95a883923e0b -// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev +replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc diff --git a/go.sum b/go.sum index 58ceb4446..ee0ff3a87 100644 --- a/go.sum +++ b/go.sum @@ -83,12 +83,12 @@ github.com/jedib0t/go-pretty/v6 v6.5.5 h1:PpIU8lOjxvVYGGKule0QxxJfNysUSbC9lggQU2 github.com/jedib0t/go-pretty/v6 v6.5.5/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= -github.com/jfrog/build-info-go v1.9.24 h1:MjT+4bYecbNQ+dbLczg0lkE5DoLAhdyrF0cRXtnEJqI= -github.com/jfrog/build-info-go v1.9.24/go.mod h1:CaCKqcg3V2W9/ZysE4ZvXZMgsvunclhjrTTQQGp3CzM= +github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 h1:au9aqxUQIhxRU6vr58rk2/w3hOwxg5ryu6pxgYkixl0= +github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1/go.mod h1:doFB4bFDVHeGulD6GF9LzsrRaIOrSoklV9DgIAEqHgc= github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc= github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg= -github.com/jfrog/jfrog-client-go v1.38.0 h1:0QP4/dSmJe0oYUrAqzoPDpGdJHcrOeq9mycnb0pSxqQ= -github.com/jfrog/jfrog-client-go v1.38.0/go.mod h1:EHRLxpu0pIT7+ulYDNQ7IeieYBHMQeEPr8CoBHoJzQY= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240319160327-95a883923e0b h1:pNrQakO24/lNCK8LuBC9FxbfbSO1G8de8n9/FKPGbVc= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240319160327-95a883923e0b/go.mod h1:/crrK2T2rXlJxBQdmw67i91W37/1R+ZM6xxAwVpm16M= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= diff --git a/utils/dependencies/utils.go b/utils/dependencies/utils.go index 4f105002c..7be49aa89 100644 --- a/utils/dependencies/utils.go +++ b/utils/dependencies/utils.go @@ -39,8 +39,7 @@ func DownloadExtractor(targetPath, downloadPath string) error { func CreateChecksumFile(targetPath, checksum string) (err error) { out, err := os.Create(targetPath) defer func() { - e := errorutils.CheckError(out.Close()) - err = errors.Join(err, e) + err = errors.Join(err, errorutils.CheckError(out.Close())) }() if errorutils.CheckError(err) != nil { return err From b5807fd0102d6b8605583788bac2b2116d36efaa Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Wed, 20 Mar 2024 12:49:52 +0200 Subject: [PATCH 05/36] Artifactory Release Lifecycle Management - Add Export bundle function (#1143) --- go.mod | 2 +- go.sum | 4 +- lifecycle/export.go | 133 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 lifecycle/export.go diff --git a/go.mod b/go.mod index 0cd206a5b..6c02ff9ac 100644 --- a/go.mod +++ b/go.mod @@ -96,7 +96,7 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240319160327-95a883923e0b +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240320102352-af2f392bb490 replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 diff --git a/go.sum b/go.sum index ee0ff3a87..109566b7f 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 h1:au9aqxUQI github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1/go.mod h1:doFB4bFDVHeGulD6GF9LzsrRaIOrSoklV9DgIAEqHgc= github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc= github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240319160327-95a883923e0b h1:pNrQakO24/lNCK8LuBC9FxbfbSO1G8de8n9/FKPGbVc= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240319160327-95a883923e0b/go.mod h1:/crrK2T2rXlJxBQdmw67i91W37/1R+ZM6xxAwVpm16M= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240320102352-af2f392bb490 h1:oGgwRJatirSNZyqO3e4FtHCe5W30VNgULCW/GYhHdao= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240320102352-af2f392bb490/go.mod h1:8z6in1qalzL1DqchUCrDKVgz2gKoPRhJpzm2Ww+VWYI= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= diff --git a/lifecycle/export.go b/lifecycle/export.go new file mode 100644 index 000000000..41001e27f --- /dev/null +++ b/lifecycle/export.go @@ -0,0 +1,133 @@ +package lifecycle + +import ( + artUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/artifactory" + artServices "github.com/jfrog/jfrog-client-go/artifactory/services" + "github.com/jfrog/jfrog-client-go/artifactory/services/utils" + clientConfig "github.com/jfrog/jfrog-client-go/config" + "github.com/jfrog/jfrog-client-go/lifecycle/services" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/jfrog/jfrog-client-go/utils/log" + "strings" +) + +type ReleaseBundleExportCommand struct { + releaseBundleCmd + modifications services.Modifications + downloadConfigurations artUtils.DownloadConfiguration + targetPath string +} + +func (rbe *ReleaseBundleExportCommand) Run() (err error) { + if err = validateArtifactoryVersionSupported(rbe.serverDetails); err != nil { + return + } + servicesManager, rbDetails, queryParams, err := rbe.getPrerequisites() + if err != nil { + return errorutils.CheckErrorf("Failed getting prerequisites for exporting command, error: '%s'", err.Error()) + } + // Start the Export process and wait for completion + log.Info("Exporting Release Bundle archive...") + exportResponse, err := servicesManager.ExportReleaseBundle(rbDetails, rbe.modifications, queryParams) + if err != nil { + return errorutils.CheckErrorf("Failed exporting release bundle, error: '%s'", err.Error()) + } + // Download the exported bundle + log.Debug("Downloading the exported bundle...") + downloaded, failed, err := rbe.downloadReleaseBundle(exportResponse, rbe.downloadConfigurations) + if err != nil || failed > 0 || downloaded < 1 { + return + } + log.Info("Successfully Downloaded Release Bundle archive") + return +} + +// Download the exported release bundle using artifactory service manager +func (rbe *ReleaseBundleExportCommand) downloadReleaseBundle(exportResponse services.ReleaseBundleExportedStatusResponse, downloadConfiguration artUtils.DownloadConfiguration) (downloaded int, failed int, err error) { + downloadParams := artServices.DownloadParams{ + CommonParams: &utils.CommonParams{ + Pattern: strings.TrimPrefix(exportResponse.RelativeUrl, "/"), + Target: rbe.targetPath, + }, + MinSplitSize: downloadConfiguration.MinSplitSize, + SplitCount: downloadConfiguration.SplitCount, + } + artifactoryServiceManager, err := createArtifactoryServiceManager(rbe.serverDetails) + if err != nil { + return + } + return artifactoryServiceManager.DownloadFiles(downloadParams) + +} +func (rbe *ReleaseBundleExportCommand) ServerDetails() (*config.ServerDetails, error) { + return rbe.serverDetails, nil +} + +func (rbe *ReleaseBundleExportCommand) CommandName() string { + return "rb_export" +} + +func NewReleaseBundleExportCommand() *ReleaseBundleExportCommand { + return &ReleaseBundleExportCommand{} +} +func (rbe *ReleaseBundleExportCommand) SetServerDetails(serverDetails *config.ServerDetails) *ReleaseBundleExportCommand { + rbe.serverDetails = serverDetails + return rbe +} + +func (rbe *ReleaseBundleExportCommand) SetReleaseBundleExportModifications(modifications services.Modifications) *ReleaseBundleExportCommand { + rbe.modifications = modifications + return rbe +} +func (rbe *ReleaseBundleExportCommand) SetReleaseBundleName(releaseBundleName string) *ReleaseBundleExportCommand { + rbe.releaseBundleName = releaseBundleName + return rbe +} + +func (rbe *ReleaseBundleExportCommand) SetReleaseBundleVersion(releaseBundleVersion string) *ReleaseBundleExportCommand { + rbe.releaseBundleVersion = releaseBundleVersion + return rbe +} + +func (rbe *ReleaseBundleExportCommand) SetProject(project string) *ReleaseBundleExportCommand { + rbe.rbProjectKey = project + return rbe +} + +func (rbe *ReleaseBundleExportCommand) SetDownloadConfiguration(downloadConfig artUtils.DownloadConfiguration) *ReleaseBundleExportCommand { + rbe.downloadConfigurations = downloadConfig + return rbe +} + +func (rbe *ReleaseBundleExportCommand) SetTargetPath(target string) *ReleaseBundleExportCommand { + if target == "" { + // Default value as current dir + target += "./" + } + rbe.targetPath = target + return rbe +} + +func createArtifactoryServiceManager(artDetails *config.ServerDetails) (artifactory.ArtifactoryServicesManager, error) { + certsPath, err := coreutils.GetJfrogCertsDir() + if err != nil { + return nil, err + } + artAuth, err := artDetails.CreateArtAuthConfig() + if err != nil { + return nil, err + } + serviceConfig, err := clientConfig.NewConfigBuilder(). + SetServiceDetails(artAuth). + SetCertificatesPath(certsPath). + SetInsecureTls(artDetails.InsecureTls). + SetDryRun(false). + Build() + if err != nil { + return nil, err + } + return artifactory.New(serviceConfig) +} From ca269eb4f5d4509db07fc2784eeb28692d729efb Mon Sep 17 00:00:00 2001 From: Assaf Attias <49212512+attiasas@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:06:40 +0200 Subject: [PATCH 06/36] Use Gradle dep tree v3.0.2 (#1160) --- buildscripts/download-jars.sh | 2 +- utils/java/resources/gradle-dep-tree.jar | Bin 12152 -> 12253 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/buildscripts/download-jars.sh b/buildscripts/download-jars.sh index 27f1d20b1..a30adc8ea 100755 --- a/buildscripts/download-jars.sh +++ b/buildscripts/download-jars.sh @@ -7,7 +7,7 @@ # https://github.com/jfrog/maven-dep-tree # 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. -GRADLE_DEP_TREE_VERSION="3.0.1" +GRADLE_DEP_TREE_VERSION="3.0.2" # Changing this version also requires a change in mavenDepTreeVersion within utils/java/mvn.go. MAVEN_DEP_TREE_VERSION="1.1.0" diff --git a/utils/java/resources/gradle-dep-tree.jar b/utils/java/resources/gradle-dep-tree.jar index b05be169487a41d066316c8c645f34634a9f3d0c..b855f258b416de4c7ef9a0d487010afc882de99e 100644 GIT binary patch delta 4336 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 S#sA5vVLwP;qHYlXUHv~AKl2*^ From 72b008905aa244888811d05182b936007263a334 Mon Sep 17 00:00:00 2001 From: Assaf Attias <49212512+attiasas@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:53:15 +0200 Subject: [PATCH 07/36] Remove Java Dep Tree content (#1161) --- .github/workflows/embedded-jar-test.yml | 29 -- buildscripts/download-jars.sh | 15 - utils/java/deptreemanager.go | 124 -------- utils/java/deptreemanager_test.go | 66 ---- utils/java/gradle.go | 199 ------------ utils/java/gradle_test.go | 230 -------------- utils/java/mvn.go | 265 ---------------- utils/java/mvn_test.go | 380 ----------------------- utils/java/resources/gradle-dep-tree.jar | Bin 12253 -> 0 bytes utils/java/resources/maven-dep-tree.jar | Bin 13862 -> 0 bytes utils/java/resources/settings.xml | 19 -- 11 files changed, 1327 deletions(-) delete mode 100644 .github/workflows/embedded-jar-test.yml delete mode 100755 buildscripts/download-jars.sh delete mode 100644 utils/java/deptreemanager.go delete mode 100644 utils/java/deptreemanager_test.go delete mode 100644 utils/java/gradle.go delete mode 100644 utils/java/gradle_test.go delete mode 100644 utils/java/mvn.go delete mode 100644 utils/java/mvn_test.go delete mode 100644 utils/java/resources/gradle-dep-tree.jar delete mode 100644 utils/java/resources/maven-dep-tree.jar delete mode 100644 utils/java/resources/settings.xml diff --git a/.github/workflows/embedded-jar-test.yml b/.github/workflows/embedded-jar-test.yml deleted file mode 100644 index a2ff93497..000000000 --- a/.github/workflows/embedded-jar-test.yml +++ /dev/null @@ -1,29 +0,0 @@ -# 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. -# It accomplishes this by downloading the JARs and executing a "git diff" command. -# In case there are any differences detected, the test will result in failure. -name: Embedded Jars Tests -on: - push: - branches: - - '**' - tags-ignore: - - '**' - pull_request: -jobs: - test: - runs-on: ubuntu-latest - env: - GOPROXY: direct - steps: - - uses: actions/checkout@v4 - - - name: Download JARs - run: buildscripts/download-jars.sh - - - name: Check Diff - run: git diff --exit-code - - - name: Log if Failure - run: echo "::warning::Please run ./buildscripts/download-jars to use compatible Maven and Gradle dependency tree JARs." - if: ${{ failure() }} - diff --git a/buildscripts/download-jars.sh b/buildscripts/download-jars.sh deleted file mode 100755 index a30adc8ea..000000000 --- a/buildscripts/download-jars.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -# Please use this script to download the JAR files for maven-dep-tree and gradle-dep-tree into the directory utils/java/. -# These JARs allow us to build Maven and Gradle dependency trees efficiently and without compilation. -# Learn more about them here: -# https://github.com/jfrog/gradle-dep-tree -# https://github.com/jfrog/maven-dep-tree - -# 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. -GRADLE_DEP_TREE_VERSION="3.0.2" -# Changing this version also requires a change in mavenDepTreeVersion within utils/java/mvn.go. -MAVEN_DEP_TREE_VERSION="1.1.0" - -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 utils/java/resources/gradle-dep-tree.jar -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 utils/java/resources/maven-dep-tree.jar diff --git a/utils/java/deptreemanager.go b/utils/java/deptreemanager.go deleted file mode 100644 index e323fad1e..000000000 --- a/utils/java/deptreemanager.go +++ /dev/null @@ -1,124 +0,0 @@ -package java - -import ( - "encoding/json" - "os" - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-core/v2/utils/xray" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" -) - -const ( - GavPackageTypeIdentifier = "gav://" -) - -func BuildDependencyTree(depTreeParams DepTreeParams, tech coreutils.Technology) ([]*xrayUtils.GraphNode, map[string][]string, error) { - if tech == coreutils.Maven { - return buildMavenDependencyTree(&depTreeParams) - } - return buildGradleDependencyTree(&depTreeParams) -} - -type DepTreeParams struct { - UseWrapper bool - Server *config.ServerDetails - DepsRepo string - IsMavenDepTreeInstalled bool - IsCurationCmd bool - CurationCacheFolder string -} - -type DepTreeManager struct { - server *config.ServerDetails - depsRepo string - useWrapper bool -} - -func NewDepTreeManager(params *DepTreeParams) DepTreeManager { - return DepTreeManager{useWrapper: params.UseWrapper, depsRepo: params.DepsRepo, server: params.Server} -} - -// 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. -type moduleDepTree struct { - Root string `json:"root"` - Nodes map[string]xray.DepTreeNode `json:"nodes"` -} - -// Reads the output files of the gradle-dep-tree and maven-dep-tree plugins and returns them as a slice of GraphNodes. -// 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. -func getGraphFromDepTree(outputFilePaths string) (depsGraph []*xrayUtils.GraphNode, uniqueDepsMap map[string][]string, err error) { - modules, err := parseDepTreeFiles(outputFilePaths) - if err != nil { - return - } - uniqueDepsMap = map[string][]string{} - for _, module := range modules { - moduleTree, moduleUniqueDeps := GetModuleTreeAndDependencies(module) - depsGraph = append(depsGraph, moduleTree) - for depToAdd, depTypes := range moduleUniqueDeps { - uniqueDepsMap[depToAdd] = depTypes - } - } - return -} - -// Returns a dependency tree and a flat list of the module's dependencies for the given module -func GetModuleTreeAndDependencies(module *moduleDepTree) (*xrayUtils.GraphNode, map[string][]string) { - moduleTreeMap := make(map[string]xray.DepTreeNode) - moduleDeps := module.Nodes - for depName, dependency := range moduleDeps { - dependencyId := GavPackageTypeIdentifier + depName - var childrenList []string - for _, childName := range dependency.Children { - childId := GavPackageTypeIdentifier + childName - childrenList = append(childrenList, childId) - } - moduleTreeMap[dependencyId] = xray.DepTreeNode{ - Types: dependency.Types, - Children: childrenList, - } - } - return xray.BuildXrayDependencyTree(moduleTreeMap, GavPackageTypeIdentifier+module.Root) -} - -func parseDepTreeFiles(jsonFilePaths string) ([]*moduleDepTree, error) { - outputFilePaths := strings.Split(strings.TrimSpace(jsonFilePaths), "\n") - var modules []*moduleDepTree - for _, path := range outputFilePaths { - results, err := parseDepTreeFile(path) - if err != nil { - return nil, err - } - modules = append(modules, results) - } - return modules, nil -} - -func parseDepTreeFile(path string) (results *moduleDepTree, err error) { - depTreeJson, err := os.ReadFile(strings.TrimSpace(path)) - if errorutils.CheckError(err) != nil { - return - } - results = &moduleDepTree{} - err = errorutils.CheckError(json.Unmarshal(depTreeJson, &results)) - return -} - -func getArtifactoryAuthFromServer(server *config.ServerDetails) (string, string, error) { - username, password, err := server.GetAuthenticationCredentials() - if err != nil { - return "", "", err - } - if username == "" { - return "", "", errorutils.CheckErrorf("a username is required for authenticating with Artifactory") - } - return username, password, nil -} - -func (dtm *DepTreeManager) GetDepsRepo() string { - return dtm.depsRepo -} diff --git a/utils/java/deptreemanager_test.go b/utils/java/deptreemanager_test.go deleted file mode 100644 index 6eb23b3d8..000000000 --- a/utils/java/deptreemanager_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package java - -import ( - "os" - "path/filepath" - "reflect" - "strings" - "testing" - - "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - "github.com/stretchr/testify/assert" -) - -func TestGetGradleGraphFromDepTree(t *testing.T) { - // Create and change directory to test workspace - tempDirPath, cleanUp := tests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "gradle")) - defer cleanUp() - assert.NoError(t, os.Chmod(filepath.Join(tempDirPath, "gradlew"), 0700)) - expectedTree := map[string]map[string]string{ - "org.jfrog.example.gradle:shared:1.0": {}, - "org.jfrog.example.gradle:" + filepath.Base(tempDirPath) + ":1.0": {}, - "org.jfrog.example.gradle:services:1.0": {}, - "org.jfrog.example.gradle:webservice:1.0": { - "junit:junit:4.11": "", - "commons-io:commons-io:1.2": "", - "org.apache.wicket:wicket:1.3.7": "", - "org.jfrog.example.gradle:shared:1.0": "", - "org.jfrog.example.gradle:api:1.0": "", - "commons-lang:commons-lang:2.4": "", - "commons-collections:commons-collections:3.2": "", - }, - "org.jfrog.example.gradle:api:1.0": { - "org.apache.wicket:wicket:1.3.7": "", - "org.jfrog.example.gradle:shared:1.0": "", - "commons-lang:commons-lang:2.4": "", - }, - } - expectedUniqueDeps := []string{ - "junit:junit:4.11", - "org.jfrog.example.gradle:webservice:1.0", - "org.jfrog.example.gradle:api:1.0", - "org.jfrog.example.gradle:" + filepath.Base(tempDirPath) + ":1.0", - "commons-io:commons-io:1.2", - "org.apache.wicket:wicket:1.3.7", - "org.jfrog.example.gradle:shared:1.0", - "org.jfrog.example.gradle:api:1.0", - "commons-collections:commons-collections:3.2", - "commons-lang:commons-lang:2.4", - "org.hamcrest:hamcrest-core:1.3", - "org.slf4j:slf4j-api:1.4.2", - } - - manager := &gradleDepTreeManager{DepTreeManager{}} - outputFileContent, err := manager.runGradleDepTree() - assert.NoError(t, err) - depTree, uniqueDeps, err := getGraphFromDepTree(outputFileContent) - assert.NoError(t, err) - reflect.DeepEqual(uniqueDeps, expectedUniqueDeps) - - for _, dependency := range depTree { - dependencyId := strings.TrimPrefix(dependency.Id, GavPackageTypeIdentifier) - depChild, exists := expectedTree[dependencyId] - assert.True(t, exists) - assert.Equal(t, len(depChild), len(dependency.Nodes)) - } -} diff --git a/utils/java/gradle.go b/utils/java/gradle.go deleted file mode 100644 index 57ceff8bd..000000000 --- a/utils/java/gradle.go +++ /dev/null @@ -1,199 +0,0 @@ -package java - -import ( - _ "embed" - "errors" - "fmt" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/jfrog/build-info-go/build" - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "github.com/jfrog/jfrog-client-go/utils/log" - xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" -) - -const ( - remoteDepTreePath = "artifactory/oss-release-local" - gradlew = "gradlew" - gradleDepTreeJarFile = "gradle-dep-tree.jar" - gradleDepTreeInitFile = "gradledeptree.init" - gradleDepTreeOutputFile = "gradledeptree.out" - gradleDepTreeInitScript = `initscript { - repositories { %s - mavenCentral() - } - dependencies { - classpath files('%s') - } -} - -allprojects { - repositories { %s - } - apply plugin: com.jfrog.GradleDepTree -}` - artifactoryRepository = ` - maven { - url "%s/%s" - credentials { - username = '%s' - password = '%s' - } - }` -) - -//go:embed resources/gradle-dep-tree.jar -var gradleDepTreeJar []byte - -type gradleDepTreeManager struct { - DepTreeManager -} - -func buildGradleDependencyTree(params *DepTreeParams) (dependencyTree []*xrayUtils.GraphNode, uniqueDeps map[string][]string, err error) { - manager := &gradleDepTreeManager{DepTreeManager: NewDepTreeManager(params)} - outputFileContent, err := manager.runGradleDepTree() - if err != nil { - return - } - dependencyTree, uniqueDeps, err = getGraphFromDepTree(outputFileContent) - return -} - -func (gdt *gradleDepTreeManager) runGradleDepTree() (string, error) { - // Create the script file in the repository - depTreeDir, err := gdt.createDepTreeScriptAndGetDir() - if err != nil { - return "", err - } - defer func() { - err = errors.Join(err, fileutils.RemoveTempDir(depTreeDir)) - }() - - if gdt.useWrapper { - gdt.useWrapper, err = isGradleWrapperExist() - if err != nil { - return "", err - } - } - - output, err := gdt.execGradleDepTree(depTreeDir) - if err != nil { - return "", err - } - return string(output), nil -} - -func (gdt *gradleDepTreeManager) createDepTreeScriptAndGetDir() (tmpDir string, err error) { - tmpDir, err = fileutils.CreateTempDir() - if err != nil { - return - } - var releasesRepo string - releasesRepo, gdt.depsRepo, err = getRemoteRepos(gdt.depsRepo, gdt.server) - if err != nil { - return - } - gradleDepTreeJarPath := filepath.Join(tmpDir, gradleDepTreeJarFile) - if err = errorutils.CheckError(os.WriteFile(gradleDepTreeJarPath, gradleDepTreeJar, 0600)); err != nil { - return - } - gradleDepTreeJarPath = ioutils.DoubleWinPathSeparator(gradleDepTreeJarPath) - - depTreeInitScript := fmt.Sprintf(gradleDepTreeInitScript, releasesRepo, gradleDepTreeJarPath, gdt.depsRepo) - return tmpDir, errorutils.CheckError(os.WriteFile(filepath.Join(tmpDir, gradleDepTreeInitFile), []byte(depTreeInitScript), 0666)) -} - -// getRemoteRepos constructs the sections of Artifactory's remote repositories in the gradle-dep-tree init script. -// depsRemoteRepo - name of the remote repository that proxies the relevant registry, e.g. maven central. -// server - the Artifactory server details on which the repositories reside in. -// Returns the constructed sections. -func getRemoteRepos(depsRepo string, server *config.ServerDetails) (string, string, error) { - constructedReleasesRepo, err := constructReleasesRemoteRepo() - if err != nil { - return "", "", err - } - - constructedDepsRepo, err := getDepTreeArtifactoryRepository(depsRepo, server) - if err != nil { - return "", "", err - } - return constructedReleasesRepo, constructedDepsRepo, nil -} - -func constructReleasesRemoteRepo() (string, error) { - // Try to retrieve the serverID and remote repository that proxies https://releases.jfrog.io, from the environment variable - serverId, repoName, err := coreutils.GetServerIdAndRepo(coreutils.ReleasesRemoteEnv) - if err != nil || serverId == "" || repoName == "" { - return "", err - } - - releasesServer, err := config.GetSpecificConfig(serverId, false, true) - if err != nil { - return "", err - } - - releasesPath := fmt.Sprintf("%s/%s", repoName, remoteDepTreePath) - log.Debug("The `"+gradleDepTreeJarFile+"` will be resolved from", repoName) - return getDepTreeArtifactoryRepository(releasesPath, releasesServer) -} - -func (gdt *gradleDepTreeManager) execGradleDepTree(depTreeDir string) (outputFileContent []byte, err error) { - gradleExecPath, err := build.GetGradleExecPath(gdt.useWrapper) - if err != nil { - err = errorutils.CheckError(err) - return - } - - outputFilePath := filepath.Join(depTreeDir, gradleDepTreeOutputFile) - tasks := []string{ - "clean", - "generateDepTrees", "-I", filepath.Join(depTreeDir, gradleDepTreeInitFile), - "-q", - fmt.Sprintf("-Dcom.jfrog.depsTreeOutputFile=%s", outputFilePath), - "-Dcom.jfrog.includeAllBuildFiles=true"} - log.Info("Running gradle deps tree command:", gradleExecPath, strings.Join(tasks, " ")) - if output, err := exec.Command(gradleExecPath, tasks...).CombinedOutput(); err != nil { - return nil, errorutils.CheckErrorf("error running gradle-dep-tree: %s\n%s", err.Error(), string(output)) - } - defer func() { - err = errors.Join(err, errorutils.CheckError(os.Remove(outputFilePath))) - }() - - outputFileContent, err = os.ReadFile(outputFilePath) - err = errorutils.CheckError(err) - return -} - -func getDepTreeArtifactoryRepository(remoteRepo string, server *config.ServerDetails) (string, error) { - if remoteRepo == "" || server.IsEmpty() { - return "", nil - } - username, password, err := getArtifactoryAuthFromServer(server) - if err != nil { - return "", err - } - - log.Debug("The project dependencies will be resolved from", server.ArtifactoryUrl, "from the", remoteRepo, "repository") - return fmt.Sprintf(artifactoryRepository, - strings.TrimSuffix(server.ArtifactoryUrl, "/"), - remoteRepo, - username, - password), nil -} - -// This function assumes that the Gradle wrapper is in the root directory. -// The --project-dir option of Gradle won't work in this case. -func isGradleWrapperExist() (bool, error) { - wrapperName := gradlew - if coreutils.IsWindows() { - wrapperName += ".bat" - } - return fileutils.IsFileExists(wrapperName, false) -} diff --git a/utils/java/gradle_test.go b/utils/java/gradle_test.go deleted file mode 100644 index 787542fa4..000000000 --- a/utils/java/gradle_test.go +++ /dev/null @@ -1,230 +0,0 @@ -package java - -import ( - "errors" - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - testsutils "github.com/jfrog/jfrog-cli-core/v2/utils/config/tests" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" - "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - - "github.com/stretchr/testify/assert" -) - -// #nosec G101 -- Dummy token for tests -// jfrog-ignore -const dummyToken = "eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJIcnU2VHctZk1yOTV3dy12TDNjV3ZBVjJ3Qm9FSHpHdGlwUEFwOE1JdDljIn0.eyJzdWIiOiJqZnJ0QDAxYzNnZmZoZzJlOHc2MTQ5ZTNhMnEwdzk3XC91c2Vyc1wvYWRtaW4iLCJzY3AiOiJtZW1iZXItb2YtZ3JvdXBzOnJlYWRlcnMgYXBpOioiLCJhdWQiOiJqZnJ0QDAxYzNnZmZoZzJlOHc2MTQ5ZTNhMnEwdzk3IiwiaXNzIjoiamZydEAwMWMzZ2ZmaGcyZTh3NjE0OWUzYTJxMHc5NyIsImV4cCI6MTU1NjAzNzc2NSwiaWF0IjoxNTU2MDM0MTY1LCJqdGkiOiI1M2FlMzgyMy05NGM3LTQ0OGItOGExOC1iZGVhNDBiZjFlMjAifQ.Bp3sdvppvRxysMlLgqT48nRIHXISj9sJUCXrm7pp8evJGZW1S9hFuK1olPmcSybk2HNzdzoMcwhUmdUzAssiQkQvqd_HanRcfFbrHeg5l1fUQ397ECES-r5xK18SYtG1VR7LNTVzhJqkmRd3jzqfmIK2hKWpEgPfm8DRz3j4GGtDRxhb3oaVsT2tSSi_VfT3Ry74tzmO0GcCvmBE2oh58kUZ4QfEsalgZ8IpYHTxovsgDx_M7ujOSZx_hzpz-iy268-OkrU22PQPCfBmlbEKeEUStUO9n0pj4l1ODL31AGARyJRy46w4yzhw7Fk5P336WmDMXYs5LAX2XxPFNLvNzA" - -const expectedInitScriptWithRepos = `initscript { - repositories { - mavenCentral() - } - dependencies { - classpath files('%s') - } -} - -allprojects { - repositories { - maven { - url "https://myartifactory.com/artifactory/deps-repo" - credentials { - username = 'admin' - password = '%s' - } - } - } - apply plugin: com.jfrog.GradleDepTree -}` - -func TestGradleTreesWithoutConfig(t *testing.T) { - // Create and change directory to test workspace - tempDirPath, cleanUp := tests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "gradle")) - defer cleanUp() - assert.NoError(t, os.Chmod(filepath.Join(tempDirPath, "gradlew"), 0700)) - - // Run getModulesDependencyTrees - modulesDependencyTrees, uniqueDeps, err := buildGradleDependencyTree(&DepTreeParams{}) - if assert.NoError(t, err) && assert.NotNil(t, modulesDependencyTrees) { - assert.Len(t, uniqueDeps, 12) - assert.Len(t, modulesDependencyTrees, 5) - // Check module - module := tests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.example.gradle:webservice:1.0") - assert.Len(t, module.Nodes, 7) - - // Check direct dependency - directDependency := tests.GetAndAssertNode(t, module.Nodes, "junit:junit:4.11") - assert.Len(t, directDependency.Nodes, 1) - - // Check transitive dependency - tests.GetAndAssertNode(t, directDependency.Nodes, "org.hamcrest:hamcrest-core:1.3") - } -} - -func TestGradleTreesWithConfig(t *testing.T) { - // Create and change directory to test workspace - tempDirPath, cleanUp := tests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "gradle-example-config")) - defer cleanUp() - assert.NoError(t, os.Chmod(filepath.Join(tempDirPath, "gradlew"), 0700)) - - // Run getModulesDependencyTrees - modulesDependencyTrees, uniqueDeps, err := buildGradleDependencyTree(&DepTreeParams{UseWrapper: true}) - if assert.NoError(t, err) && assert.NotNil(t, modulesDependencyTrees) { - assert.Len(t, modulesDependencyTrees, 5) - assert.Len(t, uniqueDeps, 11) - // Check module - module := tests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test.gradle.publish:api:1.0-SNAPSHOT") - assert.Len(t, module.Nodes, 4) - - // Check direct dependency - directDependency := tests.GetAndAssertNode(t, module.Nodes, "commons-lang:commons-lang:2.4") - assert.Len(t, directDependency.Nodes, 1) - - // Check transitive dependency - tests.GetAndAssertNode(t, directDependency.Nodes, "commons-io:commons-io:1.2") - } -} - -func TestIsGradleWrapperExist(t *testing.T) { - // Check Gradle wrapper doesn't exist - isWrapperExist, err := isGradleWrapperExist() - assert.False(t, isWrapperExist) - assert.NoError(t, err) - - // Check Gradle wrapper exist - _, cleanUp := tests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "gradle")) - defer cleanUp() - isWrapperExist, err = isGradleWrapperExist() - assert.NoError(t, err) - assert.True(t, isWrapperExist) -} - -func TestGetDepTreeArtifactoryRepository(t *testing.T) { - tests := []struct { - name string - remoteRepo string - server *config.ServerDetails - expectedUrl string - expectedErr string - }{ - { - name: "WithAccessToken", - remoteRepo: "my-remote-repo", - server: &config.ServerDetails{ - Url: "https://myartifactory.com", - // jfrog-ignore - AccessToken: dummyToken, - }, - // jfrog-ignore - expectedUrl: "\n\t\tmaven {\n\t\t\turl \"/my-remote-repo\"\n\t\t\tcredentials {\n\t\t\t\tusername = 'admin'\n\t\t\t\tpassword = 'eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJIcnU2VHctZk1yOTV3dy12TDNjV3ZBVjJ3Qm9FSHpHdGlwUEFwOE1JdDljIn0.eyJzdWIiOiJqZnJ0QDAxYzNnZmZoZzJlOHc2MTQ5ZTNhMnEwdzk3XC91c2Vyc1wvYWRtaW4iLCJzY3AiOiJtZW1iZXItb2YtZ3JvdXBzOnJlYWRlcnMgYXBpOioiLCJhdWQiOiJqZnJ0QDAxYzNnZmZoZzJlOHc2MTQ5ZTNhMnEwdzk3IiwiaXNzIjoiamZydEAwMWMzZ2ZmaGcyZTh3NjE0OWUzYTJxMHc5NyIsImV4cCI6MTU1NjAzNzc2NSwiaWF0IjoxNTU2MDM0MTY1LCJqdGkiOiI1M2FlMzgyMy05NGM3LTQ0OGItOGExOC1iZGVhNDBiZjFlMjAifQ.Bp3sdvppvRxysMlLgqT48nRIHXISj9sJUCXrm7pp8evJGZW1S9hFuK1olPmcSybk2HNzdzoMcwhUmdUzAssiQkQvqd_HanRcfFbrHeg5l1fUQ397ECES-r5xK18SYtG1VR7LNTVzhJqkmRd3jzqfmIK2hKWpEgPfm8DRz3j4GGtDRxhb3oaVsT2tSSi_VfT3Ry74tzmO0GcCvmBE2oh58kUZ4QfEsalgZ8IpYHTxovsgDx_M7ujOSZx_hzpz-iy268-OkrU22PQPCfBmlbEKeEUStUO9n0pj4l1ODL31AGARyJRy46w4yzhw7Fk5P336WmDMXYs5LAX2XxPFNLvNzA'\n\t\t\t}\n\t\t}", - expectedErr: "", - }, - { - name: "WithUsernameAndPassword", - remoteRepo: "my-remote-repo", - server: &config.ServerDetails{ - Url: "https://myartifactory.com", - User: "my-username", - Password: "my-password", - }, - expectedUrl: "\n\t\tmaven {\n\t\t\turl \"/my-remote-repo\"\n\t\t\tcredentials {\n\t\t\t\tusername = 'my-username'\n\t\t\t\tpassword = 'my-password'\n\t\t\t}\n\t\t}", - expectedErr: "", - }, - { - name: "MissingCredentials", - remoteRepo: "my-remote-repo", - server: &config.ServerDetails{ - Url: "https://myartifactory.com", - }, - expectedUrl: "", - expectedErr: "either username/password or access token must be set for https://myartifactory.com", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - url, err := getDepTreeArtifactoryRepository(test.remoteRepo, test.server) - if err != nil { - assert.Equal(t, test.expectedErr, err.Error()) - } else { - assert.Equal(t, test.expectedUrl, url) - } - }) - } -} - -func TestCreateDepTreeScript(t *testing.T) { - manager := &gradleDepTreeManager{DepTreeManager: DepTreeManager{}} - tmpDir, err := manager.createDepTreeScriptAndGetDir() - assert.NoError(t, err) - defer func() { - assert.NoError(t, os.Remove(filepath.Join(tmpDir, gradleDepTreeInitFile))) - }() - content, err := os.ReadFile(filepath.Join(tmpDir, gradleDepTreeInitFile)) - assert.NoError(t, err) - gradleDepTreeJarPath := ioutils.DoubleWinPathSeparator(filepath.Join(tmpDir, gradleDepTreeJarFile)) - assert.Equal(t, fmt.Sprintf(gradleDepTreeInitScript, "", gradleDepTreeJarPath, ""), string(content)) -} - -func TestCreateDepTreeScriptWithRepositories(t *testing.T) { - manager := &gradleDepTreeManager{DepTreeManager: DepTreeManager{}} - manager.depsRepo = "deps-repo" - manager.server = &config.ServerDetails{ - Url: "https://myartifactory.com/", - ArtifactoryUrl: "https://myartifactory.com/artifactory", - // jfrog-ignore - AccessToken: dummyToken, - } - tmpDir, err := manager.createDepTreeScriptAndGetDir() - assert.NoError(t, err) - defer func() { - assert.NoError(t, os.Remove(filepath.Join(tmpDir, gradleDepTreeInitFile))) - }() - - content, err := os.ReadFile(filepath.Join(tmpDir, gradleDepTreeInitFile)) - assert.NoError(t, err) - gradleDepTreeJarPath := ioutils.DoubleWinPathSeparator(filepath.Join(tmpDir, gradleDepTreeJarFile)) - // jfrog-ignore - assert.Equal(t, fmt.Sprintf(expectedInitScriptWithRepos, gradleDepTreeJarPath, dummyToken), string(content)) -} - -func TestConstructReleasesRemoteRepo(t *testing.T) { - cleanUp := testsutils.CreateTempEnv(t, false) - serverDetails := &config.ServerDetails{ - ServerId: "test", - ArtifactoryUrl: "https://domain.com/artifactory", - User: "user", - Password: "pass", - } - err := config.SaveServersConf([]*config.ServerDetails{serverDetails}) - assert.NoError(t, err) - defer cleanUp() - testCases := []struct { - envVar string - expectedRepo string - expectedErr error - }{ - {envVar: "", expectedRepo: "", expectedErr: nil}, - {envVar: "test/repo1", expectedRepo: "\n\t\tmaven {\n\t\t\turl \"https://domain.com/artifactory/repo1/artifactory/oss-release-local\"\n\t\t\tcredentials {\n\t\t\t\tusername = 'user'\n\t\t\t\tpassword = 'pass'\n\t\t\t}\n\t\t}", expectedErr: nil}, - {envVar: "notexist/repo1", expectedRepo: "", expectedErr: errors.New("Server ID 'notexist' does not exist.")}, - } - - for _, tc := range testCases { - // Set the environment variable for this test case - func() { - assert.NoError(t, os.Setenv(coreutils.ReleasesRemoteEnv, tc.envVar)) - defer func() { - // Reset the environment variable after each test case - assert.NoError(t, os.Unsetenv(coreutils.ReleasesRemoteEnv)) - }() - actualRepo, actualErr := constructReleasesRemoteRepo() - assert.Equal(t, tc.expectedRepo, actualRepo) - assert.Equal(t, tc.expectedErr, actualErr) - }() - } -} diff --git a/utils/java/mvn.go b/utils/java/mvn.go deleted file mode 100644 index 76514fb11..000000000 --- a/utils/java/mvn.go +++ /dev/null @@ -1,265 +0,0 @@ -package java - -import ( - _ "embed" - "errors" - "fmt" - "net/url" - "os" - "os/exec" - "path" - "path/filepath" - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "github.com/jfrog/jfrog-client-go/utils/log" - xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" -) - -const ( - mavenDepTreeJarFile = "maven-dep-tree.jar" - mavenDepTreeOutputFile = "mavendeptree.out" - // Changing this version also requires a change in MAVEN_DEP_TREE_VERSION within buildscripts/download_jars.sh - mavenDepTreeVersion = "1.1.0" - settingsXmlFile = "settings.xml" -) - -var mavenConfigPath = filepath.Join(".mvn", "maven.config") - -type MavenDepTreeCmd string - -const ( - Projects MavenDepTreeCmd = "projects" - Tree MavenDepTreeCmd = "tree" -) - -//go:embed resources/settings.xml -var settingsXmlTemplate string - -//go:embed resources/maven-dep-tree.jar -var mavenDepTreeJar []byte - -type MavenDepTreeManager struct { - DepTreeManager - isInstalled bool - // this flag its curation command, it will set dedicated cache and download url. - isCurationCmd bool - // path to the curation dedicated cache - curationCacheFolder string - cmdName MavenDepTreeCmd - settingsXmlPath string -} - -func NewMavenDepTreeManager(params *DepTreeParams, cmdName MavenDepTreeCmd) *MavenDepTreeManager { - depTreeManager := NewDepTreeManager(&DepTreeParams{ - Server: params.Server, - DepsRepo: params.DepsRepo, - }) - return &MavenDepTreeManager{ - DepTreeManager: depTreeManager, - isInstalled: params.IsMavenDepTreeInstalled, - cmdName: cmdName, - isCurationCmd: params.IsCurationCmd, - curationCacheFolder: params.CurationCacheFolder, - } -} - -func buildMavenDependencyTree(params *DepTreeParams) (dependencyTree []*xrayUtils.GraphNode, uniqueDeps map[string][]string, err error) { - manager := NewMavenDepTreeManager(params, Tree) - outputFilePaths, clearMavenDepTreeRun, err := manager.RunMavenDepTree() - if err != nil { - if clearMavenDepTreeRun != nil { - err = errors.Join(err, clearMavenDepTreeRun()) - } - return - } - defer func() { - err = errors.Join(err, clearMavenDepTreeRun()) - }() - dependencyTree, uniqueDeps, err = getGraphFromDepTree(outputFilePaths) - return -} - -// Runs maven-dep-tree according to cmdName. Returns the plugin output along with a function pointer to revert the plugin side effects. -// If a non-nil clearMavenDepTreeRun pointer is returnes it means we had no error during the entire function execution -func (mdt *MavenDepTreeManager) RunMavenDepTree() (depTreeOutput string, clearMavenDepTreeRun func() error, err error) { - // depTreeExecDir is a temp directory for all the files that are required for the maven-dep-tree run - depTreeExecDir, clearMavenDepTreeRun, err := mdt.CreateTempDirWithSettingsXmlIfNeeded() - if err != nil { - return - } - if err = mdt.installMavenDepTreePlugin(depTreeExecDir); err != nil { - return - } - - depTreeOutput, err = mdt.execMavenDepTree(depTreeExecDir) - if err != nil { - return - } - return -} - -func (mdt *MavenDepTreeManager) installMavenDepTreePlugin(depTreeExecDir string) error { - if mdt.isInstalled { - return nil - } - mavenDepTreeJarPath := filepath.Join(depTreeExecDir, mavenDepTreeJarFile) - if err := errorutils.CheckError(os.WriteFile(mavenDepTreeJarPath, mavenDepTreeJar, 0666)); err != nil { - return err - } - goals := GetMavenPluginInstallationGoals(mavenDepTreeJarPath) - _, err := mdt.RunMvnCmd(goals) - return err -} - -func GetMavenPluginInstallationGoals(pluginPath string) []string { - return []string{"org.apache.maven.plugins:maven-install-plugin:3.1.1:install-file", "-Dfile=" + pluginPath, "-B"} -} - -func (mdt *MavenDepTreeManager) execMavenDepTree(depTreeExecDir string) (string, error) { - if mdt.cmdName == Tree { - return mdt.runTreeCmd(depTreeExecDir) - } - return mdt.runProjectsCmd() -} - -func (mdt *MavenDepTreeManager) runTreeCmd(depTreeExecDir string) (string, error) { - mavenDepTreePath := filepath.Join(depTreeExecDir, mavenDepTreeOutputFile) - goals := []string{"com.jfrog:maven-dep-tree:" + mavenDepTreeVersion + ":" + string(Tree), "-DdepsTreeOutputFile=" + mavenDepTreePath, "-B"} - if mdt.isCurationCmd { - goals = append(goals, "-Dmaven.repo.local="+mdt.curationCacheFolder) - } - if _, err := mdt.RunMvnCmd(goals); err != nil { - return "", err - } - - mavenDepTreeOutput, err := os.ReadFile(mavenDepTreePath) - if err != nil { - return "", errorutils.CheckError(err) - } - return string(mavenDepTreeOutput), nil -} - -func (mdt *MavenDepTreeManager) runProjectsCmd() (string, error) { - goals := []string{"com.jfrog:maven-dep-tree:" + mavenDepTreeVersion + ":" + string(Projects), "-q"} - output, err := mdt.RunMvnCmd(goals) - if err != nil { - return "", err - } - return string(output), nil -} - -func (mdt *MavenDepTreeManager) RunMvnCmd(goals []string) (cmdOutput []byte, err error) { - restoreMavenConfig, err := removeMavenConfig() - if err != nil { - return - } - - defer func() { - if restoreMavenConfig != nil { - err = errors.Join(err, restoreMavenConfig()) - } - }() - - if mdt.settingsXmlPath != "" { - goals = append(goals, "-s", mdt.settingsXmlPath) - } - - //#nosec G204 - cmdOutput, err = exec.Command("mvn", goals...).CombinedOutput() - if err != nil { - stringOutput := string(cmdOutput) - if len(cmdOutput) > 0 { - log.Info(stringOutput) - } - if msg := mdt.suspectCurationBlockedError(stringOutput); msg != "" { - err = fmt.Errorf("failed running command 'mvn %s\n\n%s", strings.Join(goals, " "), msg) - } else { - err = fmt.Errorf("failed running command 'mvn %s': %s", strings.Join(goals, " "), err.Error()) - } - } - return -} - -func (mdt *MavenDepTreeManager) GetSettingsXmlPath() string { - return mdt.settingsXmlPath -} - -func (mdt *MavenDepTreeManager) SetSettingsXmlPath(settingsXmlPath string) { - mdt.settingsXmlPath = settingsXmlPath -} - -func removeMavenConfig() (func() error, error) { - mavenConfigExists, err := fileutils.IsFileExists(mavenConfigPath, false) - if err != nil { - return nil, err - } - if !mavenConfigExists { - return nil, nil - } - restoreMavenConfig, err := ioutils.BackupFile(mavenConfigPath, "maven.config.bkp") - if err != nil { - return nil, err - } - err = os.Remove(mavenConfigPath) - if err != nil { - err = errorutils.CheckErrorf("failed to remove %s while building the maven dependencies tree. Error received:\n%s", mavenConfigPath, err.Error()) - } - return restoreMavenConfig, err -} - -// Creates a new settings.xml file configured with the provided server and repository from the current MavenDepTreeManager instance. -// The settings.xml will be written to the given path. -func (mdt *MavenDepTreeManager) createSettingsXmlWithConfiguredArtifactory(settingsXmlPath string) error { - username, password, err := getArtifactoryAuthFromServer(mdt.server) - if err != nil { - return err - } - endPoint := mdt.depsRepo - if mdt.isCurationCmd { - endPoint = path.Join("api/curation/audit", endPoint) - } - remoteRepositoryFullPath, err := url.JoinPath(mdt.server.ArtifactoryUrl, endPoint) - if err != nil { - return err - } - mdt.settingsXmlPath = filepath.Join(settingsXmlPath, settingsXmlFile) - settingsXmlContent := fmt.Sprintf(settingsXmlTemplate, username, password, remoteRepositoryFullPath) - - return errorutils.CheckError(os.WriteFile(mdt.settingsXmlPath, []byte(settingsXmlContent), 0600)) -} - -// Creates a temporary directory. -// If Artifactory resolution repo is provided, a settings.xml file with the provided server and repository will be created inside the temprary directory. -func (mdt *MavenDepTreeManager) CreateTempDirWithSettingsXmlIfNeeded() (tempDirPath string, clearMavenDepTreeRun func() error, err error) { - tempDirPath, err = fileutils.CreateTempDir() - if err != nil { - return - } - - clearMavenDepTreeRun = func() error { return fileutils.RemoveTempDir(tempDirPath) } - - // Create a settings.xml file that sets the dependency resolution from the given server and repository - if mdt.depsRepo != "" { - err = mdt.createSettingsXmlWithConfiguredArtifactory(tempDirPath) - } - if err != nil { - err = errors.Join(err, clearMavenDepTreeRun()) - clearMavenDepTreeRun = nil - } - return -} - -// In case mvn tree fails on 403 or 500 it can be related to packages blocked by curation. -// For this use case to succeed, pass through should be enabled in the curated repos -func (mdt *MavenDepTreeManager) suspectCurationBlockedError(cmdOutput string) (msgToUser string) { - if !mdt.isCurationCmd { - return - } - if strings.Contains(cmdOutput, "status code: 403") || strings.Contains(cmdOutput, "status code: 500") { - msgToUser = "Failed to get dependencies tree for maven project, Please verify pass-through enabled on the curated repos" - } - return msgToUser -} diff --git a/utils/java/mvn_test.go b/utils/java/mvn_test.go deleted file mode 100644 index a527b768b..000000000 --- a/utils/java/mvn_test.go +++ /dev/null @@ -1,380 +0,0 @@ -package java - -import ( - "github.com/jfrog/build-info-go/utils" - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "github.com/jfrog/jfrog-client-go/utils/tests" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "golang.org/x/exp/maps" - "os" - "path/filepath" - "strings" - "testing" -) - -const ( - //#nosec G101 - dummy token for testing - settingsXmlWithUsernameAndPassword = ` - - - - artifactory - testUser - testPass - - - - - artifactory - https://myartifactory.com/artifactory/testRepo - * - - -` - //#nosec G101 - dummy token for testing - settingsXmlWithUsernameAndPasswordAndCurationDedicatedAPi = ` - - - - artifactory - testUser - testPass - - - - - artifactory - https://myartifactory.com/artifactory/api/curation/audit/testRepo - * - - -` - //#nosec G101 - dummy token for testing - settingsXmlWithUsernameAndToken = ` - - - - artifactory - testUser - eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJIcnU2VHctZk1yOTV3dy12TDNjV3ZBVjJ3Qm9FSHpHdGlwUEFwOE1JdDljIn0.eyJzdWIiOiJqZnJ0QDAxYzNnZmZoZzJlOHc2MTQ5ZTNhMnEwdzk3XC91c2Vyc1wvYWRtaW4iLCJzY3AiOiJtZW1iZXItb2YtZ3JvdXBzOnJlYWRlcnMgYXBpOioiLCJhdWQiOiJqZnJ0QDAxYzNnZmZoZzJlOHc2MTQ5ZTNhMnEwdzk3IiwiaXNzIjoiamZydEAwMWMzZ2ZmaGcyZTh3NjE0OWUzYTJxMHc5NyIsImV4cCI6MTU1NjAzNzc2NSwiaWF0IjoxNTU2MDM0MTY1LCJqdGkiOiI1M2FlMzgyMy05NGM3LTQ0OGItOGExOC1iZGVhNDBiZjFlMjAifQ.Bp3sdvppvRxysMlLgqT48nRIHXISj9sJUCXrm7pp8evJGZW1S9hFuK1olPmcSybk2HNzdzoMcwhUmdUzAssiQkQvqd_HanRcfFbrHeg5l1fUQ397ECES-r5xK18SYtG1VR7LNTVzhJqkmRd3jzqfmIK2hKWpEgPfm8DRz3j4GGtDRxhb3oaVsT2tSSi_VfT3Ry74tzmO0GcCvmBE2oh58kUZ4QfEsalgZ8IpYHTxovsgDx_M7ujOSZx_hzpz-iy268-OkrU22PQPCfBmlbEKeEUStUO9n0pj4l1ODL31AGARyJRy46w4yzhw7Fk5P336WmDMXYs5LAX2XxPFNLvNzA - - - - - artifactory - https://myartifactory.com/artifactory/testRepo - * - - -` - //#nosec G101 - dummy token for testing - settingsXmlWithAccessToken = ` - - - - artifactory - admin - eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJIcnU2VHctZk1yOTV3dy12TDNjV3ZBVjJ3Qm9FSHpHdGlwUEFwOE1JdDljIn0.eyJzdWIiOiJqZnJ0QDAxYzNnZmZoZzJlOHc2MTQ5ZTNhMnEwdzk3XC91c2Vyc1wvYWRtaW4iLCJzY3AiOiJtZW1iZXItb2YtZ3JvdXBzOnJlYWRlcnMgYXBpOioiLCJhdWQiOiJqZnJ0QDAxYzNnZmZoZzJlOHc2MTQ5ZTNhMnEwdzk3IiwiaXNzIjoiamZydEAwMWMzZ2ZmaGcyZTh3NjE0OWUzYTJxMHc5NyIsImV4cCI6MTU1NjAzNzc2NSwiaWF0IjoxNTU2MDM0MTY1LCJqdGkiOiI1M2FlMzgyMy05NGM3LTQ0OGItOGExOC1iZGVhNDBiZjFlMjAifQ.Bp3sdvppvRxysMlLgqT48nRIHXISj9sJUCXrm7pp8evJGZW1S9hFuK1olPmcSybk2HNzdzoMcwhUmdUzAssiQkQvqd_HanRcfFbrHeg5l1fUQ397ECES-r5xK18SYtG1VR7LNTVzhJqkmRd3jzqfmIK2hKWpEgPfm8DRz3j4GGtDRxhb3oaVsT2tSSi_VfT3Ry74tzmO0GcCvmBE2oh58kUZ4QfEsalgZ8IpYHTxovsgDx_M7ujOSZx_hzpz-iy268-OkrU22PQPCfBmlbEKeEUStUO9n0pj4l1ODL31AGARyJRy46w4yzhw7Fk5P336WmDMXYs5LAX2XxPFNLvNzA - - - - - artifactory - https://myartifactory.com/artifactory/testRepo - * - - -` -) - -func TestMavenTreesMultiModule(t *testing.T) { - // Create and change directory to test workspace - _, cleanUp := coreTests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "maven-example")) - defer cleanUp() - - expectedUniqueDeps := []string{ - GavPackageTypeIdentifier + "javax.mail:mail:1.4", - GavPackageTypeIdentifier + "org.testng:testng:5.9", - GavPackageTypeIdentifier + "javax.servlet:servlet-api:2.5", - GavPackageTypeIdentifier + "org.jfrog.test:multi:3.7-SNAPSHOT", - GavPackageTypeIdentifier + "org.jfrog.test:multi3:3.7-SNAPSHOT", - GavPackageTypeIdentifier + "org.jfrog.test:multi2:3.7-SNAPSHOT", - GavPackageTypeIdentifier + "junit:junit:3.8.1", - GavPackageTypeIdentifier + "org.jfrog.test:multi1:3.7-SNAPSHOT", - GavPackageTypeIdentifier + "commons-io:commons-io:1.4", - GavPackageTypeIdentifier + "org.apache.commons:commons-email:1.1", - GavPackageTypeIdentifier + "javax.activation:activation:1.1", - GavPackageTypeIdentifier + "hsqldb:hsqldb:1.8.0.10", - } - // Run getModulesDependencyTrees - modulesDependencyTrees, uniqueDeps, err := buildMavenDependencyTree(&DepTreeParams{}) - if assert.NoError(t, err) && assert.NotEmpty(t, modulesDependencyTrees) { - assert.ElementsMatch(t, maps.Keys(uniqueDeps), expectedUniqueDeps, "First is actual, Second is Expected") - // Check root module - multi := coreTests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test:multi:3.7-SNAPSHOT") - if assert.NotNil(t, multi) { - assert.Len(t, multi.Nodes, 1) - // Check multi1 with a transitive dependency - multi1 := coreTests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test:multi1:3.7-SNAPSHOT") - assert.Len(t, multi1.Nodes, 4) - commonsEmail := coreTests.GetAndAssertNode(t, multi1.Nodes, "org.apache.commons:commons-email:1.1") - assert.Len(t, commonsEmail.Nodes, 2) - - // Check multi2 and multi3 - multi2 := coreTests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test:multi2:3.7-SNAPSHOT") - assert.Len(t, multi2.Nodes, 1) - multi3 := coreTests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test:multi3:3.7-SNAPSHOT") - assert.Len(t, multi3.Nodes, 4) - } - } -} - -func TestMavenWrapperTrees(t *testing.T) { - // Create and change directory to test workspace - _, cleanUp := coreTests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "maven-example-with-wrapper")) - err := os.Chmod("mvnw", 0700) - defer cleanUp() - assert.NoError(t, err) - expectedUniqueDeps := []string{ - GavPackageTypeIdentifier + "org.jfrog.test:multi1:3.7-SNAPSHOT", - GavPackageTypeIdentifier + "org.codehaus.plexus:plexus-utils:1.5.1", - GavPackageTypeIdentifier + "org.springframework:spring-beans:2.5.6", - GavPackageTypeIdentifier + "commons-logging:commons-logging:1.1.1", - GavPackageTypeIdentifier + "org.jfrog.test:multi3:3.7-SNAPSHOT", - GavPackageTypeIdentifier + "org.apache.commons:commons-email:1.1", - GavPackageTypeIdentifier + "org.springframework:spring-aop:2.5.6", - GavPackageTypeIdentifier + "org.springframework:spring-core:2.5.6", - GavPackageTypeIdentifier + "org.jfrog.test:multi:3.7-SNAPSHOT", - GavPackageTypeIdentifier + "org.jfrog.test:multi2:3.7-SNAPSHOT", - GavPackageTypeIdentifier + "org.testng:testng:5.9", - GavPackageTypeIdentifier + "hsqldb:hsqldb:1.8.0.10", - GavPackageTypeIdentifier + "junit:junit:3.8.1", - GavPackageTypeIdentifier + "javax.activation:activation:1.1", - GavPackageTypeIdentifier + "javax.mail:mail:1.4", - GavPackageTypeIdentifier + "aopalliance:aopalliance:1.0", - GavPackageTypeIdentifier + "commons-io:commons-io:1.4", - GavPackageTypeIdentifier + "javax.servlet.jsp:jsp-api:2.1", - GavPackageTypeIdentifier + "javax.servlet:servlet-api:2.5", - } - - modulesDependencyTrees, uniqueDeps, err := buildMavenDependencyTree(&DepTreeParams{}) - if assert.NoError(t, err) && assert.NotEmpty(t, modulesDependencyTrees) { - assert.ElementsMatch(t, maps.Keys(uniqueDeps), expectedUniqueDeps, "First is actual, Second is Expected") - // Check root module - multi := coreTests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test:multi:3.7-SNAPSHOT") - if assert.NotNil(t, multi) { - assert.Len(t, multi.Nodes, 1) - // Check multi1 with a transitive dependency - multi1 := coreTests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test:multi1:3.7-SNAPSHOT") - assert.Len(t, multi1.Nodes, 7) - commonsEmail := coreTests.GetAndAssertNode(t, multi1.Nodes, "org.apache.commons:commons-email:1.1") - assert.Len(t, commonsEmail.Nodes, 2) - // Check multi2 and multi3 - multi2 := coreTests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test:multi2:3.7-SNAPSHOT") - assert.Len(t, multi2.Nodes, 1) - multi3 := coreTests.GetAndAssertNode(t, modulesDependencyTrees, "org.jfrog.test:multi3:3.7-SNAPSHOT") - assert.Len(t, multi3.Nodes, 4) - } - } -} - -func TestMavenWrapperTreesTypes(t *testing.T) { - // Create and change directory to test workspace - _, cleanUp := coreTests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "maven-example-with-many-types")) - defer cleanUp() - tree, uniqueDeps, err := buildMavenDependencyTree(&DepTreeParams{}) - require.NoError(t, err) - // dependency of pom type - depWithPomType := uniqueDeps["gav://org.webjars:lodash:4.17.21"] - assert.NotEmpty(t, depWithPomType) - assert.Equal(t, depWithPomType[0], "pom") - existInTreePom := false - for _, node := range tree[0].Nodes { - if node.Id == "gav://org.webjars:lodash:4.17.21" { - nodeTypes := *node.Types - assert.Equal(t, nodeTypes[0], "pom") - existInTreePom = true - } - } - assert.True(t, existInTreePom) - - // dependency of jar type - depWithJarType := uniqueDeps["gav://junit:junit:4.11"] - assert.NotEmpty(t, depWithJarType) - assert.Equal(t, depWithJarType[0], "jar") - existInTreeJar := false - for _, node := range tree[0].Nodes { - if node.Id == "gav://junit:junit:4.11" { - nodeTypes := *node.Types - assert.Equal(t, nodeTypes[0], "jar") - existInTreeJar = true - } - } - assert.True(t, existInTreeJar) -} - -func TestDepTreeWithDedicatedCache(t *testing.T) { - // Create and change directory to test workspace - _, cleanUp := coreTests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "maven-example-with-wrapper")) - err := os.Chmod("mvnw", 0700) - defer cleanUp() - assert.NoError(t, err) - tempDir := t.TempDir() - defer assert.NoError(t, utils.RemoveTempDir(tempDir)) - manager := NewMavenDepTreeManager(&DepTreeParams{IsCurationCmd: true, CurationCacheFolder: tempDir}, Tree) - _, err = manager.runTreeCmd(tempDir) - require.NoError(t, err) - // validate one of the jars exist in the dedicated cache for curation - fileExist, err := utils.IsFileExists(filepath.Join(tempDir, "org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar"), false) - require.NoError(t, err) - assert.True(t, fileExist) -} - -func TestGetMavenPluginInstallationArgs(t *testing.T) { - args := GetMavenPluginInstallationGoals("testPlugin") - assert.Equal(t, "org.apache.maven.plugins:maven-install-plugin:3.1.1:install-file", args[0]) - assert.Equal(t, "-Dfile=testPlugin", args[1]) -} - -func TestCreateSettingsXmlWithConfiguredArtifactory(t *testing.T) { - // Test case for successful creation of settings.xml. - mdt := MavenDepTreeManager{ - DepTreeManager: DepTreeManager{ - server: &config.ServerDetails{ - ArtifactoryUrl: "https://myartifactory.com/artifactory", - User: "testUser", - Password: "testPass", - }, - depsRepo: "testRepo", - }, - } - // Create a temporary directory for testing and settings.xml creation - tempDir := t.TempDir() - err := mdt.createSettingsXmlWithConfiguredArtifactory(tempDir) - assert.NoError(t, err) - - // Verify settings.xml file creation with username and password - settingsXmlPath := filepath.Join(tempDir, "settings.xml") - actualContent, err := os.ReadFile(settingsXmlPath) - actualContent = []byte(strings.ReplaceAll(string(actualContent), "\r\n", "\n")) - assert.NoError(t, err) - assert.Equal(t, settingsXmlWithUsernameAndPassword, string(actualContent)) - - // check curation command write a dedicated api for curation. - mdt.isCurationCmd = true - err = mdt.createSettingsXmlWithConfiguredArtifactory(tempDir) - require.NoError(t, err) - actualContent, err = os.ReadFile(settingsXmlPath) - actualContent = []byte(strings.ReplaceAll(string(actualContent), "\r\n", "\n")) - assert.NoError(t, err) - assert.Equal(t, settingsXmlWithUsernameAndPasswordAndCurationDedicatedAPi, string(actualContent)) - mdt.isCurationCmd = false - - mdt.server.Password = "" - // jfrog-ignore - mdt.server.AccessToken = dummyToken - err = mdt.createSettingsXmlWithConfiguredArtifactory(tempDir) - assert.NoError(t, err) - - // Verify settings.xml file creation with username and access token - actualContent, err = os.ReadFile(settingsXmlPath) - actualContent = []byte(strings.ReplaceAll(string(actualContent), "\r\n", "\n")) - assert.NoError(t, err) - assert.Equal(t, settingsXmlWithUsernameAndToken, string(actualContent)) - - mdt.server.User = "" - err = mdt.createSettingsXmlWithConfiguredArtifactory(tempDir) - assert.NoError(t, err) - - // Verify settings.xml file creation with access token only - actualContent, err = os.ReadFile(settingsXmlPath) - actualContent = []byte(strings.ReplaceAll(string(actualContent), "\r\n", "\n")) - assert.NoError(t, err) - assert.Equal(t, settingsXmlWithAccessToken, string(actualContent)) -} - -func TestRunProjectsCmd(t *testing.T) { - // Create and change directory to test workspace - _, cleanUp := coreTests.CreateTestWorkspace(t, filepath.Join("..", "..", "tests", "testdata", "maven-example")) - defer cleanUp() - mvnDepTreeManager := NewMavenDepTreeManager(&DepTreeParams{}, Projects) - output, clearMavenDepTreeRun, err := mvnDepTreeManager.RunMavenDepTree() - assert.NoError(t, err) - assert.NotNil(t, clearMavenDepTreeRun) - - pomPathOccurrences := strings.Count(output, "pomPath") - assert.Equal(t, 4, pomPathOccurrences) - assert.NoError(t, clearMavenDepTreeRun()) -} - -func TestRemoveMavenConfig(t *testing.T) { - tmpDir := t.TempDir() - currentDir, err := os.Getwd() - assert.NoError(t, err) - restoreDir := tests.ChangeDirWithCallback(t, currentDir, tmpDir) - defer restoreDir() - - // No maven.config exists - restoreFunc, err := removeMavenConfig() - assert.Nil(t, restoreFunc) - assert.Nil(t, err) - - // Create maven.config - err = fileutils.CreateDirIfNotExist(".mvn") - assert.NoError(t, err) - file, err := os.Create(mavenConfigPath) - assert.NoError(t, err) - err = file.Close() - assert.NoError(t, err) - restoreFunc, err = removeMavenConfig() - assert.NoError(t, err) - assert.NoFileExists(t, mavenConfigPath) - err = restoreFunc() - assert.NoError(t, err) - assert.FileExists(t, mavenConfigPath) -} - -func TestMavenDepTreeManager_suspectCurationBlockedError(t *testing.T) { - errPrefix := "[ERROR] Failed to execute goal on project my-app: Could not resolve dependencies for project com.mycompany.app:my-app:jar:1.0-SNAPSHOT: Failed to " + - "collect dependencies at junit:junit:jar:3.8.1: Failed to read artifact descriptor for junit:junit:jar:3.8.1: " + - "The following artifacts could not be resolved: junit:junit:pom:3.8.1 (absent): Could not transfer artifact junit:junit:pom:3.8.1 " + - "from/to artifactory (http://test:8046/artifactory/api/curation/audit/maven-remote):" - tests := []struct { - name string - wantMsgToUser string - input string - }{ - { - name: "failed on 403", - wantMsgToUser: "Please verify pass-through enabled on the curated repos", - input: errPrefix + "status code: 403, reason phrase: Forbidden (403)", - }, - { - name: "failed on 500", - wantMsgToUser: "Please verify pass-through enabled on the curated repos", - input: errPrefix + " status code: 500, reason phrase: Internal Server Error (500)", - }, - { - name: "not 403 or 500", - wantMsgToUser: "", - input: errPrefix + " status code: 400, reason phrase: Forbidden (400)", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mdt := &MavenDepTreeManager{} - assert.Contains(t, tt.wantMsgToUser, mdt.suspectCurationBlockedError(tt.input)) - }) - } -} diff --git a/utils/java/resources/gradle-dep-tree.jar b/utils/java/resources/gradle-dep-tree.jar deleted file mode 100644 index b855f258b416de4c7ef9a0d487010afc882de99e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12253 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 diff --git a/utils/java/resources/maven-dep-tree.jar b/utils/java/resources/maven-dep-tree.jar deleted file mode 100644 index f8d7ff406591d396976cc576c6cf0ce87e75042d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13862 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 - - - - artifactory - %s - %s - - - - - artifactory - %s - * - - - \ No newline at end of file From 4a0e1442bf74f5173f0e788879e6e762ac2f267e Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Wed, 27 Mar 2024 10:11:55 +0200 Subject: [PATCH 08/36] Fix npm publish with provided tarball (#1162) --- artifactory/commands/npm/publish.go | 5 ++-- artifactory/commands/npm/publish_test.go | 33 +++++++++++++++--------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/artifactory/commands/npm/publish.go b/artifactory/commands/npm/publish.go index 86b2056ce..ea5e7e01f 100644 --- a/artifactory/commands/npm/publish.go +++ b/artifactory/commands/npm/publish.go @@ -418,11 +418,13 @@ func (npc *NpmPublishCommand) setPackageInfo() error { } log.Debug("The provided path is not a directory, we assume this is a compressed npm package") npc.tarballProvided = true + // Sets the location of the provided tarball + npc.packedFilePaths = []string{npc.publishPath} return npc.readPackageInfoFromTarball(npc.publishPath) } func (npc *NpmPublishCommand) readPackageInfoFromTarball(packedFilePath string) (err error) { - log.Debug("Extracting info from npm package:", npc.packedFilePaths) + log.Debug("Extracting info from npm package:", packedFilePath) tarball, err := os.Open(packedFilePath) if err != nil { return errorutils.CheckError(err) @@ -449,7 +451,6 @@ func (npc *NpmPublishCommand) readPackageInfoFromTarball(packedFilePath string) if err != nil { return errorutils.CheckError(err) } - npc.packageInfo, err = biutils.ReadPackageInfo(packageJson, npc.npmVersion) return err } diff --git a/artifactory/commands/npm/publish_test.go b/artifactory/commands/npm/publish_test.go index fa3e412c6..d49d3cf36 100644 --- a/artifactory/commands/npm/publish_test.go +++ b/artifactory/commands/npm/publish_test.go @@ -9,17 +9,26 @@ import ( func TestReadPackageInfoFromTarball(t *testing.T) { npmPublish := NewNpmPublishCommand() - npmPublish.packedFilePaths = append(npmPublish.packedFilePaths, filepath.Join("..", "testdata", "npm", "npm-example-0.0.3.tgz")) - npmPublish.packedFilePaths = append(npmPublish.packedFilePaths, filepath.Join("..", "testdata", "npm", "npm-example-0.0.4.tgz")) - - err := npmPublish.readPackageInfoFromTarball(npmPublish.packedFilePaths[0]) - assert.NoError(t, err) - assert.Equal(t, "npm-example", npmPublish.packageInfo.Name) - assert.Equal(t, "0.0.3", npmPublish.packageInfo.Version) - - err = npmPublish.readPackageInfoFromTarball(npmPublish.packedFilePaths[1]) - assert.NoError(t, err) - assert.Equal(t, "npm-example", npmPublish.packageInfo.Name) - assert.Equal(t, "0.0.4", npmPublish.packageInfo.Version) + var testCases = []struct { + filePath string + packageName string + packageVersion string + }{ + { + filePath: filepath.Join("..", "testdata", "npm", "npm-example-0.0.3.tgz"), + packageName: "npm-example", + packageVersion: "0.0.3", + }, { + filePath: filepath.Join("..", "testdata", "npm", "npm-example-0.0.4.tgz"), + packageName: "npm-example", + packageVersion: "0.0.4", + }, + } + for _, test := range testCases { + err := npmPublish.readPackageInfoFromTarball(test.filePath) + assert.NoError(t, err) + assert.Equal(t, test.packageName, npmPublish.packageInfo.Name) + assert.Equal(t, test.packageVersion, npmPublish.packageInfo.Version) + } } From 8054e0dc39f54338126a07fa3719abd393c3d005 Mon Sep 17 00:00:00 2001 From: Michael Sverdlov Date: Wed, 27 Mar 2024 17:58:56 +0200 Subject: [PATCH 09/36] Update dependencies (#1163) --- .github/workflows/analysis.yml | 2 +- go.mod | 11 ++++++----- go.sum | 16 ++++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index a8a77bee8..86487ff15 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -20,7 +20,7 @@ jobs: cache: false - name: Static Code Analysis - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v4 with: args: | --timeout 5m --out-${NO_FUTURE}format colored-line-number --enable errcheck,gosimple,govet,ineffassign,staticcheck,typecheck,unused,gocritic,asasalint,asciicheck,errchkjson,exportloopref,forcetypeassert,makezero,nilerr,unparam,unconvert,wastedassign,usestdlibvars diff --git a/go.mod b/go.mod index 6c02ff9ac..80c9f283c 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,12 @@ require github.com/c-bata/go-prompt v0.2.5 // Should not be updated to 0.2.6 due require ( github.com/buger/jsonparser v1.1.1 github.com/chzyer/readline v1.5.1 - github.com/forPelevin/gomoji v1.1.8 + github.com/forPelevin/gomoji v1.2.0 github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 - github.com/jedib0t/go-pretty/v6 v6.5.5 - github.com/jfrog/build-info-go v1.9.24 + github.com/jedib0t/go-pretty/v6 v6.5.6 + github.com/jfrog/build-info-go v1.9.25 github.com/jfrog/gofrog v1.6.3 github.com/jfrog/jfrog-client-go v1.38.0 github.com/magiconair/properties v1.8.7 @@ -28,6 +28,7 @@ require ( golang.org/x/term v0.18.0 golang.org/x/text v0.14.0 gopkg.in/yaml.v3 v3.0.1 + ) require ( @@ -96,8 +97,8 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240320102352-af2f392bb490 +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240327154209-77a304635e42 -replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 +// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc diff --git a/go.sum b/go.sum index 109566b7f..1fe1f946e 100644 --- a/go.sum +++ b/go.sum @@ -49,8 +49,8 @@ github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdf github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/forPelevin/gomoji v1.1.8 h1:JElzDdt0TyiUlecy6PfITDL6eGvIaxqYH1V52zrd0qQ= -github.com/forPelevin/gomoji v1.1.8/go.mod h1:8+Z3KNGkdslmeGZBC3tCrwMrcPy5GRzAD+gL9NAwMXg= +github.com/forPelevin/gomoji v1.2.0 h1:9k4WVSSkE1ARO/BWywxgEUBvR/jMnao6EZzrql5nxJ8= +github.com/forPelevin/gomoji v1.2.0/go.mod h1:8+Z3KNGkdslmeGZBC3tCrwMrcPy5GRzAD+gL9NAwMXg= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= @@ -79,16 +79,16 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jedib0t/go-pretty/v6 v6.5.5 h1:PpIU8lOjxvVYGGKule0QxxJfNysUSbC9lggQU2cpZJc= -github.com/jedib0t/go-pretty/v6 v6.5.5/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= +github.com/jedib0t/go-pretty/v6 v6.5.6 h1:nKXVLqPfAwY7sWcYXdNZZZ2fjqDpAtj9UeWupgfUxSg= +github.com/jedib0t/go-pretty/v6 v6.5.6/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= -github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 h1:au9aqxUQIhxRU6vr58rk2/w3hOwxg5ryu6pxgYkixl0= -github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1/go.mod h1:doFB4bFDVHeGulD6GF9LzsrRaIOrSoklV9DgIAEqHgc= +github.com/jfrog/build-info-go v1.9.25 h1:IkjydGQA/HjOWjRaoKq1hOEgCCyBEJwQgXJSo4WVBSA= +github.com/jfrog/build-info-go v1.9.25/go.mod h1:doFB4bFDVHeGulD6GF9LzsrRaIOrSoklV9DgIAEqHgc= github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc= github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240320102352-af2f392bb490 h1:oGgwRJatirSNZyqO3e4FtHCe5W30VNgULCW/GYhHdao= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240320102352-af2f392bb490/go.mod h1:8z6in1qalzL1DqchUCrDKVgz2gKoPRhJpzm2Ww+VWYI= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240327154209-77a304635e42 h1:ZvG40RPTqeFeK/z0k2JmfUxHFlisjzYrjDXjoRR6yZw= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240327154209-77a304635e42/go.mod h1:tUyEmxznphh0nwAGo6xz9Sps7RRW/TBMxIJZteo+j2k= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= From d3d356015d737f25091cf8862bf55da860aa945f Mon Sep 17 00:00:00 2001 From: Michael Sverdlov Date: Thu, 28 Mar 2024 11:38:36 +0200 Subject: [PATCH 10/36] Update version to 2.50.0 (#1164) --- .github/workflows/test.yml | 2 +- go.mod | 7 +++---- go.sum | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1693490dd..ea9a56db8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: cache: false - name: Install NuGet - uses: nuget/setup-nuget@v1 + uses: nuget/setup-nuget@v2 with: nuget-version: 6.x diff --git a/go.mod b/go.mod index 80c9f283c..a4c898986 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jedib0t/go-pretty/v6 v6.5.6 github.com/jfrog/build-info-go v1.9.25 github.com/jfrog/gofrog v1.6.3 - github.com/jfrog/jfrog-client-go v1.38.0 + github.com/jfrog/jfrog-client-go v1.39.0 github.com/magiconair/properties v1.8.7 github.com/manifoldco/promptui v0.9.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -22,13 +22,12 @@ require ( github.com/stretchr/testify v1.9.0 github.com/urfave/cli v1.22.14 github.com/vbauerster/mpb/v7 v7.5.3 - golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 + golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 golang.org/x/mod v0.16.0 golang.org/x/sync v0.6.0 golang.org/x/term v0.18.0 golang.org/x/text v0.14.0 gopkg.in/yaml.v3 v3.0.1 - ) require ( @@ -97,7 +96,7 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240327154209-77a304635e42 +// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240327154209-77a304635e42 // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 diff --git a/go.sum b/go.sum index 1fe1f946e..a5a38cc2e 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.9.25 h1:IkjydGQA/HjOWjRaoKq1hOEgCCyBEJwQgXJSo4 github.com/jfrog/build-info-go v1.9.25/go.mod h1:doFB4bFDVHeGulD6GF9LzsrRaIOrSoklV9DgIAEqHgc= github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc= github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240327154209-77a304635e42 h1:ZvG40RPTqeFeK/z0k2JmfUxHFlisjzYrjDXjoRR6yZw= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240327154209-77a304635e42/go.mod h1:tUyEmxznphh0nwAGo6xz9Sps7RRW/TBMxIJZteo+j2k= +github.com/jfrog/jfrog-client-go v1.39.0 h1:GZ1qbpUDzYz8ZEycYicDkbVMN2H0VSCuz8mUNTyf7tc= +github.com/jfrog/jfrog-client-go v1.39.0/go.mod h1:tUyEmxznphh0nwAGo6xz9Sps7RRW/TBMxIJZteo+j2k= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -214,8 +214,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc= -golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= From 65190e6b1370d1107057850c6e496b8ebf71cc6b Mon Sep 17 00:00:00 2001 From: Gai Lazar Date: Wed, 3 Apr 2024 16:30:29 +0300 Subject: [PATCH 11/36] New XSC analytics metrics capabilities (#1165) --- go.mod | 4 ++-- go.sum | 4 ++-- utils/config/config.go | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index a4c898986..c7f5382ac 100644 --- a/go.mod +++ b/go.mod @@ -96,8 +96,8 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240327154209-77a304635e42 +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240403100335-8292671b7cc4 -// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240319160313-0093dee91fc1 +// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc diff --git a/go.sum b/go.sum index a5a38cc2e..7aa3a37b6 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.9.25 h1:IkjydGQA/HjOWjRaoKq1hOEgCCyBEJwQgXJSo4 github.com/jfrog/build-info-go v1.9.25/go.mod h1:doFB4bFDVHeGulD6GF9LzsrRaIOrSoklV9DgIAEqHgc= github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc= github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg= -github.com/jfrog/jfrog-client-go v1.39.0 h1:GZ1qbpUDzYz8ZEycYicDkbVMN2H0VSCuz8mUNTyf7tc= -github.com/jfrog/jfrog-client-go v1.39.0/go.mod h1:tUyEmxznphh0nwAGo6xz9Sps7RRW/TBMxIJZteo+j2k= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240403100335-8292671b7cc4 h1:A67yoFRYjRzg+xhLYhH0QN7b4/wggRa/lSQKSjzOwNQ= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240403100335-8292671b7cc4/go.mod h1:tUyEmxznphh0nwAGo6xz9Sps7RRW/TBMxIJZteo+j2k= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= diff --git a/utils/config/config.go b/utils/config/config.go index 392342210..2a073da63 100644 --- a/utils/config/config.go +++ b/utils/config/config.go @@ -19,6 +19,7 @@ import ( "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" xrayAuth "github.com/jfrog/jfrog-client-go/xray/auth" + xscAuth "github.com/jfrog/jfrog-client-go/xsc/auth" "os" "path/filepath" "strconv" @@ -572,6 +573,7 @@ type ServerDetails struct { ArtifactoryUrl string `json:"artifactoryUrl,omitempty"` DistributionUrl string `json:"distributionUrl,omitempty"` XrayUrl string `json:"xrayUrl,omitempty"` + XscUrl string `json:"xscUrl,omitempty"` MissionControlUrl string `json:"missionControlUrl,omitempty"` PipelinesUrl string `json:"pipelinesUrl,omitempty"` AccessUrl string `json:"accessUrl,omitempty"` @@ -708,6 +710,19 @@ func (serverDetails *ServerDetails) CreateXrayAuthConfig() (auth.ServiceDetails, return serverDetails.createAuthConfig(artAuth) } +func (serverDetails *ServerDetails) CreateXscAuthConfig() (auth.ServiceDetails, error) { + ascAuth := xscAuth.NewXscDetails() + ascAuth.SetUrl(serverDetails.convertXrayUrlToXscUrl()) + return serverDetails.createAuthConfig(ascAuth) +} + +// Xray and Xsc will always have the same platform url. +func (serverDetails *ServerDetails) convertXrayUrlToXscUrl() string { + xscUrl := strings.TrimSuffix(serverDetails.XrayUrl, "/") + xscUrl = strings.TrimSuffix(xscUrl, "/xray") + return xscUrl + "/xsc/" +} + func (serverDetails *ServerDetails) CreatePipelinesAuthConfig() (auth.ServiceDetails, error) { pAuth := pipelinesAuth.NewPipelinesDetails() pAuth.SetUrl(serverDetails.PipelinesUrl) From 2fbfc02df7d357f47829144a70907ff7263d6ea5 Mon Sep 17 00:00:00 2001 From: Assaf Attias <49212512+attiasas@users.noreply.github.com> Date: Wed, 3 Apr 2024 17:17:10 +0300 Subject: [PATCH 12/36] Duplicate App Name at plugins help usage (#1167) --- plugins/components/conversionlayer.go | 4 ++-- plugins/components/conversionlayer_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/components/conversionlayer.go b/plugins/components/conversionlayer.go index fafe2d9bd..dae7da806 100644 --- a/plugins/components/conversionlayer.go +++ b/plugins/components/conversionlayer.go @@ -18,7 +18,7 @@ func ConvertApp(jfrogApp App) (*cli.App, error) { app.Name = jfrogApp.Name app.Description = jfrogApp.Description app.Version = jfrogApp.Version - app.Commands, err = ConvertAppCommands(jfrogApp, jfrogApp.Name) + app.Commands, err = ConvertAppCommands(jfrogApp) if err != nil { return nil, err } @@ -127,7 +127,7 @@ func createCommandUsages(cmd Command, convertedStringFlags map[string]StringFlag } func getCmdUsageString(cmd Command, namespaces ...string) string { - return coreutils.GetCliExecutableName() + " " + strings.Join(append(removeEmptyValues(namespaces), cmd.Name), " ") + return strings.Join(append(removeEmptyValues(namespaces), cmd.Name), " ") } // Generated usages are based on the command's flags and arguments: diff --git a/plugins/components/conversionlayer_test.go b/plugins/components/conversionlayer_test.go index 2e237fc9d..018e65502 100644 --- a/plugins/components/conversionlayer_test.go +++ b/plugins/components/conversionlayer_test.go @@ -11,7 +11,7 @@ import ( func TestCreateCommandUsages(t *testing.T) { appNameSpace := "test-app" cmdName := "test-command" - expectedPrefix := fmt.Sprintf("%s %s %s", coreutils.GetCliExecutableName(), appNameSpace, cmdName) + expectedPrefix := fmt.Sprintf("%s %s", appNameSpace, cmdName) optFlag := NewBoolFlag("dummyFlag", "") optStrFlag := NewStringFlag("optFlag", "", WithHelpValue("alias")) From 3df49e9a9d645281123d865d2af7eb1a1d940548 Mon Sep 17 00:00:00 2001 From: Asaf Ambar Date: Thu, 4 Apr 2024 10:56:04 +0300 Subject: [PATCH 13/36] Support pip for curation (#1155) --- artifactory/commands/python/poetry.go | 2 +- artifactory/commands/python/python.go | 2 +- utils/coreutils/coreconsts.go | 2 ++ utils/python/utils.go | 11 ++++++++--- utils/python/utils_test.go | 28 +++++++++++++++++++++++++++ 5 files changed, 40 insertions(+), 5 deletions(-) diff --git a/artifactory/commands/python/poetry.go b/artifactory/commands/python/poetry.go index da91baa99..33152c9cf 100644 --- a/artifactory/commands/python/poetry.go +++ b/artifactory/commands/python/poetry.go @@ -126,7 +126,7 @@ func (pc *PoetryCommand) SetCommandName(commandName string) *PoetryCommand { } func (pc *PoetryCommand) SetPypiRepoUrlWithCredentials() error { - rtUrl, username, password, err := python.GetPypiRepoUrlWithCredentials(pc.serverDetails, pc.repository) + rtUrl, username, password, err := python.GetPypiRepoUrlWithCredentials(pc.serverDetails, pc.repository, false) if err != nil { return err } diff --git a/artifactory/commands/python/python.go b/artifactory/commands/python/python.go index 8d2de8b3e..fa0c37718 100644 --- a/artifactory/commands/python/python.go +++ b/artifactory/commands/python/python.go @@ -100,7 +100,7 @@ func (pc *PythonCommand) SetCommandName(commandName string) *PythonCommand { } func (pc *PythonCommand) SetPypiRepoUrlWithCredentials() error { - rtUrl, err := python.GetPypiRepoUrl(pc.serverDetails, pc.repository) + rtUrl, err := python.GetPypiRepoUrl(pc.serverDetails, pc.repository, false) if err != nil { return err } diff --git a/utils/coreutils/coreconsts.go b/utils/coreutils/coreconsts.go index 31855afcd..e9d64a753 100644 --- a/utils/coreutils/coreconsts.go +++ b/utils/coreutils/coreconsts.go @@ -34,6 +34,8 @@ const ( JfrogTransferStateFileName = "state.json" PluginsExecDirName = "bin" PluginsResourcesDirName = "resources" + //#nosec G101 + CurationPassThroughApi = "api/curation/audit/" //#nosec G101 ErrorHandling = "JFROG_CLI_ERROR_HANDLING" diff --git a/utils/python/utils.go b/utils/python/utils.go index 83d880575..7a599b28a 100644 --- a/utils/python/utils.go +++ b/utils/python/utils.go @@ -2,6 +2,7 @@ package utils import ( "fmt" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "net/url" "os" "path/filepath" @@ -25,7 +26,7 @@ const ( pyproject = "pyproject.toml" ) -func GetPypiRepoUrlWithCredentials(serverDetails *config.ServerDetails, repository string) (*url.URL, string, string, error) { +func GetPypiRepoUrlWithCredentials(serverDetails *config.ServerDetails, repository string, isCurationCmd bool) (*url.URL, string, string, error) { rtUrl, err := url.Parse(serverDetails.GetArtifactoryUrl()) if err != nil { return nil, "", "", errorutils.CheckError(err) @@ -41,6 +42,10 @@ func GetPypiRepoUrlWithCredentials(serverDetails *config.ServerDetails, reposito } password = serverDetails.GetAccessToken() } + // In case of curation command, the download urls should be routed through a dedicated api. + if isCurationCmd { + rtUrl.Path += coreutils.CurationPassThroughApi + } rtUrl.Path += "api/pypi/" + repository + "/simple" return rtUrl, username, password, err } @@ -52,8 +57,8 @@ func GetPypiRemoteRegistryFlag(tool pythonutils.PythonTool) string { return pipenvRemoteRegistryFlag } -func GetPypiRepoUrl(serverDetails *config.ServerDetails, repository string) (string, error) { - rtUrl, username, password, err := GetPypiRepoUrlWithCredentials(serverDetails, repository) +func GetPypiRepoUrl(serverDetails *config.ServerDetails, repository string, isCurationCmd bool) (string, error) { + rtUrl, username, password, err := GetPypiRepoUrlWithCredentials(serverDetails, repository, isCurationCmd) if err != nil { return "", err } diff --git a/utils/python/utils_test.go b/utils/python/utils_test.go index 45b2b19be..3ef8785c8 100644 --- a/utils/python/utils_test.go +++ b/utils/python/utils_test.go @@ -1,7 +1,11 @@ package utils import ( + "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/stretchr/testify/require" "path/filepath" + "strings" "testing" "github.com/jfrog/jfrog-cli-core/v2/utils/tests" @@ -31,3 +35,27 @@ func initPoetryTest(t *testing.T) (string, func()) { poetryProjectPath, cleanUp := tests.CreateTestWorkspace(t, testAbs) return poetryProjectPath, cleanUp } + +func TestGetPypiRepoUrlWithCredentials(t *testing.T) { + tests := []struct { + name string + curationCmd bool + }{ + { + name: "test curation command true", + curationCmd: true, + }, + { + name: "test curation command false", + curationCmd: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + url, _, _, err := GetPypiRepoUrlWithCredentials(&config.ServerDetails{}, "test", tt.curationCmd) + require.NoError(t, err) + assert.Equal(t, tt.curationCmd, strings.Contains(url.Path, coreutils.CurationPassThroughApi)) + }) + } +} From 13680c04f22e69a9e63aa00ba2602a54c7c41038 Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Mon, 8 Apr 2024 10:41:56 +0300 Subject: [PATCH 14/36] Artifactory Release Lifecycle Management - Add Import bundle function (#1153) --- go.mod | 2 +- go.sum | 4 +-- lifecycle/import.go | 60 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 lifecycle/import.go diff --git a/go.mod b/go.mod index c7f5382ac..4bee0e1b0 100644 --- a/go.mod +++ b/go.mod @@ -96,7 +96,7 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240403100335-8292671b7cc4 +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240408071430-62ee0279ac58 // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev diff --git a/go.sum b/go.sum index 7aa3a37b6..2ffd059e2 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.9.25 h1:IkjydGQA/HjOWjRaoKq1hOEgCCyBEJwQgXJSo4 github.com/jfrog/build-info-go v1.9.25/go.mod h1:doFB4bFDVHeGulD6GF9LzsrRaIOrSoklV9DgIAEqHgc= github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc= github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240403100335-8292671b7cc4 h1:A67yoFRYjRzg+xhLYhH0QN7b4/wggRa/lSQKSjzOwNQ= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240403100335-8292671b7cc4/go.mod h1:tUyEmxznphh0nwAGo6xz9Sps7RRW/TBMxIJZteo+j2k= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240408071430-62ee0279ac58 h1:yyhOfECY3WGs6MsnJQWm/U7DYNIzxBiVlEwQ3RvqxwQ= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240408071430-62ee0279ac58/go.mod h1:tUyEmxznphh0nwAGo6xz9Sps7RRW/TBMxIJZteo+j2k= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= diff --git a/lifecycle/import.go b/lifecycle/import.go new file mode 100644 index 000000000..084ca6205 --- /dev/null +++ b/lifecycle/import.go @@ -0,0 +1,60 @@ +package lifecycle + +import ( + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/jfrog/jfrog-client-go/utils/log" +) + +type ReleaseBundleImportCommand struct { + releaseBundleCmd + filePath string +} + +func (rbi *ReleaseBundleImportCommand) ServerDetails() (*config.ServerDetails, error) { + return rbi.serverDetails, nil +} + +func (rbi *ReleaseBundleImportCommand) CommandName() string { + return "rb_import" +} + +func NewReleaseBundleImportCommand() *ReleaseBundleImportCommand { + return &ReleaseBundleImportCommand{} +} +func (rbi *ReleaseBundleImportCommand) SetServerDetails(serverDetails *config.ServerDetails) *ReleaseBundleImportCommand { + rbi.serverDetails = serverDetails + return rbi +} + +func (rbi *ReleaseBundleImportCommand) SetFilepath(filePath string) *ReleaseBundleImportCommand { + rbi.filePath = filePath + return rbi +} + +func (rbi *ReleaseBundleImportCommand) Run() (err error) { + if err = validateArtifactoryVersionSupported(rbi.serverDetails); err != nil { + return + } + artService, err := utils.CreateServiceManager(rbi.serverDetails, 3, 0, false) + if err != nil { + return + } + + exists, err := fileutils.IsFileExists(rbi.filePath, false) + if err != nil { + return + } + if !exists { + return fmt.Errorf("file not found: %s", rbi.filePath) + } + + log.Info("Importing the release bundle archive...") + if err = artService.ImportReleaseBundle(rbi.filePath); err != nil { + return + } + log.Info("Successfully imported the release bundle archive") + return +} From d5bc1eb525b6767393ccd9b3e9b7be6e96c06bd6 Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Mon, 15 Apr 2024 12:05:13 +0300 Subject: [PATCH 15/36] Fix npm packed tarball files identification (#1171) --- artifactory/utils/npm/pack.go | 34 +++++++++++++++++++--- tests/testdata/npm-workspaces/package.json | 3 +- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/artifactory/utils/npm/pack.go b/artifactory/utils/npm/pack.go index 9f9686709..24ff8e289 100644 --- a/artifactory/utils/npm/pack.go +++ b/artifactory/utils/npm/pack.go @@ -1,6 +1,8 @@ package npm import ( + "fmt" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "strings" gofrogcmd "github.com/jfrog/gofrog/io" @@ -8,13 +10,17 @@ import ( "github.com/jfrog/jfrog-client-go/utils/errorutils" ) +const ( + npmPackedTarballSuffix = ".tgz" +) + func Pack(npmFlags []string, executablePath string) ([]string, error) { configListCmdConfig := createPackCmdConfig(executablePath, npmFlags) output, err := gofrogcmd.RunCmdOutput(configListCmdConfig) if err != nil { return []string{}, errorutils.CheckError(err) } - return getPackageFileNameFromOutput(output), nil + return getPackageFileNameFromOutput(output) } func createPackCmdConfig(executablePath string, splitFlags []string) *npmutils.NpmConfig { @@ -27,7 +33,27 @@ func createPackCmdConfig(executablePath string, splitFlags []string) *npmutils.N } } -func getPackageFileNameFromOutput(output string) []string { - output = strings.TrimSpace(output) - return strings.Split(output, "\n") +// Extracts packed file names from npm pack command output +// The output can differ when a prePack script exists, +// This function will filter the output and search for the .tgz files +// To avoid misidentifying files, we will verify file exists +func getPackageFileNameFromOutput(output string) (packedTgzFiles []string, err error) { + lines := strings.Split(output, "\n") + var packedFileNamesFromOutput []string + for _, line := range lines { + line = strings.TrimSpace(line) + if strings.HasSuffix(line, npmPackedTarballSuffix) { + packedFileNamesFromOutput = append(packedFileNamesFromOutput, line) + } + } + for _, file := range packedFileNamesFromOutput { + exists, err := fileutils.IsFileExists(file, true) + if err != nil { + return nil, fmt.Errorf("error occurred while checking packed npm tarball exists: %w", err) + } + if exists { + packedTgzFiles = append(packedTgzFiles, file) + } + } + return } diff --git a/tests/testdata/npm-workspaces/package.json b/tests/testdata/npm-workspaces/package.json index 59c936a79..ee7c9c0a6 100644 --- a/tests/testdata/npm-workspaces/package.json +++ b/tests/testdata/npm-workspaces/package.json @@ -4,7 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "prepack": "echo 'prepack script executed'" }, "keywords": [], "author": "", From d0547c3ef8990315fc18b3320fd9b35c516bccda Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Mon, 15 Apr 2024 17:17:56 +0300 Subject: [PATCH 16/36] Update Dependencies (#1172) --- go.mod | 8 ++++---- go.sum | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 4bee0e1b0..b87ef9676 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,9 @@ require ( github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 github.com/jedib0t/go-pretty/v6 v6.5.6 - github.com/jfrog/build-info-go v1.9.25 - github.com/jfrog/gofrog v1.6.3 - github.com/jfrog/jfrog-client-go v1.39.0 + github.com/jfrog/build-info-go v1.9.26 + github.com/jfrog/gofrog v1.7.1 + github.com/jfrog/jfrog-client-go v1.40.1 github.com/magiconair/properties v1.8.7 github.com/manifoldco/promptui v0.9.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -96,7 +96,7 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240408071430-62ee0279ac58 +// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240408071430-62ee0279ac58 // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev diff --git a/go.sum b/go.sum index 2ffd059e2..534583ca6 100644 --- a/go.sum +++ b/go.sum @@ -83,12 +83,12 @@ github.com/jedib0t/go-pretty/v6 v6.5.6 h1:nKXVLqPfAwY7sWcYXdNZZZ2fjqDpAtj9UeWupg github.com/jedib0t/go-pretty/v6 v6.5.6/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= -github.com/jfrog/build-info-go v1.9.25 h1:IkjydGQA/HjOWjRaoKq1hOEgCCyBEJwQgXJSo4WVBSA= -github.com/jfrog/build-info-go v1.9.25/go.mod h1:doFB4bFDVHeGulD6GF9LzsrRaIOrSoklV9DgIAEqHgc= -github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc= -github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240408071430-62ee0279ac58 h1:yyhOfECY3WGs6MsnJQWm/U7DYNIzxBiVlEwQ3RvqxwQ= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240408071430-62ee0279ac58/go.mod h1:tUyEmxznphh0nwAGo6xz9Sps7RRW/TBMxIJZteo+j2k= +github.com/jfrog/build-info-go v1.9.26 h1:1Ddc6+Ecvhc+UMnKhRVG1jGM6fYNwA49207azTBGBc8= +github.com/jfrog/build-info-go v1.9.26/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= +github.com/jfrog/gofrog v1.7.1 h1:ME1Meg4hukAT/7X6HUQCVSe4DNjMZACCP8aCY37EW/w= +github.com/jfrog/gofrog v1.7.1/go.mod h1:X7bjfWoQDN0Z4FQGbE91j3gbPP7Urwzm4Z8tkvrlbRI= +github.com/jfrog/jfrog-client-go v1.40.1 h1:ISSSV7/IUS8R+QCPfH2lVKLburbv2Xn07fvNyDc17rI= +github.com/jfrog/jfrog-client-go v1.40.1/go.mod h1:FprEW0Sqhj6ZSFTFk9NCni+ovFAYMA3zCBmNX4hGXgQ= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= From 5ef50ba4c8ce386e4ae2f71293af415a70f3c56d Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Wed, 24 Apr 2024 12:48:15 +0300 Subject: [PATCH 17/36] Lock config during import (#1176) --- common/commands/config.go | 51 ++++++++++++++++++++++------------ common/commands/config_test.go | 29 ++++++++++++++++++- 2 files changed, 61 insertions(+), 19 deletions(-) diff --git a/common/commands/config.go b/common/commands/config.go index 53ce635e4..c51ded1fb 100644 --- a/common/commands/config.go +++ b/common/commands/config.go @@ -3,6 +3,13 @@ package commands import ( "errors" "fmt" + "net/url" + "os" + "reflect" + "strconv" + "strings" + "sync" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" @@ -14,12 +21,6 @@ import ( "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" - "net/url" - "os" - "reflect" - "strconv" - "strings" - "sync" ) type ConfigAction string @@ -105,17 +106,7 @@ func (cc *ConfigCommand) SetDetails(details *config.ServerDetails) *ConfigComman func (cc *ConfigCommand) Run() (err error) { log.Debug("Locking config file to run config " + cc.cmdType + " command.") - mutex.Lock() - defer func() { - mutex.Unlock() - log.Debug("Config " + cc.cmdType + " command completed successfully. config file is released.") - }() - - lockDirPath, err := coreutils.GetJfrogConfigLockDir() - if err != nil { - return - } - unlockFunc, err := lock.CreateLock(lockDirPath) + unlockFunc, err := lockConfig() // Defer the lockFile.Unlock() function before throwing a possible error to avoid deadlock situations. defer func() { err = errors.Join(err, unlockFunc()) @@ -551,7 +542,21 @@ func ShowConfig(serverName string) error { return nil } -func Import(configTokenString string) error { +func lockConfig() (unlockFunc func() error, err error) { + mutex.Lock() + defer func() { + mutex.Unlock() + log.Debug("config file is released.") + }() + + lockDirPath, err := coreutils.GetJfrogConfigLockDir() + if err != nil { + return + } + return lock.CreateLock(lockDirPath) +} + +func Import(configTokenString string) (err error) { serverDetails, err := config.Import(configTokenString) if err != nil { return err @@ -561,6 +566,16 @@ func Import(configTokenString string) error { details: serverDetails, serverId: serverDetails.ServerId, } + + log.Debug("Locking config file to run config import command.") + unlockFunc, err := lockConfig() + // Defer the lockFile.Unlock() function before throwing a possible error to avoid deadlock situations. + defer func() { + err = errors.Join(err, unlockFunc()) + }() + if err != nil { + return err + } return configCommand.config() } diff --git a/common/commands/config_test.go b/common/commands/config_test.go index 0002abfd9..cef289187 100644 --- a/common/commands/config_test.go +++ b/common/commands/config_test.go @@ -15,7 +15,12 @@ import ( "github.com/stretchr/testify/assert" ) -const testServerId = "test" +const ( + testServerId = "test" + // #nosec G101 -- False positive - no hardcoded credentials. + // jfrog-ignore - not a real token + acmeConfigToken = "eyJ2ZXJzaW9uIjoyLCJ1cmwiOiJodHRwczovL2FjbWUuamZyb2cuaW8vIiwiYXJ0aWZhY3RvcnlVcmwiOiJodHRwczovL2FjbWUuamZyb2cuaW8vYXJ0aWZhY3RvcnkvIiwiZGlzdHJpYnV0aW9uVXJsIjoiaHR0cHM6Ly9hY21lLmpmcm9nLmlvL2Rpc3RyaWJ1dGlvbi8iLCJ4cmF5VXJsIjoiaHR0cHM6Ly9hY21lLmpmcm9nLmlvL3hyYXkvIiwibWlzc2lvbkNvbnRyb2xVcmwiOiJodHRwczovL2FjbWUuamZyb2cuaW8vbWMvIiwicGlwZWxpbmVzVXJsIjoiaHR0cHM6Ly9hY21lLmpmcm9nLmlvL3BpcGVsaW5lcy8iLCJ1c2VyIjoiYWRtaW4iLCJwYXNzd29yZCI6InBhc3N3b3JkIiwidG9rZW5SZWZyZXNoSW50ZXJ2YWwiOjYwLCJzZXJ2ZXJJZCI6ImFjbWUifQ==" +) func init() { log.SetDefaultLogger() @@ -317,6 +322,28 @@ func TestKeyDecryptionError(t *testing.T) { assert.ErrorContains(t, err, "cannot decrypt config") } +func TestImport(t *testing.T) { + // Create temp jfrog home + cleanUpJfrogHome, err := utilsTests.SetJfrogHome() + assert.NoError(t, err) + defer cleanUpJfrogHome() + + // Import config token + assert.NoError(t, Import(acmeConfigToken)) + serverDetails, err := GetConfig("acme", true) + assert.NoError(t, err) + + // Verify that the configuration was imported correctly + assert.Equal(t, "https://acme.jfrog.io/", serverDetails.GetUrl()) + assert.Equal(t, "https://acme.jfrog.io/artifactory/", serverDetails.GetArtifactoryUrl()) + assert.Equal(t, "https://acme.jfrog.io/distribution/", serverDetails.GetDistributionUrl()) + assert.Equal(t, "https://acme.jfrog.io/xray/", serverDetails.GetXrayUrl()) + assert.Equal(t, "https://acme.jfrog.io/mc/", serverDetails.GetMissionControlUrl()) + assert.Equal(t, "https://acme.jfrog.io/pipelines/", serverDetails.GetPipelinesUrl()) + assert.Equal(t, "admin", serverDetails.GetUser()) + assert.Equal(t, "password", serverDetails.GetPassword()) +} + func testExportImport(t *testing.T, inputDetails *config.ServerDetails) { configToken, err := config.Export(inputDetails) assert.NoError(t, err) From dac0f92a2aae4e82703548ccd025d81873c64117 Mon Sep 17 00:00:00 2001 From: Robi Nino Date: Wed, 24 Apr 2024 16:50:31 +0300 Subject: [PATCH 18/36] Support providing chunk size in multi part upload (#1169) --- artifactory/commands/generic/upload.go | 1 + artifactory/commands/transferfiles/utils.go | 2 +- artifactory/utils/storageinfo.go | 22 --------------------- artifactory/utils/storageinfo_test.go | 18 ----------------- artifactory/utils/upload.go | 1 + go.mod | 2 +- go.sum | 4 ++-- utils/progressbar/progressbarmng.go | 21 ++++++++++---------- 8 files changed, 16 insertions(+), 55 deletions(-) diff --git a/artifactory/commands/generic/upload.go b/artifactory/commands/generic/upload.go index e346a9d53..082595956 100644 --- a/artifactory/commands/generic/upload.go +++ b/artifactory/commands/generic/upload.go @@ -201,6 +201,7 @@ func getUploadParams(f *spec.File, configuration *utils.UploadConfiguration, bui uploadParams.MinChecksumDeploy = configuration.MinChecksumDeploySize uploadParams.MinSplitSize = configuration.MinSplitSizeMB * rtServicesUtils.SizeMiB uploadParams.SplitCount = configuration.SplitCount + uploadParams.ChunkSize = configuration.ChunkSizeMB * rtServicesUtils.SizeMiB uploadParams.AddVcsProps = addVcsProps uploadParams.BuildProps = buildProps uploadParams.Archive = f.Archive diff --git a/artifactory/commands/transferfiles/utils.go b/artifactory/commands/transferfiles/utils.go index 622f768e4..4db4c0587 100644 --- a/artifactory/commands/transferfiles/utils.go +++ b/artifactory/commands/transferfiles/utils.go @@ -115,7 +115,7 @@ func (clcm *ChunksLifeCycleManager) StoreStaleChunks(stateManager *state.Transfe for _, file := range uploadedChunkData.ChunkFiles { var sizeStr string if file.Size > 0 { - sizeStr = " (" + utils.ConvertIntToStorageSizeString(file.Size) + ")" + sizeStr = " (" + serviceUtils.ConvertIntToStorageSizeString(file.Size) + ")" } staleNodeChunk.Files = append(staleNodeChunk.Files, path.Join(file.Repo, file.Path, file.Name)+sizeStr) } diff --git a/artifactory/utils/storageinfo.go b/artifactory/utils/storageinfo.go index 29f3a7031..87321f8b2 100644 --- a/artifactory/utils/storageinfo.go +++ b/artifactory/utils/storageinfo.go @@ -3,7 +3,6 @@ package utils import ( "context" "errors" - "fmt" "strconv" "strings" "time" @@ -179,24 +178,3 @@ func convertStorageSizeStringToBytes(sizeStr string) (int64, error) { } return int64(sizeInBytes), nil } - -func ConvertIntToStorageSizeString(num int64) string { - if num > utils.SizeTiB { - newNum := float64(num) / float64(utils.SizeTiB) - stringNum := fmt.Sprintf("%.1f", newNum) - return stringNum + "TB" - } - if num > utils.SizeGiB { - newNum := float64(num) / float64(utils.SizeGiB) - stringNum := fmt.Sprintf("%.1f", newNum) - return stringNum + "GB" - } - if num > utils.SizeMiB { - newNum := float64(num) / float64(utils.SizeMiB) - stringNum := fmt.Sprintf("%.1f", newNum) - return stringNum + "MB" - } - newNum := float64(num) / float64(utils.SizeKib) - stringNum := fmt.Sprintf("%.1f", newNum) - return stringNum + "KB" -} diff --git a/artifactory/utils/storageinfo_test.go b/artifactory/utils/storageinfo_test.go index e559f4209..cc36dbcf0 100644 --- a/artifactory/utils/storageinfo_test.go +++ b/artifactory/utils/storageinfo_test.go @@ -159,21 +159,3 @@ func getStorageInfoResponse(t *testing.T, w http.ResponseWriter, r *http.Request assert.NoError(t, err) } } - -func TestConvertIntToStorageSizeString(t *testing.T) { - tests := []struct { - num int - output string - }{ - {12546, "12.3KB"}, - {148576, "145.1KB"}, - {2587985, "2.5MB"}, - {12896547, "12.3MB"}, - {12896547785, "12.0GB"}, - {5248965785422365, "4773.9TB"}, - } - - for _, test := range tests { - assert.Equal(t, test.output, ConvertIntToStorageSizeString(int64(test.num))) - } -} diff --git a/artifactory/utils/upload.go b/artifactory/utils/upload.go index ed00f67f9..4f95a0dc2 100644 --- a/artifactory/utils/upload.go +++ b/artifactory/utils/upload.go @@ -22,6 +22,7 @@ type UploadConfiguration struct { ExplodeArchive bool SplitCount int MinSplitSizeMB int64 + ChunkSizeMB int64 } func GetMinChecksumDeploySize() (int64, error) { diff --git a/go.mod b/go.mod index b87ef9676..fa1d1e0b1 100644 --- a/go.mod +++ b/go.mod @@ -96,7 +96,7 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240408071430-62ee0279ac58 +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240424133643-5bf715f66eac // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev diff --git a/go.sum b/go.sum index 534583ca6..6175ab28e 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.9.26 h1:1Ddc6+Ecvhc+UMnKhRVG1jGM6fYNwA49207azT github.com/jfrog/build-info-go v1.9.26/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= github.com/jfrog/gofrog v1.7.1 h1:ME1Meg4hukAT/7X6HUQCVSe4DNjMZACCP8aCY37EW/w= github.com/jfrog/gofrog v1.7.1/go.mod h1:X7bjfWoQDN0Z4FQGbE91j3gbPP7Urwzm4Z8tkvrlbRI= -github.com/jfrog/jfrog-client-go v1.40.1 h1:ISSSV7/IUS8R+QCPfH2lVKLburbv2Xn07fvNyDc17rI= -github.com/jfrog/jfrog-client-go v1.40.1/go.mod h1:FprEW0Sqhj6ZSFTFk9NCni+ovFAYMA3zCBmNX4hGXgQ= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240424133643-5bf715f66eac h1:e/QfkFN/Qtkn1rBg/p7JCOMFLmE2EgfPBx57m2yIF1k= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240424133643-5bf715f66eac/go.mod h1:FprEW0Sqhj6ZSFTFk9NCni+ovFAYMA3zCBmNX4hGXgQ= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= diff --git a/utils/progressbar/progressbarmng.go b/utils/progressbar/progressbarmng.go index 4b6e7b523..d58b0d1ab 100644 --- a/utils/progressbar/progressbarmng.go +++ b/utils/progressbar/progressbarmng.go @@ -1,24 +1,23 @@ package progressbar import ( - golangLog "log" - "math" - "os" - "strconv" - "strings" - "sync" - "time" - "github.com/gookit/color" - artifactoryutils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" corelog "github.com/jfrog/jfrog-cli-core/v2/utils/log" + servicesUtils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" "github.com/jfrog/jfrog-client-go/utils" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/log" "github.com/vbauerster/mpb/v7" "github.com/vbauerster/mpb/v7/decor" "golang.org/x/term" + golangLog "log" + "math" + "os" + "strconv" + "strings" + "sync" + "time" ) const ( @@ -98,8 +97,8 @@ func (bm *ProgressBarMng) newDoubleValueProgressBar(getVal func() (firstNumerato if err != nil { log.Error(err) } - s1 := artifactoryutils.ConvertIntToStorageSizeString(*firstNumerator) - s2 := artifactoryutils.ConvertIntToStorageSizeString(*firstDenominator) + s1 := servicesUtils.ConvertIntToStorageSizeString(*firstNumerator) + s2 := servicesUtils.ConvertIntToStorageSizeString(*firstDenominator) return color.Green.Render(s1 + "/" + s2) }), decor.Name(" "+secondValueLine+": "), decor.Any(func(statistics decor.Statistics) string { _, _, secondNumerator, secondDenominator, err := getVal() From bd3f34188b088626ddf8a8dde8da642e7ceaf4ba Mon Sep 17 00:00:00 2001 From: Guy Sheffer <144031599+guyshe-jfrog@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:38:44 +0300 Subject: [PATCH 19/36] Run contextual analysis and secret detection in Docker scans https://github.com/jfrog/jfrog-cli-security/pull/10 https://github.com/jfrog/jfrog-cli-security/issues/4 (#1146) --- utils/coreutils/techutils.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/utils/coreutils/techutils.go b/utils/coreutils/techutils.go index fa12fc2b2..cc7e6ae8b 100644 --- a/utils/coreutils/techutils.go +++ b/utils/coreutils/techutils.go @@ -33,6 +33,7 @@ const ( Nuget Technology = "nuget" Dotnet Technology = "dotnet" Docker Technology = "docker" + Oci Technology = "oci" ) const Pypi = "pypi" @@ -145,6 +146,12 @@ var technologiesData = map[Technology]TechData{ packageDescriptors: []string{".sln", ".csproj"}, formal: ".NET", }, + Docker: { + applicabilityScannable: true, + }, + Oci: { + applicabilityScannable: true, + }, } func (tech Technology) ToFormal() string { From 1d8d9c096cc45f6ffb0a6227a9aabc027875adb5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 25 Apr 2024 12:21:19 +0300 Subject: [PATCH 20/36] Upgrade golang.org/x/net to 0.23.0 (#1175) Co-authored-by: JFrog-Frogbot Co-authored-by: Yahav Itzhak --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index fa1d1e0b1..e8b300baa 100644 --- a/go.mod +++ b/go.mod @@ -89,7 +89,7 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/sys v0.18.0 // indirect golang.org/x/tools v0.19.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 6175ab28e..c8e2d14a5 100644 --- a/go.sum +++ b/go.sum @@ -229,6 +229,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From cca50551d839dccdee32a32ced04565d90154367 Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Wed, 1 May 2024 10:51:58 +0300 Subject: [PATCH 21/36] Update web login prompts (#1178) --- artifactory/utils/weblogin.go | 4 ++-- common/commands/config.go | 8 ++++++-- general/login/login.go | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/artifactory/utils/weblogin.go b/artifactory/utils/weblogin.go index 6f630c7d9..bb628e1de 100644 --- a/artifactory/utils/weblogin.go +++ b/artifactory/utils/weblogin.go @@ -28,8 +28,8 @@ func DoWebLogin(serverDetails *config.ServerDetails) (token auth.CommonTokenPara } if err = accessManager.SendLoginAuthenticationRequest(uuidStr); err != nil { err = errors.Join(err, - errorutils.CheckErrorf("The 'Web Login' functionality is only supported for Artifactory version 7.64.0 and above. "+ - "Make sure the details you entered are correct and that Artifactory meets the version requirement.")) + errorutils.CheckErrorf("Oops! it looks like the web login option is unavailable right now. This could be because your JFrog Artifactory version is less than 7.64.0. \n"+ + "Don't worry! You can use the \"jf c add\" command to authenticate with the JFrog Platform using other methods")) return } log.Info("After logging in via your web browser, please enter the code if prompted: " + uuidStr[len(uuidStr)-4:]) diff --git a/common/commands/config.go b/common/commands/config.go index c51ded1fb..1569da0ac 100644 --- a/common/commands/config.go +++ b/common/commands/config.go @@ -322,7 +322,11 @@ func (cc *ConfigCommand) getConfigurationFromUser() (err error) { } if cc.details.Url == "" { - ioutils.ScanFromConsole("JFrog Platform URL", &cc.details.Url, cc.defaultDetails.Url) + urlPrompt := "JFrog Platform URL" + if cc.useWebLogin { + urlPrompt = "Enter your " + urlPrompt + } + ioutils.ScanFromConsole(urlPrompt, &cc.details.Url, cc.defaultDetails.Url) } if fileutils.IsSshUrl(cc.details.Url) || fileutils.IsSshUrl(cc.details.ArtifactoryUrl) { @@ -462,7 +466,7 @@ func (cc *ConfigCommand) readClientCertInfoFromConsole() { } func (cc *ConfigCommand) checkClientCertForReverseProxy() { - if cc.details.ClientCertPath != "" && cc.details.ClientCertKeyPath != "" { + if cc.details.ClientCertPath != "" && cc.details.ClientCertKeyPath != "" || cc.useWebLogin { return } if coreutils.AskYesNo("Is the Artifactory reverse proxy configured to accept a client certificate?", false) { diff --git a/general/login/login.go b/general/login/login.go index 2845bb814..589651987 100644 --- a/general/login/login.go +++ b/general/login/login.go @@ -42,7 +42,7 @@ func newConfLogin() error { func promptPlatformUrl() (string, error) { var platformUrl string - ioutils.ScanFromConsole("JFrog Platform URL", &platformUrl, "") + ioutils.ScanFromConsole("Enter your JFrog Platform URL", &platformUrl, "") if platformUrl == "" { return "", errorutils.CheckErrorf("providing JFrog Platform URL is mandatory") } From 934fb7391b5c4e192153aab9a7b3989fa4f0677e Mon Sep 17 00:00:00 2001 From: Robi Nino Date: Thu, 2 May 2024 18:16:49 +0300 Subject: [PATCH 22/36] Support npm dist tags (#1168) --- artifactory/commands/npm/npmcommand.go | 39 ++++++---- artifactory/commands/npm/publish.go | 52 ++++++++++--- utils/coreutils/cmdutils.go | 101 +++++++------------------ 3 files changed, 91 insertions(+), 101 deletions(-) diff --git a/artifactory/commands/npm/npmcommand.go b/artifactory/commands/npm/npmcommand.go index f3d477c97..f0f63d1db 100644 --- a/artifactory/commands/npm/npmcommand.go +++ b/artifactory/commands/npm/npmcommand.go @@ -5,23 +5,23 @@ import ( "errors" "fmt" "github.com/jfrog/build-info-go/build" - biutils "github.com/jfrog/build-info-go/build/utils" + biUtils "github.com/jfrog/build-info-go/build/utils" "github.com/jfrog/gofrog/version" - "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/npm" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-client-go/auth" - "os" - "path/filepath" - "strconv" - "strings" - commandUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/utils" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils/npm" buildUtils "github.com/jfrog/jfrog-cli-core/v2/common/build" "github.com/jfrog/jfrog-cli-core/v2/common/project" "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" + "github.com/jfrog/jfrog-client-go/auth" "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/spf13/viper" + "os" + "path/filepath" + "strconv" + "strings" ) const ( @@ -102,8 +102,8 @@ func (nc *NpmCommand) Init() error { if err != nil { return err } - // Extract resolution params. - resolverParams, err := project.GetRepoConfigByPrefix(nc.configFilePath, project.ProjectConfigResolverPrefix, vConfig) + + repoConfig, err := nc.getRepoConfig(vConfig) if err != nil { return err } @@ -111,10 +111,21 @@ func (nc *NpmCommand) Init() error { if err != nil { return err } - nc.SetRepoConfig(resolverParams).SetArgs(filteredNpmArgs).SetBuildConfiguration(buildConfiguration) + nc.SetRepoConfig(repoConfig).SetArgs(filteredNpmArgs).SetBuildConfiguration(buildConfiguration) return nil } +// Get the repository configuration from the config file. +// Use the resolver prefix for all commands except for 'dist-tag' which use the deployer prefix. +func (nc *NpmCommand) getRepoConfig(vConfig *viper.Viper) (repoConfig *project.RepositoryConfig, err error) { + prefix := project.ProjectConfigResolverPrefix + // Aliases accepted by npm. + if nc.cmdName == "dist-tag" || nc.cmdName == "dist-tags" { + prefix = project.ProjectConfigDeployerPrefix + } + return project.GetRepoConfigByPrefix(nc.configFilePath, prefix, vConfig) +} + func (nc *NpmCommand) SetBuildConfiguration(buildConfiguration *buildUtils.BuildConfiguration) *NpmCommand { nc.buildConfiguration = buildConfiguration return nc @@ -131,7 +142,7 @@ func (nc *NpmCommand) RestoreNpmrcFunc() func() error { func (nc *NpmCommand) PreparePrerequisites(repo string) error { log.Debug("Preparing prerequisites...") var err error - nc.npmVersion, nc.executablePath, err = biutils.GetNpmVersionAndExecPath(log.Logger) + nc.npmVersion, nc.executablePath, err = biUtils.GetNpmVersionAndExecPath(log.Logger) if err != nil { return err } @@ -229,7 +240,7 @@ func (nc *NpmCommand) setNpmConfigAuthEnv(value string) error { scopedRegistryEnv := fmt.Sprintf(npmConfigAuthEnv, registryWithoutProtocolName) return os.Setenv(scopedRegistryEnv, value) } - // Set "npm_config__auth" environment variable to allow authentication with Artifactory when running postinstall scripts on subdirectories. + // Set "npm_config__auth" environment variable to allow authentication with Artifactory when running post-install scripts on subdirectories. // For Legacy NPM version < 9.3.1 return os.Setenv(npmLegacyConfigAuthEnv, value) } diff --git a/artifactory/commands/npm/publish.go b/artifactory/commands/npm/publish.go index ea5e7e01f..ae91b9df6 100644 --- a/artifactory/commands/npm/publish.go +++ b/artifactory/commands/npm/publish.go @@ -5,14 +5,9 @@ import ( "compress/gzip" "errors" "fmt" - ioutils "github.com/jfrog/gofrog/io" - "io" - "os" - "path/filepath" - "strings" - "github.com/jfrog/build-info-go/build" biutils "github.com/jfrog/build-info-go/build/utils" + ioutils "github.com/jfrog/gofrog/io" "github.com/jfrog/gofrog/version" commandsutils "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/utils" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" @@ -29,10 +24,17 @@ import ( "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io/content" "github.com/jfrog/jfrog-client-go/utils/log" + "io" + "os" + "path/filepath" + "strings" ) -// The --pack-destination argument of npm pack was introduced in npm version 7.18.0. -const packDestinationNpmMinVersion = "7.18.0" +const ( + DistTagPropKey = "npm.disttag" + // The --pack-destination argument of npm pack was introduced in npm version 7.18.0. + packDestinationNpmMinVersion = "7.18.0" +) type NpmPublishCommandArgs struct { CommonArgs @@ -46,6 +48,7 @@ type NpmPublishCommandArgs struct { artifactsDetailsReader *content.ContentReader xrayScan bool scanOutputFormat format.OutputFormat + distTag string } type NpmPublishCommand struct { @@ -98,6 +101,11 @@ func (npc *NpmPublishCommand) SetScanOutputFormat(format format.OutputFormat) *N return npc } +func (npc *NpmPublishCommand) SetDistTag(tag string) *NpmPublishCommand { + npc.distTag = tag + return npc +} + func (npc *NpmPublishCommand) Result() *commandsutils.Result { return npc.result } @@ -116,6 +124,10 @@ func (npc *NpmPublishCommand) Init() error { if err != nil { return err } + filteredNpmArgs, tag, err := coreutils.ExtractTagFromArgs(filteredNpmArgs) + if err != nil { + return err + } if npc.configFilePath != "" { // Read config file. log.Debug("Preparing to read the config file", npc.configFilePath) @@ -133,7 +145,7 @@ func (npc *NpmPublishCommand) Init() error { } npc.SetBuildConfiguration(buildConfiguration).SetRepo(deployerParams.TargetRepo()).SetNpmArgs(filteredNpmArgs).SetServerDetails(rtDetails) } - npc.SetDetailedSummary(detailedSummary).SetXrayScan(xrayScan).SetScanOutputFormat(scanOutputFormat) + npc.SetDetailedSummary(detailedSummary).SetXrayScan(xrayScan).SetScanOutputFormat(scanOutputFormat).SetDistTag(tag) return nil } @@ -145,7 +157,7 @@ func (npc *NpmPublishCommand) Run() (err error) { } var npmBuild *build.Build - var buildName, buildNumber, project string + var buildName, buildNumber, projectKey string if npc.collectBuildInfo { buildName, err = npc.buildConfiguration.GetBuildName() if err != nil { @@ -155,9 +167,9 @@ func (npc *NpmPublishCommand) Run() (err error) { if err != nil { return err } - project = npc.buildConfiguration.GetProject() + projectKey = npc.buildConfiguration.GetProject() buildInfoService := buildUtils.CreateBuildInfoService() - npmBuild, err = buildInfoService.GetOrCreateBuildWithProject(buildName, buildNumber, project) + npmBuild, err = buildInfoService.GetOrCreateBuildWithProject(buildName, buildNumber, projectKey) if err != nil { return errorutils.CheckError(err) } @@ -309,6 +321,9 @@ func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerD } up := services.NewUploadParams() up.CommonParams = &specutils.CommonParams{Pattern: packedFilePath, Target: target} + if err = npc.addDistTagIfSet(up.CommonParams); err != nil { + return err + } var totalFailed int if npc.collectBuildInfo || npc.detailedSummary { if npc.collectBuildInfo { @@ -365,6 +380,19 @@ func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerD return nil } +// Set the dist tag property to the package if required by the --tag option. +func (npc *NpmPublishCommand) addDistTagIfSet(params *specutils.CommonParams) error { + if npc.distTag == "" { + return nil + } + props, err := specutils.ParseProperties(DistTagPropKey + "=" + npc.distTag) + if err != nil { + return err + } + params.TargetProps = props + return nil +} + func (npc *NpmPublishCommand) setDetailedSummary(summary *specutils.OperationSummary) (err error) { npc.result.SetFailCount(npc.result.FailCount() + summary.TotalFailed) npc.result.SetSuccessCount(npc.result.SuccessCount() + summary.TotalSucceeded) diff --git a/utils/coreutils/cmdutils.go b/utils/coreutils/cmdutils.go index cd0305584..4ef9fe34f 100644 --- a/utils/coreutils/cmdutils.go +++ b/utils/coreutils/cmdutils.go @@ -138,15 +138,7 @@ func FindFlagFirstMatch(flags, args []string) (flagIndex, flagValueIndex int, fl } func ExtractServerIdFromCommand(args []string) (cleanArgs []string, serverId string, err error) { - cleanArgs = append([]string(nil), args...) - - // Get --server-id flag value from the command, and remove it. - flagIndex, valueIndex, serverId, err := FindFlag("--server-id", cleanArgs) - if err != nil { - return nil, "", err - } - RemoveFlagFromCommand(&cleanArgs, flagIndex, valueIndex) - return + return extractStringOptionFromArgs(args, "server-id") } func ExtractThreadsFromArgs(args []string, defaultValue int) (cleanArgs []string, threads int, err error) { @@ -169,111 +161,70 @@ func ExtractThreadsFromArgs(args []string, defaultValue int) (cleanArgs []string } func ExtractInsecureTlsFromArgs(args []string) (cleanArgs []string, insecureTls bool, err error) { - cleanArgs = append([]string(nil), args...) - - flagIndex, insecureTls, err := FindBooleanFlag("--insecure-tls", args) - if err != nil { - return - } - RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) - return + return extractBoolOptionFromArgs(args, "insecure-tls") } // Used by docker func ExtractSkipLoginFromArgs(args []string) (cleanArgs []string, skipLogin bool, err error) { - cleanArgs = append([]string(nil), args...) - - flagIndex, skipLogin, err := FindBooleanFlag("--skip-login", cleanArgs) - if err != nil { - return - } - // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. - RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) - return + return extractBoolOptionFromArgs(args, "skip-login") } // Used by docker func ExtractFailFromArgs(args []string) (cleanArgs []string, fail bool, err error) { - cleanArgs = append([]string(nil), args...) - - flagIndex, fail, err := FindBooleanFlag("--fail", cleanArgs) - if err != nil { - return - } - // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. - RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) - return + return extractBoolOptionFromArgs(args, "fail") } // Used by docker scan (Xray) func ExtractLicensesFromArgs(args []string) (cleanArgs []string, licenses bool, err error) { - cleanArgs = append([]string(nil), args...) - - flagIndex, licenses, err := FindBooleanFlag("--licenses", cleanArgs) - if err != nil { - return - } - // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. - RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) - return + return extractBoolOptionFromArgs(args, "licenses") } // Used by docker scan (Xray) func ExtractRepoPathFromArgs(args []string) (cleanArgs []string, repoPath string, err error) { - cleanArgs = append([]string(nil), args...) - - flagIndex, valIndex, repoPath, err := FindFlag("--repo-path", cleanArgs) - if err != nil { - return - } - RemoveFlagFromCommand(&cleanArgs, flagIndex, valIndex) - return + return extractStringOptionFromArgs(args, "repo-path") } // Used by docker scan (Xray) func ExtractWatchesFromArgs(args []string) (cleanArgs []string, watches string, err error) { - cleanArgs = append([]string(nil), args...) - - flagIndex, valIndex, watches, err := FindFlag("--watches", cleanArgs) - if err != nil { - return - } - RemoveFlagFromCommand(&cleanArgs, flagIndex, valIndex) - return + return extractStringOptionFromArgs(args, "watches") } func ExtractDetailedSummaryFromArgs(args []string) (cleanArgs []string, detailedSummary bool, err error) { - cleanArgs = append([]string(nil), args...) - - flagIndex, detailedSummary, err := FindBooleanFlag("--detailed-summary", cleanArgs) - if err != nil { - return - } - // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. - RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) - return + return extractBoolOptionFromArgs(args, "detailed-summary") } func ExtractXrayScanFromArgs(args []string) (cleanArgs []string, xrayScan bool, err error) { + return extractBoolOptionFromArgs(args, "scan") +} + +func ExtractXrayOutputFormatFromArgs(args []string) (cleanArgs []string, format string, err error) { + return extractStringOptionFromArgs(args, "format") +} + +func ExtractTagFromArgs(args []string) (cleanArgs []string, tag string, err error) { + return extractStringOptionFromArgs(args, "tag") +} + +func extractStringOptionFromArgs(args []string, optionName string) (cleanArgs []string, value string, err error) { cleanArgs = append([]string(nil), args...) - flagIndex, xrayScan, err := FindBooleanFlag("--scan", cleanArgs) + flagIndex, valIndex, value, err := FindFlag("--"+optionName, cleanArgs) if err != nil { return } - // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. - RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) + RemoveFlagFromCommand(&cleanArgs, flagIndex, valIndex) return } -func ExtractXrayOutputFormatFromArgs(args []string) (cleanArgs []string, format string, err error) { +func extractBoolOptionFromArgs(args []string, optionName string) (cleanArgs []string, value bool, err error) { cleanArgs = append([]string(nil), args...) - flagIndex, valIndex, format, err := FindFlag("--format", cleanArgs) + flagIndex, value, err := FindBooleanFlag("--"+optionName, cleanArgs) if err != nil { return } - RemoveFlagFromCommand(&cleanArgs, flagIndex, valIndex) + // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. + RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) return } From aa682847c3039980c5182fc2d61d577adf2ee418 Mon Sep 17 00:00:00 2001 From: Robi Nino Date: Sun, 5 May 2024 16:50:56 +0300 Subject: [PATCH 23/36] Fix Refreshing Platform Access Tokens (#1177) --- utils/config/tokenrefresh.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/utils/config/tokenrefresh.go b/utils/config/tokenrefresh.go index e8f4da70b..e4362e2ea 100644 --- a/utils/config/tokenrefresh.go +++ b/utils/config/tokenrefresh.go @@ -143,7 +143,7 @@ func refreshArtifactoryTokenAndWriteToConfig(serverConfiguration *ServerDetails, log.Debug("Token refreshed successfully.") } - err = writeNewArtifactoryTokens(serverConfiguration, tokenRefreshServerId, newToken.AccessToken, newToken.RefreshToken) + err = writeNewTokens(serverConfiguration, tokenRefreshServerId, newToken.AccessToken, newToken.RefreshToken, ArtifactoryToken) return newToken.AccessToken, err } @@ -153,13 +153,19 @@ func refreshAccessTokenAndWriteToConfig(serverConfiguration *ServerDetails, curr if err != nil { return "", errorutils.CheckErrorf("Refresh access token failed: " + err.Error()) } - err = writeNewArtifactoryTokens(serverConfiguration, tokenRefreshServerId, newToken.AccessToken, newToken.RefreshToken) + err = writeNewTokens(serverConfiguration, tokenRefreshServerId, newToken.AccessToken, newToken.RefreshToken, AccessToken) return newToken.AccessToken, err } -func writeNewArtifactoryTokens(serverConfiguration *ServerDetails, serverId, accessToken, refreshToken string) error { +func writeNewTokens(serverConfiguration *ServerDetails, serverId, accessToken, refreshToken string, tokenType TokenType) error { serverConfiguration.SetAccessToken(accessToken) - serverConfiguration.SetArtifactoryRefreshToken(refreshToken) + + switch tokenType { + case ArtifactoryToken: + serverConfiguration.SetArtifactoryRefreshToken(refreshToken) + case AccessToken: + serverConfiguration.SetRefreshToken(refreshToken) + } // Get configurations list configurations, err := GetAllServersConfigs() @@ -221,7 +227,7 @@ func CreateInitialRefreshableTokensIfNeeded(serverDetails *ServerDetails) (err e } // Remove initializing value. serverDetails.ArtifactoryTokenRefreshInterval = 0 - err = writeNewArtifactoryTokens(serverDetails, serverDetails.ServerId, newToken.AccessToken, newToken.RefreshToken) + err = writeNewTokens(serverDetails, serverDetails.ServerId, newToken.AccessToken, newToken.RefreshToken, ArtifactoryToken) return } From ffadfdefbd51928840f0427b5c9cad5aa033ef3d Mon Sep 17 00:00:00 2001 From: Michael Sverdlov Date: Sun, 5 May 2024 18:31:37 +0300 Subject: [PATCH 24/36] Update dependencies (#1182) Signed-off-by: Michael Sverdlov --- go.mod | 24 ++++++++++++------------ go.sum | 51 +++++++++++++++++++++++++-------------------------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index e8b300baa..3f9ac8171 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 - github.com/jedib0t/go-pretty/v6 v6.5.6 + github.com/jedib0t/go-pretty/v6 v6.5.8 github.com/jfrog/build-info-go v1.9.26 github.com/jfrog/gofrog v1.7.1 github.com/jfrog/jfrog-client-go v1.40.1 @@ -20,13 +20,13 @@ require ( github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 - github.com/urfave/cli v1.22.14 + github.com/urfave/cli v1.22.15 github.com/vbauerster/mpb/v7 v7.5.3 - golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 - golang.org/x/mod v0.16.0 - golang.org/x/sync v0.6.0 - golang.org/x/term v0.18.0 - golang.org/x/text v0.14.0 + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f + golang.org/x/mod v0.17.0 + golang.org/x/sync v0.7.0 + golang.org/x/term v0.20.0 + golang.org/x/text v0.15.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -40,7 +40,7 @@ require ( github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dsnet/compress v0.0.1 // indirect @@ -88,10 +88,10 @@ require ( github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.23.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/tools v0.19.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/tools v0.20.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index c8e2d14a5..3d72fda0d 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38 github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -79,8 +79,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jedib0t/go-pretty/v6 v6.5.6 h1:nKXVLqPfAwY7sWcYXdNZZZ2fjqDpAtj9UeWupgfUxSg= -github.com/jedib0t/go-pretty/v6 v6.5.6/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= +github.com/jedib0t/go-pretty/v6 v6.5.8 h1:8BCzJdSvUbaDuRba4YVh+SKMGcAAKdkcF3SVFbrHAtQ= +github.com/jedib0t/go-pretty/v6 v6.5.8/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= github.com/jfrog/build-info-go v1.9.26 h1:1Ddc6+Ecvhc+UMnKhRVG1jGM6fYNwA49207azTBGBc8= @@ -175,6 +175,7 @@ github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMV github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -189,8 +190,8 @@ github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uR github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= -github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= +github.com/urfave/cli v1.22.15 h1:nuqt+pdC/KqswQKhETJjo7pvn/k4xMUxgW6liI7XpnM= +github.com/urfave/cli v1.22.15/go.mod h1:wSan1hmo5zeyLGBjRJbzRTNk8gwoYa2B9n4q9dmRIc0= github.com/vbauerster/mpb/v7 v7.5.3 h1:BkGfmb6nMrrBQDFECR/Q7RkKCw7ylMetCb4079CGs4w= github.com/vbauerster/mpb/v7 v7.5.3/go.mod h1:i+h4QY6lmLvBNK2ah1fSreiw3ajskRlBp9AhY/PnuOE= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -212,14 +213,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= -golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= +golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -227,16 +228,14 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -263,15 +262,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -279,14 +278,14 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 7173b506c6b7551fbcc1f70d7335b94ce7c1c38c Mon Sep 17 00:00:00 2001 From: Assaf Attias <49212512+attiasas@users.noreply.github.com> Date: Sun, 5 May 2024 19:04:19 +0300 Subject: [PATCH 25/36] Add description as usage for subcommands (#1181) --- plugins/components/conversionlayer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/components/conversionlayer.go b/plugins/components/conversionlayer.go index dae7da806..fa159cbd8 100644 --- a/plugins/components/conversionlayer.go +++ b/plugins/components/conversionlayer.go @@ -84,6 +84,7 @@ func convertCommand(cmd Command, namespaces ...string) (cli.Command, error) { Flags: convertedFlags, Aliases: cmd.Aliases, Category: cmd.Category, + Usage: cmd.Description, Description: cmd.Description, HelpName: common.CreateUsage(getCmdUsageString(cmd, namespaces...), cmd.Description, cmdUsages), UsageText: createArgumentsSummary(cmd), From 5433b78a03680404d958afd67532e885395ca40b Mon Sep 17 00:00:00 2001 From: Michael Sverdlov Date: Thu, 9 May 2024 15:15:12 +0300 Subject: [PATCH 26/36] Validate defered callback funcs are not nil before running (#1184) --- artifactory/commands/dotnet/dotnetcommand.go | 4 +- .../commands/transferfiles/transfer.go | 4 +- common/commands/config.go | 3 ++ go.mod | 18 ++++----- go.sum | 39 +++++++++---------- 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/artifactory/commands/dotnet/dotnetcommand.go b/artifactory/commands/dotnet/dotnetcommand.go index 54ddebe93..435e2f45b 100644 --- a/artifactory/commands/dotnet/dotnetcommand.go +++ b/artifactory/commands/dotnet/dotnetcommand.go @@ -118,7 +118,9 @@ func (dc *DotnetCommand) Exec() (err error) { return err } defer func() { - err = errors.Join(err, callbackFunc()) + if callbackFunc != nil { + err = errors.Join(err, callbackFunc()) + } }() if err = buildInfoModule.CalcDependencies(); err != nil { if dc.isDotnetTestCommand() { diff --git a/artifactory/commands/transferfiles/transfer.go b/artifactory/commands/transferfiles/transfer.go index 92840e75f..ba872ffd2 100644 --- a/artifactory/commands/transferfiles/transfer.go +++ b/artifactory/commands/transferfiles/transfer.go @@ -390,7 +390,9 @@ func (tdc *TransferFilesCommand) transferSingleRepo(sourceRepoKey string, target return } defer func() { - err = errors.Join(err, restoreFunc()) + if restoreFunc != nil { + err = errors.Join(err, restoreFunc()) + } }() if err = tdc.initCurThreads(buildInfoRepo); err != nil { diff --git a/common/commands/config.go b/common/commands/config.go index 1569da0ac..0870614a1 100644 --- a/common/commands/config.go +++ b/common/commands/config.go @@ -547,6 +547,9 @@ func ShowConfig(serverName string) error { } func lockConfig() (unlockFunc func() error, err error) { + unlockFunc = func() error { + return nil + } mutex.Lock() defer func() { mutex.Unlock() diff --git a/go.mod b/go.mod index 3f9ac8171..0e5ea7fe3 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 - github.com/jedib0t/go-pretty/v6 v6.5.8 + github.com/jedib0t/go-pretty/v6 v6.5.9 github.com/jfrog/build-info-go v1.9.26 github.com/jfrog/gofrog v1.7.1 github.com/jfrog/jfrog-client-go v1.40.1 @@ -22,7 +22,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/urfave/cli v1.22.15 github.com/vbauerster/mpb/v7 v7.5.3 - golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 golang.org/x/mod v0.17.0 golang.org/x/sync v0.7.0 golang.org/x/term v0.20.0 @@ -48,7 +48,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect - github.com/go-git/go-git/v5 v5.11.0 // indirect + github.com/go-git/go-git/v5 v5.12.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.4 // indirect @@ -75,8 +75,8 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sergi/go-diff v1.1.0 // indirect - github.com/skeema/knownhosts v1.2.1 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect @@ -88,15 +88,15 @@ require ( github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/net v0.24.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/net v0.25.0 // indirect golang.org/x/sys v0.20.0 // indirect - golang.org/x/tools v0.20.0 // indirect + golang.org/x/tools v0.21.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240424133643-5bf715f66eac +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240509093347-62649bc00e43 // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev diff --git a/go.sum b/go.sum index 3d72fda0d..63e466907 100644 --- a/go.sum +++ b/go.sum @@ -54,14 +54,14 @@ github.com/forPelevin/gomoji v1.2.0/go.mod h1:8+Z3KNGkdslmeGZBC3tCrwMrcPy5GRzAD+ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a h1:RYfmiM0zluBJOiPDJseKLEN4BapJ42uSi9SZBQ2YyiA= github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -79,16 +79,16 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jedib0t/go-pretty/v6 v6.5.8 h1:8BCzJdSvUbaDuRba4YVh+SKMGcAAKdkcF3SVFbrHAtQ= -github.com/jedib0t/go-pretty/v6 v6.5.8/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= +github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU= +github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= github.com/jfrog/build-info-go v1.9.26 h1:1Ddc6+Ecvhc+UMnKhRVG1jGM6fYNwA49207azTBGBc8= github.com/jfrog/build-info-go v1.9.26/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= github.com/jfrog/gofrog v1.7.1 h1:ME1Meg4hukAT/7X6HUQCVSe4DNjMZACCP8aCY37EW/w= github.com/jfrog/gofrog v1.7.1/go.mod h1:X7bjfWoQDN0Z4FQGbE91j3gbPP7Urwzm4Z8tkvrlbRI= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240424133643-5bf715f66eac h1:e/QfkFN/Qtkn1rBg/p7JCOMFLmE2EgfPBx57m2yIF1k= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240424133643-5bf715f66eac/go.mod h1:FprEW0Sqhj6ZSFTFk9NCni+ovFAYMA3zCBmNX4hGXgQ= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240509093347-62649bc00e43 h1:3kmtQcvoMvKgDY/aBC4lNHTkY6hxH/1e/np+TnGb+3U= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240509093347-62649bc00e43/go.mod h1:m3hIn12eFWk5nJH1swPRtFrjXbiiCscOpX+v/vCdmNI= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -157,11 +157,11 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -213,10 +213,10 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= @@ -228,8 +228,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -284,8 +284,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -295,7 +295,6 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 9914ee15059f91c01d41e28c59c4f20b36d0fc40 Mon Sep 17 00:00:00 2001 From: Yahav Itschak Date: Thu, 9 May 2024 16:02:48 +0300 Subject: [PATCH 27/36] Update version to 2.52.0 (#1185) --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 0e5ea7fe3..03a6bb477 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/jedib0t/go-pretty/v6 v6.5.9 github.com/jfrog/build-info-go v1.9.26 github.com/jfrog/gofrog v1.7.1 - github.com/jfrog/jfrog-client-go v1.40.1 + github.com/jfrog/jfrog-client-go v1.40.2 github.com/magiconair/properties v1.8.7 github.com/manifoldco/promptui v0.9.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -96,7 +96,7 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240509093347-62649bc00e43 +// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240509093347-62649bc00e43 // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev diff --git a/go.sum b/go.sum index 63e466907..eab5c98cd 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.9.26 h1:1Ddc6+Ecvhc+UMnKhRVG1jGM6fYNwA49207azT github.com/jfrog/build-info-go v1.9.26/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= github.com/jfrog/gofrog v1.7.1 h1:ME1Meg4hukAT/7X6HUQCVSe4DNjMZACCP8aCY37EW/w= github.com/jfrog/gofrog v1.7.1/go.mod h1:X7bjfWoQDN0Z4FQGbE91j3gbPP7Urwzm4Z8tkvrlbRI= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240509093347-62649bc00e43 h1:3kmtQcvoMvKgDY/aBC4lNHTkY6hxH/1e/np+TnGb+3U= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240509093347-62649bc00e43/go.mod h1:m3hIn12eFWk5nJH1swPRtFrjXbiiCscOpX+v/vCdmNI= +github.com/jfrog/jfrog-client-go v1.40.2 h1:zdCWPPT11r0bMGnAXGhZPb3RrIINhiTFCceQABhguZ4= +github.com/jfrog/jfrog-client-go v1.40.2/go.mod h1:m3hIn12eFWk5nJH1swPRtFrjXbiiCscOpX+v/vCdmNI= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= From a62576f8d17fe6a780af6afc08833af625ef294d Mon Sep 17 00:00:00 2001 From: Asaf Ambar Date: Wed, 22 May 2024 10:32:34 +0300 Subject: [PATCH 28/36] Move depTree logic out from 'xrayutils.go' file (#1180) --- utils/xray/xrayutils.go | 62 ----------------------------------------- 1 file changed, 62 deletions(-) diff --git a/utils/xray/xrayutils.go b/utils/xray/xrayutils.go index fc2f0f928..dfc40a5d8 100644 --- a/utils/xray/xrayutils.go +++ b/utils/xray/xrayutils.go @@ -4,7 +4,6 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" clientconfig "github.com/jfrog/jfrog-client-go/config" "github.com/jfrog/jfrog-client-go/xray" - xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils" ) func CreateXrayServiceManager(serviceDetails *config.ServerDetails) (*xray.XrayServicesManager, error) { @@ -20,64 +19,3 @@ func CreateXrayServiceManager(serviceDetails *config.ServerDetails) (*xray.XrayS } return xray.New(serviceConfig) } - -func CreateXrayServiceManagerAndGetVersion(serviceDetails *config.ServerDetails) (*xray.XrayServicesManager, string, error) { - xrayManager, err := CreateXrayServiceManager(serviceDetails) - if err != nil { - return nil, "", err - } - xrayVersion, err := xrayManager.GetVersion() - if err != nil { - return nil, "", err - } - return xrayManager, xrayVersion, nil -} - -const maxUniqueAppearances = 10 - -type DepTreeNode struct { - Types *[]string `json:"types"` - Children []string `json:"children"` -} - -func toNodeTypesMap(depMap map[string]DepTreeNode) map[string][]string { - mapOfTypes := map[string][]string{} - for nodId, value := range depMap { - mapOfTypes[nodId] = nil - if value.Types != nil { - mapOfTypes[nodId] = *value.Types - } - } - return mapOfTypes -} - -func BuildXrayDependencyTree(treeHelper map[string]DepTreeNode, nodeId string) (*xrayUtils.GraphNode, map[string][]string) { - rootNode := &xrayUtils.GraphNode{ - Id: nodeId, - Nodes: []*xrayUtils.GraphNode{}, - } - dependencyAppearances := map[string]int8{} - populateXrayDependencyTree(rootNode, treeHelper, dependencyAppearances) - return rootNode, toNodeTypesMap(treeHelper) -} - -func populateXrayDependencyTree(currNode *xrayUtils.GraphNode, treeHelper map[string]DepTreeNode, dependencyAppearances map[string]int8) { - dependencyAppearances[currNode.Id]++ - if _, ok := treeHelper[currNode.Id]; !ok { - treeHelper[currNode.Id] = DepTreeNode{} - } - // Recursively create & append all node's dependencies. - for _, childDepId := range treeHelper[currNode.Id].Children { - childNode := &xrayUtils.GraphNode{ - Id: childDepId, - Nodes: []*xrayUtils.GraphNode{}, - Parent: currNode, - Types: treeHelper[childDepId].Types, - } - if dependencyAppearances[childDepId] >= maxUniqueAppearances || childNode.NodeHasLoop() { - continue - } - currNode.Nodes = append(currNode.Nodes, childNode) - populateXrayDependencyTree(childNode, treeHelper, dependencyAppearances) - } -} From 44e989e0a4423b6bc1d882742536ad1024830077 Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Wed, 22 May 2024 13:14:56 +0300 Subject: [PATCH 29/36] Command Summaries (#1179) --- artifactory/commands/buildinfo/publish.go | 18 ++ .../commandssummaries/buildinfosummary.go | 57 ++++++ .../buildinfosummary_test.go | 32 ++++ .../commandssummaries/uploadsummary.go | 66 +++++++ .../commandssummaries/uploadsummary_test.go | 24 +++ artifactory/commands/generic/upload.go | 44 +++++ artifactory/utils/filetree.go | 54 ++++-- artifactory/utils/filetree_test.go | 67 ++++++- commandsummary/commandsummary.go | 172 ++++++++++++++++++ commandsummary/commandsummary_test.go | 141 ++++++++++++++ utils/coreutils/coreconsts.go | 1 + 11 files changed, 656 insertions(+), 20 deletions(-) create mode 100644 artifactory/commands/commandssummaries/buildinfosummary.go create mode 100644 artifactory/commands/commandssummaries/buildinfosummary_test.go create mode 100644 artifactory/commands/commandssummaries/uploadsummary.go create mode 100644 artifactory/commands/commandssummaries/uploadsummary_test.go create mode 100644 commandsummary/commandsummary.go create mode 100644 commandsummary/commandsummary_test.go diff --git a/artifactory/commands/buildinfo/publish.go b/artifactory/commands/buildinfo/publish.go index 360c95e74..4bb4cf127 100644 --- a/artifactory/commands/buildinfo/publish.go +++ b/artifactory/commands/buildinfo/publish.go @@ -3,6 +3,8 @@ package buildinfo import ( "errors" "fmt" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/commandssummaries" + "github.com/jfrog/jfrog-cli-core/v2/commandsummary" "net/url" "strconv" "strings" @@ -139,6 +141,10 @@ func (bpc *BuildPublishCommand) Run() error { return err } + if err = recordCommandSummary(buildInfo, buildLink); err != nil { + return err + } + logMsg := "Build info successfully deployed." if bpc.IsDetailedSummary() { log.Info(logMsg + " Browse it in Artifactory under " + buildLink) @@ -229,3 +235,15 @@ func (bpc *BuildPublishCommand) getNextBuildNumber(buildName string, servicesMan latestBuildNumber++ return strconv.Itoa(latestBuildNumber), nil } + +func recordCommandSummary(buildInfo *buildinfo.BuildInfo, buildLink string) (err error) { + if !commandsummary.ShouldRecordSummary() { + return + } + buildInfo.BuildUrl = buildLink + buildInfoSummary, err := commandsummary.New(commandssummaries.NewBuildInfo(), "build-info") + if err != nil { + return + } + return buildInfoSummary.Record(buildInfo) +} diff --git a/artifactory/commands/commandssummaries/buildinfosummary.go b/artifactory/commands/commandssummaries/buildinfosummary.go new file mode 100644 index 000000000..5624a432a --- /dev/null +++ b/artifactory/commands/commandssummaries/buildinfosummary.go @@ -0,0 +1,57 @@ +package commandssummaries + +import ( + "fmt" + buildInfo "github.com/jfrog/build-info-go/entities" + "github.com/jfrog/jfrog-cli-core/v2/commandsummary" + "strings" + "time" +) + +const timeFormat = "Jan 2, 2006 , 15:04:05" + +type BuildInfoSummary struct{} + +func NewBuildInfo() *BuildInfoSummary { + return &BuildInfoSummary{} +} + +func (bis *BuildInfoSummary) GenerateMarkdownFromFiles(dataFilePaths []string) (finalMarkdown string, err error) { + // Aggregate all the build info files into a slice + var builds []*buildInfo.BuildInfo + for _, path := range dataFilePaths { + var publishBuildInfo buildInfo.BuildInfo + if err = commandsummary.UnmarshalFromFilePath(path, &publishBuildInfo); err != nil { + return + } + builds = append(builds, &publishBuildInfo) + } + + if len(builds) > 0 { + finalMarkdown = bis.buildInfoTable(builds) + } + return +} + +func (bis *BuildInfoSummary) buildInfoTable(builds []*buildInfo.BuildInfo) string { + // Generate a string that represents a Markdown table + var tableBuilder strings.Builder + tableBuilder.WriteString("\n\n| Build Info | Time Stamp | \n") + tableBuilder.WriteString("|---------|------------| \n") + for _, build := range builds { + buildTime := parseBuildTime(build.Started) + tableBuilder.WriteString(fmt.Sprintf("| [%s](%s) | %s |\n", build.Name+" "+build.Number, build.BuildUrl, buildTime)) + } + tableBuilder.WriteString("\n\n") + return tableBuilder.String() +} + +func parseBuildTime(timestamp string) string { + // Parse the timestamp string into a time.Time object + buildInfoTime, err := time.Parse(buildInfo.TimeFormat, timestamp) + if err != nil { + return "N/A" + } + // Format the time in a more human-readable format and save it in a variable + return buildInfoTime.Format(timeFormat) +} diff --git a/artifactory/commands/commandssummaries/buildinfosummary_test.go b/artifactory/commands/commandssummaries/buildinfosummary_test.go new file mode 100644 index 000000000..9b8ac30aa --- /dev/null +++ b/artifactory/commands/commandssummaries/buildinfosummary_test.go @@ -0,0 +1,32 @@ +package commandssummaries + +import ( + buildinfo "github.com/jfrog/build-info-go/entities" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBuildInfoTable(t *testing.T) { + gh := &BuildInfoSummary{} + var builds = []*buildinfo.BuildInfo{ + { + Name: "buildName", + Number: "123", + Started: "2024-05-05T12:47:20.803+0300", + BuildUrl: "http://myJFrogPlatform/builds/buildName/123", + }, + } + expected := "\n\n| Build Info | Time Stamp | \n|---------|------------| \n| [buildName 123](http://myJFrogPlatform/builds/buildName/123) | May 5, 2024 , 12:47:20 |\n\n\n" + assert.Equal(t, expected, gh.buildInfoTable(builds)) +} + +func TestParseBuildTime(t *testing.T) { + // Test format + actual := parseBuildTime("2006-01-02T15:04:05.000-0700") + expected := "Jan 2, 2006 , 15:04:05" + assert.Equal(t, expected, actual) + // Test invalid format + expected = "N/A" + actual = parseBuildTime("") + assert.Equal(t, expected, actual) +} diff --git a/artifactory/commands/commandssummaries/uploadsummary.go b/artifactory/commands/commandssummaries/uploadsummary.go new file mode 100644 index 000000000..b28d1ccbe --- /dev/null +++ b/artifactory/commands/commandssummaries/uploadsummary.go @@ -0,0 +1,66 @@ +package commandssummaries + +import ( + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + "github.com/jfrog/jfrog-cli-core/v2/commandsummary" +) + +type UploadSummary struct { + uploadTree *utils.FileTree + uploadedArtifacts ResultsWrapper + PlatformUrl string + JfrogProjectKey string +} + +type UploadResult struct { + SourcePath string `json:"sourcePath"` + TargetPath string `json:"targetPath"` + RtUrl string `json:"rtUrl"` +} + +type ResultsWrapper struct { + Results []UploadResult `json:"results"` +} + +func NewUploadSummary(platformUrl, projectKey string) *UploadSummary { + return &UploadSummary{ + PlatformUrl: platformUrl, + JfrogProjectKey: projectKey, + } +} + +func (us *UploadSummary) GenerateMarkdownFromFiles(dataFilePaths []string) (markdown string, err error) { + if err = us.loadResults(dataFilePaths); err != nil { + return + } + // Wrap the markdown in a
 tags to preserve spaces
+	markdown = fmt.Sprintf("\n
\n\n\n" + us.generateFileTreeMarkdown() + "
\n\n") + return +} + +// Loads all the recorded results from the given file paths. +func (us *UploadSummary) loadResults(filePaths []string) error { + us.uploadedArtifacts = ResultsWrapper{} + for _, path := range filePaths { + var uploadResult ResultsWrapper + if err := commandsummary.UnmarshalFromFilePath(path, &uploadResult); err != nil { + return err + } + us.uploadedArtifacts.Results = append(us.uploadedArtifacts.Results, uploadResult.Results...) + } + return nil +} + +func (us *UploadSummary) generateFileTreeMarkdown() string { + us.uploadTree = utils.NewFileTree() + for _, uploadResult := range us.uploadedArtifacts.Results { + us.uploadTree.AddFile(uploadResult.TargetPath, us.buildUiUrl(uploadResult.TargetPath)) + } + return us.uploadTree.String() +} + +func (us *UploadSummary) buildUiUrl(targetPath string) string { + template := "%sui/repos/tree/General/%s/?projectKey=%s" + return fmt.Sprintf(template, us.PlatformUrl, targetPath, us.JfrogProjectKey) +} diff --git a/artifactory/commands/commandssummaries/uploadsummary_test.go b/artifactory/commands/commandssummaries/uploadsummary_test.go new file mode 100644 index 000000000..0a51eef6b --- /dev/null +++ b/artifactory/commands/commandssummaries/uploadsummary_test.go @@ -0,0 +1,24 @@ +package commandssummaries + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBuildUiUrl(t *testing.T) { + gh := &UploadSummary{ + PlatformUrl: "https://myplatform.com/", + JfrogProjectKey: "myProject", + } + expected := "https://myplatform.com/ui/repos/tree/General/myPath/?projectKey=myProject" + actual := gh.buildUiUrl("myPath") + assert.Equal(t, expected, actual) + + gh = &UploadSummary{ + PlatformUrl: "https://myplatform.com/", + JfrogProjectKey: "", + } + expected = "https://myplatform.com/ui/repos/tree/General/myPath/?projectKey=" + actual = gh.buildUiUrl("myPath") + assert.Equal(t, expected, actual) +} diff --git a/artifactory/commands/generic/upload.go b/artifactory/commands/generic/upload.go index 082595956..e331e0db7 100644 --- a/artifactory/commands/generic/upload.go +++ b/artifactory/commands/generic/upload.go @@ -2,6 +2,9 @@ package generic import ( "errors" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/commands/commandssummaries" + "github.com/jfrog/jfrog-cli-core/v2/commandsummary" + "os" buildInfo "github.com/jfrog/build-info-go/entities" @@ -153,6 +156,10 @@ func (uc *UploadCommand) upload() (err error) { } successCount = summary.TotalSucceeded failCount = summary.TotalFailed + + if err = recordCommandSummary(summary, serverDetails.Url, uc.buildConfiguration); err != nil { + return + } } } else { successCount, failCount, err = servicesManager.UploadFiles(uploadParamsArray...) @@ -188,6 +195,7 @@ func (uc *UploadCommand) upload() (err error) { } return build.PopulateBuildArtifactsAsPartials(buildArtifacts, uc.buildConfiguration, buildInfo.Generic) } + return } @@ -271,3 +279,39 @@ func createDeleteSpecForSync(deletePattern string, syncDeletesProp string) *spec Recursive(true). BuildSpec() } + +func recordCommandSummary(summary *rtServicesUtils.OperationSummary, platformUrl string, buildConfig *build.BuildConfiguration) (err error) { + if !commandsummary.ShouldRecordSummary() { + return + } + // Get project key if exists + var projectKey string + if buildConfig != nil { + projectKey = buildConfig.GetProject() + } + uploadSummary, err := commandsummary.New(commandssummaries.NewUploadSummary(platformUrl, projectKey), "upload") + if err != nil { + return + } + data, err := readDetailsFromReader(summary.TransferDetailsReader) + if err != nil { + return + } + return uploadSummary.Record(data) +} + +// Reads transfer details from the reader and return the content as bytes for further processing +func readDetailsFromReader(reader *content.ContentReader) (readContent []byte, err error) { + if reader == nil { + return + } + for _, file := range reader.GetFilesPaths() { + // Read source file + sourceBytes, err := os.ReadFile(file) + if err != nil { + return nil, errorutils.CheckError(err) + } + readContent = append(readContent, sourceBytes...) + } + return +} diff --git a/artifactory/utils/filetree.go b/artifactory/utils/filetree.go index 26fd553b2..88131f6c1 100644 --- a/artifactory/utils/filetree.go +++ b/artifactory/utils/filetree.go @@ -1,6 +1,10 @@ package utils import ( + "fmt" + "github.com/jfrog/jfrog-client-go/utils/log" + "golang.org/x/exp/maps" + "sort" "strings" ) @@ -17,16 +21,20 @@ func NewFileTree() *FileTree { return &FileTree{repos: map[string]*dirNode{}, size: 0} } -func (ft *FileTree) AddFile(path string) { +// Path - file structure path to artifact +// UploadedFileUrl - URL to the uploaded file in Artifactory, +// if UploadedFileUrl not provided, the file name will be displayed without a link. +func (ft *FileTree) AddFile(path, uploadedFileUrl string) { if ft.size >= maxFilesInTree { + log.Info("Exceeded maximum number of files in tree") ft.exceedsMax = true return } splitPath := strings.Split(path, "/") if _, exist := ft.repos[splitPath[0]]; !exist { - ft.repos[splitPath[0]] = &dirNode{name: splitPath[0], prefix: "📦 ", subDirNodes: map[string]*dirNode{}, fileNames: map[string]bool{}} + ft.repos[splitPath[0]] = &dirNode{name: splitPath[0], prefix: "📦 ", subDirNodes: map[string]*dirNode{}, fileNames: map[string]string{}} } - if ft.repos[splitPath[0]].addArtifact(splitPath[1:]) { + if ft.repos[splitPath[0]].addArtifact(splitPath[1:], uploadedFileUrl) { ft.size++ } } @@ -38,7 +46,7 @@ func (ft *FileTree) String() string { } treeStr := "" for _, repo := range ft.repos { - treeStr += strings.Join(repo.strings(), "\n") + "\n" + treeStr += strings.Join(repo.strings(), "\n") + "\n\n" } return treeStr } @@ -47,26 +55,26 @@ type dirNode struct { name string prefix string subDirNodes map[string]*dirNode - fileNames map[string]bool + fileNames map[string]string } -func (dn *dirNode) addArtifact(pathInDir []string) bool { +func (dn *dirNode) addArtifact(pathInDir []string, artifactUrl string) bool { if len(pathInDir) == 1 { if _, exist := dn.fileNames[pathInDir[0]]; exist { return false } - dn.fileNames[pathInDir[0]] = true + dn.fileNames[pathInDir[0]] = artifactUrl } else { if _, exist := dn.subDirNodes[pathInDir[0]]; !exist { - dn.subDirNodes[pathInDir[0]] = &dirNode{name: pathInDir[0], prefix: "📁 ", subDirNodes: map[string]*dirNode{}, fileNames: map[string]bool{}} + dn.subDirNodes[pathInDir[0]] = &dirNode{name: pathInDir[0], prefix: "📁 ", subDirNodes: map[string]*dirNode{}, fileNames: map[string]string{}} } - return dn.subDirNodes[pathInDir[0]].addArtifact(pathInDir[1:]) + return dn.subDirNodes[pathInDir[0]].addArtifact(pathInDir[1:], artifactUrl) } return true } func (dn *dirNode) strings() []string { - strs := []string{dn.prefix + dn.name} + repoAsString := []string{dn.prefix + dn.name} subDirIndex := 0 for subDirName := range dn.subDirNodes { var subDirPrefix string @@ -79,22 +87,34 @@ func (dn *dirNode) strings() []string { innerStrPrefix = "│ " } subDirStrs := dn.subDirNodes[subDirName].strings() - strs = append(strs, subDirPrefix+subDirStrs[0]) + repoAsString = append(repoAsString, subDirPrefix+subDirStrs[0]) for subDirStrIndex := 1; subDirStrIndex < len(subDirStrs); subDirStrIndex++ { - strs = append(strs, innerStrPrefix+subDirStrs[subDirStrIndex]) + repoAsString = append(repoAsString, innerStrPrefix+subDirStrs[subDirStrIndex]) } subDirIndex++ } fileIndex := 0 - for fileName := range dn.fileNames { + + // Sort File names inside each sub dir + sortedFileNames := maps.Keys(dn.fileNames) + sort.Slice(sortedFileNames, func(i, j int) bool { return sortedFileNames[i] < sortedFileNames[j] }) + + for _, fileNameKey := range sortedFileNames { var filePrefix string if fileIndex == len(dn.fileNames)-1 { - filePrefix = "└── 📄 " + filePrefix = "└── " } else { - filePrefix = "├── 📄 " + filePrefix = "├── " fileIndex++ } - strs = append(strs, filePrefix+fileName) + + var fullFileName string + if dn.fileNames[fileNameKey] != "" { + fullFileName = fmt.Sprintf("%s%s", filePrefix, dn.fileNames[fileNameKey], fileNameKey) + } else { + fullFileName = filePrefix + "📄 " + fileNameKey + } + repoAsString = append(repoAsString, fullFileName) } - return strs + return repoAsString } diff --git a/artifactory/utils/filetree_test.go b/artifactory/utils/filetree_test.go index 9fc825718..c00e22e9d 100644 --- a/artifactory/utils/filetree_test.go +++ b/artifactory/utils/filetree_test.go @@ -15,12 +15,73 @@ func TestFileTree(t *testing.T) { fileTree := NewFileTree() // Add a new file and check String() - fileTree.AddFile("repoName/path/to/first/artifact") - result, excpected := fileTree.String(), "📦 repoName\n└── 📁 path\n └── 📁 to\n └── 📁 first\n └── 📄 artifact\n" + fileTree.AddFile("repoName/path/to/first/artifact", "") + result, excpected := fileTree.String(), "📦 repoName\n└── 📁 path\n └── 📁 to\n └── 📁 first\n └── 📄 artifact\n\n" assert.Equal(t, excpected, result) // If maxFileInTree has exceeded, Check String() returns an empty string - fileTree.AddFile("repoName/path/to/second/artifact") + fileTree.AddFile("repoName/path/to/second/artifact", "") result, excpected = fileTree.String(), "" assert.Equal(t, excpected, result) } + +func TestFileTreeSort(t *testing.T) { + testCases := []struct { + name string + files []string + expected string + }{ + { + name: "Test Case 1", + files: []string{ + "repoName/path/to/fileC", + "repoName/path/to/fileA", + "repoName/path/to/fileB", + }, + expected: "📦 repoName\n└── 📁 path\n └── 📁 to\n ├── 📄 fileA\n ├── 📄 fileB\n └── 📄 fileC\n\n", + }, + { + name: "Test Case 2", + files: []string{ + "repoName/path/to/file3", + "repoName/path/to/file1", + "repoName/path/to/file2", + }, + expected: "📦 repoName\n└── 📁 path\n └── 📁 to\n ├── 📄 file1\n ├── 📄 file2\n └── 📄 file3\n\n", + }, + { + name: "Test Case 3", + files: []string{ + "repoName/path/to/fileZ", + "repoName/path/to/fileX", + "repoName/path/to/fileY", + }, + expected: "📦 repoName\n└── 📁 path\n └── 📁 to\n ├── 📄 fileX\n ├── 📄 fileY\n └── 📄 fileZ\n\n", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + fileTree := NewFileTree() + + // Add files + for _, file := range tc.files { + fileTree.AddFile(file, "") + } + + // Get the string representation of the FileTree + result := fileTree.String() + + assert.Equal(t, tc.expected, result) + }) + } +} + +func TestFileTreeWithUrls(t *testing.T) { + fileTree := NewFileTree() + // Add a new file and check String() + fileTree.AddFile("repoName/path/to/first/artifact", "http://myJFrogPlatform/customLink/first/artifact") + result, expected := fileTree.String(), "📦 repoName\n└── 📁 path\n └── 📁 to\n └── 📁 first\n └── artifact\n\n" + assert.Equal(t, expected, result) + +} diff --git a/commandsummary/commandsummary.go b/commandsummary/commandsummary.go new file mode 100644 index 000000000..0337a2952 --- /dev/null +++ b/commandsummary/commandsummary.go @@ -0,0 +1,172 @@ +package commandsummary + +import ( + "encoding/json" + "errors" + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "os" + "path" + "path/filepath" + "strings" +) + +type CommandSummaryInterface interface { + GenerateMarkdownFromFiles(dataFilePaths []string) (finalMarkdown string, err error) +} + +const ( + // The name of the directory where all the commands summaries will be stored. + // Inside this directory, each command will have its own directory. + OutputDirName = "jfrog-command-summary" +) + +type CommandSummary struct { + CommandSummaryInterface + summaryOutputPath string + commandsName string +} + +// Create a new instance of CommandSummary. +// Notice to check if the command should record the summary before calling this function. +// You can do this by calling the helper function ShouldRecordSummary. +func New(userImplementation CommandSummaryInterface, commandsName string) (cs *CommandSummary, err error) { + outputDir := os.Getenv(coreutils.OutputDirPathEnv) + if outputDir == "" { + return nil, fmt.Errorf("output dir path is not defined,please set the JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR environment variable") + } + cs = &CommandSummary{ + CommandSummaryInterface: userImplementation, + commandsName: commandsName, + summaryOutputPath: outputDir, + } + err = cs.prepareFileSystem() + return +} + +// This function stores the current data on the file system. +// It then invokes the GenerateMarkdownFromFiles function on all existing data files. +// Finally, it saves the generated markdown file to the file system. +func (cs *CommandSummary) Record(data any) (err error) { + if err = cs.saveDataToFileSystem(data); err != nil { + return + } + dataFilesPaths, err := cs.getAllDataFilesPaths() + if err != nil { + return fmt.Errorf("failed to load data files from directory %s, with error: %w", cs.commandsName, err) + } + markdown, err := cs.GenerateMarkdownFromFiles(dataFilesPaths) + if err != nil { + return fmt.Errorf("failed to render markdown: %w", err) + } + if err = cs.saveMarkdownToFileSystem(markdown); err != nil { + return fmt.Errorf("failed to save markdown to file system: %w", err) + } + return +} + +func (cs *CommandSummary) getAllDataFilesPaths() ([]string, error) { + entries, err := os.ReadDir(cs.summaryOutputPath) + if err != nil { + return nil, errorutils.CheckError(err) + } + // Exclude markdown files + var filePaths []string + for _, entry := range entries { + if !entry.IsDir() && !strings.HasSuffix(entry.Name(), ".md") { + filePaths = append(filePaths, path.Join(cs.summaryOutputPath, entry.Name())) + } + } + return filePaths, nil +} + +func (cs *CommandSummary) saveMarkdownToFileSystem(markdown string) (err error) { + file, err := os.OpenFile(path.Join(cs.summaryOutputPath, "markdown.md"), os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return errorutils.CheckError(err) + } + defer func() { + err = errors.Join(err, errorutils.CheckError(file.Close())) + }() + if _, err = file.WriteString(markdown); err != nil { + return errorutils.CheckError(err) + } + return +} + +// Saves the given data into a file in the specified directory. +func (cs *CommandSummary) saveDataToFileSystem(data interface{}) error { + // Create a random file name in the data file path. + fd, err := os.CreateTemp(cs.summaryOutputPath, "data-*") + if err != nil { + return errorutils.CheckError(err) + } + defer func() { + err = errors.Join(err, fd.Close()) + }() + + // Convert the data into bytes. + bytes, err := convertDataToBytes(data) + if err != nil { + return errorutils.CheckError(err) + } + + // Write the bytes to the file. + if _, err = fd.Write(bytes); err != nil { + return errorutils.CheckError(err) + } + + return nil +} + +// This function creates the base dir for the command summary inside +// the path the user has provided, userPath/OutputDirName. +// Then it creates a specific directory for the command, path/OutputDirName/commandsName. +// And set the summaryOutputPath to the specific command directory. +func (cs *CommandSummary) prepareFileSystem() (err error) { + summaryBaseDirPath := filepath.Join(cs.summaryOutputPath, OutputDirName) + if err = createDirIfNotExists(summaryBaseDirPath); err != nil { + return err + } + specificCommandOutputPath := filepath.Join(summaryBaseDirPath, cs.commandsName) + if err = createDirIfNotExists(specificCommandOutputPath); err != nil { + return err + } + // Sets the specific command output path + cs.summaryOutputPath = specificCommandOutputPath + return +} + +// If the output dir path is not defined, the command summary should not be recorded. +func ShouldRecordSummary() bool { + return os.Getenv(coreutils.OutputDirPathEnv) != "" +} + +// Helper function to unmarshal data from a file path into the target object. +func UnmarshalFromFilePath(dataFile string, target any) (err error) { + data, err := fileutils.ReadFile(dataFile) + if err != nil { + return + } + if err = json.Unmarshal(data, target); err != nil { + return errorutils.CheckError(err) + } + return +} + +// Converts the given data into a byte array. +// Handle specific conversion cases +func convertDataToBytes(data interface{}) ([]byte, error) { + switch v := data.(type) { + case []byte: + return v, nil + default: + return json.Marshal(data) + } +} + +func createDirIfNotExists(homeDir string) error { + return errorutils.CheckError(os.MkdirAll(homeDir, 0755)) +} diff --git a/commandsummary/commandsummary_test.go b/commandsummary/commandsummary_test.go new file mode 100644 index 000000000..a284ba34b --- /dev/null +++ b/commandsummary/commandsummary_test.go @@ -0,0 +1,141 @@ +package commandsummary + +import ( + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/stretchr/testify/assert" + "os" + "path" + "testing" +) + +type mockCommandSummary struct { + CommandSummaryInterface +} + +type BasicStruct struct { + Field1 string + Field2 int +} + +func (tcs *mockCommandSummary) GenerateMarkdownFromFiles(dataFilePaths []string) (finalMarkdown string, err error) { + return "mockMarkdown", nil +} + +// Without output dir env, New should return an error. +func TestInitWithoutOutputDir(t *testing.T) { + _, err := New(&mockCommandSummary{}, "testsCommands") + assert.Error(t, err) +} + +func TestCommandSummaryFileSystemBehaviour(t *testing.T) { + cs, cleanUp := prepareTest(t) + defer func() { + cleanUp() + }() + + // Call GenerateMarkdownFromFiles + err := cs.Record("someData") + assert.NoError(t, err) + + // Verify that the directory contains two files + files, err := os.ReadDir(cs.summaryOutputPath) + assert.NoError(t, err, "Failed to read directory 'test'") + assert.Equal(t, 2, len(files), "Directory 'test' does not contain exactly two files") + + // Verify a markdown file has been created + assert.FileExists(t, path.Join(cs.summaryOutputPath, "markdown.md")) +} + +func TestDataPersistence(t *testing.T) { + // Define test cases + testCases := []struct { + name string + dirName string + originalData interface{} + }{ + { + name: "Test with a simple object", + dirName: "testDir", + originalData: map[string]string{"key": "value"}, + }, + { + name: "Test with a string", + dirName: "testDir3", + originalData: "test string", + }, + { + name: "Test with a basic struct", + dirName: "testDir4", + originalData: BasicStruct{ + Field1: "test string", + Field2: 123, + }, + }, + } + + // Run test cases + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Prepare a new CommandSummary for each test case + cs, cleanUp := prepareTest(t) + defer func() { + cleanUp() + }() + // Save data to file + err := cs.saveDataToFileSystem(tc.originalData) + assert.NoError(t, err) + + // Verify file has been saved + dataFiles, err := cs.getAllDataFilesPaths() + assert.NoError(t, err) + assert.NotEqual(t, 0, len(dataFiles)) + + // Verify that data has not been corrupted + loadedData, err := unmarshalData(tc.originalData, dataFiles[0]) + assert.NoError(t, err) + assert.EqualValues(t, tc.originalData, loadedData) + }) + } +} + +func unmarshalData(expected interface{}, filePath string) (interface{}, error) { + switch expected := expected.(type) { + case map[string]string: + var loadedData map[string]string + err := UnmarshalFromFilePath(filePath, &loadedData) + return loadedData, err + case []byte: + var loadedData []byte + err := UnmarshalFromFilePath(filePath, &loadedData) + return loadedData, err + case string: + var loadedData string + err := UnmarshalFromFilePath(filePath, &loadedData) + return loadedData, err + case BasicStruct: + var loadedData BasicStruct + err := UnmarshalFromFilePath(filePath, &loadedData) + return loadedData, err + default: + return nil, fmt.Errorf("unsupported data type: %T", expected) + } +} + +func prepareTest(t *testing.T) (cs *CommandSummary, cleanUp func()) { + // Prepare test env + tempDir, err := fileutils.CreateTempDir() + assert.NoError(t, err) + // Set env + assert.NoError(t, os.Setenv(coreutils.OutputDirPathEnv, tempDir)) + // Create the job summaries home directory + cs, err = New(&mockCommandSummary{}, "testsCommands") + assert.NoError(t, err) + + cleanUp = func() { + assert.NoError(t, os.Unsetenv(coreutils.OutputDirPathEnv)) + assert.NoError(t, fileutils.RemoveTempDir(tempDir)) + } + return +} diff --git a/utils/coreutils/coreconsts.go b/utils/coreutils/coreconsts.go index e9d64a753..6f9ec2dac 100644 --- a/utils/coreutils/coreconsts.go +++ b/utils/coreutils/coreconsts.go @@ -46,6 +46,7 @@ const ( DependenciesDir = "JFROG_CLI_DEPENDENCIES_DIR" TransitiveDownload = "JFROG_CLI_TRANSITIVE_DOWNLOAD_EXPERIMENTAL" FailNoOp = "JFROG_CLI_FAIL_NO_OP" + OutputDirPathEnv = "JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR" CI = "CI" ServerID = "JFROG_CLI_SERVER_ID" ) From 15961aaedca18fed5ed7802a5fab065426d4f287 Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Wed, 22 May 2024 16:16:17 +0300 Subject: [PATCH 30/36] Update dependencies (#1186) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 03a6bb477..c9a5b3c7a 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 github.com/jedib0t/go-pretty/v6 v6.5.9 - github.com/jfrog/build-info-go v1.9.26 + github.com/jfrog/build-info-go v1.9.27 github.com/jfrog/gofrog v1.7.1 github.com/jfrog/jfrog-client-go v1.40.2 github.com/magiconair/properties v1.8.7 diff --git a/go.sum b/go.sum index eab5c98cd..cdf89edac 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,8 @@ github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+ github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= -github.com/jfrog/build-info-go v1.9.26 h1:1Ddc6+Ecvhc+UMnKhRVG1jGM6fYNwA49207azTBGBc8= -github.com/jfrog/build-info-go v1.9.26/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= +github.com/jfrog/build-info-go v1.9.27 h1:7RWJcajqtNNbGHuYkgOLUIG7mmRKF0yxC7mvYAbdVlU= +github.com/jfrog/build-info-go v1.9.27/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= github.com/jfrog/gofrog v1.7.1 h1:ME1Meg4hukAT/7X6HUQCVSe4DNjMZACCP8aCY37EW/w= github.com/jfrog/gofrog v1.7.1/go.mod h1:X7bjfWoQDN0Z4FQGbE91j3gbPP7Urwzm4Z8tkvrlbRI= github.com/jfrog/jfrog-client-go v1.40.2 h1:zdCWPPT11r0bMGnAXGhZPb3RrIINhiTFCceQABhguZ4= From abaa6aeedab055f2f3a760bbbaa35e0e90e02457 Mon Sep 17 00:00:00 2001 From: David Lesner Date: Thu, 30 May 2024 13:31:36 +0300 Subject: [PATCH 31/36] Support evidence service (#1188) --- artifactory/utils/utils.go | 22 ++++++++++++++++++++++ go.mod | 6 +++--- go.sum | 12 ++++++------ utils/config/config.go | 12 ++++++++++++ 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/artifactory/utils/utils.go b/artifactory/utils/utils.go index 1699a4d43..3879559cc 100644 --- a/artifactory/utils/utils.go +++ b/artifactory/utils/utils.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" ioutils "github.com/jfrog/gofrog/io" + "github.com/jfrog/jfrog-client-go/evidence" "io" "net/http" "net/url" @@ -214,6 +215,27 @@ func CreateLifecycleServiceManager(serviceDetails *config.ServerDetails, isDryRu return lifecycle.New(serviceConfig) } +func CreateEvidenceServiceManager(serviceDetails *config.ServerDetails, isDryRun bool) (*evidence.EvidenceServicesManager, error) { + certsPath, err := coreutils.GetJfrogCertsDir() + if err != nil { + return nil, err + } + evdAuth, err := serviceDetails.CreateEvidenceAuthConfig() + if err != nil { + return nil, err + } + serviceConfig, err := clientConfig.NewConfigBuilder(). + SetServiceDetails(evdAuth). + SetCertificatesPath(certsPath). + SetInsecureTls(serviceDetails.InsecureTls). + SetDryRun(isDryRun). + Build() + if err != nil { + return nil, err + } + return evidence.New(serviceConfig) +} + // This error indicates that the build was scanned by Xray, but Xray found issues with the build. // If Xray failed to scan the build, for example due to a networking issue, a regular error should be returned. var errBuildScan = errors.New("issues found during xray build scan") diff --git a/go.mod b/go.mod index c9a5b3c7a..66709f03e 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/gookit/color v1.5.4 github.com/jedib0t/go-pretty/v6 v6.5.9 github.com/jfrog/build-info-go v1.9.27 - github.com/jfrog/gofrog v1.7.1 + github.com/jfrog/gofrog v1.7.2 github.com/jfrog/jfrog-client-go v1.40.2 github.com/magiconair/properties v1.8.7 github.com/manifoldco/promptui v0.9.0 @@ -71,7 +71,7 @@ require ( github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/term v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/rivo/uniseg v0.4.3 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -96,7 +96,7 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240509093347-62649bc00e43 +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev diff --git a/go.sum b/go.sum index cdf89edac..a7e03a5e7 100644 --- a/go.sum +++ b/go.sum @@ -85,10 +85,10 @@ github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= github.com/jfrog/build-info-go v1.9.27 h1:7RWJcajqtNNbGHuYkgOLUIG7mmRKF0yxC7mvYAbdVlU= github.com/jfrog/build-info-go v1.9.27/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= -github.com/jfrog/gofrog v1.7.1 h1:ME1Meg4hukAT/7X6HUQCVSe4DNjMZACCP8aCY37EW/w= -github.com/jfrog/gofrog v1.7.1/go.mod h1:X7bjfWoQDN0Z4FQGbE91j3gbPP7Urwzm4Z8tkvrlbRI= -github.com/jfrog/jfrog-client-go v1.40.2 h1:zdCWPPT11r0bMGnAXGhZPb3RrIINhiTFCceQABhguZ4= -github.com/jfrog/jfrog-client-go v1.40.2/go.mod h1:m3hIn12eFWk5nJH1swPRtFrjXbiiCscOpX+v/vCdmNI= +github.com/jfrog/gofrog v1.7.2 h1:VkAaA/9tmbw27IqgUOmaZWnO6ATUqL3vRzDnsROKATw= +github.com/jfrog/gofrog v1.7.2/go.mod h1:WJFk88SR9Sr9mKl1bQBig7DmSdXiBGKV3WhL9O6jL9w= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 h1:ERLE/L7YPr6aCUTeAnE8SXU5VOZHd5/XK16rM1TEpts= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04/go.mod h1:37RR4pYgXZM4w7tywyfRu8t2wagt0qf5wBtpDILWBsk= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -148,8 +148,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= -github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= diff --git a/utils/config/config.go b/utils/config/config.go index 2a073da63..287085cb2 100644 --- a/utils/config/config.go +++ b/utils/config/config.go @@ -12,6 +12,7 @@ import ( artifactoryAuth "github.com/jfrog/jfrog-client-go/artifactory/auth" "github.com/jfrog/jfrog-client-go/auth" distributionAuth "github.com/jfrog/jfrog-client-go/distribution/auth" + evidenceAuth "github.com/jfrog/jfrog-client-go/evidence/auth" lifecycleAuth "github.com/jfrog/jfrog-client-go/lifecycle/auth" pipelinesAuth "github.com/jfrog/jfrog-client-go/pipelines/auth" "github.com/jfrog/jfrog-client-go/utils" @@ -578,6 +579,7 @@ type ServerDetails struct { PipelinesUrl string `json:"pipelinesUrl,omitempty"` AccessUrl string `json:"accessUrl,omitempty"` LifecycleUrl string `json:"-"` + EvidenceUrl string `json:"-"` User string `json:"user,omitempty"` Password string `json:"password,omitempty"` SshKeyPath string `json:"sshKeyPath,omitempty"` @@ -668,6 +670,10 @@ func (serverDetails *ServerDetails) GetLifecycleUrl() string { return serverDetails.LifecycleUrl } +func (serverDetails *ServerDetails) GetEvidenceUrl() string { + return serverDetails.EvidenceUrl +} + func (serverDetails *ServerDetails) GetUser() string { return serverDetails.User } @@ -741,6 +747,12 @@ func (serverDetails *ServerDetails) CreateLifecycleAuthConfig() (auth.ServiceDet return serverDetails.createAuthConfig(lcAuth) } +func (serverDetails *ServerDetails) CreateEvidenceAuthConfig() (auth.ServiceDetails, error) { + evdAuth := evidenceAuth.NewEvidenceDetails() + evdAuth.SetUrl(serverDetails.EvidenceUrl) + return serverDetails.createAuthConfig(evdAuth) +} + func (serverDetails *ServerDetails) createAuthConfig(details auth.ServiceDetails) (auth.ServiceDetails, error) { details.SetSshUrl(serverDetails.SshUrl) details.SetAccessToken(serverDetails.AccessToken) From 539f1c60160f7d044a8a29f1e2e9c81191048a8a Mon Sep 17 00:00:00 2001 From: Eyal Ben Moshe Date: Mon, 3 Jun 2024 09:24:21 +0300 Subject: [PATCH 32/36] Remove the unused `project-init` and `ci-setup` commands (#1190) --- general/cisetup/cisetup.go | 68 --- general/cisetup/githubactionsfilegenerator.go | 69 --- general/cisetup/jenkinsfiledslgenerator.go | 214 --------- general/cisetup/jenkinsfilegenerator.go | 105 ---- general/cisetup/pipelinesconfig.go | 189 -------- general/cisetup/pipelinesyaml.go | 452 ------------------ general/cisetup/utils.go | 147 ------ general/cisetup/utils_test.go | 40 -- general/project/projectinit.go | 257 ---------- general/project/repoutils.go | 186 ------- 10 files changed, 1727 deletions(-) delete mode 100644 general/cisetup/cisetup.go delete mode 100644 general/cisetup/githubactionsfilegenerator.go delete mode 100644 general/cisetup/jenkinsfiledslgenerator.go delete mode 100644 general/cisetup/jenkinsfilegenerator.go delete mode 100644 general/cisetup/pipelinesconfig.go delete mode 100644 general/cisetup/pipelinesyaml.go delete mode 100644 general/cisetup/utils.go delete mode 100644 general/cisetup/utils_test.go delete mode 100644 general/project/projectinit.go delete mode 100644 general/project/repoutils.go diff --git a/general/cisetup/cisetup.go b/general/cisetup/cisetup.go deleted file mode 100644 index adc8f7479..000000000 --- a/general/cisetup/cisetup.go +++ /dev/null @@ -1,68 +0,0 @@ -package cisetup - -import ( - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" -) - -const ConfigServerId = "jfrog-instance" - -type CiSetupData struct { - RepositoryName string - ProjectDomain string - VcsBaseUrl string - LocalDirPath string - GitBranch string - BuildName string - CiType CiType - // A collection of the technologies that were detected in the project. - DetectedTechnologies map[coreutils.Technology]bool - // The chosen build technology stored with all the necessary information. - BuiltTechnology *TechnologyInfo - VcsCredentials VcsServerDetails - GitProvider GitProvider -} - -type TechnologyInfo struct { - Type coreutils.Technology - VirtualRepo string - LocalSnapshotsRepo string - LocalReleasesRepo string - BuildCmd string -} - -func (sd *CiSetupData) GetRepoFullName() string { - return sd.ProjectDomain + "/" + sd.RepositoryName -} - -// Trim technology name from command prefix. (example: mvn clean install >> clean install) -func (sd *CiSetupData) GetBuildCmdForNativeStep() string { - // Remove exec name. - return strings.TrimPrefix(strings.TrimSpace(sd.BuiltTechnology.BuildCmd), sd.BuiltTechnology.Type.GetExecCommandName()+" ") -} - -type VcsServerDetails struct { - Url string `json:"url,omitempty"` - User string `json:"user,omitempty"` - Password string `json:"-"` - AccessToken string `json:"-"` -} - -type GitProvider string - -const ( - Github = "GitHub" - GithubEnterprise = "GitHub Enterprise" - Bitbucket = "Bitbucket" - BitbucketServer = "Bitbucket Server" - Gitlab = "GitLab" -) - -type CiType string - -const ( - Jenkins = "Jenkins" - GithubActions = "GitHub Actions" - Pipelines = "JFrog Pipelines" -) diff --git a/general/cisetup/githubactionsfilegenerator.go b/general/cisetup/githubactionsfilegenerator.go deleted file mode 100644 index 69750c2d0..000000000 --- a/general/cisetup/githubactionsfilegenerator.go +++ /dev/null @@ -1,69 +0,0 @@ -package cisetup - -import ( - "fmt" - "path/filepath" - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" -) - -var GithubActionsDir = filepath.Join(".github", "workflows") -var GithubActionsFilePath = filepath.Join(GithubActionsDir, GithubActionsFileName) - -const GithubActionsFileName = "build.yml" -const githubActionsTemplate = ` -name: 'JFrog CI Integration' -on: [push] -jobs: - jfrog-ci-integration: - runs-on: ubuntu-latest - env: - JF_ARTIFACTORY_1: ${{ secrets.JF_ARTIFACTORY_SECRET_1 }} - JFROG_BUILD_STATUS: PASS - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup JFrog CLI - uses: jfrog/setup-jfrog-cli@v1 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: '11' - distribution: 'adopt' - - name: Build - run: | - # Configure the project - %s - # Build the project using JFrog CLI - %s - - name: Failure check - run: | - echo "JFROG_BUILD_STATUS=FAIL" >> $GITHUB_ENV - if: failure() - - name: Publish build - run: | - # Collect and store environment variables in the build-info - jfrog rt bce - # Collect and store VCS details in the build-info - jfrog rt bag - # Publish the build-info to Artifactory - jfrog rt bp - # Scan the published build-info with Xray - jfrog rt bs - if: always()` - -type GithubActionsGenerator struct { - SetupData *CiSetupData -} - -func (gg *GithubActionsGenerator) Generate() (githubActionsBytes []byte, githubActionsName string, err error) { - // setM2 env variable if maven is used. - setM2 := gg.SetupData.BuiltTechnology.Type == coreutils.Maven - buildToolsConfigCommands := strings.Join(getTechConfigsCommands(ConfigServerId, setM2, gg.SetupData), "\n ") - buildCommand, err := convertBuildCmd(gg.SetupData) - if err != nil { - return nil, "", err - } - return []byte(fmt.Sprintf(githubActionsTemplate, buildToolsConfigCommands, buildCommand)), GithubActionsFileName, nil -} diff --git a/general/cisetup/jenkinsfiledslgenerator.go b/general/cisetup/jenkinsfiledslgenerator.go deleted file mode 100644 index 3734aec36..000000000 --- a/general/cisetup/jenkinsfiledslgenerator.go +++ /dev/null @@ -1,214 +0,0 @@ -package cisetup - -import ( - "fmt" - "golang.org/x/text/cases" - "golang.org/x/text/language" - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" -) - -const ( - JenkinsDslFileName = "Jenkinsfile" - resolverIdTemplate = "%s_RESOLVER" - deployerIdTemplate = "%s_DEPLOYER" - homeEnv = "%[1]s_HOME = '/full/path/to/%[1]s' // Set to the local %[1]s installation path." - - jenkinsfileTemplate2 = `pipeline { - - // More info about the Declarative Pipeline Syntax on https://www.jfrog.com/confluence/display/JFROG/Declarative+Pipeline+Syntax - // Declarative syntax is available from version 3.0.0 of the Jenkins Artifactory Plugin. - - agent any - - %s - - %s -}` - - environmentsTemplate = ` - environment { - %s - }` - - allStagesTemplate = ` - stages { - %s - }` - - stageTemplate = ` - stage (%q) { - steps {%s - } - } -` - - cloneStepsTemplate = ` - git branch: %q, - url: %q - // credentialsId: 'git_cred_id'. If cloning the code requires credentials, set the credentials to your git in Jenkins > Configure System > credentials > "username with password" > ID: "git-cred-id"` - - rtConfigServerStepTemplate = ` - rtServer ( - id: %[1]q, - url: %[2]q, - credentialsId: 'rt-cred-id', // Set the credentials to your JFrog instance in Jenkins > Configure System > credentials > "username with password" > ID: "rt-cred-id" - - // bypassProxy: true, (If Jenkins is configured to use an http proxy, you can bypass the proxy when using this Artifactory server) - // timeout: 300 , (Configure the connection timeout (in seconds). The default value (if not configured) is 300 seconds) - ) - rt%[3]sDeployer ( - id: %[4]q, - serverId: %[1]q, - %[5]s, - - // threads: 6, (Optional - Attach custom properties to the published artifacts) - // properties: ['key1=value1', 'key2=value2'], (Optional - Attach custom properties to the published artifacts) - ) - rt%[3]sResolver ( - id: %[6]q, - serverId: %[1]q, - %[7]s - )` - - mavenRepoTemplate = `releaseRepo: %q, - snapshotRepo: %q` - - singleRepoTemplate = `repo: %q` - - mavenRunStepTemplate = ` - rtMavenRun ( - pom: 'pom.xml', // path to pom.xml file - goals: %q, - resolverId: %q, - deployerId: %q, - - // tool: {build installation name}, (Maven tool installation from jenkins from : Jenkins > Manage jenkins > Global Tool Configuration > Maven installations) - // useWrapper: true, (Set to true if you'd like the build to use the Maven Wrapper.) - // opts: '-Xms1024m -Xmx4096m', (Optional - Maven options) - )` - - gradleRunStepTemplate = ` - rtGradleRun ( - buildFile: 'build.gradle', - tasks: %q, - rootDir: "", - resolverId: %q, - deployerId: %q, - - // tool: {build installation name}, // Jenkins > Gradle jenkins > Global Tool Configuration > Gradle installations - )` - - npmInstallStepTemplate = ` - rtNpmInstall ( - resolverId: %q, - - // tool: {build installation name}, (Npm tool installation from jenkins from : Jenkins > Manage jenkins > Global Tool Configuration > NodeJS installations - )` - - npmPublishStepTemplate = ` - rtNpmPublish ( - deployerId: %q, - - // tool: {build installation name}, (Npm tool installation from jenkins from : Jenkins > Manage jenkins > Global Tool Configuration > NodeJS installations - // path: '', (Optional path to the project root. If not set, the root of the workspace is assumed as the root project path.) - // javaArgs: '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005' , (Jenkins spawns a new java process during this step's execution. You have the option of passing any java args to this new process.) - )` - - publishBuildInfoStepsTemplate = ` - rtPublishBuildInfo ( - serverId: %q, - )` -) - -type JenkinsfileDslGenerator struct { - SetupData *CiSetupData -} - -func (jg *JenkinsfileDslGenerator) GenerateDsl() (jenkinsfileBytes []byte, jenkinsfileName string, err error) { - serviceDetails, err := config.GetSpecificConfig(ConfigServerId, false, false) - if err != nil { - return nil, "", err - } - // Generate environments sections - environments := generateEnvironments(jg.SetupData.BuiltTechnology.Type) - // Generate Stages Section - cloneStage := generateStage("Clone", fmt.Sprintf(cloneStepsTemplate, jg.SetupData.GitBranch, jg.SetupData.VcsCredentials.Url)) - rtConfigStage := generateStage("Artifactory configuration", generateRtConfigSteps(jg.SetupData.BuiltTechnology, serviceDetails.ArtifactoryUrl)) - execBuildStage := generateBuildStages(jg.SetupData.GetBuildCmdForNativeStep(), jg.SetupData.BuiltTechnology.Type) - publishBuildInfoStage := generateStage("Publish build info", fmt.Sprintf(publishBuildInfoStepsTemplate, ConfigServerId)) - // Combine all stages together - stagesString := generateAllStages(cloneStage, rtConfigStage, execBuildStage, publishBuildInfoStage) - - return []byte(fmt.Sprintf(jenkinsfileTemplate2, environments, stagesString)), JenkinsDslFileName, nil -} - -func generateStage(stageName, steps string) (stageString string) { - return fmt.Sprintf(stageTemplate, stageName, steps) -} - -func generateAllStages(stages ...string) (allStagesString string) { - allStagesString = "" - for _, stage := range stages { - allStagesString += stage - } - return fmt.Sprintf(allStagesTemplate, allStagesString) -} - -func generateEnvironments(buildType coreutils.Technology) string { - envs := "" - switch buildType { - case coreutils.Maven: - fallthrough - case coreutils.Gradle: - envs += fmt.Sprintf(homeEnv, strings.ToUpper(buildType.String())) - default: - envs += "" - } - if envs == "" { - return "" - } - return fmt.Sprintf(environmentsTemplate, envs) -} - -func generateRtConfigSteps(techInfo *TechnologyInfo, rtUrl string) string { - var deployerRepos string - var resolverRepos string - switch techInfo.Type { - case coreutils.Maven: - deployerRepos = fmt.Sprintf(mavenRepoTemplate, techInfo.LocalReleasesRepo, techInfo.LocalSnapshotsRepo) - resolverRepos = fmt.Sprintf(mavenRepoTemplate, techInfo.VirtualRepo, techInfo.VirtualRepo) - case coreutils.Gradle: - fallthrough - case coreutils.Npm: - deployerRepos = fmt.Sprintf(singleRepoTemplate, techInfo.LocalReleasesRepo) - resolverRepos = fmt.Sprintf(singleRepoTemplate, techInfo.VirtualRepo) - default: - deployerRepos = "//Build type is not supported at the moment" - resolverRepos = "//Build type is not supported at the moment" - } - buildType := string(techInfo.Type) - resolverId := fmt.Sprintf(resolverIdTemplate, strings.ToUpper(buildType)) - deployerId := fmt.Sprintf(deployerIdTemplate, strings.ToUpper(buildType)) - return fmt.Sprintf(rtConfigServerStepTemplate, ConfigServerId, rtUrl, cases.Title(language.Und, cases.NoLower).String(buildType), deployerId, deployerRepos, resolverId, resolverRepos) -} - -func generateBuildStages(buildCmd string, buildType coreutils.Technology) (buildStages string) { - buildStages = "" - resolverId := fmt.Sprintf(resolverIdTemplate, strings.ToUpper(buildType.String())) - deployerId := fmt.Sprintf(deployerIdTemplate, strings.ToUpper(buildType.String())) - switch buildType { - case coreutils.Maven: - buildStages += generateStage("Exec Maven", fmt.Sprintf(mavenRunStepTemplate, buildCmd, resolverId, deployerId)) - case coreutils.Gradle: - buildStages += generateStage("Exec Gradle", fmt.Sprintf(gradleRunStepTemplate, buildCmd, resolverId, deployerId)) - case coreutils.Npm: - buildStages += generateStage("Exec Npm install", fmt.Sprintf(npmInstallStepTemplate, resolverId)) - buildStages += generateStage("Exec Npm publish", fmt.Sprintf(npmPublishStepTemplate, deployerId)) - default: - buildStages = "//Build type is not supported at the moment" - } - return buildStages -} diff --git a/general/cisetup/jenkinsfilegenerator.go b/general/cisetup/jenkinsfilegenerator.go deleted file mode 100644 index 81cbb09a7..000000000 --- a/general/cisetup/jenkinsfilegenerator.go +++ /dev/null @@ -1,105 +0,0 @@ -package cisetup - -import ( - "fmt" - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" -) - -const JenkinsfileName = "Jenkinsfile" -const m2HomeSet = ` - // The M2_HOME environment variable should be set to the local maven installation path. - M2_HOME = ""` -const jenkinsfileTemplate = `pipeline { - agent any - environment { - %s - - JFROG_CLI_BUILD_NAME = "${JOB_NAME}" - JFROG_CLI_BUILD_NUMBER = "${BUILD_NUMBER}" - - // Sets the CI server build URL in the build-info. - JFROG_CLI_BUILD_URL = "https:////${BUILD_NUMBER}/console" - - } - stages { - stage ('Clone') { - steps { - // If cloning the code requires credentials, follow these steps: - // 1. Uncomment the ending of the below 'git' step. - // 2. Create the 'git_cred_id' credentials as described here - https://www.jenkins.io/doc/book/using/using-credentials/ - git branch: %q, url: %q //, credentialsId: 'git_cred_id' - } - } - - stage ('Config') { - steps { - // Download JFrog CLI. - sh 'curl -fL https://getcli.jfrog.io | sh && chmod +x jfrog' - - // Configure JFrog CLI - withCredentials([string(credentialsId: 'rt-password', variable: 'RT_PASSWORD')]) { - sh '''./jfrog c add %s --url %s --user ${RT_USERNAME} --password ${RT_PASSWORD} - ./%s - ''' - } - } - } - - stage ('Build') { - steps { - dir('%s') { - sh '''./%s''' - } - } - } - } - - post { - success { - script { - env.JFROG_BUILD_STATUS="PASS" - } - } - - failure { - script { - env.JFROG_BUILD_STATUS="FAIL" - } - } - - cleanup { - // Collect and store environment variables in the build-info - sh './jfrog rt bce' - // Collect and store VCS details in the build-info - sh './jfrog rt bag' - // Publish the build-info to Artifactory - sh './jfrog rt bp' - sh './jfrog c remove %s --quiet' - } - } - }` - -type JenkinsfileGenerator struct { - SetupData *CiSetupData -} - -func (jg *JenkinsfileGenerator) Generate() (jenkinsfileBytes []byte, jenkinsfileName string, err error) { - serviceDetails, err := config.GetSpecificConfig(ConfigServerId, false, false) - if err != nil { - return nil, "", err - } - buildToolsConfigCommands := strings.Join(getTechConfigsCommands(ConfigServerId, false, jg.SetupData), cmdAndOperator) - buildCommand, err := convertBuildCmd(jg.SetupData) - if err != nil { - return nil, "", err - } - var envSet string - // Set the M2_HOME env variable if maven is used. - if jg.SetupData.BuiltTechnology.Type == coreutils.Maven { - envSet = m2HomeSet - } - return []byte(fmt.Sprintf(jenkinsfileTemplate, envSet, jg.SetupData.GitBranch, jg.SetupData.VcsCredentials.Url, ConfigServerId, serviceDetails.Url, buildToolsConfigCommands, jg.SetupData.RepositoryName, buildCommand, ConfigServerId)), JenkinsfileName, nil -} diff --git a/general/cisetup/pipelinesconfig.go b/general/cisetup/pipelinesconfig.go deleted file mode 100644 index 34f685f01..000000000 --- a/general/cisetup/pipelinesconfig.go +++ /dev/null @@ -1,189 +0,0 @@ -package cisetup - -import ( - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-client-go/artifactory" - clientConfig "github.com/jfrog/jfrog-client-go/config" - "github.com/jfrog/jfrog-client-go/pipelines" - "github.com/jfrog/jfrog-client-go/pipelines/services" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/log" -) - -const ( - PipelinesYamlName = "pipelines.yml" -) - -type JFrogPipelinesConfigurator struct { - SetupData *CiSetupData - PipelinesToken string -} - -func (pc *JFrogPipelinesConfigurator) Config() (vcsIntName, rtIntName string, err error) { - log.Info("Configuring JFrog Pipelines...") - serviceDetails, err := config.GetSpecificConfig(ConfigServerId, false, false) - if err != nil { - return "", "", err - } - - psm, err := pc.createPipelinesServiceManager(serviceDetails) - if err != nil { - return "", "", err - } - - vcsIntName, vcsIntId, err := pc.createVcsIntegration(psm) - if err != nil { - return "", "", err - } - - rtIntName, err = pc.createArtifactoryIntegration(psm, serviceDetails) - if err != nil { - return "", "", err - } - - err = pc.doAddPipelineSource(psm, vcsIntId) - if err != nil { - return "", "", err - } - return vcsIntName, rtIntName, nil -} - -func (pc *JFrogPipelinesConfigurator) doAddPipelineSource(psm *pipelines.PipelinesServicesManager, projectIntegrationId int) (err error) { - _, err = psm.AddPipelineSource(projectIntegrationId, pc.SetupData.GetRepoFullName(), pc.SetupData.GitBranch, PipelinesYamlName) - // If source already exists, ignore error. - if _, ok := err.(*services.SourceAlreadyExistsError); ok { - log.Debug("Pipeline Source for repo '" + pc.SetupData.GetRepoFullName() + "' and branch '" + pc.SetupData.GitBranch + "' already exists and will be used.") - err = nil - } - return -} - -func (pc *JFrogPipelinesConfigurator) createPipelinesServiceManager(details *config.ServerDetails) (*pipelines.PipelinesServicesManager, error) { - // Create new details with pipelines token. - pipelinesDetails := *details - pipelinesDetails.AccessToken = pc.PipelinesToken - pipelinesDetails.User = "" - pipelinesDetails.Password = "" - - certsPath, err := coreutils.GetJfrogCertsDir() - if err != nil { - return nil, err - } - pAuth, err := pipelinesDetails.CreatePipelinesAuthConfig() - if err != nil { - return nil, err - } - serviceConfig, err := clientConfig.NewConfigBuilder(). - SetServiceDetails(pAuth). - SetCertificatesPath(certsPath). - SetInsecureTls(pipelinesDetails.InsecureTls). - SetDryRun(false). - Build() - if err != nil { - return nil, err - } - return pipelines.New(serviceConfig) -} - -func (pc *JFrogPipelinesConfigurator) createVcsIntegration(psm *pipelines.PipelinesServicesManager) (integrationName string, integrationId int, err error) { - switch pc.SetupData.GitProvider { - case Github: - integrationName = pc.createIntegrationName(services.GithubName) - integrationId, err = psm.CreateGithubIntegration(integrationName, pc.SetupData.VcsCredentials.AccessToken) - case GithubEnterprise: - integrationName = pc.createIntegrationName(services.GithubEnterpriseName) - integrationId, err = psm.CreateGithubEnterpriseIntegration(integrationName, pc.SetupData.VcsBaseUrl, pc.SetupData.VcsCredentials.AccessToken) - case Bitbucket: - integrationName = pc.createIntegrationName(services.BitbucketName) - integrationId, err = psm.CreateBitbucketIntegration(integrationName, pc.SetupData.VcsCredentials.User, pc.SetupData.VcsCredentials.AccessToken) - case BitbucketServer: - integrationName = pc.createIntegrationName(services.BitbucketServerName) - cred := pc.SetupData.VcsCredentials.AccessToken - if cred == "" { - cred = pc.SetupData.VcsCredentials.Password - } - integrationId, err = psm.CreateBitbucketServerIntegration(integrationName, pc.SetupData.VcsBaseUrl, pc.SetupData.VcsCredentials.User, cred) - case Gitlab: - integrationName = pc.createIntegrationName(services.GitlabName) - integrationId, err = psm.CreateGitlabIntegration(integrationName, pc.SetupData.VcsBaseUrl, pc.SetupData.VcsCredentials.AccessToken) - default: - return "", -1, errorutils.CheckErrorf("vcs type is not supported at the moment") - } - if _, ok := err.(*services.IntegrationAlreadyExistsError); ok { - // If integration already exists, get the id from pipelines. - log.Debug("Integration '" + integrationName + "' already exists and will be used. Fetching id from pipelines...") - var integration *services.Integration - integration, err = psm.GetIntegrationByName(integrationName) - if err != nil { - return - } - integrationId = integration.Id - } - return -} - -func (pc *JFrogPipelinesConfigurator) createArtifactoryIntegration(psm *pipelines.PipelinesServicesManager, details *config.ServerDetails) (string, error) { - integrationName := pc.createIntegrationName("rt") - apiKey, err := pc.getApiKey(details) - if err != nil { - return "", err - } - user := details.User - _, err = psm.CreateArtifactoryIntegration(integrationName, details.ArtifactoryUrl, user, apiKey) - // If integration already exists, ignore error. - if _, ok := err.(*services.IntegrationAlreadyExistsError); ok { - log.Debug("Integration '" + integrationName + "' already exists and will be used.") - err = nil - } - return integrationName, err -} - -// Get API Key if exists, generate one if needed. -func (pc *JFrogPipelinesConfigurator) getApiKey(details *config.ServerDetails) (string, error) { - // Try getting API Key for the user if exists. - asm, err := pc.createRtServiceManager(details) - if err != nil { - return "", err - } - apiKey, err := asm.GetAPIKey() - if err != nil || apiKey != "" { - return apiKey, err - } - - // Generate API Key for the user. - return asm.CreateAPIKey() -} - -func (pc *JFrogPipelinesConfigurator) createIntegrationName(intType string) string { - return intType + "_" + createPipelinesSuitableName(pc.SetupData, "integration") -} - -func (pc *JFrogPipelinesConfigurator) createRtServiceManager(artDetails *config.ServerDetails) (artifactory.ArtifactoryServicesManager, error) { - certsPath, err := coreutils.GetJfrogCertsDir() - if err != nil { - return nil, err - } - artAuth, err := artDetails.CreateArtAuthConfig() - if err != nil { - return nil, err - } - serviceConfig, err := clientConfig.NewConfigBuilder(). - SetServiceDetails(artAuth). - SetCertificatesPath(certsPath). - SetInsecureTls(artDetails.InsecureTls). - SetDryRun(false). - Build() - if err != nil { - return nil, err - } - return artifactory.New(serviceConfig) -} - -func createPipelinesSuitableName(data *CiSetupData, suffix string) string { - name := strings.Join([]string{data.ProjectDomain, data.RepositoryName, suffix}, "_") - // Pipelines does not allow "-" which might exist in repo names. - return strings.ReplaceAll(name, "-", "_") -} diff --git a/general/cisetup/pipelinesyaml.go b/general/cisetup/pipelinesyaml.go deleted file mode 100644 index 1302b754f..000000000 --- a/general/cisetup/pipelinesyaml.go +++ /dev/null @@ -1,452 +0,0 @@ -package cisetup - -import ( - "encoding/json" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-client-go/utils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "gopkg.in/yaml.v3" - "strconv" -) - -const addRunFilesCmd = "add_run_files /tmp/jfrog/. jfrog" - -type JFrogPipelinesYamlGenerator struct { - VcsIntName string - RtIntName string - SetupData *CiSetupData -} - -func (yg *JFrogPipelinesYamlGenerator) Generate() (pipelineBytes []byte, pipelineName string, err error) { - pipelineName = yg.createPipelineName() - gitResourceName := yg.createGitResourceName() - biResourceName := yg.createBuildInfoResourceName() - gitResource := yg.createGitResource(gitResourceName) - biResource := yg.createBuildInfoResource(biResourceName) - pipeline, err := yg.createPipeline(pipelineName, gitResourceName, biResourceName) - if err != nil { - return nil, "", err - } - pipelineYaml := PipelineYml{ - Resources: []Resource{gitResource, biResource}, - Pipelines: []Pipeline{pipeline}, - } - pipelineBytes, err = yaml.Marshal(&pipelineYaml) - return pipelineBytes, pipelineName, errorutils.CheckError(err) -} - -func (yg *JFrogPipelinesYamlGenerator) getNpmBashCommands(serverId, gitResourceName, convertedBuildCmd string) []string { - var commandsArray []string - commandsArray = append(commandsArray, getCdToResourceCmd(gitResourceName)) - commandsArray = append(commandsArray, getJfrogCliConfigCmd(yg.RtIntName, serverId, true)) - commandsArray = append(commandsArray, getBuildToolConfigCmd(npmConfigCmdName, serverId, yg.SetupData.BuiltTechnology.VirtualRepo)) - commandsArray = append(commandsArray, convertedBuildCmd) - commandsArray = append(commandsArray, jfrogCliBag) - commandsArray = append(commandsArray, jfrogCliBce) - return commandsArray -} - -// Converts build tools commands to run via JFrog CLI. -func (yg *JFrogPipelinesYamlGenerator) convertNpmBuildCmd() (string, error) { - // Replace npm-i. - converted, err := replaceCmdWithRegexp(yg.SetupData.BuiltTechnology.BuildCmd, npmInstallRegexp, npmInstallRegexpReplacement) - if err != nil { - return "", err - } - // Replace npm-ci. - return replaceCmdWithRegexp(converted, npmCiRegexp, npmCiRegexpReplacement) -} - -func replaceCmdWithRegexp(buildCmd, cmdRegexp, replacement string) (string, error) { - regexp, err := utils.GetRegExp(cmdRegexp) - if err != nil { - return "", err - } - return regexp.ReplaceAllString(buildCmd, replacement), nil -} - -func (yg *JFrogPipelinesYamlGenerator) getPipelineEnvVars() map[string]string { - return map[string]string{ - coreutils.CI: strconv.FormatBool(true), - buildNameEnvVar: yg.SetupData.BuildName, - buildNumberEnvVar: runNumberEnvVar, - buildUrlEnvVar: stepUrlEnvVar, - } -} - -func (yg *JFrogPipelinesYamlGenerator) createGitResource(gitResourceName string) Resource { - return Resource{ - Name: gitResourceName, - ResourceType: GitRepo, - ResourceConfiguration: GitRepoResourceConfiguration{ - Path: yg.SetupData.GetRepoFullName(), - GitProvider: yg.VcsIntName, - BuildOn: BuildOn{ - PullRequestCreate: true, - }, - Branches: IncludeExclude{Include: yg.SetupData.GitBranch}, - }, - } -} - -func (yg *JFrogPipelinesYamlGenerator) createBuildInfoResource(buildInfoResourceName string) Resource { - return Resource{ - Name: buildInfoResourceName, - ResourceType: BuildInfo, - ResourceConfiguration: BuildInfoResourceConfiguration{ - SourceArtifactoryIntegration: yg.RtIntName, - BuildName: yg.SetupData.BuildName, - BuildNumber: runNumberEnvVar, - }, - } -} - -func (yg *JFrogPipelinesYamlGenerator) createPipeline(pipelineName, gitResourceName, buildInfoResourceName string) (Pipeline, error) { - steps, err := yg.createSteps(gitResourceName, buildInfoResourceName) - if err != nil { - return Pipeline{}, err - } - return Pipeline{ - Name: pipelineName, - Steps: steps, - Configuration: PipelineConfiguration{ - PipelineEnvVars: PipelineEnvVars{ - ReadOnlyEnvVars: yg.getPipelineEnvVars(), - }, - }, - }, nil -} - -func (yg *JFrogPipelinesYamlGenerator) createSteps(gitResourceName, buildInfoResourceName string) (steps []PipelineStep, err error) { - var step PipelineStep - - switch yg.SetupData.BuiltTechnology.Type { - case coreutils.Maven: - step = yg.createMavenStep(gitResourceName) - case coreutils.Gradle: - step = yg.createGradleStep(gitResourceName) - case coreutils.Npm: - step, err = yg.createNpmStep(gitResourceName) - if err != nil { - return nil, err - } - } - - return []PipelineStep{step, yg.createBuildInfoStep(gitResourceName, step.Name, buildInfoResourceName)}, nil -} - -func (yg *JFrogPipelinesYamlGenerator) createMavenStep(gitResourceName string) PipelineStep { - return PipelineStep{ - Name: createTechStepName(MvnBuild), - StepType: MvnBuild, - Configuration: &MavenStepConfiguration{ - NativeStepConfiguration: yg.getDefaultNativeStepConfiguration(gitResourceName), - MvnCommand: yg.SetupData.GetBuildCmdForNativeStep(), - ResolverSnapshotRepo: yg.SetupData.BuiltTechnology.VirtualRepo, - ResolverReleaseRepo: yg.SetupData.BuiltTechnology.VirtualRepo, - }, - Execution: StepExecution{ - OnFailure: yg.getOnFailureCommands(), - }, - } -} - -func (yg *JFrogPipelinesYamlGenerator) getDefaultNativeStepConfiguration(gitResourceName string) NativeStepConfiguration { - step := NativeStepConfiguration{ - BaseStepConfiguration: BaseStepConfiguration{ - EnvironmentVariables: map[string]string{ - buildStatusEnvVar: passResult, - }, - Integrations: []StepIntegration{ - { - Name: yg.RtIntName, - }, - }, - InputResources: []StepResource{ - { - Name: gitResourceName, - }, - }, - }, - AutoPublishBuildInfo: false, - ForceXrayScan: false, - } - return step -} - -func (yg *JFrogPipelinesYamlGenerator) createGradleStep(gitResourceName string) PipelineStep { - return PipelineStep{ - Name: createTechStepName(GradleBuild), - StepType: GradleBuild, - Configuration: &GradleStepConfiguration{ - NativeStepConfiguration: yg.getDefaultNativeStepConfiguration(gitResourceName), - GradleCommand: yg.SetupData.GetBuildCmdForNativeStep(), - ResolverRepo: yg.SetupData.BuiltTechnology.VirtualRepo, - }, - Execution: StepExecution{ - OnFailure: yg.getOnFailureCommands(), - }, - } -} - -func (yg *JFrogPipelinesYamlGenerator) createNpmStep(gitResourceName string) (PipelineStep, error) { - serverId := yg.createServerIdName() - - converted, err := yg.convertNpmBuildCmd() - if err != nil { - return PipelineStep{}, err - } - - commands := yg.getNpmBashCommands(serverId, gitResourceName, converted) - - step := PipelineStep{ - Name: createTechStepName(NpmBuild), - StepType: Bash, - Configuration: &BaseStepConfiguration{ - EnvironmentVariables: map[string]string{ - buildStatusEnvVar: passResult, - }, - InputResources: []StepResource{ - { - Name: gitResourceName, - }, - }, - Integrations: []StepIntegration{ - { - Name: yg.RtIntName, - }, - }, - }, - Execution: StepExecution{ - OnExecute: commands, - OnComplete: []string{addRunFilesCmd}, - OnFailure: yg.getOnFailureCommands(), - }, - } - return step, nil -} - -func (yg *JFrogPipelinesYamlGenerator) createBuildInfoStep(gitResourceName, previousStepName, buildInfoResourceName string) PipelineStep { - return PipelineStep{ - Name: createTechStepName(PublishBuildInfo), - StepType: PublishBuildInfo, - Configuration: &NativeStepConfiguration{ - BaseStepConfiguration: BaseStepConfiguration{ - InputSteps: []InputStep{ - { - Name: previousStepName, - }, - }, - InputResources: []StepResource{ - { - Name: gitResourceName, - }, - }, - OutputResources: []StepResource{ - { - Name: buildInfoResourceName, - }, - }, - }, - ForceXrayScan: true, - }, - Execution: StepExecution{ - OnComplete: []string{yg.getUpdateCommitStatusCmd(gitResourceName)}, - }, - } -} - -type PipelineYml struct { - Resources []Resource `yaml:"resources,omitempty"` - Pipelines []Pipeline `yaml:"pipelines,omitempty"` -} - -type ResourceType string - -const ( - GitRepo ResourceType = "GitRepo" - BuildInfo ResourceType = "BuildInfo" -) - -type Resource struct { - Name string `yaml:"name,omitempty"` - ResourceType `yaml:"type,omitempty"` - ResourceConfiguration `yaml:"configuration,omitempty"` -} - -type ResourceConfiguration interface { - ResourceConfigurationMarkerFunction() -} - -type GitRepoResourceConfiguration struct { - Path string `yaml:"path,omitempty"` - GitProvider string `yaml:"gitProvider,omitempty"` - BuildOn `yaml:"buildOn,omitempty"` - Branches IncludeExclude `yaml:"branches,omitempty"` -} - -func (g GitRepoResourceConfiguration) ResourceConfigurationMarkerFunction() {} - -type BuildInfoResourceConfiguration struct { - SourceArtifactoryIntegration string `yaml:"sourceArtifactory,omitempty"` - BuildName string `yaml:"buildName,omitempty"` - BuildNumber json.Number `yaml:"buildNumber,omitempty"` -} - -func (b BuildInfoResourceConfiguration) ResourceConfigurationMarkerFunction() {} - -type IncludeExclude struct { - Include string `yaml:"include,omitempty"` - Exclude string `yaml:"exclude,omitempty"` -} - -type BuildOn struct { - PullRequestCreate bool `yaml:"pullRequestCreate,omitempty"` - Commit bool `yaml:"commit,omitempty"` -} - -type Pipeline struct { - Name string `yaml:"name,omitempty"` - Configuration PipelineConfiguration `yaml:"configuration,omitempty"` - Steps []PipelineStep `yaml:"steps,omitempty"` -} - -type PipelineConfiguration struct { - Runtime `yaml:"runtime,omitempty"` - PipelineEnvVars `yaml:"environmentVariables,omitempty"` -} - -type PipelineEnvVars struct { - ReadOnlyEnvVars map[string]string `yaml:"readOnly,omitempty"` -} - -type RuntimeType string - -const ( - Image RuntimeType = "image" -) - -type Runtime struct { - RuntimeType `yaml:"type,omitempty"` - Image RuntimeImage `yaml:"image,omitempty"` -} - -type RuntimeImage struct { - Custom CustomImage `yaml:"custom,omitempty"` -} - -type CustomImage struct { - Name string `yaml:"name,omitempty"` - Tag string `yaml:"tag,omitempty"` - Options string `yaml:"options,omitempty"` - Registry string `yaml:"registry,omitempty"` - SourceRepository string `yaml:"sourceRepository,omitempty"` - Region string `yaml:"region,omitempty"` -} - -type StepType string - -const ( - MvnBuild StepType = "MvnBuild" - GradleBuild StepType = "GradleBuild" - NpmBuild StepType = "NpmBuild" - Bash StepType = "Bash" - PublishBuildInfo StepType = "PublishBuildInfo" -) - -type PipelineStep struct { - Name string `yaml:"name,omitempty"` - StepType `yaml:"type,omitempty"` - Configuration StepConfiguration `yaml:"configuration,omitempty"` - Execution StepExecution `yaml:"execution,omitempty"` -} - -type StepConfiguration interface { - appendInputSteps([]InputStep) -} - -type BaseStepConfiguration struct { - EnvironmentVariables map[string]string `yaml:"environmentVariables,omitempty"` - Integrations []StepIntegration `yaml:"integrations,omitempty"` - InputResources []StepResource `yaml:"inputResources,omitempty"` - OutputResources []StepResource `yaml:"outputResources,omitempty"` - InputSteps []InputStep `yaml:"inputSteps,omitempty"` -} - -func (b *BaseStepConfiguration) appendInputSteps(steps []InputStep) { - b.InputSteps = append(b.InputSteps, steps...) -} - -type NativeStepConfiguration struct { - BaseStepConfiguration `yaml:",inline"` - ForceXrayScan bool `yaml:"forceXrayScan,omitempty"` - FailOnScan bool `yaml:"failOnScan,omitempty"` - AutoPublishBuildInfo bool `yaml:"autoPublishBuildInfo,omitempty"` -} - -type MavenStepConfiguration struct { - NativeStepConfiguration `yaml:",inline"` - MvnCommand string `yaml:"mvnCommand,omitempty"` - ResolverSnapshotRepo string `yaml:"resolverSnapshotRepo,omitempty"` - ResolverReleaseRepo string `yaml:"resolverReleaseRepo,omitempty"` - DeployerSnapshotRepo string `yaml:"deployerSnapshotRepo,omitempty"` - DeployerReleaseRepo string `yaml:"deployerReleaseRepo,omitempty"` -} - -type GradleStepConfiguration struct { - NativeStepConfiguration `yaml:",inline"` - GradleCommand string `yaml:"gradleCommand,omitempty"` - ResolverRepo string `yaml:"resolverRepo,omitempty"` - UsesPlugin bool `yaml:"usesPlugin,omitempty"` - UseWrapper bool `yaml:"useWrapper,omitempty"` -} - -type StepIntegration struct { - Name string `yaml:"name,omitempty"` -} - -type StepResource struct { - Name string `yaml:"name,omitempty"` -} - -type InputStep struct { - Name string `yaml:"name,omitempty"` -} - -type StepExecution struct { - OnStart []string `yaml:"onStart,omitempty"` - OnExecute []string `yaml:"onExecute,omitempty"` - OnComplete []string `yaml:"onComplete,omitempty"` - OnSuccess []string `yaml:"onSuccess,omitempty"` - OnFailure []string `yaml:"onFailure,omitempty"` -} - -func (yg *JFrogPipelinesYamlGenerator) getOnFailureCommands() []string { - return []string{getExportCmd(buildStatusEnvVar, failResult), - jfrogCliBce, - jfrogCliBp} -} - -func (yg *JFrogPipelinesYamlGenerator) getUpdateCommitStatusCmd(gitResourceName string) string { - return updateCommitStatusCmd + " " + gitResourceName -} - -func (yg *JFrogPipelinesYamlGenerator) createGitResourceName() string { - return createPipelinesSuitableName(yg.SetupData, "gitResource") -} - -func (yg *JFrogPipelinesYamlGenerator) createBuildInfoResourceName() string { - return createPipelinesSuitableName(yg.SetupData, "buildInfoResource") -} - -func (yg *JFrogPipelinesYamlGenerator) createPipelineName() string { - return createPipelinesSuitableName(yg.SetupData, "pipeline") -} - -func (yg *JFrogPipelinesYamlGenerator) createServerIdName() string { - return createPipelinesSuitableName(yg.SetupData, "serverId") -} - -func createTechStepName(stepType StepType) string { - return string(stepType) + "Step" -} diff --git a/general/cisetup/utils.go b/general/cisetup/utils.go deleted file mode 100644 index 089c496c6..000000000 --- a/general/cisetup/utils.go +++ /dev/null @@ -1,147 +0,0 @@ -package cisetup - -import ( - "fmt" - "strings" - - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" -) - -const ( - m2pathCmd = "MVN_PATH=`which mvn` && export M2_HOME=`readlink -f $MVN_PATH | xargs dirname | xargs dirname`" - jfrogCliRtPrefix = "jfrog rt" - jfrogCliConfig = "jfrog c add" - jfrogCliOldConfig = "jfrog rt c" - jfrogCliBce = "jfrog rt bce" - jfrogCliBag = "jfrog rt bag" - jfrogCliBp = "jfrog rt bp" - buildNameEnvVar = "JFROG_CLI_BUILD_NAME" - buildNumberEnvVar = "JFROG_CLI_BUILD_NUMBER" - buildUrlEnvVar = "JFROG_CLI_BUILD_URL" - buildStatusEnvVar = "JFROG_BUILD_STATUS" - runNumberEnvVar = "$run_number" - stepUrlEnvVar = "$step_url" - updateCommitStatusCmd = "update_commit_status" - - gradleConfigCmdName = "gradle-config" - npmConfigCmdName = "npm-config" - mvnConfigCmdName = "mvn-config" - serverIdResolve = "server-id-resolve" - repoResolveReleases = "repo-resolve-releases" - repoResolveSnapshots = "repo-resolve-snapshots" - repoResolve = "repo-resolve" - - passResult = "PASS" - failResult = "FAIL" - - urlFlag = "url" - rtUrlFlag = "artifactory-url" - userFlag = "user" - - // Replace exe (group 2) with "jfrog rt exe" while maintaining preceding (if any) and succeeding spaces. - mvnGradleRegexp = `(^|\s)(mvn|gradle)(\s)` - mvnGradleRegexpReplacement = `${1}jfrog rt ${2}${3}` - npmInstallRegexp = `(^|\s)(npm i|npm install)(\s|$)` - npmInstallRegexpReplacement = `${1}jfrog rt npmi${3}` - npmCiRegexp = `(^|\s)(npm ci)(\s|$)` - npmCiRegexpReplacement = `${1}jfrog rt npmci${3}` - - cmdAndOperator = " &&\n" -) - -func getFlagSyntax(flagName string) string { - return fmt.Sprintf("--%s", flagName) -} - -func getCdToResourceCmd(gitResourceName string) string { - return fmt.Sprintf("cd $res_%s_resourcePath", gitResourceName) -} - -func getIntDetailForCmd(intName, detail string) string { - return fmt.Sprintf("$int_%s_%s", intName, detail) -} - -// Returns the JFrog CLI config command according to the given server details. -func getJfrogCliConfigCmd(rtIntName, serverId string, useOld bool) string { - usedConfigCmd := jfrogCliConfig - usedUrlFlag := rtUrlFlag - if useOld { - usedConfigCmd = jfrogCliOldConfig - usedUrlFlag = urlFlag - } - return strings.Join([]string{ - usedConfigCmd, serverId, - getFlagSyntax(usedUrlFlag), getIntDetailForCmd(rtIntName, urlFlag), - getFlagSyntax(userFlag), getIntDetailForCmd(rtIntName, userFlag), - "--enc-password=false", - }, " ") -} - -// Returns an array of JFrog CLI config commands according to the given CiSetupData. -func getTechConfigsCommands(serverId string, setM2ForMaven bool, data *CiSetupData) []string { - var configs []string - switch data.BuiltTechnology.Type { - case coreutils.Maven: - if setM2ForMaven { - configs = append(configs, m2pathCmd) - } - configs = append(configs, getMavenConfigCmd(serverId, data.BuiltTechnology.VirtualRepo)) - - case coreutils.Gradle: - configs = append(configs, getBuildToolConfigCmd(gradleConfigCmdName, serverId, data.BuiltTechnology.VirtualRepo)) - - case coreutils.Npm: - configs = append(configs, getBuildToolConfigCmd(npmConfigCmdName, serverId, data.BuiltTechnology.VirtualRepo)) - - } - return configs -} - -// Converts build tools commands to run via JFrog CLI. -func convertBuildCmd(data *CiSetupData) (buildCmd string, err error) { - commandsArray := []string{} - switch data.BuiltTechnology.Type { - case coreutils.Npm: - buildCmd, err = replaceCmdWithRegexp(data.BuiltTechnology.BuildCmd, npmInstallRegexp, npmInstallRegexpReplacement) - if err != nil { - return "", err - } - buildCmd, err = replaceCmdWithRegexp(buildCmd, npmCiRegexp, npmCiRegexpReplacement) - if err != nil { - return "", err - } - case coreutils.Maven, coreutils.Gradle: - buildCmd, err = replaceCmdWithRegexp(data.BuiltTechnology.BuildCmd, mvnGradleRegexp, mvnGradleRegexpReplacement) - if err != nil { - return "", err - } - } - commandsArray = append(commandsArray, buildCmd) - return strings.Join(commandsArray, cmdAndOperator), nil -} - -// Returns Maven's config command according to given server and repo information. -func getMavenConfigCmd(serverId, repo string) string { - return strings.Join([]string{ - jfrogCliRtPrefix, mvnConfigCmdName, - getFlagSyntax(serverIdResolve), serverId, - getFlagSyntax(repoResolveReleases), repo, - getFlagSyntax(repoResolveSnapshots), repo, - }, " ") -} - -// Returns build tool's (except Maven) config command according to given server and repo information. -func getBuildToolConfigCmd(configCmd, serverId, repo string) string { - return strings.Join([]string{ - jfrogCliRtPrefix, configCmd, - getFlagSyntax(serverIdResolve), serverId, - getFlagSyntax(repoResolve), repo, - }, " ") -} - -// Returns a string of environment variable export command. -// key - The variable name. -// value - the value to be set. -func getExportCmd(key, value string) string { - return fmt.Sprintf("export %s=%s", key, value) -} diff --git a/general/cisetup/utils_test.go b/general/cisetup/utils_test.go deleted file mode 100644 index 42d01e238..000000000 --- a/general/cisetup/utils_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package cisetup - -import ( - "testing" - - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/stretchr/testify/assert" -) - -func TestConvertBuildCmd(t *testing.T) { - tests := []buildCmd{ - {"simpleMvn", coreutils.Maven, "mvn clean install", "jfrog rt mvn clean install"}, - {"simpleGradle", coreutils.Gradle, "gradle clean build", "jfrog rt gradle clean build"}, - {"simpleNpmInstall", coreutils.Npm, "npm install", "jfrog rt npmi"}, - {"simpleNpmI", coreutils.Npm, "npm i", "jfrog rt npmi"}, - {"simpleNpmCi", coreutils.Npm, "npm ci", "jfrog rt npmci"}, - {"hiddenMvn", coreutils.Npm, "npm i FOLDERmvnHERE", "jfrog rt npmi FOLDERmvnHERE"}, - {"hiddenNpm", coreutils.Maven, "mvn clean install -f \"HIDDENnpm/pom.xml\"", "jfrog rt mvn clean install -f \"HIDDENnpm/pom.xml\""}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - data := &CiSetupData{} - data.BuiltTechnology = &TechnologyInfo{Type: test.tech, BuildCmd: test.original} - converted, err := convertBuildCmd(data) - if err != nil { - assert.NoError(t, err) - return - } - assert.Equal(t, test.expected, converted) - }) - } -} - -type buildCmd struct { - name string - tech coreutils.Technology - original string - expected string -} diff --git a/general/project/projectinit.go b/general/project/projectinit.go deleted file mode 100644 index aa133e601..000000000 --- a/general/project/projectinit.go +++ /dev/null @@ -1,257 +0,0 @@ -package project - -import ( - "os" - "os/exec" - "path" - "path/filepath" - "strings" - - commonCommands "github.com/jfrog/jfrog-cli-core/v2/common/commands" - "github.com/jfrog/jfrog-cli-core/v2/common/project" - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" - "gopkg.in/yaml.v3" -) - -const ( - buildFileName = "build.yaml" -) - -type ProjectInitCommand struct { - projectPath string - serverId string - serverUrl string -} - -func NewProjectInitCommand() *ProjectInitCommand { - return &ProjectInitCommand{} -} - -func (pic *ProjectInitCommand) SetProjectPath(path string) *ProjectInitCommand { - pic.projectPath = path - return pic -} - -func (pic *ProjectInitCommand) SetServerId(id string) *ProjectInitCommand { - pic.serverId = id - return pic -} - -func (pic *ProjectInitCommand) Run() (err error) { - if pic.serverId == "" { - defaultServer, err := config.GetSpecificConfig("", true, false) - if err != nil { - return err - } - pic.serverId = defaultServer.ServerId - pic.serverUrl = defaultServer.Url - } - technologiesMap, err := pic.detectTechnologies() - if err != nil { - return err - } - if _, errNotFound := exec.LookPath("docker"); errNotFound == nil { - technologiesMap[coreutils.Docker] = true - } - // First create repositories for the detected technologies. - for techName := range technologiesMap { - // First create repositories for the detected technology. - err = createDefaultReposIfNeeded(techName, pic.serverId) - if err != nil { - return err - } - err = createProjectBuildConfigs(techName, pic.projectPath, pic.serverId) - if err != nil { - return err - } - } - // Create build config - if err = pic.createBuildConfig(); err != nil { - return - } - - err = coreutils.PrintTable("", "", pic.createSummarizeMessage(technologiesMap), false) - return -} - -func (pic *ProjectInitCommand) createSummarizeMessage(technologiesMap map[coreutils.Technology]bool) string { - return coreutils.PrintBold("This project is initialized!\n") + - coreutils.PrintBold("The project config is stored inside the .jfrog directory.") + - "\n\n" + - coreutils.PrintTitle("🔍 Scan the dependencies of this project for security vulnerabilities by running") + - "\n" + - "jf audit\n\n" + - coreutils.PrintTitle("📦 Scan any software package on you machine for security vulnerabilities by running") + - "\n" + - "jf scan path/to/dir/or/package\n\n" + - coreutils.PrintTitle("🐳 Scan any local docker image on you machine for security vulnerabilities by running") + - "\n" + - "jf docker scan :\n\n" + - coreutils.PrintTitle("💻 If you're using VS Code, IntelliJ IDEA, WebStorm, PyCharm, Android Studio or GoLand") + - "\n" + - "Open the IDE 👉 Install the JFrog extension or plugin 👉 View the JFrog panel" + - "\n\n" + - pic.createBuildMessage(technologiesMap) + - coreutils.PrintTitle("📚 Read more using this link:") + - "\n" + - coreutils.PrintLink(coreutils.GettingStartedGuideUrl) -} - -// Return a string message, which includes all the build and deployment commands, matching the technologiesMap sent. -func (pic *ProjectInitCommand) createBuildMessage(technologiesMap map[coreutils.Technology]bool) string { - message := "" - for tech := range technologiesMap { - switch tech { - case coreutils.Maven: - message += "jf mvn install deploy\n" - case coreutils.Gradle: - message += "jf gradle artifactoryP\n" - case coreutils.Npm: - message += "jf npm install\n" - message += "jf npm publish\n" - case coreutils.Go: - message += - "jf go build\n" + - "jf go-publish v1.0.0\n" - case coreutils.Pip, coreutils.Pipenv: - message += - "jf " + string(tech) + " install\n" + - "jf rt upload path/to/package/file default-pypi-local" + - coreutils.PrintComment(" #Publish your "+string(tech)+" package") + - "\n" - case coreutils.Dotnet: - executableName := coreutils.Nuget - _, errNotFound := exec.LookPath("dotnet") - if errNotFound == nil { - // dotnet exists in path, So use it in the instruction message. - executableName = coreutils.Dotnet - } - message += - "jf " + string(executableName) + " restore\n" + - "jf rt upload '*.nupkg'" + RepoDefaultName[tech][Virtual] + "\n" - } - } - if message != "" { - message = coreutils.PrintTitle("🚧 Build the code & deploy the packages by running") + - "\n" + - message + - "\n" - } - if ok := technologiesMap[coreutils.Docker]; ok { - baseurl := strings.TrimPrefix(strings.TrimSpace(pic.serverUrl), "https://") - baseurl = strings.TrimPrefix(baseurl, "http://") - imageUrl := path.Join(baseurl, DockerVirtualDefaultName, ":") - message += coreutils.PrintTitle("🐳 Pull and push any docker image using Artifactory") + - "\n" + - "jf docker tag : " + imageUrl + "\n" + - "jf docker push " + imageUrl + "\n" + - "jf docker pull " + imageUrl + "\n\n" - } - - if message != "" { - message += coreutils.PrintTitle("📤 Publish the build-info to Artifactory") + - "\n" + - "jf rt build-publish\n\n" - } - return message -} - -// Returns all detected technologies found in the project directory. -// First, try to return only the technologies that detected according to files in the root directory. -// In case no indication found in the root directory, the search continue recursively. -func (pic *ProjectInitCommand) detectTechnologies() (technologiesMap map[coreutils.Technology]bool, err error) { - technologiesMap, err = coreutils.DetectTechnologies(pic.projectPath, false, false) - if err != nil { - return - } - // In case no technologies were detected in the root directory, try again recursively. - if len(technologiesMap) == 0 { - technologiesMap, err = coreutils.DetectTechnologies(pic.projectPath, false, true) - if err != nil { - return - } - } - return -} - -type BuildConfigFile struct { - Version int `yaml:"version,omitempty"` - ConfigType string `yaml:"type,omitempty"` - BuildName string `yaml:"name,omitempty"` -} - -func (pic *ProjectInitCommand) createBuildConfig() error { - jfrogProjectDir := filepath.Join(pic.projectPath, ".jfrog", "projects") - if err := fileutils.CreateDirIfNotExist(jfrogProjectDir); err != nil { - return errorutils.CheckError(err) - } - configFilePath := filepath.Join(jfrogProjectDir, buildFileName) - projectDirName := filepath.Base(filepath.Dir(pic.projectPath)) - buildConfigFile := &BuildConfigFile{Version: 1, ConfigType: "build", BuildName: projectDirName} - resBytes, err := yaml.Marshal(&buildConfigFile) - if err != nil { - return errorutils.CheckError(err) - } - return errorutils.CheckError(os.WriteFile(configFilePath, resBytes, 0644)) -} - -func createDefaultReposIfNeeded(tech coreutils.Technology, serverId string) error { - err := CreateDefaultLocalRepo(tech, serverId) - if err != nil { - return err - } - err = CreateDefaultRemoteRepo(tech, serverId) - if err != nil { - return err - } - - return CreateDefaultVirtualRepo(tech, serverId) -} - -func createProjectBuildConfigs(tech coreutils.Technology, projectPath string, serverId string) error { - jfrogProjectDir := filepath.Join(projectPath, ".jfrog", "projects") - if err := fileutils.CreateDirIfNotExist(jfrogProjectDir); err != nil { - return errorutils.CheckError(err) - } - techName := strings.ToLower(string(tech)) - configFilePath := filepath.Join(jfrogProjectDir, techName+".yaml") - configFile := commonCommands.ConfigFile{ - Version: commonCommands.BuildConfVersion, - ConfigType: techName, - } - configFile.Resolver = project.Repository{ServerId: serverId} - configFile.Deployer = project.Repository{ServerId: serverId} - switch tech { - case coreutils.Maven: - configFile.Resolver.ReleaseRepo = MavenVirtualDefaultName - configFile.Resolver.SnapshotRepo = MavenVirtualDefaultName - configFile.Deployer.ReleaseRepo = MavenVirtualDefaultName - configFile.Deployer.SnapshotRepo = MavenVirtualDefaultName - case coreutils.Dotnet: - fallthrough - case coreutils.Nuget: - configFile.Resolver.NugetV2 = true - fallthrough - default: - configFile.Resolver.Repo = RepoDefaultName[tech][Virtual] - configFile.Deployer.Repo = RepoDefaultName[tech][Virtual] - - } - resBytes, err := yaml.Marshal(&configFile) - if err != nil { - return errorutils.CheckError(err) - } - - return errorutils.CheckError(os.WriteFile(configFilePath, resBytes, 0644)) -} - -func (pic *ProjectInitCommand) CommandName() string { - return "project_init" -} - -func (pic *ProjectInitCommand) ServerDetails() (*config.ServerDetails, error) { - return config.GetSpecificConfig("", true, false) -} diff --git a/general/project/repoutils.go b/general/project/repoutils.go deleted file mode 100644 index 0d2ad0d07..000000000 --- a/general/project/repoutils.go +++ /dev/null @@ -1,186 +0,0 @@ -package project - -import ( - rtUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" - "github.com/jfrog/jfrog-cli-core/v2/utils/config" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" - - "github.com/jfrog/jfrog-client-go/artifactory" - "github.com/jfrog/jfrog-client-go/artifactory/services" -) - -const ( - Local = "local" - Remote = "remote" - Virtual = "virtual" - RemoteUrl = "url" - - // Defaults Repositories - MavenLocalDefaultName = "default-maven-local" - MavenRemoteDefaultName = "default-maven-remote" - MavenRemoteDefaultUrl = "https://repo.maven.apache.org/maven2" - MavenVirtualDefaultName = "default-maven-virtual" - GradleLocalDefaultName = "default-gradle-local" - GradleRemoteDefaultName = "default-gradle-remote" - GradleRemoteDefaultUrl = "https://repo.maven.apache.org/maven2" - GradleVirtualDefaultName = "default-gradle-virtual" - NpmLocalDefaultName = "default-npm-local" - NpmRemoteDefaultName = "default-npm-remote" - NpmRemoteDefaultUrl = "https://registry.npmjs.org" - NpmVirtualDefaultName = "default-npm-virtual" - GoLocalDefaultName = "default-go-local" - GoRemoteDefaultName = "default-go-remote" - GoRemoteDefaultUrl = "https://gocenter.io/" - GoVirtualDefaultName = "default-go-virtual" - PypiLocalDefaultName = "default-pypi-local" - PypiRemoteDefaultName = "default-pypi-remote" - PypiRemoteDefaultUrl = "https://files.pythonhosted.org" - PypiVirtualDefaultName = "default-pypi-virtual" - NugetLocalDefaultName = "default-nuget-local" - NugetRemoteDefaultName = "default-nuget-remote" - NugetRemoteDefaultUrl = "https://www.nuget.org/" - NugetVirtualDefaultName = "default-nuget-virtual" - DockerLocalDefaultName = "default-docker-local" - DockerRemoteDefaultName = "default-docker-remote" - DockerRemoteDefaultUrl = "https://registry-1.docker.io" - DockerVirtualDefaultName = "default-docker-virtual" -) - -var RepoDefaultName = map[coreutils.Technology]map[string]string{ - coreutils.Maven: { - Local: MavenLocalDefaultName, - Remote: MavenRemoteDefaultName, - RemoteUrl: MavenRemoteDefaultUrl, - Virtual: MavenVirtualDefaultName, - }, - coreutils.Gradle: { - Local: GradleLocalDefaultName, - Remote: GradleRemoteDefaultName, - RemoteUrl: GradleRemoteDefaultUrl, - Virtual: GradleVirtualDefaultName, - }, - coreutils.Npm: { - Local: NpmLocalDefaultName, - Remote: NpmRemoteDefaultName, - RemoteUrl: NpmRemoteDefaultUrl, - Virtual: NpmVirtualDefaultName, - }, - coreutils.Go: { - Local: GoLocalDefaultName, - Remote: GoRemoteDefaultName, - RemoteUrl: GoRemoteDefaultUrl, - Virtual: GoVirtualDefaultName, - }, - coreutils.Pip: { - Local: PypiLocalDefaultName, - Remote: PypiRemoteDefaultName, - RemoteUrl: PypiRemoteDefaultUrl, - Virtual: PypiVirtualDefaultName, - }, - coreutils.Pipenv: { - Local: PypiLocalDefaultName, - Remote: PypiRemoteDefaultName, - RemoteUrl: PypiRemoteDefaultUrl, - Virtual: PypiVirtualDefaultName, - }, - coreutils.Nuget: { - Local: NugetLocalDefaultName, - Remote: NugetRemoteDefaultName, - RemoteUrl: NugetRemoteDefaultUrl, - Virtual: NugetVirtualDefaultName, - }, - coreutils.Dotnet: { - Local: NugetLocalDefaultName, - Remote: NugetRemoteDefaultName, - RemoteUrl: NugetRemoteDefaultUrl, - Virtual: NugetVirtualDefaultName, - }, - coreutils.Docker: { - Local: DockerLocalDefaultName, - Remote: DockerRemoteDefaultName, - RemoteUrl: DockerRemoteDefaultUrl, - Virtual: DockerVirtualDefaultName, - }, -} - -func CreateDefaultLocalRepo(technologyType coreutils.Technology, serverId string) error { - servicesManager, err := getServiceManager(serverId) - if err != nil { - return err - } - params := services.NewLocalRepositoryBaseParams() - params.PackageType = technologyType.GetPackageType() - params.Key = RepoDefaultName[technologyType][Local] - // Check if default repository already exists - if exists, err := servicesManager.IsRepoExists(params.Key); exists { - return err - } - if err != nil { - return err - } - return servicesManager.CreateLocalRepositoryWithParams(params) -} - -func createDefaultRemoteNugetRepo(serverId string, baseParams services.RemoteRepositoryBaseParams) error { - servicesManager, err := getServiceManager(serverId) - if err != nil { - return err - } - params := services.NewNugetRemoteRepositoryParams() - params.RemoteRepositoryBaseParams = baseParams - params.DownloadContextPath = "api/v2/package" - params.FeedContextPath = "api/v2" - return servicesManager.CreateRemoteRepository().Nuget(params) -} - -func CreateDefaultRemoteRepo(technologyType coreutils.Technology, serverId string) error { - servicesManager, err := getServiceManager(serverId) - if err != nil { - return err - } - params := services.NewRemoteRepositoryBaseParams() - params.PackageType = technologyType.GetPackageType() - params.Key = RepoDefaultName[technologyType][Remote] - params.Url = RepoDefaultName[technologyType][RemoteUrl] - // Check if default repository already exists - if exists, err := servicesManager.IsRepoExists(params.Key); exists { - return err - } - if err != nil { - return err - } - // NuGet specific case, due to required DownloadContextPath param by Artifactory - if technologyType == coreutils.Nuget || technologyType == coreutils.Dotnet { - return createDefaultRemoteNugetRepo(serverId, params) - } - return servicesManager.CreateRemoteRepositoryWithParams(params) -} - -func CreateDefaultVirtualRepo(technologyType coreutils.Technology, serverId string) error { - servicesManager, err := getServiceManager(serverId) - if err != nil { - return err - } - params := services.NewVirtualRepositoryBaseParams() - params.PackageType = technologyType.GetPackageType() - params.Key = RepoDefaultName[technologyType][Virtual] - params.Repositories = []string{RepoDefaultName[technologyType][Local], RepoDefaultName[technologyType][Remote]} - params.DefaultDeploymentRepo = RepoDefaultName[technologyType][Local] - // Check if default repository already exists - if exists, err := servicesManager.IsRepoExists(params.Key); exists { - return err - } - if err != nil { - return err - } - return servicesManager.CreateVirtualRepositoryWithParams(params) -} - -func getServiceManager(serverId string) (artifactory.ArtifactoryServicesManager, error) { - serviceDetails, err := config.GetSpecificConfig(serverId, true, false) - if err != nil { - return nil, err - } - return rtUtils.CreateServiceManager(serviceDetails, -1, 0, false) - -} From c15cde9842c703c8b9ec51d1e695ce9bfb230e36 Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Mon, 3 Jun 2024 18:32:34 +0300 Subject: [PATCH 33/36] Update Go to 1.22.3 (#1191) --- .github/workflows/analysis.yml | 4 ++-- .github/workflows/frogbot-scan-pull-request.yml | 6 ++++++ .github/workflows/frogbot-scan-repository.yml | 6 ++++++ .github/workflows/test.yml | 2 +- go.mod | 2 +- go.sum | 17 +++++++++++++++++ 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index 86487ff15..858ab05c2 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: 1.20.x + go-version: 1.22.x cache: false - name: Static Code Analysis @@ -35,7 +35,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: 1.20.x + go-version: 1.22.x cache: false - name: Run Gosec Security Scanner diff --git a/.github/workflows/frogbot-scan-pull-request.yml b/.github/workflows/frogbot-scan-pull-request.yml index 998c8c91f..e6fc7ef30 100644 --- a/.github/workflows/frogbot-scan-pull-request.yml +++ b/.github/workflows/frogbot-scan-pull-request.yml @@ -12,6 +12,12 @@ jobs: # "frogbot" GitHub environment can approve the pull request to be scanned. environment: frogbot steps: + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.22.x + cache: false + - uses: jfrog/frogbot@v2 env: JFROG_CLI_LOG_LEVEL: "DEBUG" diff --git a/.github/workflows/frogbot-scan-repository.yml b/.github/workflows/frogbot-scan-repository.yml index 01b568f67..0921b2459 100644 --- a/.github/workflows/frogbot-scan-repository.yml +++ b/.github/workflows/frogbot-scan-repository.yml @@ -16,6 +16,12 @@ jobs: # The repository scanning will be triggered periodically on the following branches. branch: [ "dev" ] steps: + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.22.x + cache: false + - uses: jfrog/frogbot@v2 env: JFROG_CLI_LOG_LEVEL: "DEBUG" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ea9a56db8..5c3853066 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,7 +31,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 with: - go-version: 1.20.x + go-version: 1.22.x cache: false - name: Install NuGet diff --git a/go.mod b/go.mod index 66709f03e..f5b9ece9b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/jfrog/jfrog-cli-core/v2 -go 1.20 +go 1.22.3 require github.com/c-bata/go-prompt v0.2.5 // Should not be updated to 0.2.6 due to a bug (https://github.com/jfrog/jfrog-cli-core/pull/372) diff --git a/go.sum b/go.sum index a7e03a5e7..bb180023f 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,11 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat6 github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= @@ -47,19 +50,23 @@ github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/forPelevin/gomoji v1.2.0 h1:9k4WVSSkE1ARO/BWywxgEUBvR/jMnao6EZzrql5nxJ8= github.com/forPelevin/gomoji v1.2.0/go.mod h1:8+Z3KNGkdslmeGZBC3tCrwMrcPy5GRzAD+gL9NAwMXg= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a h1:RYfmiM0zluBJOiPDJseKLEN4BapJ42uSi9SZBQ2YyiA= @@ -71,6 +78,7 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= @@ -101,9 +109,11 @@ github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= @@ -132,6 +142,7 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= @@ -151,6 +162,7 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= @@ -187,6 +199,7 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= +github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -197,8 +210,11 @@ github.com/vbauerster/mpb/v7 v7.5.3/go.mod h1:i+h4QY6lmLvBNK2ah1fSreiw3ajskRlBp9 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= @@ -290,6 +306,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= From fdc77c0dcf9d259f31040441f22ad8464d5fa71f Mon Sep 17 00:00:00 2001 From: Assaf Attias <49212512+attiasas@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:16:42 +0300 Subject: [PATCH 34/36] Move techutils to the jfrog-cli-security module (#1189) --- utils/coreutils/techutils.go | 496 ----------------------------- utils/coreutils/techutils_test.go | 509 ------------------------------ 2 files changed, 1005 deletions(-) delete mode 100644 utils/coreutils/techutils.go delete mode 100644 utils/coreutils/techutils_test.go diff --git a/utils/coreutils/techutils.go b/utils/coreutils/techutils.go deleted file mode 100644 index cc7e6ae8b..000000000 --- a/utils/coreutils/techutils.go +++ /dev/null @@ -1,496 +0,0 @@ -package coreutils - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/jfrog/gofrog/datastructures" - "github.com/jfrog/jfrog-client-go/artifactory/services/fspatterns" - "github.com/jfrog/jfrog-client-go/utils/errorutils" - "github.com/jfrog/jfrog-client-go/utils/log" - - "golang.org/x/exp/maps" - "golang.org/x/text/cases" - "golang.org/x/text/language" - - "github.com/jfrog/jfrog-client-go/utils/io/fileutils" -) - -type Technology string - -const ( - Maven Technology = "maven" - Gradle Technology = "gradle" - Npm Technology = "npm" - Pnpm Technology = "pnpm" - Yarn Technology = "yarn" - Go Technology = "go" - Pip Technology = "pip" - Pipenv Technology = "pipenv" - Poetry Technology = "poetry" - Nuget Technology = "nuget" - Dotnet Technology = "dotnet" - Docker Technology = "docker" - Oci Technology = "oci" -) - -const Pypi = "pypi" - -type TechData struct { - // The name of the package type used in this technology. - packageType string - // Suffixes of file/directory names that indicate if a project uses this technology. - // The name of at least one of the files/directories in the project's directory must end with one of these suffixes. - indicators []string - // Suffixes of file/directory names that indicate if a project does not use this technology. - // The names of all the files/directories in the project's directory must NOT end with any of these suffixes. - exclude []string - // Whether this technology is supported by the 'jf ci-setup' command. - ciSetupSupport bool - // Whether Contextual Analysis supported in this technology. - applicabilityScannable bool - // The files that handle the project's dependencies. - packageDescriptors []string - // Formal name of the technology - formal string - // The executable name of the technology - execCommand string - // The operator for package versioning - packageVersionOperator string - // The package installation command of a package - packageInstallationCommand string -} - -var technologiesData = map[Technology]TechData{ - Maven: { - indicators: []string{"pom.xml"}, - ciSetupSupport: true, - packageDescriptors: []string{"pom.xml"}, - execCommand: "mvn", - applicabilityScannable: true, - }, - Gradle: { - indicators: []string{"build.gradle", "build.gradle.kts"}, - ciSetupSupport: true, - packageDescriptors: []string{"build.gradle", "build.gradle.kts"}, - applicabilityScannable: true, - }, - Npm: { - indicators: []string{"package.json", "package-lock.json", "npm-shrinkwrap.json"}, - exclude: []string{"pnpm-lock.yaml", ".yarnrc.yml", "yarn.lock", ".yarn"}, - ciSetupSupport: true, - packageDescriptors: []string{"package.json"}, - formal: string(Npm), - packageVersionOperator: "@", - packageInstallationCommand: "install", - applicabilityScannable: true, - }, - Pnpm: { - indicators: []string{"pnpm-lock.yaml"}, - exclude: []string{".yarnrc.yml", "yarn.lock", ".yarn"}, - packageDescriptors: []string{"package.json"}, - packageVersionOperator: "@", - packageInstallationCommand: "update", - applicabilityScannable: true, - }, - Yarn: { - indicators: []string{".yarnrc.yml", "yarn.lock", ".yarn", ".yarnrc"}, - exclude: []string{"pnpm-lock.yaml"}, - packageDescriptors: []string{"package.json"}, - packageVersionOperator: "@", - applicabilityScannable: true, - }, - Go: { - indicators: []string{"go.mod"}, - packageDescriptors: []string{"go.mod"}, - packageVersionOperator: "@v", - packageInstallationCommand: "get", - }, - Pip: { - packageType: Pypi, - indicators: []string{"setup.py", "requirements.txt"}, - packageDescriptors: []string{"setup.py", "requirements.txt"}, - exclude: []string{"Pipfile", "Pipfile.lock", "pyproject.toml", "poetry.lock"}, - applicabilityScannable: true, - }, - Pipenv: { - packageType: Pypi, - indicators: []string{"Pipfile", "Pipfile.lock"}, - packageDescriptors: []string{"Pipfile"}, - packageVersionOperator: "==", - packageInstallationCommand: "install", - applicabilityScannable: true, - }, - Poetry: { - packageType: Pypi, - indicators: []string{"pyproject.toml", "poetry.lock"}, - packageDescriptors: []string{"pyproject.toml"}, - packageInstallationCommand: "add", - packageVersionOperator: "==", - applicabilityScannable: true, - }, - Nuget: { - indicators: []string{".sln", ".csproj"}, - packageDescriptors: []string{".sln", ".csproj"}, - formal: "NuGet", - // .NET CLI is used for NuGet projects - execCommand: "dotnet", - packageInstallationCommand: "add", - // packageName -v packageVersion - packageVersionOperator: " -v ", - }, - Dotnet: { - indicators: []string{".sln", ".csproj"}, - packageDescriptors: []string{".sln", ".csproj"}, - formal: ".NET", - }, - Docker: { - applicabilityScannable: true, - }, - Oci: { - applicabilityScannable: true, - }, -} - -func (tech Technology) ToFormal() string { - if technologiesData[tech].formal == "" { - return cases.Title(language.Und).String(tech.String()) - } - return technologiesData[tech].formal -} - -func (tech Technology) String() string { - return string(tech) -} - -func (tech Technology) GetExecCommandName() string { - if technologiesData[tech].execCommand == "" { - return tech.String() - } - return technologiesData[tech].execCommand -} - -func (tech Technology) GetPackageType() string { - if technologiesData[tech].packageType == "" { - return tech.String() - } - return technologiesData[tech].packageType -} - -func (tech Technology) GetPackageDescriptor() []string { - return technologiesData[tech].packageDescriptors -} - -func (tech Technology) IsCiSetup() bool { - return technologiesData[tech].ciSetupSupport -} - -func (tech Technology) GetPackageVersionOperator() string { - return technologiesData[tech].packageVersionOperator -} - -func (tech Technology) GetPackageInstallationCommand() string { - return technologiesData[tech].packageInstallationCommand -} - -func (tech Technology) ApplicabilityScannable() bool { - return technologiesData[tech].applicabilityScannable -} - -func DetectedTechnologiesList() (technologies []string) { - wd, err := os.Getwd() - if errorutils.CheckError(err) != nil { - return - } - return detectedTechnologiesListInPath(wd, false) -} - -func detectedTechnologiesListInPath(path string, recursive bool) (technologies []string) { - detectedTechnologies, err := DetectTechnologies(path, false, recursive) - if err != nil { - return - } - if len(detectedTechnologies) == 0 { - return - } - techStringsList := DetectedTechnologiesToSlice(detectedTechnologies) - log.Info(fmt.Sprintf("Detected: %s.", strings.Join(techStringsList, ", "))) - return techStringsList -} - -// If recursive is true, the search will not be limited to files in the root path. -// If requestedTechs is empty, all technologies will be checked. -// If excludePathPattern is not empty, files/directories that match the wildcard pattern will be excluded from the search. -func DetectTechnologiesDescriptors(path string, recursive bool, requestedTechs []string, requestedDescriptors map[Technology][]string, excludePathPattern string) (technologiesDetected map[Technology]map[string][]string, err error) { - filesList, err := fspatterns.ListFiles(path, recursive, false, true, true, excludePathPattern) - if err != nil { - return - } - workingDirectoryToIndicators, excludedTechAtWorkingDir := mapFilesToRelevantWorkingDirectories(filesList, requestedDescriptors) - var strJson string - if strJson, err = GetJsonIndent(workingDirectoryToIndicators); err != nil { - return - } else if len(workingDirectoryToIndicators) > 0 { - log.Debug(fmt.Sprintf("mapped %d working directories with indicators/descriptors:\n%s", len(workingDirectoryToIndicators), strJson)) - } - technologiesDetected = mapWorkingDirectoriesToTechnologies(workingDirectoryToIndicators, excludedTechAtWorkingDir, ToTechnologies(requestedTechs), requestedDescriptors) - if len(technologiesDetected) > 0 { - log.Debug(fmt.Sprintf("Detected %d technologies at %s: %s.", len(technologiesDetected), path, maps.Keys(technologiesDetected))) - } - return -} - -// Map files to relevant working directories according to the technologies' indicators/descriptors and requested descriptors. -// files: The file paths to map. -// requestedDescriptors: Special requested descriptors (for example in Pip requirement.txt can have different path) for each technology. -// Returns: -// 1. workingDirectoryToIndicators: A map of working directories to the files that are relevant to the technologies. -// wd1: [wd1/indicator, wd1/descriptor] -// wd/wd2: [wd/wd2/indicator] -// 2. excludedTechAtWorkingDir: A map of working directories to the technologies that are excluded from the working directory. -// wd1: [tech1, tech2] -// wd/wd2: [tech1] -func mapFilesToRelevantWorkingDirectories(files []string, requestedDescriptors map[Technology][]string) (workingDirectoryToIndicators map[string][]string, excludedTechAtWorkingDir map[string][]Technology) { - workingDirectoryToIndicatorsSet := make(map[string]*datastructures.Set[string]) - excludedTechAtWorkingDir = make(map[string][]Technology) - for _, path := range files { - directory := filepath.Dir(path) - - for tech, techData := range technologiesData { - // Check if the working directory contains indicators/descriptors for the technology - relevant := isIndicator(path, techData) || isDescriptor(path, techData) || isRequestedDescriptor(path, requestedDescriptors[tech]) - if relevant { - if _, exist := workingDirectoryToIndicatorsSet[directory]; !exist { - workingDirectoryToIndicatorsSet[directory] = datastructures.MakeSet[string]() - } - workingDirectoryToIndicatorsSet[directory].Add(path) - } - // Check if the working directory contains a file/directory with a name that ends with an excluded suffix - if isExclude(path, techData) { - excludedTechAtWorkingDir[directory] = append(excludedTechAtWorkingDir[directory], tech) - } - } - } - workingDirectoryToIndicators = make(map[string][]string) - for wd, indicators := range workingDirectoryToIndicatorsSet { - workingDirectoryToIndicators[wd] = indicators.ToSlice() - } - return -} - -func isDescriptor(path string, techData TechData) bool { - for _, descriptor := range techData.packageDescriptors { - if strings.HasSuffix(path, descriptor) { - return true - } - } - return false -} - -func isRequestedDescriptor(path string, requestedDescriptors []string) bool { - for _, requestedDescriptor := range requestedDescriptors { - if strings.HasSuffix(path, requestedDescriptor) { - return true - } - } - return false -} - -func isIndicator(path string, techData TechData) bool { - for _, indicator := range techData.indicators { - if strings.HasSuffix(path, indicator) { - return true - } - } - return false -} - -func isExclude(path string, techData TechData) bool { - for _, exclude := range techData.exclude { - if strings.HasSuffix(path, exclude) { - return true - } - } - return false -} - -// Map working directories to technologies according to the given workingDirectoryToIndicators map files. -// workingDirectoryToIndicators: A map of working directories to the files inside the directory that are relevant to the technologies. -// excludedTechAtWorkingDir: A map of working directories to the technologies that are excluded from the working directory. -// requestedTechs: The technologies to check, if empty all technologies will be checked. -// requestedDescriptors: Special requested descriptors (for example in Pip requirement.txt can have different path) for each technology to detect. -func mapWorkingDirectoriesToTechnologies(workingDirectoryToIndicators map[string][]string, excludedTechAtWorkingDir map[string][]Technology, requestedTechs []Technology, requestedDescriptors map[Technology][]string) (technologiesDetected map[Technology]map[string][]string) { - // Get the relevant technologies to check - technologies := requestedTechs - if len(technologies) == 0 { - technologies = GetAllTechnologiesList() - } - technologiesDetected = make(map[Technology]map[string][]string) - // Map working directories to technologies - for _, tech := range technologies { - techWorkingDirs := getTechInformationFromWorkingDir(tech, workingDirectoryToIndicators, excludedTechAtWorkingDir, requestedDescriptors) - if len(techWorkingDirs) > 0 { - // Found indicators of the technology, add to detected. - technologiesDetected[tech] = techWorkingDirs - } - } - for _, tech := range requestedTechs { - if _, exist := technologiesDetected[tech]; !exist { - // Requested (forced with flag) technology and not found any indicators/descriptors in detection, add as detected. - log.Warn(fmt.Sprintf("Requested technology %s but not found any indicators/descriptors in detection.", tech)) - technologiesDetected[tech] = map[string][]string{} - } - } - return -} - -func getTechInformationFromWorkingDir(tech Technology, workingDirectoryToIndicators map[string][]string, excludedTechAtWorkingDir map[string][]Technology, requestedDescriptors map[Technology][]string) (techWorkingDirs map[string][]string) { - techWorkingDirs = make(map[string][]string) - for wd, indicators := range workingDirectoryToIndicators { - descriptorsAtWd := []string{} - foundIndicator := false - if isTechExcludedInWorkingDir(tech, wd, excludedTechAtWorkingDir) { - // Exclude this technology from this working directory - continue - } - // Check if the working directory contains indicators/descriptors for the technology - for _, path := range indicators { - if isDescriptor(path, technologiesData[tech]) || isRequestedDescriptor(path, requestedDescriptors[tech]) { - descriptorsAtWd = append(descriptorsAtWd, path) - } - if isIndicator(path, technologiesData[tech]) || isRequestedDescriptor(path, requestedDescriptors[tech]) { - foundIndicator = true - } - } - if foundIndicator { - // Found indicators of the technology in the current working directory, add to detected. - techWorkingDirs[wd] = descriptorsAtWd - } - } - // Don't allow working directory if sub directory already exists as key for the same technology - techWorkingDirs = cleanSubDirectories(techWorkingDirs) - return -} - -func isTechExcludedInWorkingDir(tech Technology, wd string, excludedTechAtWorkingDir map[string][]Technology) bool { - if excludedTechs, exist := excludedTechAtWorkingDir[wd]; exist { - for _, excludedTech := range excludedTechs { - if excludedTech == tech { - return true - } - } - } - return false -} - -// Remove sub directories keys from the given workingDirectoryToFiles map. -// Keys: [dir/dir, dir/directory] -> [dir/dir, dir/directory] -// Keys: [dir, directory] -> [dir, directory] -// Keys: [dir/dir2, dir/dir2/dir3, dir/dir2/dir3/dir4] -> [dir/dir2] -// Values of removed sub directories will be added to the root directory. -func cleanSubDirectories(workingDirectoryToFiles map[string][]string) (result map[string][]string) { - result = make(map[string][]string) - for wd, files := range workingDirectoryToFiles { - root := getExistingRootDir(wd, workingDirectoryToFiles) - result[root] = append(result[root], files...) - } - return -} - -// Get the root directory of the given path according to the given workingDirectoryToIndicators map. -func getExistingRootDir(path string, workingDirectoryToIndicators map[string][]string) (root string) { - root = path - for wd := range workingDirectoryToIndicators { - parentWd := filepath.Dir(wd) - parentRoot := filepath.Dir(root) - if parentRoot != parentWd && strings.HasPrefix(root, wd) { - root = wd - } - } - return -} - -// DetectTechnologies tries to detect all technologies types according to the files in the given path. -// 'isCiSetup' will limit the search of possible techs to Maven, Gradle, and npm. -// 'recursive' will determine if the search will be limited to files in the root path or not. -func DetectTechnologies(path string, isCiSetup, recursive bool) (map[Technology]bool, error) { - var filesList []string - var err error - if recursive { - filesList, err = fileutils.ListFilesRecursiveWalkIntoDirSymlink(path, false) - } else { - filesList, err = fileutils.ListFiles(path, true) - } - if err != nil { - return nil, err - } - log.Info(fmt.Sprintf("Scanning %d file(s):%s", len(filesList), filesList)) - detectedTechnologies := detectTechnologiesByFilePaths(filesList, isCiSetup) - return detectedTechnologies, nil -} - -func detectTechnologiesByFilePaths(paths []string, isCiSetup bool) (detected map[Technology]bool) { - detected = make(map[Technology]bool) - exclude := make(map[Technology]bool) - for _, path := range paths { - for techName, techData := range technologiesData { - // If the detection is in a 'jf ci-setup' command, then the checked technology must be supported. - if !isCiSetup || (isCiSetup && techData.ciSetupSupport) { - // If the project contains a file/directory with a name that ends with an excluded suffix, then this technology is excluded. - for _, excludeFile := range techData.exclude { - if strings.HasSuffix(path, excludeFile) { - exclude[techName] = true - } - } - // If this technology was already excluded, there's no need to look for indicator files/directories. - if _, exist := exclude[techName]; !exist { - // If the project contains a file/directory with a name that ends with the indicator suffix, then the project probably uses this technology. - for _, indicator := range techData.indicators { - if strings.HasSuffix(path, indicator) { - detected[techName] = true - } - } - } - } - } - } - // Remove excluded technologies. - for excludeTech := range exclude { - delete(detected, excludeTech) - } - return detected -} - -// DetectedTechnologiesToSlice returns a string slice that includes all the names of the detected technologies. -func DetectedTechnologiesToSlice(detected map[Technology]bool) []string { - keys := make([]string, 0, len(detected)) - for tech := range detected { - keys = append(keys, string(tech)) - } - return keys -} - -func ToTechnologies(args []string) (technologies []Technology) { - for _, argument := range args { - technologies = append(technologies, Technology(argument)) - } - return -} - -func GetAllTechnologiesList() (technologies []Technology) { - for tech := range technologiesData { - technologies = append(technologies, tech) - } - return -} - -func ContainsApplicabilityScannableTech(technologies []Technology) bool { - for _, technology := range technologies { - if technology.ApplicabilityScannable() { - return true - } - } - return false -} diff --git a/utils/coreutils/techutils_test.go b/utils/coreutils/techutils_test.go deleted file mode 100644 index c69d58ebe..000000000 --- a/utils/coreutils/techutils_test.go +++ /dev/null @@ -1,509 +0,0 @@ -package coreutils - -import ( - "path/filepath" - "reflect" - "testing" - - "github.com/stretchr/testify/assert" - "golang.org/x/exp/maps" -) - -func TestDetectTechnologiesByFilePaths(t *testing.T) { - tests := []struct { - name string - paths []string - expected map[Technology]bool - }{ - {"simpleMavenTest", []string{"pom.xml"}, map[Technology]bool{Maven: true}}, - {"npmTest", []string{"../package.json"}, map[Technology]bool{Npm: true}}, - {"pnpmTest", []string{"../package.json", "pnpm-lock.yaml"}, map[Technology]bool{Pnpm: true}}, - {"yarnTest", []string{"./package.json", "./.yarn"}, map[Technology]bool{Yarn: true}}, - {"windowsGradleTest", []string{"c:\\users\\test\\package\\build.gradle"}, map[Technology]bool{Gradle: true}}, - {"windowsPipTest", []string{"c:\\users\\test\\package\\setup.py"}, map[Technology]bool{Pip: true}}, - {"windowsPipenvTest", []string{"c:\\users\\test\\package\\Pipfile"}, map[Technology]bool{Pipenv: true}}, - {"golangTest", []string{"/Users/eco/dev/jfrog-cli-core/go.mod"}, map[Technology]bool{Go: true}}, - {"windowsNugetTest", []string{"c:\\users\\test\\package\\project.sln"}, map[Technology]bool{Nuget: true, Dotnet: true}}, - {"noTechTest", []string{"pomxml"}, map[Technology]bool{}}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - detectedTech := detectTechnologiesByFilePaths(test.paths, false) - assert.True(t, reflect.DeepEqual(test.expected, detectedTech), "expected: %s, actual: %s", test.expected, detectedTech) - }) - } -} - -func TestMapFilesToRelevantWorkingDirectories(t *testing.T) { - noRequest := map[Technology][]string{} - noExclude := map[string][]Technology{} - - tests := []struct { - name string - paths []string - requestedDescriptors map[Technology][]string - expectedWorkingDir map[string][]string - expectedExcluded map[string][]Technology - }{ - { - name: "noTechTest", - paths: []string{"pomxml", filepath.Join("sub1", "file"), filepath.Join("sub", "sub", "file")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{}, - expectedExcluded: noExclude, - }, - { - name: "mavenTest", - paths: []string{"pom.xml", filepath.Join("sub1", "pom.xml"), filepath.Join("sub2", "pom.xml")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{ - ".": {"pom.xml"}, - "sub1": {filepath.Join("sub1", "pom.xml")}, - "sub2": {filepath.Join("sub2", "pom.xml")}, - }, - expectedExcluded: noExclude, - }, - { - name: "npmTest", - paths: []string{filepath.Join("dir", "package.json"), filepath.Join("dir", "package-lock.json"), filepath.Join("dir2", "npm-shrinkwrap.json")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{ - "dir": {filepath.Join("dir", "package.json"), filepath.Join("dir", "package-lock.json")}, - "dir2": {filepath.Join("dir2", "npm-shrinkwrap.json")}, - }, - expectedExcluded: noExclude, - }, - { - name: "pnpmTest", - paths: []string{filepath.Join("dir", "package.json"), filepath.Join("dir", "pnpm-lock.yaml")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{"dir": {filepath.Join("dir", "package.json"), filepath.Join("dir", "pnpm-lock.yaml")}}, - expectedExcluded: map[string][]Technology{"dir": {Npm, Yarn}}, - }, - { - name: "yarnTest", - paths: []string{filepath.Join("dir", "package.json"), filepath.Join("dir", ".yarn")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{"dir": {filepath.Join("dir", "package.json"), filepath.Join("dir", ".yarn")}}, - expectedExcluded: map[string][]Technology{"dir": {Npm, Pnpm}}, - }, - { - name: "golangTest", - paths: []string{filepath.Join("dir", "dir2", "go.mod")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{filepath.Join("dir", "dir2"): {filepath.Join("dir", "dir2", "go.mod")}}, - expectedExcluded: noExclude, - }, - { - name: "pipTest", - paths: []string{ - filepath.Join("users_dir", "test", "package", "setup.py"), - filepath.Join("users_dir", "test", "package", "blabla.txt"), - filepath.Join("users_dir", "test", "package2", "requirements.txt"), - }, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{ - filepath.Join("users_dir", "test", "package"): {filepath.Join("users_dir", "test", "package", "setup.py")}, - filepath.Join("users_dir", "test", "package2"): {filepath.Join("users_dir", "test", "package2", "requirements.txt")}}, - expectedExcluded: noExclude, - }, - { - name: "pipRequestedDescriptorTest", - paths: []string{filepath.Join("dir", "blabla.txt"), filepath.Join("dir", "somefile")}, - requestedDescriptors: map[Technology][]string{Pip: {"blabla.txt"}}, - expectedWorkingDir: map[string][]string{"dir": {filepath.Join("dir", "blabla.txt")}}, - expectedExcluded: noExclude, - }, - { - name: "pipenvTest", - paths: []string{filepath.Join("users", "test", "package", "Pipfile")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{filepath.Join("users", "test", "package"): {filepath.Join("users", "test", "package", "Pipfile")}}, - expectedExcluded: map[string][]Technology{filepath.Join("users", "test", "package"): {Pip}}, - }, - { - name: "gradleTest", - paths: []string{filepath.Join("users", "test", "package", "build.gradle"), filepath.Join("dir", "build.gradle.kts"), filepath.Join("dir", "file")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{ - filepath.Join("users", "test", "package"): {filepath.Join("users", "test", "package", "build.gradle")}, - "dir": {filepath.Join("dir", "build.gradle.kts")}, - }, - expectedExcluded: noExclude, - }, - { - name: "nugetTest", - paths: []string{filepath.Join("dir", "project.sln"), filepath.Join("dir", "sub1", "project.csproj"), filepath.Join("dir", "file")}, - requestedDescriptors: noRequest, - expectedWorkingDir: map[string][]string{ - "dir": {filepath.Join("dir", "project.sln")}, - filepath.Join("dir", "sub1"): {filepath.Join("dir", "sub1", "project.csproj")}, - }, - expectedExcluded: noExclude, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - detectedWd, detectedExcluded := mapFilesToRelevantWorkingDirectories(test.paths, test.requestedDescriptors) - // Assert working directories - expectedKeys := maps.Keys(test.expectedWorkingDir) - actualKeys := maps.Keys(detectedWd) - assert.ElementsMatch(t, expectedKeys, actualKeys, "expected: %s, actual: %s", expectedKeys, actualKeys) - for key, value := range test.expectedWorkingDir { - assert.ElementsMatch(t, value, detectedWd[key], "expected: %s, actual: %s", value, detectedWd[key]) - } - // Assert excluded - expectedKeys = maps.Keys(test.expectedExcluded) - actualKeys = maps.Keys(detectedExcluded) - assert.ElementsMatch(t, expectedKeys, actualKeys, "expected: %s, actual: %s", expectedKeys, actualKeys) - for key, value := range test.expectedExcluded { - assert.ElementsMatch(t, value, detectedExcluded[key], "expected: %s, actual: %s", value, detectedExcluded[key]) - } - }) - } -} - -func TestMapWorkingDirectoriesToTechnologies(t *testing.T) { - noRequestSpecialDescriptors := map[Technology][]string{} - noRequestTech := []Technology{} - tests := []struct { - name string - workingDirectoryToIndicators map[string][]string - excludedTechAtWorkingDir map[string][]Technology - requestedTechs []Technology - requestedDescriptors map[Technology][]string - - expected map[Technology]map[string][]string - }{ - { - name: "noTechTest", - workingDirectoryToIndicators: map[string][]string{}, - excludedTechAtWorkingDir: map[string][]Technology{}, - requestedTechs: noRequestTech, - requestedDescriptors: noRequestSpecialDescriptors, - expected: map[Technology]map[string][]string{}, - }, - { - name: "all techs test", - workingDirectoryToIndicators: map[string][]string{ - "folder": {filepath.Join("folder", "pom.xml")}, - filepath.Join("folder", "sub1"): {filepath.Join("folder", "sub1", "pom.xml")}, - filepath.Join("folder", "sub2"): {filepath.Join("folder", "sub2", "pom.xml")}, - "dir": {filepath.Join("dir", "package.json"), filepath.Join("dir", "package-lock.json"), filepath.Join("dir", "build.gradle.kts"), filepath.Join("dir", "project.sln")}, - "directory": {filepath.Join("directory", "npm-shrinkwrap.json")}, - "dir3": {filepath.Join("dir3", "package.json"), filepath.Join("dir3", ".yarn")}, - filepath.Join("dir3", "dir"): {filepath.Join("dir3", "dir", "package.json"), filepath.Join("dir3", "dir", "pnpm-lock.yaml")}, - filepath.Join("dir", "dir2"): {filepath.Join("dir", "dir2", "go.mod")}, - filepath.Join("users_dir", "test", "package"): {filepath.Join("users_dir", "test", "package", "setup.py")}, - filepath.Join("users_dir", "test", "package2"): {filepath.Join("users_dir", "test", "package2", "requirements.txt")}, - filepath.Join("users", "test", "package"): {filepath.Join("users", "test", "package", "Pipfile"), filepath.Join("users", "test", "package", "build.gradle")}, - filepath.Join("dir", "sub1"): {filepath.Join("dir", "sub1", "project.csproj")}, - }, - excludedTechAtWorkingDir: map[string][]Technology{ - filepath.Join("users", "test", "package"): {Pip}, - "dir3": {Npm}, - filepath.Join("dir3", "dir"): {Npm, Yarn}, - }, - requestedTechs: noRequestTech, - requestedDescriptors: noRequestSpecialDescriptors, - expected: map[Technology]map[string][]string{ - Maven: {"folder": {filepath.Join("folder", "pom.xml"), filepath.Join("folder", "sub1", "pom.xml"), filepath.Join("folder", "sub2", "pom.xml")}}, - Npm: { - "dir": {filepath.Join("dir", "package.json")}, - "directory": {}, - }, - Pnpm: {filepath.Join("dir3", "dir"): {filepath.Join("dir3", "dir", "package.json")}}, - Yarn: {"dir3": {filepath.Join("dir3", "package.json")}}, - Go: {filepath.Join("dir", "dir2"): {filepath.Join("dir", "dir2", "go.mod")}}, - Pip: { - filepath.Join("users_dir", "test", "package"): {filepath.Join("users_dir", "test", "package", "setup.py")}, - filepath.Join("users_dir", "test", "package2"): {filepath.Join("users_dir", "test", "package2", "requirements.txt")}, - }, - Pipenv: {filepath.Join("users", "test", "package"): {filepath.Join("users", "test", "package", "Pipfile")}}, - Gradle: { - "dir": {filepath.Join("dir", "build.gradle.kts")}, - filepath.Join("users", "test", "package"): {filepath.Join("users", "test", "package", "build.gradle")}, - }, - Nuget: {"dir": {filepath.Join("dir", "project.sln"), filepath.Join("dir", "sub1", "project.csproj")}}, - Dotnet: {"dir": {filepath.Join("dir", "project.sln"), filepath.Join("dir", "sub1", "project.csproj")}}, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - detectedTech := mapWorkingDirectoriesToTechnologies(test.workingDirectoryToIndicators, test.excludedTechAtWorkingDir, test.requestedTechs, test.requestedDescriptors) - expectedKeys := maps.Keys(test.expected) - detectedKeys := maps.Keys(detectedTech) - assert.ElementsMatch(t, expectedKeys, detectedKeys, "expected: %s, actual: %s", expectedKeys, detectedKeys) - for key, value := range test.expected { - actualKeys := maps.Keys(detectedTech[key]) - expectedKeys := maps.Keys(value) - assert.ElementsMatch(t, expectedKeys, actualKeys, "for tech %s, expected: %s, actual: %s", key, expectedKeys, actualKeys) - for innerKey, innerValue := range value { - assert.ElementsMatch(t, innerValue, detectedTech[key][innerKey], "expected: %s, actual: %s", innerValue, detectedTech[key][innerKey]) - } - } - }) - } -} - -func TestGetExistingRootDir(t *testing.T) { - tests := []struct { - name string - path string - workingDirectoryToIndicators map[string][]string - expected string - }{ - { - name: "empty", - path: "", - workingDirectoryToIndicators: map[string][]string{}, - expected: "", - }, - { - name: "no match", - path: "dir", - workingDirectoryToIndicators: map[string][]string{ - filepath.Join("folder", "sub1"): {filepath.Join("folder", "sub1", "pom.xml")}, - "dir2": {filepath.Join("dir2", "go.mod")}, - "dir3": {}, - filepath.Join("directory", "dir2"): {filepath.Join("directory", "dir2", "go.mod")}, - }, - expected: "dir", - }, - { - name: "match root", - path: filepath.Join("directory", "dir2"), - workingDirectoryToIndicators: map[string][]string{ - filepath.Join("folder", "sub1"): {filepath.Join("folder", "sub1", "pom.xml")}, - "dir2": {filepath.Join("dir2", "go.mod")}, - "dir3": {}, - filepath.Join("directory", "dir2"): {filepath.Join("directory", "dir2", "go.mod")}, - }, - expected: filepath.Join("directory", "dir2"), - }, - { - name: "match sub", - path: filepath.Join("directory", "dir2"), - workingDirectoryToIndicators: map[string][]string{ - filepath.Join("folder", "sub1"): {filepath.Join("folder", "sub1", "pom.xml")}, - "dir2": {filepath.Join("dir2", "go.mod")}, - "directory": {}, - filepath.Join("directory", "dir2"): {filepath.Join("directory", "dir2", "go.mod")}, - }, - expected: "directory", - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - assert.Equal(t, test.expected, getExistingRootDir(test.path, test.workingDirectoryToIndicators)) - }) - } -} - -func TestCleanSubDirectories(t *testing.T) { - tests := []struct { - name string - workingDirectoryToFiles map[string][]string - expected map[string][]string - }{ - { - name: "empty", - workingDirectoryToFiles: map[string][]string{}, - expected: map[string][]string{}, - }, - { - name: "no sub directories", - workingDirectoryToFiles: map[string][]string{ - "directory": {filepath.Join("directory", "file")}, - filepath.Join("dir", "dir"): {filepath.Join("dir", "dir", "file")}, - filepath.Join("dir", "directory"): {filepath.Join("dir", "directory", "file")}, - }, - expected: map[string][]string{ - "directory": {filepath.Join("directory", "file")}, - filepath.Join("dir", "dir"): {filepath.Join("dir", "dir", "file")}, - filepath.Join("dir", "directory"): {filepath.Join("dir", "directory", "file")}, - }, - }, - { - name: "sub directories", - workingDirectoryToFiles: map[string][]string{ - filepath.Join("dir", "dir"): {filepath.Join("dir", "dir", "file")}, - filepath.Join("dir", "directory"): {filepath.Join("dir", "directory", "file")}, - "dir": {filepath.Join("dir", "file")}, - "directory": {filepath.Join("directory", "file")}, - filepath.Join("dir", "dir2"): {filepath.Join("dir", "dir2", "file")}, - filepath.Join("dir", "dir2", "dir3"): {filepath.Join("dir", "dir2", "dir3", "file")}, - filepath.Join("dir", "dir2", "dir3", "dir4"): {filepath.Join("dir", "dir2", "dir3", "dir4", "file")}, - }, - expected: map[string][]string{ - "directory": {filepath.Join("directory", "file")}, - "dir": { - filepath.Join("dir", "file"), - filepath.Join("dir", "dir", "file"), - filepath.Join("dir", "directory", "file"), - filepath.Join("dir", "dir2", "file"), - filepath.Join("dir", "dir2", "dir3", "file"), - filepath.Join("dir", "dir2", "dir3", "dir4", "file"), - }, - }, - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - cleaned := cleanSubDirectories(test.workingDirectoryToFiles) - cleanedKeys := maps.Keys(cleaned) - expectedKeys := maps.Keys(test.expected) - assert.ElementsMatch(t, expectedKeys, cleanedKeys, "expected: %s, actual: %s", expectedKeys, cleanedKeys) - for key, value := range test.expected { - assert.ElementsMatch(t, value, cleaned[key], "expected: %s, actual: %s", value, cleaned[key]) - } - }) - } -} - -func TestGetTechInformationFromWorkingDir(t *testing.T) { - workingDirectoryToIndicators := map[string][]string{ - "folder": {filepath.Join("folder", "pom.xml")}, - filepath.Join("folder", "sub1"): {filepath.Join("folder", "sub1", "pom.xml")}, - filepath.Join("folder", "sub2"): {filepath.Join("folder", "sub2", "pom.xml")}, - "dir": {filepath.Join("dir", "package.json"), filepath.Join("dir", "package-lock.json"), filepath.Join("dir", "build.gradle.kts"), filepath.Join("dir", "project.sln"), filepath.Join("dir", "blabla.txt")}, - "directory": {filepath.Join("directory", "npm-shrinkwrap.json")}, - "dir3": {filepath.Join("dir3", "package.json"), filepath.Join("dir3", ".yarn")}, - filepath.Join("dir3", "dir"): {filepath.Join("dir3", "dir", "package.json"), filepath.Join("dir3", "dir", "pnpm-lock.yaml")}, - filepath.Join("dir", "dir2"): {filepath.Join("dir", "dir2", "go.mod")}, - filepath.Join("users_dir", "test", "package"): {filepath.Join("users_dir", "test", "package", "setup.py")}, - filepath.Join("users_dir", "test", "package2"): {filepath.Join("users_dir", "test", "package2", "requirements.txt")}, - filepath.Join("users", "test", "package"): {filepath.Join("users", "test", "package", "Pipfile"), filepath.Join("users", "test", "package", "build.gradle")}, - filepath.Join("dir", "sub1"): {filepath.Join("dir", "sub1", "project.csproj")}, - } - excludedTechAtWorkingDir := map[string][]Technology{ - filepath.Join("users", "test", "package"): {Pip}, - "dir3": {Npm, Pnpm}, - filepath.Join("dir3", "dir"): {Npm, Yarn}, - } - - tests := []struct { - name string - tech Technology - requestedDescriptors map[Technology][]string - expected map[string][]string - }{ - { - name: "mavenTest", - tech: Maven, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{ - "folder": { - filepath.Join("folder", "pom.xml"), - filepath.Join("folder", "sub1", "pom.xml"), - filepath.Join("folder", "sub2", "pom.xml"), - }, - }, - }, - { - name: "npmTest", - tech: Npm, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{ - "dir": {filepath.Join("dir", "package.json")}, - "directory": {}, - }, - }, - { - name: "pnpmTest", - tech: Pnpm, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{filepath.Join("dir3", "dir"): {filepath.Join("dir3", "dir", "package.json")}}, - }, - { - name: "yarnTest", - tech: Yarn, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{"dir3": {filepath.Join("dir3", "package.json")}}, - }, - { - name: "golangTest", - tech: Go, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{filepath.Join("dir", "dir2"): {filepath.Join("dir", "dir2", "go.mod")}}, - }, - { - name: "pipTest", - tech: Pip, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{ - filepath.Join("users_dir", "test", "package"): {filepath.Join("users_dir", "test", "package", "setup.py")}, - filepath.Join("users_dir", "test", "package2"): {filepath.Join("users_dir", "test", "package2", "requirements.txt")}, - }, - }, - { - name: "pipRequestedDescriptorTest", - tech: Pip, - requestedDescriptors: map[Technology][]string{Pip: {"blabla.txt"}}, - expected: map[string][]string{ - "dir": {filepath.Join("dir", "blabla.txt")}, - filepath.Join("users_dir", "test", "package"): {filepath.Join("users_dir", "test", "package", "setup.py")}, - filepath.Join("users_dir", "test", "package2"): {filepath.Join("users_dir", "test", "package2", "requirements.txt")}, - }, - }, - { - name: "pipenvTest", - tech: Pipenv, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{filepath.Join("users", "test", "package"): {filepath.Join("users", "test", "package", "Pipfile")}}, - }, - { - name: "gradleTest", - tech: Gradle, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{ - filepath.Join("users", "test", "package"): {filepath.Join("users", "test", "package", "build.gradle")}, - "dir": {filepath.Join("dir", "build.gradle.kts")}, - }, - }, - { - name: "nugetTest", - tech: Nuget, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{"dir": {filepath.Join("dir", "project.sln"), filepath.Join("dir", "sub1", "project.csproj")}}, - }, - { - name: "dotnetTest", - tech: Dotnet, - requestedDescriptors: map[Technology][]string{}, - expected: map[string][]string{"dir": {filepath.Join("dir", "project.sln"), filepath.Join("dir", "sub1", "project.csproj")}}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - techInformation := getTechInformationFromWorkingDir(test.tech, workingDirectoryToIndicators, excludedTechAtWorkingDir, test.requestedDescriptors) - expectedKeys := maps.Keys(test.expected) - actualKeys := maps.Keys(techInformation) - assert.ElementsMatch(t, expectedKeys, actualKeys, "expected: %s, actual: %s", expectedKeys, actualKeys) - for key, value := range test.expected { - assert.ElementsMatch(t, value, techInformation[key], "expected: %s, actual: %s", value, techInformation[key]) - } - }) - } -} - -func TestContainsApplicabilityScannableTech(t *testing.T) { - tests := []struct { - name string - technologies []Technology - want bool - }{ - {name: "contains supported and unsupported techs", technologies: []Technology{Nuget, Go, Npm}, want: true}, - {name: "contains supported techs only", technologies: []Technology{Maven, Yarn, Npm}, want: true}, - {name: "contains unsupported techs only", technologies: []Technology{Dotnet, Nuget, Go}, want: false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.want, ContainsApplicabilityScannableTech(tt.technologies)) - }) - } -} From f80a1af64bfeeb2f8d6ca50261044de8a39c3a76 Mon Sep 17 00:00:00 2001 From: Asaf Ambar Date: Sun, 9 Jun 2024 22:22:15 +0300 Subject: [PATCH 35/36] Utils enhancements to allow go support for JFrog Curation (#1187) --- artifactory/commands/golang/go.go | 22 +++++----- artifactory/commands/golang/go_test.go | 12 +++++- go.mod | 2 +- go.sum | 4 +- utils/golang/utils.go | 42 +++++++++++-------- utils/golang/utils_test.go | 56 ++++++++++++++++++++++++-- 6 files changed, 103 insertions(+), 35 deletions(-) diff --git a/artifactory/commands/golang/go.go b/artifactory/commands/golang/go.go index b6950c50a..4847855a5 100644 --- a/artifactory/commands/golang/go.go +++ b/artifactory/commands/golang/go.go @@ -153,14 +153,12 @@ func (gc *GoCommand) run() (err error) { if err != nil { return } - repoUrl, err := goutils.GetArtifactoryRemoteRepoUrl(resolverDetails, gc.resolverParams.TargetRepo()) + // If noFallback=false, missing packages will be fetched directly from VCS + repoUrl, err := goutils.GetArtifactoryRemoteRepoUrl(resolverDetails, gc.resolverParams.TargetRepo(), goutils.GoProxyUrlParams{Direct: !gc.noFallback}) if err != nil { return } - // If noFallback=false, missing packages will be fetched directly from VCS - if !gc.noFallback { - repoUrl += "|direct" - } + err = biutils.RunGo(gc.goArg, repoUrl) if errorutils.CheckError(err) != nil { err = coreutils.ConvertExitCodeError(err) @@ -330,19 +328,21 @@ func buildPackageVersionRequest(name, branchName string) string { return path.Join(packageVersionRequest, "latest.info") } -func SetArtifactoryAsResolutionServer(serverDetails *config.ServerDetails, depsRepo string) (err error) { - err = setGoProxy(serverDetails, depsRepo) - if err != nil { +func SetArtifactoryAsResolutionServer(serverDetails *config.ServerDetails, depsRepo string, goProxyParams goutils.GoProxyUrlParams) (err error) { + if err = setGoProxy(serverDetails, depsRepo, goProxyParams); err != nil { err = fmt.Errorf("failed while setting Artifactory as a dependencies resolution registry: %s", err.Error()) } return } -func setGoProxy(server *config.ServerDetails, remoteGoRepo string) error { - repoUrl, err := goutils.GetArtifactoryRemoteRepoUrl(server, remoteGoRepo) +func setGoProxy(server *config.ServerDetails, remoteGoRepo string, goProxyParams goutils.GoProxyUrlParams) error { + repoUrl, err := goutils.GetArtifactoryRemoteRepoUrl(server, remoteGoRepo, goProxyParams) if err != nil { return err } - repoUrl += "|direct" return os.Setenv("GOPROXY", repoUrl) } + +func SetGoModCache(cacheFolder string) error { + return os.Setenv("GOMODCACHE", cacheFolder) +} diff --git a/artifactory/commands/golang/go_test.go b/artifactory/commands/golang/go_test.go index ed899aad3..6aaf77d26 100644 --- a/artifactory/commands/golang/go_test.go +++ b/artifactory/commands/golang/go_test.go @@ -3,6 +3,7 @@ package golang import ( "fmt" "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" goutils "github.com/jfrog/jfrog-cli-core/v2/utils/golang" testsutils "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/stretchr/testify/assert" @@ -60,9 +61,18 @@ func TestSetArtifactoryAsResolutionServer(t *testing.T) { cleanup := testsutils.SetEnvWithCallbackAndAssert(t, "GOPROXY", "") defer cleanup() - assert.NoError(t, SetArtifactoryAsResolutionServer(server, repo)) + assert.NoError(t, SetArtifactoryAsResolutionServer(server, repo, goutils.GoProxyUrlParams{Direct: true})) serverUrlWithoutHttp := strings.TrimPrefix(server.ArtifactoryUrl, "http://") expectedGoProxy := fmt.Sprintf("http://%s:%s@%sapi/go/%s|direct", server.User, server.Password, serverUrlWithoutHttp, repo) assert.Equal(t, expectedGoProxy, os.Getenv("GOPROXY")) + + // Verify that the EndpointPrefix value is correctly added to the GOPROXY. + // In this test case, the endpoint prefix is set to api/curation/audit/. + // This parameter allows downloading dependencies from a custom API instead of the default one. + assert.NoError(t, SetArtifactoryAsResolutionServer(server, repo, goutils.GoProxyUrlParams{Direct: true, EndpointPrefix: coreutils.CurationPassThroughApi})) + + serverUrlWithoutHttp = strings.TrimPrefix(server.ArtifactoryUrl, "http://") + expectedGoProxy = fmt.Sprintf("http://%s:%s@%sapi/curation/audit/api/go/%s|direct", server.User, server.Password, serverUrlWithoutHttp, repo) + assert.Equal(t, expectedGoProxy, os.Getenv("GOPROXY")) } diff --git a/go.mod b/go.mod index f5b9ece9b..a321d6552 100644 --- a/go.mod +++ b/go.mod @@ -98,6 +98,6 @@ require ( replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 -// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev +replace github.com/jfrog/build-info-go => github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371 // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc diff --git a/go.sum b/go.sum index bb180023f..e468dfe92 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,8 @@ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer5 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371 h1:U7bqNQ40AfeC55m9v9r8vy/Iza4xrUJiJ2DYcE031Oo= +github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371/go.mod h1:5TH6zBwOpQxGXgn+WX4OlH4q5P4k1zE1sFksU5VDhbE= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= @@ -91,8 +93,6 @@ github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+ github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= -github.com/jfrog/build-info-go v1.9.27 h1:7RWJcajqtNNbGHuYkgOLUIG7mmRKF0yxC7mvYAbdVlU= -github.com/jfrog/build-info-go v1.9.27/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw= github.com/jfrog/gofrog v1.7.2 h1:VkAaA/9tmbw27IqgUOmaZWnO6ATUqL3vRzDnsROKATw= github.com/jfrog/gofrog v1.7.2/go.mod h1:WJFk88SR9Sr9mKl1bQBig7DmSdXiBGKV3WhL9O6jL9w= github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 h1:ERLE/L7YPr6aCUTeAnE8SXU5VOZHd5/XK16rM1TEpts= diff --git a/utils/golang/utils.go b/utils/golang/utils.go index ab4176111..645b23bad 100644 --- a/utils/golang/utils.go +++ b/utils/golang/utils.go @@ -9,6 +9,8 @@ import ( "io" "net/url" "os/exec" + "path" + "strings" ) type GoCmdConfig struct { @@ -83,33 +85,41 @@ func GetModuleName(projectDir string) (string, error) { return path, nil } -func GetDependenciesList(projectDir string) (map[string]bool, error) { - deps, err := utils.GetDependenciesList(projectDir, log.Logger) - if err != nil { - return nil, errorutils.CheckError(err) - } - return deps, nil +type GoProxyUrlParams struct { + // Fallback to retrieve the modules directly from the source if + // the module failed to be retrieved from the proxy. + // add |direct to the end of the url. + // example: https://gocenter.io|direct + Direct bool + // The path from baseUrl to the standard Go repository path + // URL structure: //api/go/ + EndpointPrefix string } -func GetDependenciesGraph(projectDir string) (map[string][]string, error) { - deps, err := utils.GetDependenciesGraph(projectDir, log.Logger) - if err != nil { - return nil, errorutils.CheckError(err) +func (gdu *GoProxyUrlParams) BuildUrl(url *url.URL, repoName string) string { + url.Path = path.Join(url.Path, gdu.EndpointPrefix, "api/go/", repoName) + + return gdu.addDirect(url.String()) +} + +func (gdu *GoProxyUrlParams) addDirect(url string) string { + if gdu.Direct && !strings.HasSuffix(url, "|direct") { + return url + "|direct" } - return deps, nil + return url } -func GetArtifactoryRemoteRepoUrl(serverDetails *config.ServerDetails, repo string) (string, error) { +func GetArtifactoryRemoteRepoUrl(serverDetails *config.ServerDetails, repo string, goProxyParams GoProxyUrlParams) (string, error) { authServerDetails, err := serverDetails.CreateArtAuthConfig() if err != nil { return "", err } - return getArtifactoryApiUrl(repo, authServerDetails) + return getArtifactoryApiUrl(repo, authServerDetails, goProxyParams) } // Gets the URL of the specified repository Go API in Artifactory. // The URL contains credentials (username and access token or password). -func getArtifactoryApiUrl(repoName string, details auth.ServiceDetails) (string, error) { +func getArtifactoryApiUrl(repoName string, details auth.ServiceDetails, goProxyParams GoProxyUrlParams) (string, error) { rtUrl, err := url.Parse(details.GetUrl()) if err != nil { return "", errorutils.CheckError(err) @@ -129,6 +139,6 @@ func getArtifactoryApiUrl(repoName string, details auth.ServiceDetails) (string, if password != "" { rtUrl.User = url.UserPassword(username, password) } - rtUrl.Path += "api/go/" + repoName - return rtUrl.String(), nil + + return goProxyParams.BuildUrl(rtUrl, repoName), nil } diff --git a/utils/golang/utils_test.go b/utils/golang/utils_test.go index c2326b21b..e6ec32041 100644 --- a/utils/golang/utils_test.go +++ b/utils/golang/utils_test.go @@ -4,6 +4,8 @@ import ( "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-client-go/artifactory/auth" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "net/url" "testing" ) @@ -13,7 +15,7 @@ func TestGetArtifactoryRemoteRepoUrl(t *testing.T) { AccessToken: "eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA", } repoName := "test-repo" - repoUrl, err := GetArtifactoryRemoteRepoUrl(server, repoName) + repoUrl, err := GetArtifactoryRemoteRepoUrl(server, repoName, GoProxyUrlParams{}) assert.NoError(t, err) assert.Equal(t, "https://test:eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA@server.com/artifactory/api/go/test-repo", repoUrl) } @@ -25,15 +27,22 @@ func TestGetArtifactoryApiUrl(t *testing.T) { // Test username and password details.SetUser("frog") details.SetPassword("passfrog") - url, err := getArtifactoryApiUrl("test-repo", details) + url, err := getArtifactoryApiUrl("test-repo", details, GoProxyUrlParams{}) assert.NoError(t, err) assert.Equal(t, "https://frog:passfrog@test.com/artifactory/api/go/test-repo", url) + // Test username and password with EndpointPrefix and direct + details.SetUser("frog") + details.SetPassword("passfrog") + url, err = getArtifactoryApiUrl("test-repo", details, GoProxyUrlParams{EndpointPrefix: "test", Direct: true}) + assert.NoError(t, err) + assert.Equal(t, "https://frog:passfrog@test.com/artifactory/test/api/go/test-repo|direct", url) + // Test access token // Set fake access token with username "test" details.SetUser("") details.SetAccessToken("eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA") - url, err = getArtifactoryApiUrl("test-repo", details) + url, err = getArtifactoryApiUrl("test-repo", details, GoProxyUrlParams{}) assert.NoError(t, err) assert.Equal(t, "https://test:eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA@test.com/artifactory/api/go/test-repo", url) @@ -42,7 +51,46 @@ func TestGetArtifactoryApiUrl(t *testing.T) { // Expect username to be "frog" details.SetUser("frog") details.SetAccessToken("eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA") - url, err = getArtifactoryApiUrl("test-repo", details) + url, err = getArtifactoryApiUrl("test-repo", details, GoProxyUrlParams{}) assert.NoError(t, err) assert.Equal(t, "https://frog:eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA@test.com/artifactory/api/go/test-repo", url) } + +func TestGoProxyUrlParams_BuildUrl(t *testing.T) { + tests := []struct { + name string + RepoName string + Direct bool + EndpointPrefix string + ExpectedUrl string + }{ + { + name: "Url Without direct or Prefix", + RepoName: "go", + ExpectedUrl: "https://test/api/go/go", + }, + { + name: "Url With direct", + RepoName: "go", + Direct: true, + ExpectedUrl: "https://test/api/go/go|direct", + }, + { + name: "Url With Prefix", + RepoName: "go", + EndpointPrefix: "prefix", + ExpectedUrl: "https://test/prefix/api/go/go", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + remoteUrl, err := url.Parse("https://test") + require.NoError(t, err) + gdu := &GoProxyUrlParams{ + Direct: tt.Direct, + EndpointPrefix: tt.EndpointPrefix, + } + assert.Equalf(t, tt.ExpectedUrl, gdu.BuildUrl(remoteUrl, tt.RepoName), "BuildUrl(%v, %v)", remoteUrl, tt.RepoName) + }) + } +} From d8879506936bba9f601b8326af4e337508004be8 Mon Sep 17 00:00:00 2001 From: Eyal Ben Moshe Date: Mon, 10 Jun 2024 11:00:23 +0300 Subject: [PATCH 36/36] Upgrade depedencies (#1192) --- go.mod | 8 ++++---- go.sum | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index a321d6552..9dfff0a10 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,9 @@ require ( github.com/google/uuid v1.6.0 github.com/gookit/color v1.5.4 github.com/jedib0t/go-pretty/v6 v6.5.9 - github.com/jfrog/build-info-go v1.9.27 + github.com/jfrog/build-info-go v1.9.29 github.com/jfrog/gofrog v1.7.2 - github.com/jfrog/jfrog-client-go v1.40.2 + github.com/jfrog/jfrog-client-go v1.41.0 github.com/magiconair/properties v1.8.7 github.com/manifoldco/promptui v0.9.0 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c @@ -96,8 +96,8 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 +// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 -replace github.com/jfrog/build-info-go => github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371 +// replace github.com/jfrog/build-info-go => github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371 // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc diff --git a/go.sum b/go.sum index e468dfe92..1cc7cde52 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,6 @@ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer5 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= -github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371 h1:U7bqNQ40AfeC55m9v9r8vy/Iza4xrUJiJ2DYcE031Oo= -github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371/go.mod h1:5TH6zBwOpQxGXgn+WX4OlH4q5P4k1zE1sFksU5VDhbE= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= @@ -93,10 +91,12 @@ github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+ github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w= github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI= +github.com/jfrog/build-info-go v1.9.29 h1:3vJ+kbk9PpU6wjisXi9c4qISNpYkISh/NmB5mq1ZlSY= +github.com/jfrog/build-info-go v1.9.29/go.mod h1:AzFJlN/yKfKuKcSBaGy5nNmKN1xzx6+XcRWAswCTLTA= github.com/jfrog/gofrog v1.7.2 h1:VkAaA/9tmbw27IqgUOmaZWnO6ATUqL3vRzDnsROKATw= github.com/jfrog/gofrog v1.7.2/go.mod h1:WJFk88SR9Sr9mKl1bQBig7DmSdXiBGKV3WhL9O6jL9w= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 h1:ERLE/L7YPr6aCUTeAnE8SXU5VOZHd5/XK16rM1TEpts= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04/go.mod h1:37RR4pYgXZM4w7tywyfRu8t2wagt0qf5wBtpDILWBsk= +github.com/jfrog/jfrog-client-go v1.41.0 h1:g5OTFvreOVQ6U/5LUXFJfA3Bc+AZCo2PO/EzCLxLbLE= +github.com/jfrog/jfrog-client-go v1.41.0/go.mod h1:AN+/mT2DIBE4oRZicJojqND2BEKLfA7f73i5rT3Lfcc= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=