From 5979ebb571c755650006c238ecf692cdb5e053ad Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Tue, 12 Mar 2024 17:10:07 +0200 Subject: [PATCH 01/16] Publish multiple npm workspaces packages (#1149) --- artifactory/commands/npm/publish.go | 117 +++++++++++------- artifactory/commands/npm/publish_test.go | 13 +- .../testdata/npm/npm-example-0.0.4.tgz | Bin 0 -> 1500 bytes artifactory/utils/npm/pack.go | 11 +- artifactory/utils/npm/pack_test.go | 78 ++++++++---- .../utils/testdata/npm/npmPackOutputV6 | 28 ----- .../utils/testdata/npm/npmPackOutputV7 | 28 ----- .../npm-workspaces/module1/package.json | 12 ++ .../npm-workspaces/module2/package.json | 12 ++ tests/testdata/npm-workspaces/package.json | 13 ++ 10 files changed, 175 insertions(+), 137 deletions(-) create mode 100644 artifactory/commands/testdata/npm/npm-example-0.0.4.tgz delete mode 100644 artifactory/utils/testdata/npm/npmPackOutputV6 delete mode 100644 artifactory/utils/testdata/npm/npmPackOutputV7 create mode 100644 tests/testdata/npm-workspaces/module1/package.json create mode 100644 tests/testdata/npm-workspaces/module2/package.json create mode 100644 tests/testdata/npm-workspaces/package.json diff --git a/artifactory/commands/npm/publish.go b/artifactory/commands/npm/publish.go index 5313d2d74..764fc1b73 100644 --- a/artifactory/commands/npm/publish.go +++ b/artifactory/commands/npm/publish.go @@ -3,6 +3,7 @@ package npm import ( "archive/tar" "compress/gzip" + "errors" "fmt" "io" "os" @@ -37,7 +38,7 @@ type NpmPublishCommandArgs struct { executablePath string workingDirectory string collectBuildInfo bool - packedFilePath string + packedFilePaths []string packageInfo *biutils.PackageInfo publishPath string tarballProvided bool @@ -172,11 +173,11 @@ func (npc *NpmPublishCommand) Run() (err error) { return err } // We should delete the tarball we created - return deleteCreatedTarballAndError(npc.packedFilePath, err) + return errors.Join(err, deleteCreatedTarball(npc.packedFilePaths)) } if !npc.tarballProvided { - if err := deleteCreatedTarball(npc.packedFilePath); err != nil { + if err := deleteCreatedTarball(npc.packedFilePaths); err != nil { return err } } @@ -217,6 +218,7 @@ func (npc *NpmPublishCommand) CommandName() string { } func (npc *NpmPublishCommand) preparePrerequisites() error { + npc.packedFilePaths = make([]string, 0) currentDir, err := os.Getwd() if err != nil { return errorutils.CheckError(err) @@ -251,7 +253,7 @@ func (npc *NpmPublishCommand) preparePrerequisites() error { func (npc *NpmPublishCommand) pack() error { log.Debug("Creating npm package.") - packageFileName, err := npm.Pack(npc.npmArgs, npc.executablePath) + packedFileNames, err := npm.Pack(npc.npmArgs, npc.executablePath) if err != nil { return err } @@ -261,8 +263,10 @@ func (npc *NpmPublishCommand) pack() error { return err } - npc.packedFilePath = filepath.Join(tarballDir, packageFileName) - log.Debug("Created npm package at", npc.packedFilePath) + for _, packageFileName := range packedFileNames { + npc.packedFilePaths = append(npc.packedFilePaths, filepath.Join(tarballDir, packageFileName)) + } + return nil } @@ -279,34 +283,36 @@ func (npc *NpmPublishCommand) getTarballDir() (string, error) { return dest, nil } -func (npc *NpmPublishCommand) publish() error { - log.Debug("Deploying npm package.") - if err := npc.readPackageInfoFromTarball(); err != nil { - return err - } - target := fmt.Sprintf("%s/%s", npc.repo, npc.packageInfo.GetDeployPath()) - - // If requested, perform a Xray binary scan before deployment. If a FailBuildError is returned, skip the deployment. - if npc.xrayScan { - fileSpec := spec.NewBuilder(). - Pattern(npc.packedFilePath). - Target(npc.repo + "/"). - BuildSpec() - err := commandsutils.ConditionalUploadScanFunc(npc.serverDetails, fileSpec, 1, npc.scanOutputFormat) - if err != nil { - return err +func (npc *NpmPublishCommand) publish() (err error) { + for _, packedFilePath := range npc.packedFilePaths { + log.Debug("Deploying npm package.") + if err = npc.readPackageInfoFromTarball(packedFilePath); err != nil { + return } + target := fmt.Sprintf("%s/%s", npc.repo, npc.packageInfo.GetDeployPath()) + + // If requested, perform a Xray binary scan before deployment. If a FailBuildError is returned, skip the deployment. + if npc.xrayScan { + fileSpec := spec.NewBuilder(). + Pattern(packedFilePath). + Target(npc.repo + "/"). + BuildSpec() + if err = commandsutils.ConditionalUploadScanFunc(npc.serverDetails, fileSpec, 1, npc.scanOutputFormat); err != nil { + return + } + } + err = errors.Join(err, npc.doDeploy(target, npc.serverDetails, packedFilePath)) } - return npc.doDeploy(target, npc.serverDetails) + return } -func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerDetails) error { +func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerDetails, packedFilePath string) error { servicesManager, err := utils.CreateServiceManager(artDetails, -1, 0, false) if err != nil { return err } up := services.NewUploadParams() - up.CommonParams = &specutils.CommonParams{Pattern: npc.packedFilePath, Target: target} + up.CommonParams = &specutils.CommonParams{Pattern: packedFilePath, Target: target} var totalFailed int if npc.collectBuildInfo || npc.detailedSummary { if npc.collectBuildInfo { @@ -341,12 +347,11 @@ func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerD } } if npc.detailedSummary { - npc.result.SetReader(summary.TransferDetailsReader) - npc.result.SetFailCount(totalFailed) - npc.result.SetSuccessCount(summary.TotalSucceeded) + if err = npc.setDetailedSummary(summary); err != nil { + return err + } } else { - err = summary.TransferDetailsReader.Close() - if err != nil { + if err = summary.TransferDetailsReader.Close(); err != nil { return err } } @@ -364,6 +369,29 @@ func (npc *NpmPublishCommand) doDeploy(target string, artDetails *config.ServerD 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) + if npc.result.Reader() == nil { + npc.result.SetReader(summary.TransferDetailsReader) + } else { + if err = npc.appendReader(summary); err != nil { + return + } + } + return +} + +func (npc *NpmPublishCommand) appendReader(summary *specutils.OperationSummary) error { + readersSlice := []*content.ContentReader{npc.result.Reader(), summary.TransferDetailsReader} + reader, err := content.MergeReaders(readersSlice, content.DefaultKey) + if err != nil { + return err + } + npc.result.SetReader(reader) + return nil +} + func (npc *NpmPublishCommand) setPublishPath() error { log.Debug("Reading Package Json.") @@ -394,13 +422,12 @@ 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 - npc.packedFilePath = npc.publishPath - return npc.readPackageInfoFromTarball() + return npc.readPackageInfoFromTarball(npc.publishPath) } -func (npc *NpmPublishCommand) readPackageInfoFromTarball() (err error) { - log.Debug("Extracting info from npm package:", npc.packedFilePath) - tarball, err := os.Open(npc.packedFilePath) +func (npc *NpmPublishCommand) readPackageInfoFromTarball(packedFilePath string) (err error) { + log.Debug("Extracting info from npm package:", npc.packedFilePaths) + tarball, err := os.Open(packedFilePath) if err != nil { return errorutils.CheckError(err) } @@ -420,7 +447,7 @@ func (npc *NpmPublishCommand) readPackageInfoFromTarball() (err error) { hdr, err := tarReader.Next() if err != nil { if err == io.EOF { - return errorutils.CheckErrorf("Could not find 'package.json' in the compressed npm package: " + npc.packedFilePath) + return errorutils.CheckErrorf("Could not find 'package.json' in the compressed npm package: " + packedFilePath) } return errorutils.CheckError(err) } @@ -436,18 +463,12 @@ func (npc *NpmPublishCommand) readPackageInfoFromTarball() (err error) { } } -func deleteCreatedTarballAndError(packedFilePath string, currentError error) error { - if err := deleteCreatedTarball(packedFilePath); err != nil { - errorText := fmt.Sprintf("Two errors occurred: \n%s \n%s", currentError, err) - return errorutils.CheckErrorf(errorText) - } - return currentError -} - -func deleteCreatedTarball(packedFilePath string) error { - if err := os.Remove(packedFilePath); err != nil { - return errorutils.CheckError(err) +func deleteCreatedTarball(packedFilesPath []string) error { + for _, packedFilePath := range packedFilesPath { + if err := os.Remove(packedFilePath); err != nil { + return errorutils.CheckError(err) + } + log.Debug("Successfully deleted the created npm package:", packedFilePath) } - log.Debug("Successfully deleted the created npm package:", packedFilePath) return nil } diff --git a/artifactory/commands/npm/publish_test.go b/artifactory/commands/npm/publish_test.go index 91174289e..fa3e412c6 100644 --- a/artifactory/commands/npm/publish_test.go +++ b/artifactory/commands/npm/publish_test.go @@ -9,10 +9,17 @@ import ( func TestReadPackageInfoFromTarball(t *testing.T) { npmPublish := NewNpmPublishCommand() - npmPublish.packedFilePath = filepath.Join("..", "testdata", "npm", "npm-example-0.0.3.tgz") - err := npmPublish.readPackageInfoFromTarball() - assert.NoError(t, err) + 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) + } diff --git a/artifactory/commands/testdata/npm/npm-example-0.0.4.tgz b/artifactory/commands/testdata/npm/npm-example-0.0.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5d3f4db173ff30266a3edc55e0ea3ad46ae82f82 GIT binary patch literal 1500 zcmV<21ta<&iwFP!00002|Ls>>Z`(E$&a-~SLGs{BZQ73G1jw)fY0@qodI^#i!_aLg zEzvSliPT8Su2JN_?;J|96enp{tP3!}3}VS7&;2_WXFUAKV=+KYrzf7oy*`y zFygOV8qsdi_g3eJAfOi(8o`~o5@sPxdzP!vNv+y=xrY?C1D^w+7q&FgiF3iD_Wp3# zgU_u~t(;J<|8|v$792y%iBE2jC0wf34YDuDgo@g&b3z~dO7Qz#k?5NaOQc2e_Gmml z>OpI?f5e9PH=@&>?fPCTEAzj6V)ARX^SJpx9v~JDpMT9TdAZG%|A*cZr%d(1p%3(2;<;mF(j2jVFmjhKVjzC`FSF z_lWFI%(Sh2W-Sfo+7x}7KDGD|Ci5B&R#uZY4jh+_;UVF#^XEv zf4I&6M_POE`r;KlE0R9g+k-cl^9w1K!HIEl#zUvg3NoV?G7=VMd6Iz5vrHQYGi@N{ zipNsLfVBfkFj?R#0-eFwz*oB94B~ zvfw!Zi@X>K$7O;TQngc%ffKPQJegB`U~O6t5F^|Q#K8>tp`PzO&kCRyWq`lYkNE!t zqxYonXT$V8Ji!CM-`MU~LSJWTC9+c)UdQ1bS^jg5h-3f(CEwe*wCiN_U&?ljo=CMq z(Bmj>VXl{CTN$asH;Ctd!+XcUh{0KjVG6DFyr^53t+xP1 zGupvE^L{MAQRISMhul?3v}Su1Y91>yEBqoeplSaUtO;W zYRJvIuPMu0j`_$a_9u8h)voFS>rzkiYvcpjFD`VOc9F!!Wsi|624yQ*v2`2j0u=!n zBPDvf$O)?cZSo>{o7hES#<3$|Tfx#8R_5Lo)bZ{;DZy~Rw*IW^bK~T`9#&sPi-H4e zkwvJzsHVLh7Y&xT9gAjUIH7}{c|s+YRhHZl$$|-kE8%W2kxPp1wqkV zh*!m?m_DfdlmVUkb@f6LG9(VnIaf4z5>8ekDD(dU{Bu}SU*+)Te644xl zPSDCbYr&15e{5yy1Hz`^2J4bnjLo+>NPLA0kMD4y%H6ELMZD_SXQKrB$te+~>nLQX z0XmGASE`cpu+uWn{hPdY(NL{1Mr<~Rrlr}Yp@fy~&%*86uI<{chu7cW{td?f8UO&z C9^x|q literal 0 HcmV?d00001 diff --git a/artifactory/utils/npm/pack.go b/artifactory/utils/npm/pack.go index 0cefe8cd8..9f9686709 100644 --- a/artifactory/utils/npm/pack.go +++ b/artifactory/utils/npm/pack.go @@ -8,13 +8,13 @@ import ( "github.com/jfrog/jfrog-client-go/utils/errorutils" ) -func Pack(npmFlags []string, executablePath string) (string, error) { +func Pack(npmFlags []string, executablePath string) ([]string, error) { configListCmdConfig := createPackCmdConfig(executablePath, npmFlags) output, err := gofrogcmd.RunCmdOutput(configListCmdConfig) if err != nil { - return "", errorutils.CheckError(err) + return []string{}, errorutils.CheckError(err) } - return getPackageFileNameFromOutput(output) + return getPackageFileNameFromOutput(output), nil } func createPackCmdConfig(executablePath string, splitFlags []string) *npmutils.NpmConfig { @@ -27,8 +27,7 @@ func createPackCmdConfig(executablePath string, splitFlags []string) *npmutils.N } } -func getPackageFileNameFromOutput(output string) (string, error) { +func getPackageFileNameFromOutput(output string) []string { output = strings.TrimSpace(output) - lines := strings.Split(output, "\n") - return strings.TrimSpace(lines[len(lines)-1]), nil + return strings.Split(output, "\n") } diff --git a/artifactory/utils/npm/pack_test.go b/artifactory/utils/npm/pack_test.go index 8b8533b4b..68ec6c5c8 100644 --- a/artifactory/utils/npm/pack_test.go +++ b/artifactory/utils/npm/pack_test.go @@ -1,36 +1,66 @@ package npm import ( + biutils "github.com/jfrog/build-info-go/build/utils" + "github.com/jfrog/build-info-go/utils" + "github.com/jfrog/jfrog-cli-core/v2/utils/tests" + "github.com/jfrog/jfrog-client-go/utils/log" + testsUtils "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/stretchr/testify/assert" "os" "path/filepath" "testing" ) -const testdataDir = "../testdata/npm/" +const minimumWorkspacesNpmVersion = "7.24.2" -func TestGetPackageFileNameFromOutput(t *testing.T) { - tests := []struct { - testName string - outputTestDataFile string - expectedPackageFilename string - }{ - {"Get package filename for npm 6", "npmPackOutputV6", "npm-example-0.0.3.tgz"}, - {"Get package filename for npm 7", "npmPackOutputV7", "npm-example-ver0.0.3.tgz"}, - } - for _, test := range tests { - t.Run(test.testName, func(t *testing.T) { - output, err := os.ReadFile(filepath.Join(testdataDir, test.outputTestDataFile)) - if err != nil { - assert.NoError(t, err) - return - } - actualFilename, err := getPackageFileNameFromOutput(string(output)) - if err != nil { - assert.NoError(t, err) - return - } - assert.Equal(t, test.expectedPackageFilename, actualFilename) - }) +func TestNpmPackWorkspaces(t *testing.T) { + + npmVersion, executablePath, err := biutils.GetNpmVersionAndExecPath(nil) + assert.NoError(t, err) + // In npm under v7 skip test + if npmVersion.Compare(minimumWorkspacesNpmVersion) > 0 { + log.Info("Test skipped as this function in not supported in npm version " + npmVersion.GetVersion()) + return } + + tmpDir, createTempDirCallback := tests.CreateTempDirWithCallbackAndAssert(t) + defer createTempDirCallback() + + npmProjectPath := filepath.Join("..", "..", "..", "tests", "testdata", "npm-workspaces") + err = utils.CopyDir(npmProjectPath, tmpDir, true, nil) + assert.NoError(t, err) + + cwd, err := os.Getwd() + assert.NoError(t, err) + chdirCallback := testsUtils.ChangeDirWithCallback(t, cwd, tmpDir) + defer chdirCallback() + + packedFileNames, err := Pack([]string{"--workspaces", "--verbose"}, executablePath) + assert.NoError(t, err) + + expected := []string{"module1-1.0.0.tgz", "module2-1.0.0.tgz"} + assert.Equal(t, expected, packedFileNames) +} + +func TestNpmPack(t *testing.T) { + + _, executablePath, err := biutils.GetNpmVersionAndExecPath(nil) + assert.NoError(t, err) + tmpDir, createTempDirCallback := tests.CreateTempDirWithCallbackAndAssert(t) + defer createTempDirCallback() + npmProjectPath := filepath.Join("..", "..", "..", "tests", "testdata", "npm-workspaces") + err = utils.CopyDir(npmProjectPath, tmpDir, false, nil) + assert.NoError(t, err) + + cwd, err := os.Getwd() + assert.NoError(t, err) + chdirCallback := testsUtils.ChangeDirWithCallback(t, cwd, tmpDir) + defer chdirCallback() + + packedFileNames, err := Pack([]string{"--verbose"}, executablePath) + assert.NoError(t, err) + + expected := []string{"npm-pack-test-1.0.0.tgz"} + assert.Equal(t, expected, packedFileNames) } diff --git a/artifactory/utils/testdata/npm/npmPackOutputV6 b/artifactory/utils/testdata/npm/npmPackOutputV6 deleted file mode 100644 index b0eb2668b..000000000 --- a/artifactory/utils/testdata/npm/npmPackOutputV6 +++ /dev/null @@ -1,28 +0,0 @@ -> npm-example@0.0.3 prepack /Users/robin/proj/project-examples/npm-example -> echo pre-helloworld - -pre-helloworld - -> npm-example@0.0.3 postpack /Users/robin/proj/project-examples/npm-example -> echo post-helloworld - -post-helloworld -npm notice -npm notice 📦 npm-example@0.0.3 -npm notice === Tarball Contents === -npm notice 181B helloworld.js -npm notice 276B package.json -npm notice 2.8kB README.md -npm notice 5.5kB npm-example-ver0.0.3.tgz -npm notice 97B .jfrog/projects/npm.yaml -npm notice === Tarball Details === -npm notice name: npm-example -npm notice version: 0.0.3 -npm notice filename: npm-example-0.0.3.tgz -npm notice package size: 7.5 kB -npm notice unpacked size: 8.8 kB -npm notice shasum: fd0a95ccbb62ff833cd89cf4bb5296486c9a63aa -npm notice integrity: sha512-pMRH9mUXGZzeC[...]eJk8tQc1qSbRA== -npm notice total files: 5 -npm notice -npm-example-0.0.3.tgz \ No newline at end of file diff --git a/artifactory/utils/testdata/npm/npmPackOutputV7 b/artifactory/utils/testdata/npm/npmPackOutputV7 deleted file mode 100644 index 602a97930..000000000 --- a/artifactory/utils/testdata/npm/npmPackOutputV7 +++ /dev/null @@ -1,28 +0,0 @@ -> npm-example@ver0.0.3 prepack -> echo pre-helloworld - -pre-helloworld - -> npm-example@ver0.0.3 postpack -> echo post-helloworld - -post-helloworld -npm notice -npm notice 📦 npm-example@ver0.0.3 -npm notice === Tarball Contents === -npm notice 2.8kB README.md -npm notice 97B .jfrog/projects/npm.yaml -npm notice 181B helloworld.js -npm notice 3.5kB npm-example-ver0.0.3.tgz -npm notice 279B package.json -npm notice === Tarball Details === -npm notice name: npm-example -npm notice version: ver0.0.3 -npm notice filename: npm-example-ver0.0.3.tgz -npm notice package size: 5.5 kB -npm notice unpacked size: 6.8 kB -npm notice shasum: e3af25617b6c58c7f803d919949fc3d8993ce9dc -npm notice integrity: sha512-nTrTk6ph83jLL[...]ipNTJhWUci8Wg== -npm notice total files: 5 -npm notice -npm-example-ver0.0.3.tgz \ No newline at end of file diff --git a/tests/testdata/npm-workspaces/module1/package.json b/tests/testdata/npm-workspaces/module1/package.json new file mode 100644 index 000000000..c98ade642 --- /dev/null +++ b/tests/testdata/npm-workspaces/module1/package.json @@ -0,0 +1,12 @@ +{ + "name": "module1", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/tests/testdata/npm-workspaces/module2/package.json b/tests/testdata/npm-workspaces/module2/package.json new file mode 100644 index 000000000..d584476e5 --- /dev/null +++ b/tests/testdata/npm-workspaces/module2/package.json @@ -0,0 +1,12 @@ +{ + "name": "module2", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/tests/testdata/npm-workspaces/package.json b/tests/testdata/npm-workspaces/package.json new file mode 100644 index 000000000..59c936a79 --- /dev/null +++ b/tests/testdata/npm-workspaces/package.json @@ -0,0 +1,13 @@ +{ + "name": "npm-pack-test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "workspaces": ["module1","module2"] +} From 662abefabe8e42f6e2720a2ead8b9693e848bdf5 Mon Sep 17 00:00:00 2001 From: Robi Nino Date: Sun, 17 Mar 2024 18:11:37 +0200 Subject: [PATCH 02/16] Artifactory Release Lifecycle Management - Support release bundles deletion (#1136) --- .../testdata/npm/npm-example-0.0.4.tgz | Bin 1500 -> 0 bytes go.mod | 2 +- go.sum | 4 +- lifecycle/common.go | 1 - lifecycle/createcommon.go | 1 + lifecycle/deletelocal.go | 132 +++++++++++++++ lifecycle/deleteremote.go | 159 ++++++++++++++++++ lifecycle/promote.go | 1 + 8 files changed, 296 insertions(+), 4 deletions(-) delete mode 100644 artifactory/commands/testdata/npm/npm-example-0.0.4.tgz create mode 100644 lifecycle/deletelocal.go create mode 100644 lifecycle/deleteremote.go diff --git a/artifactory/commands/testdata/npm/npm-example-0.0.4.tgz b/artifactory/commands/testdata/npm/npm-example-0.0.4.tgz deleted file mode 100644 index 5d3f4db173ff30266a3edc55e0ea3ad46ae82f82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1500 zcmV<21ta<&iwFP!00002|Ls>>Z`(E$&a-~SLGs{BZQ73G1jw)fY0@qodI^#i!_aLg zEzvSliPT8Su2JN_?;J|96enp{tP3!}3}VS7&;2_WXFUAKV=+KYrzf7oy*`y zFygOV8qsdi_g3eJAfOi(8o`~o5@sPxdzP!vNv+y=xrY?C1D^w+7q&FgiF3iD_Wp3# zgU_u~t(;J<|8|v$792y%iBE2jC0wf34YDuDgo@g&b3z~dO7Qz#k?5NaOQc2e_Gmml z>OpI?f5e9PH=@&>?fPCTEAzj6V)ARX^SJpx9v~JDpMT9TdAZG%|A*cZr%d(1p%3(2;<;mF(j2jVFmjhKVjzC`FSF z_lWFI%(Sh2W-Sfo+7x}7KDGD|Ci5B&R#uZY4jh+_;UVF#^XEv zf4I&6M_POE`r;KlE0R9g+k-cl^9w1K!HIEl#zUvg3NoV?G7=VMd6Iz5vrHQYGi@N{ zipNsLfVBfkFj?R#0-eFwz*oB94B~ zvfw!Zi@X>K$7O;TQngc%ffKPQJegB`U~O6t5F^|Q#K8>tp`PzO&kCRyWq`lYkNE!t zqxYonXT$V8Ji!CM-`MU~LSJWTC9+c)UdQ1bS^jg5h-3f(CEwe*wCiN_U&?ljo=CMq z(Bmj>VXl{CTN$asH;Ctd!+XcUh{0KjVG6DFyr^53t+xP1 zGupvE^L{MAQRISMhul?3v}Su1Y91>yEBqoeplSaUtO;W zYRJvIuPMu0j`_$a_9u8h)voFS>rzkiYvcpjFD`VOc9F!!Wsi|624yQ*v2`2j0u=!n zBPDvf$O)?cZSo>{o7hES#<3$|Tfx#8R_5Lo)bZ{;DZy~Rw*IW^bK~T`9#&sPi-H4e zkwvJzsHVLh7Y&xT9gAjUIH7}{c|s+YRhHZl$$|-kE8%W2kxPp1wqkV zh*!m?m_DfdlmVUkb@f6LG9(VnIaf4z5>8ekDD(dU{Bu}SU*+)Te644xl zPSDCbYr&15e{5yy1Hz`^2J4bnjLo+>NPLA0kMD4y%H6ELMZD_SXQKrB$te+~>nLQX z0XmGASE`cpu+uWn{hPdY(NL{1Mr<~Rrlr}Yp@fy~&%*86uI<{chu7cW{td?f8UO&z C9^x|q diff --git a/go.mod b/go.mod index 0cc3899cd..4e010a20e 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.20240228121257-3414cc0ffcb6 +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240317160615-e419c2a9e723 replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c diff --git a/go.sum b/go.sum index 172a51532..b61111a8f 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c h1:M1QiuCYGC github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c/go.mod h1:QHcKuesY4MrBVBuEwwBz4uIsX6mwYuMEDV09ng4AvAU= 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.20240228121257-3414cc0ffcb6 h1:W+79g2W3ARRhIZtBfG0t73fi4IlyiIRWwdm1tajOkkc= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240228121257-3414cc0ffcb6/go.mod h1:WhVrqiqhSNFwj58/RQIrJEd28PHH1LTD4eWE0vBXv1o= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240317160615-e419c2a9e723 h1:0N/fdI2PXLjdWZieh7ib+6gb87yw3x22V7t1YZJvWOA= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240317160615-e419c2a9e723/go.mod h1:NB8tYFgkWtn+wHsKC+aYC75aLnS6yW81d8JAFTBxsi0= 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/common.go b/lifecycle/common.go index e185cb578..b5cf6de7d 100644 --- a/lifecycle/common.go +++ b/lifecycle/common.go @@ -14,7 +14,6 @@ type releaseBundleCmd struct { serverDetails *config.ServerDetails releaseBundleName string releaseBundleVersion string - signingKeyName string sync bool rbProjectKey string } diff --git a/lifecycle/createcommon.go b/lifecycle/createcommon.go index 4d5fba599..b5a83ee07 100644 --- a/lifecycle/createcommon.go +++ b/lifecycle/createcommon.go @@ -6,6 +6,7 @@ import ( type ReleaseBundleCreateCommand struct { releaseBundleCmd + signingKeyName string buildsSpecPath string releaseBundlesSpecPath string } diff --git a/lifecycle/deletelocal.go b/lifecycle/deletelocal.go new file mode 100644 index 000000000..d1e434aa8 --- /dev/null +++ b/lifecycle/deletelocal.go @@ -0,0 +1,132 @@ +package lifecycle + +import ( + "errors" + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/lifecycle" + "github.com/jfrog/jfrog-client-go/lifecycle/services" + "github.com/jfrog/jfrog-client-go/utils/log" + "strings" +) + +type ReleaseBundleDeleteCommand struct { + releaseBundleCmd + environment string + quiet bool +} + +func NewReleaseBundleDeleteCommand() *ReleaseBundleDeleteCommand { + return &ReleaseBundleDeleteCommand{} +} + +func (rbd *ReleaseBundleDeleteCommand) SetServerDetails(serverDetails *config.ServerDetails) *ReleaseBundleDeleteCommand { + rbd.serverDetails = serverDetails + return rbd +} + +func (rbd *ReleaseBundleDeleteCommand) SetReleaseBundleName(releaseBundleName string) *ReleaseBundleDeleteCommand { + rbd.releaseBundleName = releaseBundleName + return rbd +} + +func (rbd *ReleaseBundleDeleteCommand) SetReleaseBundleVersion(releaseBundleVersion string) *ReleaseBundleDeleteCommand { + rbd.releaseBundleVersion = releaseBundleVersion + return rbd +} + +func (rbd *ReleaseBundleDeleteCommand) SetSync(sync bool) *ReleaseBundleDeleteCommand { + rbd.sync = sync + return rbd +} + +func (rbd *ReleaseBundleDeleteCommand) SetReleaseBundleProject(rbProjectKey string) *ReleaseBundleDeleteCommand { + rbd.rbProjectKey = rbProjectKey + return rbd +} + +func (rbd *ReleaseBundleDeleteCommand) SetEnvironment(environment string) *ReleaseBundleDeleteCommand { + rbd.environment = environment + return rbd +} + +func (rbd *ReleaseBundleDeleteCommand) SetQuiet(quiet bool) *ReleaseBundleDeleteCommand { + rbd.quiet = quiet + return rbd +} + +func (rbd *ReleaseBundleDeleteCommand) CommandName() string { + return "rb_delete" +} + +func (rbd *ReleaseBundleDeleteCommand) ServerDetails() (*config.ServerDetails, error) { + return rbd.serverDetails, nil +} + +func (rbd *ReleaseBundleDeleteCommand) Run() error { + if err := validateArtifactoryVersionSupported(rbd.serverDetails); err != nil { + return err + } + + servicesManager, rbDetails, queryParams, err := rbd.getPrerequisites() + if err != nil { + return err + } + + if rbd.environment != "" { + return rbd.deletePromotionsOnly(servicesManager, rbDetails, queryParams) + } + return rbd.deleteLocalReleaseBundle(servicesManager, rbDetails, queryParams) +} + +func (rbd *ReleaseBundleDeleteCommand) deletePromotionsOnly(servicesManager *lifecycle.LifecycleServicesManager, + rbDetails services.ReleaseBundleDetails, commonQueryParams services.CommonOptionalQueryParams) error { + + deletionSubject := fmt.Sprintf("all promotions to environment '%s' of release bundle '%s/%s'", rbd.environment, rbd.releaseBundleName, rbd.releaseBundleVersion) + if !rbd.confirmDelete(deletionSubject) { + return nil + } + + optionalQueryParams := services.GetPromotionsOptionalQueryParams{ProjectKey: commonQueryParams.ProjectKey} + response, err := servicesManager.GetReleaseBundleVersionPromotions(rbDetails, optionalQueryParams) + if err != nil { + return err + } + success := 0 + fail := 0 + for _, promotion := range response.Promotions { + if strings.EqualFold(promotion.Environment, rbd.environment) { + if curErr := servicesManager.DeleteReleaseBundleVersionPromotion(rbDetails, commonQueryParams, promotion.CreatedMillis.String()); curErr != nil { + err = errors.Join(err, curErr) + fail++ + } else { + success++ + } + } + } + if success == 0 && fail == 0 { + log.Info(fmt.Sprintf("No promotions were found for environment '%s'", rbd.environment)) + } else { + log.Info(fmt.Sprintf("Promotions deleted successfully: %d, failed: %d", success, fail)) + } + + return err +} + +func (rbd *ReleaseBundleDeleteCommand) deleteLocalReleaseBundle(servicesManager *lifecycle.LifecycleServicesManager, + rbDetails services.ReleaseBundleDetails, queryParams services.CommonOptionalQueryParams) error { + deletionSubject := fmt.Sprintf("release bundle '%s/%s' locally with all its promotions", rbd.releaseBundleName, rbd.releaseBundleVersion) + if !rbd.confirmDelete(deletionSubject) { + return nil + } + return servicesManager.DeleteReleaseBundleVersion(rbDetails, queryParams) +} + +func (rbd *ReleaseBundleDeleteCommand) confirmDelete(deletionSubject string) bool { + if rbd.quiet { + return true + } + return coreutils.AskYesNo( + fmt.Sprintf("Are you sure you want to delete %s?\n"+avoidConfirmationMsg, deletionSubject), false) +} diff --git a/lifecycle/deleteremote.go b/lifecycle/deleteremote.go new file mode 100644 index 000000000..6b1665131 --- /dev/null +++ b/lifecycle/deleteremote.go @@ -0,0 +1,159 @@ +package lifecycle + +import ( + "encoding/json" + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/common/spec" + "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/lifecycle" + "github.com/jfrog/jfrog-client-go/lifecycle/services" + clientutils "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/utils/distribution" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/jfrog/jfrog-client-go/utils/log" +) + +const avoidConfirmationMsg = "You can avoid this confirmation message by adding --quiet to the command." + +type ReleaseBundleRemoteDeleteCommand struct { + releaseBundleCmd + distributionRules *spec.DistributionRules + dryRun bool + quiet bool + maxWaitMinutes int +} + +func NewReleaseBundleRemoteDeleteCommand() *ReleaseBundleRemoteDeleteCommand { + return &ReleaseBundleRemoteDeleteCommand{} +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetServerDetails(serverDetails *config.ServerDetails) *ReleaseBundleRemoteDeleteCommand { + rbd.serverDetails = serverDetails + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetReleaseBundleName(releaseBundleName string) *ReleaseBundleRemoteDeleteCommand { + rbd.releaseBundleName = releaseBundleName + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetReleaseBundleVersion(releaseBundleVersion string) *ReleaseBundleRemoteDeleteCommand { + rbd.releaseBundleVersion = releaseBundleVersion + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetSync(sync bool) *ReleaseBundleRemoteDeleteCommand { + rbd.sync = sync + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetReleaseBundleProject(rbProjectKey string) *ReleaseBundleRemoteDeleteCommand { + rbd.rbProjectKey = rbProjectKey + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetDistributionRules(distributionRules *spec.DistributionRules) *ReleaseBundleRemoteDeleteCommand { + rbd.distributionRules = distributionRules + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetDryRun(dryRun bool) *ReleaseBundleRemoteDeleteCommand { + rbd.dryRun = dryRun + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetQuiet(quiet bool) *ReleaseBundleRemoteDeleteCommand { + rbd.quiet = quiet + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) SetMaxWaitMinutes(maxWaitMinutes int) *ReleaseBundleRemoteDeleteCommand { + rbd.maxWaitMinutes = maxWaitMinutes + return rbd +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) CommandName() string { + return "rb_remote_delete" +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) ServerDetails() (*config.ServerDetails, error) { + return rbd.serverDetails, nil +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) Run() error { + if err := validateArtifactoryVersionSupported(rbd.serverDetails); err != nil { + return err + } + + servicesManager, rbDetails, queryParams, err := rbd.getPrerequisites() + if err != nil { + return err + } + + return rbd.deleteRemote(servicesManager, rbDetails, queryParams) +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) deleteRemote(servicesManager *lifecycle.LifecycleServicesManager, + rbDetails services.ReleaseBundleDetails, queryParams services.CommonOptionalQueryParams) error { + + confirm, err := rbd.confirmDelete() + if err != nil || !confirm { + return err + } + + aggregatedRules := rbd.getAggregatedDistRules() + + return servicesManager.RemoteDeleteReleaseBundle(rbDetails, services.ReleaseBundleRemoteDeleteParams{ + DistributionRules: aggregatedRules, + DryRun: rbd.dryRun, + MaxWaitMinutes: rbd.maxWaitMinutes, + CommonOptionalQueryParams: queryParams, + }) +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) distributionRulesEmpty() bool { + return rbd.distributionRules == nil || + len(rbd.distributionRules.DistributionRules) == 0 || + len(rbd.distributionRules.DistributionRules) == 1 && rbd.distributionRules.DistributionRules[0].IsEmpty() +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) confirmDelete() (bool, error) { + if rbd.quiet { + return true, nil + } + + message := fmt.Sprintf("Are you sure you want to delete the release bundle '%s/%s' remotely ", rbd.releaseBundleName, rbd.releaseBundleVersion) + if rbd.distributionRulesEmpty() { + message += "from all edges?" + } else { + var distributionRulesBodies []distribution.DistributionRulesBody + for _, rule := range rbd.distributionRules.DistributionRules { + distributionRulesBodies = append(distributionRulesBodies, distribution.DistributionRulesBody{ + SiteName: rule.SiteName, + CityName: rule.CityName, + CountryCodes: rule.CountryCodes, + }) + } + bytes, err := json.Marshal(distributionRulesBodies) + if err != nil { + return false, errorutils.CheckError(err) + } + + log.Output(clientutils.IndentJson(bytes)) + message += "from all edges with the above distribution rules?" + } + + return coreutils.AskYesNo(message+"\n"+avoidConfirmationMsg, false), nil +} + +func (rbd *ReleaseBundleRemoteDeleteCommand) getAggregatedDistRules() (aggregatedRules []*distribution.DistributionCommonParams) { + if rbd.distributionRulesEmpty() { + aggregatedRules = append(aggregatedRules, &distribution.DistributionCommonParams{SiteName: "*"}) + } else { + for _, rules := range rbd.distributionRules.DistributionRules { + aggregatedRules = append(aggregatedRules, rules.ToDistributionCommonParams()) + } + } + return +} diff --git a/lifecycle/promote.go b/lifecycle/promote.go index 0cf8b64d0..fb078ff36 100644 --- a/lifecycle/promote.go +++ b/lifecycle/promote.go @@ -10,6 +10,7 @@ import ( type ReleaseBundlePromoteCommand struct { releaseBundleCmd + signingKeyName string environment string includeReposPatterns []string excludeReposPatterns []string From b785b7d7f6939a6d1972182aa5abdf214587d2db Mon Sep 17 00:00:00 2001 From: Robi Nino Date: Mon, 18 Mar 2024 08:58:53 +0200 Subject: [PATCH 03/16] Artifactory Release Lifecycle Management - Support distribution sync and project (#1140) --- go.mod | 2 +- go.sum | 4 +-- lifecycle/common.go | 20 ++++++++++++++ lifecycle/distribute.go | 60 ++++++++++++++++++++++++++--------------- 4 files changed, 61 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 4e010a20e..2d8febd38 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.20240317160615-e419c2a9e723 +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240318065424-90669dbbcc54 replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c diff --git a/go.sum b/go.sum index b61111a8f..909812c3f 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c h1:M1QiuCYGC github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c/go.mod h1:QHcKuesY4MrBVBuEwwBz4uIsX6mwYuMEDV09ng4AvAU= 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.20240317160615-e419c2a9e723 h1:0N/fdI2PXLjdWZieh7ib+6gb87yw3x22V7t1YZJvWOA= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240317160615-e419c2a9e723/go.mod h1:NB8tYFgkWtn+wHsKC+aYC75aLnS6yW81d8JAFTBxsi0= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240318065424-90669dbbcc54 h1:FTrss/ffJPjTHOOhQ8P+8DrkGYkxcaHlxp12nOfeZJQ= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240318065424-90669dbbcc54/go.mod h1:NB8tYFgkWtn+wHsKC+aYC75aLnS6yW81d8JAFTBxsi0= 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/common.go b/lifecycle/common.go index b5cf6de7d..5e1b2d0a2 100644 --- a/lifecycle/common.go +++ b/lifecycle/common.go @@ -2,10 +2,12 @@ package lifecycle import ( "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-client-go/lifecycle" "github.com/jfrog/jfrog-client-go/lifecycle/services" clientUtils "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/utils/distribution" ) const minimalLifecycleArtifactoryVersion = "7.63.2" @@ -48,3 +50,21 @@ func validateArtifactoryVersionSupported(serverDetails *config.ServerDetails) er return clientUtils.ValidateMinimumVersion(clientUtils.Artifactory, versionStr, minimalLifecycleArtifactoryVersion) } + +// If distribution rules are empty, distribute to all edges. +func getAggregatedDistRules(distributionRules *spec.DistributionRules) (aggregatedRules []*distribution.DistributionCommonParams) { + if isDistributionRulesEmpty(distributionRules) { + aggregatedRules = append(aggregatedRules, &distribution.DistributionCommonParams{SiteName: "*"}) + } else { + for _, rules := range distributionRules.DistributionRules { + aggregatedRules = append(aggregatedRules, rules.ToDistributionCommonParams()) + } + } + return +} + +func isDistributionRulesEmpty(distributionRules *spec.DistributionRules) bool { + return distributionRules == nil || + len(distributionRules.DistributionRules) == 0 || + len(distributionRules.DistributionRules) == 1 && distributionRules.DistributionRules[0].IsEmpty() +} diff --git a/lifecycle/distribute.go b/lifecycle/distribute.go index 76a187330..76165ef56 100644 --- a/lifecycle/distribute.go +++ b/lifecycle/distribute.go @@ -1,21 +1,19 @@ package lifecycle import ( - "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-client-go/lifecycle/services" - "github.com/jfrog/jfrog-client-go/utils/distribution" ) type ReleaseBundleDistributeCommand struct { - serverDetails *config.ServerDetails - distributeBundlesParams distribution.DistributionParams - distributionRules *spec.DistributionRules - dryRun bool - autoCreateRepo bool - pathMappingPattern string - pathMappingTarget string + releaseBundleCmd + distributionRules *spec.DistributionRules + dryRun bool + autoCreateRepo bool + pathMappingPattern string + pathMappingTarget string + maxWaitMinutes int } func NewReleaseBundleDistributeCommand() *ReleaseBundleDistributeCommand { @@ -27,8 +25,18 @@ func (rbd *ReleaseBundleDistributeCommand) SetServerDetails(serverDetails *confi return rbd } -func (rbd *ReleaseBundleDistributeCommand) SetDistributeBundleParams(params distribution.DistributionParams) *ReleaseBundleDistributeCommand { - rbd.distributeBundlesParams = params +func (rbd *ReleaseBundleDistributeCommand) SetReleaseBundleName(releaseBundleName string) *ReleaseBundleDistributeCommand { + rbd.releaseBundleName = releaseBundleName + return rbd +} + +func (rbd *ReleaseBundleDistributeCommand) SetReleaseBundleVersion(releaseBundleVersion string) *ReleaseBundleDistributeCommand { + rbd.releaseBundleVersion = releaseBundleVersion + return rbd +} + +func (rbd *ReleaseBundleDistributeCommand) SetReleaseBundleProject(rbProjectKey string) *ReleaseBundleDistributeCommand { + rbd.rbProjectKey = rbProjectKey return rbd } @@ -57,33 +65,41 @@ func (rbd *ReleaseBundleDistributeCommand) SetPathMappingTarget(pathMappingTarge return rbd } +func (rbd *ReleaseBundleDistributeCommand) SetSync(sync bool) *ReleaseBundleDistributeCommand { + rbd.sync = sync + return rbd +} + +func (rbd *ReleaseBundleDistributeCommand) SetMaxWaitMinutes(maxWaitMinutes int) *ReleaseBundleDistributeCommand { + rbd.maxWaitMinutes = maxWaitMinutes + return rbd +} + func (rbd *ReleaseBundleDistributeCommand) Run() error { if err := validateArtifactoryVersionSupported(rbd.serverDetails); err != nil { return err } - servicesManager, err := utils.CreateLifecycleServiceManager(rbd.serverDetails, rbd.dryRun) + servicesManager, rbDetails, _, err := rbd.getPrerequisites() if err != nil { return err } - for _, rule := range rbd.distributionRules.DistributionRules { - rbd.distributeBundlesParams.DistributionRules = append(rbd.distributeBundlesParams.DistributionRules, rule.ToDistributionCommonParams()) - } - pathMapping := services.PathMapping{ Pattern: rbd.pathMappingPattern, Target: rbd.pathMappingTarget, } - return servicesManager.DistributeReleaseBundle(services.ReleaseBundleDetails{ - ReleaseBundleName: rbd.distributeBundlesParams.Name, - ReleaseBundleVersion: rbd.distributeBundlesParams.Version, - }, services.DistributeReleaseBundleParams{ + distributeParams := services.DistributeReleaseBundleParams{ + Sync: rbd.sync, AutoCreateRepo: rbd.autoCreateRepo, - DistributionRules: rbd.distributeBundlesParams.DistributionRules, + MaxWaitMinutes: rbd.maxWaitMinutes, + DistributionRules: getAggregatedDistRules(rbd.distributionRules), PathMappings: []services.PathMapping{pathMapping}, - }) + ProjectKey: rbd.rbProjectKey, + } + + return servicesManager.DistributeReleaseBundle(rbDetails, distributeParams) } func (rbd *ReleaseBundleDistributeCommand) ServerDetails() (*config.ServerDetails, error) { From d0b217bd56c360a10d462c3f67e3921478b57503 Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Mon, 18 Mar 2024 11:54:34 +0200 Subject: [PATCH 04/16] Fix npm publish test (#1156) --- .../commands/testdata/npm/npm-example-0.0.4.tgz | Bin 0 -> 1500 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 artifactory/commands/testdata/npm/npm-example-0.0.4.tgz diff --git a/artifactory/commands/testdata/npm/npm-example-0.0.4.tgz b/artifactory/commands/testdata/npm/npm-example-0.0.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5d3f4db173ff30266a3edc55e0ea3ad46ae82f82 GIT binary patch literal 1500 zcmV<21ta<&iwFP!00002|Ls>>Z`(E$&a-~SLGs{BZQ73G1jw)fY0@qodI^#i!_aLg zEzvSliPT8Su2JN_?;J|96enp{tP3!}3}VS7&;2_WXFUAKV=+KYrzf7oy*`y zFygOV8qsdi_g3eJAfOi(8o`~o5@sPxdzP!vNv+y=xrY?C1D^w+7q&FgiF3iD_Wp3# zgU_u~t(;J<|8|v$792y%iBE2jC0wf34YDuDgo@g&b3z~dO7Qz#k?5NaOQc2e_Gmml z>OpI?f5e9PH=@&>?fPCTEAzj6V)ARX^SJpx9v~JDpMT9TdAZG%|A*cZr%d(1p%3(2;<;mF(j2jVFmjhKVjzC`FSF z_lWFI%(Sh2W-Sfo+7x}7KDGD|Ci5B&R#uZY4jh+_;UVF#^XEv zf4I&6M_POE`r;KlE0R9g+k-cl^9w1K!HIEl#zUvg3NoV?G7=VMd6Iz5vrHQYGi@N{ zipNsLfVBfkFj?R#0-eFwz*oB94B~ zvfw!Zi@X>K$7O;TQngc%ffKPQJegB`U~O6t5F^|Q#K8>tp`PzO&kCRyWq`lYkNE!t zqxYonXT$V8Ji!CM-`MU~LSJWTC9+c)UdQ1bS^jg5h-3f(CEwe*wCiN_U&?ljo=CMq z(Bmj>VXl{CTN$asH;Ctd!+XcUh{0KjVG6DFyr^53t+xP1 zGupvE^L{MAQRISMhul?3v}Su1Y91>yEBqoeplSaUtO;W zYRJvIuPMu0j`_$a_9u8h)voFS>rzkiYvcpjFD`VOc9F!!Wsi|624yQ*v2`2j0u=!n zBPDvf$O)?cZSo>{o7hES#<3$|Tfx#8R_5Lo)bZ{;DZy~Rw*IW^bK~T`9#&sPi-H4e zkwvJzsHVLh7Y&xT9gAjUIH7}{c|s+YRhHZl$$|-kE8%W2kxPp1wqkV zh*!m?m_DfdlmVUkb@f6LG9(VnIaf4z5>8ekDD(dU{Bu}SU*+)Te644xl zPSDCbYr&15e{5yy1Hz`^2J4bnjLo+>NPLA0kMD4y%H6ELMZD_SXQKrB$te+~>nLQX z0XmGASE`cpu+uWn{hPdY(NL{1Mr<~Rrlr}Yp@fy~&%*86uI<{chu7cW{td?f8UO&z C9^x|q literal 0 HcmV?d00001 From d80615689adc2084e82f9b83c919e7679d43878f Mon Sep 17 00:00:00 2001 From: Robi Nino Date: Mon, 18 Mar 2024 13:36:20 +0200 Subject: [PATCH 05/16] Artifactory Release Lifecycle Management - Support release bundle creation by aql and artifacts (#1142) --- artifactory/commands/generic/search.go | 28 ++-- artifactory/utils/search.go | 27 ++++ go.mod | 2 +- go.sum | 4 +- lifecycle/createcommon.go | 179 ++++++++++++++++++++++++- lifecycle/createcommon_test.go | 76 +++++++++++ lifecycle/createfromaql.go | 13 ++ lifecycle/createfromartifacts.go | 55 ++++++++ lifecycle/createfrombuilds.go | 71 ++++++++-- lifecycle/createfrombundles.go | 51 ++++++- 10 files changed, 463 insertions(+), 43 deletions(-) create mode 100644 lifecycle/createcommon_test.go create mode 100644 lifecycle/createfromaql.go create mode 100644 lifecycle/createfromartifacts.go diff --git a/artifactory/commands/generic/search.go b/artifactory/commands/generic/search.go index cad7f1890..b5cf9ff40 100644 --- a/artifactory/commands/generic/search.go +++ b/artifactory/commands/generic/search.go @@ -1,6 +1,7 @@ package generic import ( + "errors" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" clientartutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" "github.com/jfrog/jfrog-client-go/utils/errorutils" @@ -26,7 +27,7 @@ func (sc *SearchCommand) Run() error { return err } -func (sc *SearchCommand) Search() (contentReader *content.ContentReader, err error) { +func (sc *SearchCommand) Search() (*content.ContentReader, error) { // Service Manager serverDetails, err := sc.ServerDetails() if errorutils.CheckError(err) != nil { @@ -38,28 +39,15 @@ func (sc *SearchCommand) Search() (contentReader *content.ContentReader, err err } // Search Loop log.Info("Searching artifacts...") - var searchResults []*content.ContentReader + + searchResults, callbackFunc, err := utils.SearchFiles(servicesManager, sc.Spec()) defer func() { - for _, reader := range searchResults { - e := reader.Close() - if err == nil { - err = e - } - } + err = errors.Join(err, callbackFunc()) }() - for i := 0; i < len(sc.Spec().Files); i++ { - searchParams, err := utils.GetSearchParams(sc.Spec().Get(i)) - if err != nil { - log.Error(err) - return nil, err - } - reader, err := servicesManager.SearchFiles(searchParams) - if err != nil { - log.Error(err) - return nil, err - } - searchResults = append(searchResults, reader) + if err != nil { + return nil, err } + reader, err := utils.AqlResultToSearchResult(searchResults) if err != nil { return nil, err diff --git a/artifactory/utils/search.go b/artifactory/utils/search.go index a8888c82e..1ed5823a5 100644 --- a/artifactory/utils/search.go +++ b/artifactory/utils/search.go @@ -2,6 +2,8 @@ package utils import ( "encoding/json" + "errors" + "github.com/jfrog/jfrog-client-go/artifactory" "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-client-go/artifactory/services" @@ -170,3 +172,28 @@ func SearchResultNoDate(reader *content.ContentReader) (contentReader *content.C contentReader = content.NewContentReader(writer.GetFilePath(), writer.GetArrayKey()) return } + +func SearchFiles(servicesManager artifactory.ArtifactoryServicesManager, spec *spec.SpecFiles) (searchResults []*content.ContentReader, callbackFunc func() error, err error) { + callbackFunc = func() error { + var errs error + for _, reader := range searchResults { + errs = errors.Join(errs, reader.Close()) + } + return errs + } + + var curSearchParams services.SearchParams + var curReader *content.ContentReader + for i := 0; i < len(spec.Files); i++ { + curSearchParams, err = GetSearchParams(spec.Get(i)) + if err != nil { + return + } + curReader, err = servicesManager.SearchFiles(curSearchParams) + if err != nil { + return + } + searchResults = append(searchResults, curReader) + } + return +} diff --git a/go.mod b/go.mod index 2d8febd38..5d072cb22 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.20240318065424-90669dbbcc54 +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240318111807-75c3311549ab replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c diff --git a/go.sum b/go.sum index 909812c3f..6bdaf3eda 100644 --- a/go.sum +++ b/go.sum @@ -87,8 +87,8 @@ github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c h1:M1QiuCYGC github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c/go.mod h1:QHcKuesY4MrBVBuEwwBz4uIsX6mwYuMEDV09ng4AvAU= 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.20240318065424-90669dbbcc54 h1:FTrss/ffJPjTHOOhQ8P+8DrkGYkxcaHlxp12nOfeZJQ= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240318065424-90669dbbcc54/go.mod h1:NB8tYFgkWtn+wHsKC+aYC75aLnS6yW81d8JAFTBxsi0= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240318111807-75c3311549ab h1:A5VTYC5x9swhypyJt2j47WBRPiJjn+0mc7DMgcmdiSE= +github.com/jfrog/jfrog-client-go v1.28.1-0.20240318111807-75c3311549ab/go.mod h1:NB8tYFgkWtn+wHsKC+aYC75aLnS6yW81d8JAFTBxsi0= 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/createcommon.go b/lifecycle/createcommon.go index b5a83ee07..6b0e7f35c 100644 --- a/lifecycle/createcommon.go +++ b/lifecycle/createcommon.go @@ -1,12 +1,24 @@ package lifecycle import ( + "github.com/jfrog/jfrog-cli-core/v2/common/spec" "github.com/jfrog/jfrog-cli-core/v2/utils/config" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-client-go/lifecycle/services" + "github.com/jfrog/jfrog-client-go/utils/errorutils" +) + +const ( + missingCreationSourcesErrMsg = "unexpected err while validating spec - could not detect any creation sources" + multipleCreationSourcesErrMsg = "multiple creation sources were detected in separate spec files. Only a single creation source should be provided. Detected:" + singleAqlErrMsg = "only a single aql query can be provided" ) type ReleaseBundleCreateCommand struct { releaseBundleCmd - signingKeyName string + signingKeyName string + spec *spec.SpecFiles + // Backward compatibility: buildsSpecPath string releaseBundlesSpecPath string } @@ -45,11 +57,18 @@ func (rbc *ReleaseBundleCreateCommand) SetReleaseBundleProject(rbProjectKey stri return rbc } +func (rbc *ReleaseBundleCreateCommand) SetSpec(spec *spec.SpecFiles) *ReleaseBundleCreateCommand { + rbc.spec = spec + return rbc +} + +// Deprecated func (rbc *ReleaseBundleCreateCommand) SetBuildsSpecPath(buildsSpecPath string) *ReleaseBundleCreateCommand { rbc.buildsSpecPath = buildsSpecPath return rbc } +// Deprecated func (rbc *ReleaseBundleCreateCommand) SetReleaseBundlesSpecPath(releaseBundlesSpecPath string) *ReleaseBundleCreateCommand { rbc.releaseBundlesSpecPath = releaseBundlesSpecPath return rbc @@ -73,8 +92,162 @@ func (rbc *ReleaseBundleCreateCommand) Run() error { return err } - if rbc.buildsSpecPath != "" { + sourceType, err := rbc.identifySourceType() + if err != nil { + return err + } + + switch sourceType { + case services.Aql: + return rbc.createFromAql(servicesManager, rbDetails, queryParams) + case services.Artifacts: + return rbc.createFromArtifacts(servicesManager, rbDetails, queryParams) + case services.Builds: return rbc.createFromBuilds(servicesManager, rbDetails, queryParams) + case services.ReleaseBundles: + return rbc.createFromReleaseBundles(servicesManager, rbDetails, queryParams) + default: + return errorutils.CheckErrorf("unknown source for release bundle creation was provided") + } +} + +func (rbc *ReleaseBundleCreateCommand) identifySourceType() (services.SourceType, error) { + switch { + case rbc.buildsSpecPath != "": + return services.Builds, nil + case rbc.releaseBundlesSpecPath != "": + return services.ReleaseBundles, nil + case rbc.spec != nil: + return validateAndIdentifyRbCreationSpec(rbc.spec.Files) + default: + return "", errorutils.CheckErrorf("a spec file input is mandatory") + } +} + +func validateAndIdentifyRbCreationSpec(files []spec.File) (services.SourceType, error) { + if len(files) == 0 { + return "", errorutils.CheckErrorf("spec must include at least one file group") + } + + var detectedCreationSources []services.SourceType + for _, file := range files { + sourceType, err := validateFile(file) + if err != nil { + return "", err + } + detectedCreationSources = append(detectedCreationSources, sourceType) + } + + if err := validateCreationSources(detectedCreationSources); err != nil { + return "", err + } + return detectedCreationSources[0], nil +} + +func validateCreationSources(detectedCreationSources []services.SourceType) error { + if len(detectedCreationSources) == 0 { + return errorutils.CheckErrorf(missingCreationSourcesErrMsg) + } + + // Assert single creation source. + for i := 1; i < len(detectedCreationSources); i++ { + if detectedCreationSources[i] != detectedCreationSources[0] { + return generateSingleCreationSourceErr(detectedCreationSources) + } + } + + // If aql, assert single file. + if detectedCreationSources[0] == services.Aql && len(detectedCreationSources) > 1 { + return errorutils.CheckErrorf(singleAqlErrMsg) + } + return nil +} + +func generateSingleCreationSourceErr(detectedCreationSources []services.SourceType) error { + var detectedStr []string + for _, source := range detectedCreationSources { + detectedStr = append(detectedStr, string(source)) + } + return errorutils.CheckErrorf( + "%s '%s'", multipleCreationSourcesErrMsg, coreutils.ListToText(detectedStr)) +} + +func validateFile(file spec.File) (services.SourceType, error) { + // Aql creation source: + isAql := len(file.Aql.ItemsFind) > 0 + + // Build creation source: + isBuild := len(file.Build) > 0 + isIncludeDeps, _ := file.IsIncludeDeps(false) + + // Bundle creation source: + isBundle := len(file.Bundle) > 0 + + // Build & bundle: + isProject := len(file.Project) > 0 + + // Artifacts creation source: + isPattern := len(file.Pattern) > 0 + isExclusions := len(file.Exclusions) > 0 && len(file.Exclusions[0]) > 0 + isProps := len(file.Props) > 0 + isExcludeProps := len(file.ExcludeProps) > 0 + isRecursive, err := file.IsRecursive(true) + if err != nil { + return "", errorutils.CheckErrorf("invalid value provided to the 'recursive' field. error: %s", err.Error()) + } + + // Unsupported: + isPathMapping := len(file.PathMapping.Input) > 0 || len(file.PathMapping.Output) > 0 + isTarget := len(file.Target) > 0 + isSortOrder := len(file.SortOrder) > 0 + isSortBy := len(file.SortBy) > 0 + isExcludeArtifacts, _ := file.IsExcludeArtifacts(false) + isGPGKey := len(file.PublicGpgKey) > 0 + isOffset := file.Offset > 0 + isLimit := file.Limit > 0 + isArchive := len(file.Archive) > 0 + isSymlinks, _ := file.IsSymlinks(false) + isRegexp := file.Regexp == "true" + isAnt := file.Ant == "true" + isExplode, _ := file.IsExplode(false) + isBypassArchiveInspection, _ := file.IsBypassArchiveInspection(false) + isTransitive, _ := file.IsTransitive(false) + + if isPathMapping || isTarget || isSortOrder || isSortBy || isExcludeArtifacts || isGPGKey || isOffset || isLimit || + isSymlinks || isArchive || isAnt || isRegexp || isExplode || isBypassArchiveInspection || isTransitive { + return "", errorutils.CheckErrorf("unsupported fields were provided in file spec. " + + "release bundle creation file spec only supports the following fields: " + + "'aql', 'build', 'includeDeps', 'bundle', 'project', 'pattern', 'exclusions', 'props', 'excludeProps' and 'recursive'") + } + if coreutils.SumTrueValues([]bool{isAql, isBuild, isBundle, isPattern}) != 1 { + return "", errorutils.CheckErrorf("exactly one creation source is supported (aql, builds, release bundles or pattern (artifacts))") + } + + switch { + case isAql: + return services.Aql, + validateCreationSource([]bool{isIncludeDeps, isProject, isExclusions, isProps, isExcludeProps, !isRecursive}, + "aql creation source supports no other fields") + case isBuild: + return services.Builds, + validateCreationSource([]bool{isExclusions, isProps, isExcludeProps, !isRecursive}, + "builds creation source only supports the 'includeDeps' and 'project' fields") + case isBundle: + return services.ReleaseBundles, + validateCreationSource([]bool{isIncludeDeps, isExclusions, isProps, isExcludeProps, !isRecursive}, + "release bundles creation source only supports the 'project' field") + case isPattern: + return services.Artifacts, + validateCreationSource([]bool{isIncludeDeps, isProject}, + "release bundles creation source only supports the 'exclusions', 'props', 'excludeProps' and 'recursive' fields") + default: + return "", errorutils.CheckErrorf("unexpected err in spec validation") + } +} + +func validateCreationSource(unsupportedFields []bool, errMsg string) error { + if coreutils.SumTrueValues(unsupportedFields) > 0 { + return errorutils.CheckErrorf(errMsg) } - return rbc.createFromReleaseBundles(servicesManager, rbDetails, queryParams) + return nil } diff --git a/lifecycle/createcommon_test.go b/lifecycle/createcommon_test.go new file mode 100644 index 000000000..a0c3b598f --- /dev/null +++ b/lifecycle/createcommon_test.go @@ -0,0 +1,76 @@ +package lifecycle + +import ( + "github.com/jfrog/jfrog-cli-core/v2/common/spec" + "github.com/jfrog/jfrog-client-go/artifactory/services/utils" + "github.com/jfrog/jfrog-client-go/lifecycle/services" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestValidateCreationSources(t *testing.T) { + testCases := []struct { + testName string + detectedCreationSources []services.SourceType + errExpected bool + errMsg string + }{ + {"missing creation sources", []services.SourceType{}, true, missingCreationSourcesErrMsg}, + {"single creation source", []services.SourceType{services.Aql, services.Artifacts, services.Builds}, + true, multipleCreationSourcesErrMsg + " 'aql, artifacts and builds'"}, + {"single aql err", []services.SourceType{services.Aql, services.Aql}, true, singleAqlErrMsg}, + {"valid aql", []services.SourceType{services.Aql}, false, ""}, + {"valid artifacts", []services.SourceType{services.Artifacts, services.Artifacts}, false, ""}, + {"valid builds", []services.SourceType{services.Builds, services.Builds}, false, ""}, + {"valid release bundles", []services.SourceType{services.ReleaseBundles, services.ReleaseBundles}, false, ""}, + } + for _, testCase := range testCases { + t.Run(testCase.testName, func(t *testing.T) { + err := validateCreationSources(testCase.detectedCreationSources) + if testCase.errExpected { + assert.EqualError(t, err, testCase.errMsg) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestValidateFile(t *testing.T) { + testCases := []struct { + testName string + file spec.File + errExpected bool + expectedSourceType services.SourceType + }{ + {"valid aql", spec.File{Aql: utils.Aql{ItemsFind: "abc"}}, false, services.Aql}, + {"valid build", spec.File{Build: "name/number", IncludeDeps: "true", Project: "project"}, false, services.Builds}, + {"valid bundle", spec.File{Bundle: "name/number", Project: "project"}, false, services.ReleaseBundles}, + {"valid artifacts", + spec.File{ + Pattern: "repo/path/file", + Exclusions: []string{"exclude"}, + Props: "prop", + ExcludeProps: "exclude prop", + Recursive: "false"}, false, services.Artifacts}, + {"invalid fields", spec.File{PathMapping: utils.PathMapping{Input: "input"}, Target: "target"}, true, ""}, + {"multiple creation sources", + spec.File{Aql: utils.Aql{ItemsFind: "abc"}, Build: "name/number", Bundle: "name/number", Pattern: "repo/path/file"}, + true, ""}, + {"invalid aql", spec.File{Aql: utils.Aql{ItemsFind: "abc"}, Props: "prop"}, true, ""}, + {"invalid builds", spec.File{Build: "name/number", Recursive: "false"}, true, ""}, + {"invalid bundles", spec.File{Bundle: "name/number", IncludeDeps: "true"}, true, ""}, + {"invalid artifacts", spec.File{Pattern: "repo/path/file", Project: "proj"}, true, ""}, + } + for _, testCase := range testCases { + t.Run(testCase.testName, func(t *testing.T) { + sourceType, err := validateFile(testCase.file) + if testCase.errExpected { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, testCase.expectedSourceType, sourceType) + } + }) + } +} diff --git a/lifecycle/createfromaql.go b/lifecycle/createfromaql.go new file mode 100644 index 000000000..12918bd75 --- /dev/null +++ b/lifecycle/createfromaql.go @@ -0,0 +1,13 @@ +package lifecycle + +import ( + "fmt" + "github.com/jfrog/jfrog-client-go/lifecycle" + "github.com/jfrog/jfrog-client-go/lifecycle/services" +) + +func (rbc *ReleaseBundleCreateCommand) createFromAql(servicesManager *lifecycle.LifecycleServicesManager, + rbDetails services.ReleaseBundleDetails, queryParams services.CommonOptionalQueryParams) error { + aqlQuery := fmt.Sprintf(`items.find(%s)`, rbc.spec.Get(0).Aql.ItemsFind) + return servicesManager.CreateReleaseBundleFromAql(rbDetails, queryParams, rbc.signingKeyName, aqlQuery) +} diff --git a/lifecycle/createfromartifacts.go b/lifecycle/createfromartifacts.go new file mode 100644 index 000000000..8a2633451 --- /dev/null +++ b/lifecycle/createfromartifacts.go @@ -0,0 +1,55 @@ +package lifecycle + +import ( + "errors" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + rtServicesUtils "github.com/jfrog/jfrog-client-go/artifactory/services/utils" + "github.com/jfrog/jfrog-client-go/lifecycle" + "github.com/jfrog/jfrog-client-go/lifecycle/services" + "github.com/jfrog/jfrog-client-go/utils/io/content" + "github.com/jfrog/jfrog-client-go/utils/log" + "path" +) + +func (rbc *ReleaseBundleCreateCommand) createFromArtifacts(lcServicesManager *lifecycle.LifecycleServicesManager, + rbDetails services.ReleaseBundleDetails, queryParams services.CommonOptionalQueryParams) (err error) { + + rtServicesManager, err := utils.CreateServiceManager(rbc.serverDetails, 3, 0, false) + if err != nil { + return err + } + + log.Info("Searching artifacts...") + searchResults, callbackFunc, err := utils.SearchFiles(rtServicesManager, rbc.spec) + defer func() { + err = errors.Join(err, callbackFunc()) + }() + if err != nil { + return err + } + artifactsSource, err := aqlResultToArtifactsSource(searchResults) + if err != nil { + return err + } + + return lcServicesManager.CreateReleaseBundleFromArtifacts(rbDetails, queryParams, rbc.signingKeyName, artifactsSource) +} + +func aqlResultToArtifactsSource(readers []*content.ContentReader) (artifactsSource services.CreateFromArtifacts, err error) { + for _, reader := range readers { + for searchResult := new(rtServicesUtils.ResultItem); reader.NextRecord(searchResult) == nil; searchResult = new(rtServicesUtils.ResultItem) { + if err != nil { + return + } + artifactsSource.Artifacts = append(artifactsSource.Artifacts, services.ArtifactSource{ + Path: path.Join(searchResult.Repo, searchResult.Path, searchResult.Name), + Sha256: searchResult.Sha256, + }) + } + if err = reader.GetError(); err != nil { + return + } + reader.Reset() + } + return +} diff --git a/lifecycle/createfrombuilds.go b/lifecycle/createfrombuilds.go index a955b997a..02e54e644 100644 --- a/lifecycle/createfrombuilds.go +++ b/lifecycle/createfrombuilds.go @@ -3,6 +3,7 @@ package lifecycle import ( "encoding/json" rtUtils "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + "github.com/jfrog/jfrog-cli-core/v2/common/spec" rtServices "github.com/jfrog/jfrog-client-go/artifactory/services" "github.com/jfrog/jfrog-client-go/artifactory/services/utils" "github.com/jfrog/jfrog-client-go/lifecycle" @@ -14,27 +15,38 @@ import ( func (rbc *ReleaseBundleCreateCommand) createFromBuilds(servicesManager *lifecycle.LifecycleServicesManager, rbDetails services.ReleaseBundleDetails, queryParams services.CommonOptionalQueryParams) error { - builds := CreateFromBuildsSpec{} - content, err := fileutils.ReadFile(rbc.buildsSpecPath) + var buildsSource services.CreateFromBuildsSource + var err error + if rbc.buildsSpecPath != "" { + buildsSource, err = rbc.getBuildSourceFromBuildsSpec() + } else { + buildsSource, err = rbc.convertSpecToBuildsSource(rbc.spec.Files) + } if err != nil { return err } - if err = json.Unmarshal(content, &builds); err != nil { - return errorutils.CheckError(err) - } - if len(builds.Builds) == 0 { + if len(buildsSource.Builds) == 0 { return errorutils.CheckErrorf("at least one build is expected in order to create a release bundle from builds") } - buildsSource, err := rbc.convertToBuildsSource(builds) + return servicesManager.CreateReleaseBundleFromBuilds(rbDetails, queryParams, rbc.signingKeyName, buildsSource) +} + +func (rbc *ReleaseBundleCreateCommand) getBuildSourceFromBuildsSpec() (buildsSource services.CreateFromBuildsSource, err error) { + builds := CreateFromBuildsSpec{} + content, err := fileutils.ReadFile(rbc.buildsSpecPath) if err != nil { - return err + return } - return servicesManager.CreateReleaseBundleFromBuilds(rbDetails, queryParams, rbc.signingKeyName, buildsSource) + if err = json.Unmarshal(content, &builds); errorutils.CheckError(err) != nil { + return + } + + return rbc.convertBuildsSpecToBuildsSource(builds) } -func (rbc *ReleaseBundleCreateCommand) convertToBuildsSource(builds CreateFromBuildsSpec) (services.CreateFromBuildsSource, error) { +func (rbc *ReleaseBundleCreateCommand) convertBuildsSpecToBuildsSource(builds CreateFromBuildsSpec) (services.CreateFromBuildsSource, error) { buildsSource := services.CreateFromBuildsSource{} for _, build := range builds.Builds { buildSource := services.BuildSource{BuildName: build.Name, IncludeDependencies: build.IncludeDependencies} @@ -49,6 +61,29 @@ func (rbc *ReleaseBundleCreateCommand) convertToBuildsSource(builds CreateFromBu return buildsSource, nil } +func (rbc *ReleaseBundleCreateCommand) convertSpecToBuildsSource(files []spec.File) (services.CreateFromBuildsSource, error) { + buildsSource := services.CreateFromBuildsSource{} + for _, file := range files { + buildName, buildNumber, err := rbc.getBuildDetailsFromIdentifier(file.Build, file.Project) + if err != nil { + return services.CreateFromBuildsSource{}, err + } + isIncludeDeps, err := file.IsIncludeDeps(false) + if err != nil { + return services.CreateFromBuildsSource{}, err + } + + buildSource := services.BuildSource{ + BuildName: buildName, + BuildNumber: buildNumber, + BuildRepository: utils.GetBuildInfoRepositoryByProject(file.Project), + IncludeDependencies: isIncludeDeps, + } + buildsSource.Builds = append(buildsSource.Builds, buildSource) + } + return buildsSource, nil +} + func (rbc *ReleaseBundleCreateCommand) getLatestBuildNumberIfEmpty(buildName, buildNumber, project string) (string, error) { if buildNumber != "" { return buildNumber, nil @@ -69,6 +104,22 @@ func (rbc *ReleaseBundleCreateCommand) getLatestBuildNumberIfEmpty(buildName, bu return buildNumber, nil } +func (rbc *ReleaseBundleCreateCommand) getBuildDetailsFromIdentifier(buildIdentifier, project string) (string, string, error) { + aqlService, err := rbc.getAqlService() + if err != nil { + return "", "", err + } + + buildName, buildNumber, err := utils.GetBuildNameAndNumberFromBuildIdentifier(buildIdentifier, project, aqlService) + if err != nil { + return "", "", err + } + if buildName == "" || buildNumber == "" { + return "", "", errorutils.CheckErrorf("could not identify a build info by the '%s' identifier in artifactory", buildIdentifier) + } + return buildName, buildNumber, nil +} + func (rbc *ReleaseBundleCreateCommand) getAqlService() (*rtServices.AqlService, error) { rtServiceManager, err := rtUtils.CreateServiceManager(rbc.serverDetails, 3, 0, false) if err != nil { diff --git a/lifecycle/createfrombundles.go b/lifecycle/createfrombundles.go index 1e9253351..7c18141de 100644 --- a/lifecycle/createfrombundles.go +++ b/lifecycle/createfrombundles.go @@ -2,6 +2,8 @@ package lifecycle import ( "encoding/json" + "github.com/jfrog/jfrog-cli-core/v2/common/spec" + "github.com/jfrog/jfrog-client-go/artifactory/services/utils" "github.com/jfrog/jfrog-client-go/lifecycle" "github.com/jfrog/jfrog-client-go/lifecycle/services" "github.com/jfrog/jfrog-client-go/utils/errorutils" @@ -11,20 +13,21 @@ import ( func (rbc *ReleaseBundleCreateCommand) createFromReleaseBundles(servicesManager *lifecycle.LifecycleServicesManager, rbDetails services.ReleaseBundleDetails, queryParams services.CommonOptionalQueryParams) error { - bundles := CreateFromReleaseBundlesSpec{} - content, err := fileutils.ReadFile(rbc.releaseBundlesSpecPath) + var releaseBundlesSource services.CreateFromReleaseBundlesSource + var err error + if rbc.releaseBundlesSpecPath != "" { + releaseBundlesSource, err = rbc.getReleaseBundlesSourceFromBundlesSpec() + } else { + releaseBundlesSource, err = rbc.convertSpecToReleaseBundlesSource(rbc.spec.Files) + } if err != nil { return err } - if err = json.Unmarshal(content, &bundles); err != nil { - return errorutils.CheckError(err) - } - if len(bundles.ReleaseBundles) == 0 { + if len(releaseBundlesSource.ReleaseBundles) == 0 { return errorutils.CheckErrorf("at least one release bundle is expected in order to create a release bundle from release bundles") } - releaseBundlesSource := rbc.convertToReleaseBundlesSource(bundles) return servicesManager.CreateReleaseBundleFromBundles(rbDetails, queryParams, rbc.signingKeyName, releaseBundlesSource) } @@ -41,6 +44,40 @@ func (rbc *ReleaseBundleCreateCommand) convertToReleaseBundlesSource(bundles Cre return releaseBundlesSource } +func (rbc *ReleaseBundleCreateCommand) convertSpecToReleaseBundlesSource(files []spec.File) (services.CreateFromReleaseBundlesSource, error) { + releaseBundlesSource := services.CreateFromReleaseBundlesSource{} + for _, file := range files { + name, version, err := utils.ParseNameAndVersion(file.Bundle, false) + if err != nil { + return releaseBundlesSource, err + } + if name == "" || version == "" { + return releaseBundlesSource, errorutils.CheckErrorf( + "invalid release bundle source was provided. Both name and version are mandatory. Provided name: '%s', version: '%s'", name, version) + } + rbSource := services.ReleaseBundleSource{ + ReleaseBundleName: name, + ReleaseBundleVersion: version, + ProjectKey: file.Project, + } + releaseBundlesSource.ReleaseBundles = append(releaseBundlesSource.ReleaseBundles, rbSource) + } + return releaseBundlesSource, nil +} + +func (rbc *ReleaseBundleCreateCommand) getReleaseBundlesSourceFromBundlesSpec() (releaseBundlesSource services.CreateFromReleaseBundlesSource, err error) { + releaseBundles := CreateFromReleaseBundlesSpec{} + content, err := fileutils.ReadFile(rbc.releaseBundlesSpecPath) + if err != nil { + return + } + if err = json.Unmarshal(content, &releaseBundles); errorutils.CheckError(err) != nil { + return + } + + return rbc.convertToReleaseBundlesSource(releaseBundles), nil +} + type CreateFromReleaseBundlesSpec struct { ReleaseBundles []SourceReleaseBundleSpec `json:"releaseBundles,omitempty"` } From bc03905e2da7c943218ad46c265debaff3bcf295 Mon Sep 17 00:00:00 2001 From: Yahav Itzhak Date: Mon, 18 Mar 2024 15:06:37 +0200 Subject: [PATCH 06/16] Transfer - Consider the MIN_CHECKSUM_DEPLOY_SIZE_KB env var (#1129) --- artifactory/commands/generic/upload.go | 16 +--------------- .../commands/transferfiles/api/types.go | 2 ++ .../commands/transferfiles/fulltransfer.go | 3 ++- artifactory/commands/transferfiles/phase.go | 6 ++++++ artifactory/commands/transferfiles/transfer.go | 13 +++++++++---- artifactory/commands/transferfiles/utils.go | 1 + artifactory/utils/upload.go | 18 ++++++++++++++++++ go.mod | 4 ++-- go.sum | 8 ++++---- 9 files changed, 45 insertions(+), 26 deletions(-) diff --git a/artifactory/commands/generic/upload.go b/artifactory/commands/generic/upload.go index b16e83ffd..9fa2a0831 100644 --- a/artifactory/commands/generic/upload.go +++ b/artifactory/commands/generic/upload.go @@ -5,7 +5,6 @@ import ( buildInfo "github.com/jfrog/build-info-go/entities" - "os" "strconv" "time" @@ -81,7 +80,7 @@ func (uc *UploadCommand) upload() (err error) { } // Create Service Manager: - uc.uploadConfiguration.MinChecksumDeploySize, err = getMinChecksumDeploySize() + uc.uploadConfiguration.MinChecksumDeploySize, err = utils.GetMinChecksumDeploySize() if err != nil { return } @@ -197,19 +196,6 @@ func (uc *UploadCommand) upload() (err error) { return } -func getMinChecksumDeploySize() (int64, error) { - minChecksumDeploySize := os.Getenv("JFROG_CLI_MIN_CHECKSUM_DEPLOY_SIZE_KB") - if minChecksumDeploySize == "" { - return services.DefaultMinChecksumDeploy, nil - } - minSize, err := strconv.ParseInt(minChecksumDeploySize, 10, 64) - err = errorutils.CheckError(err) - if err != nil { - return 0, err - } - return minSize * 1000, nil -} - func getUploadParams(f *spec.File, configuration *utils.UploadConfiguration, buildProps string, addVcsProps bool) (uploadParams services.UploadParams, err error) { uploadParams = services.NewUploadParams() uploadParams.CommonParams, err = f.ToCommonParams() diff --git a/artifactory/commands/transferfiles/api/types.go b/artifactory/commands/transferfiles/api/types.go index 7cbadd8f3..708ee49f0 100644 --- a/artifactory/commands/transferfiles/api/types.go +++ b/artifactory/commands/transferfiles/api/types.go @@ -47,6 +47,8 @@ type UploadChunk struct { CheckExistenceInFilestore bool `json:"check_existence_in_filestore,omitempty"` // True if should skip file filtering in the Data Transfer plugin SkipFileFiltering bool `json:"skip_file_filtering,omitempty"` + // Minimum file size in bytes for which JFrog CLI performs checksum deploy optimization + MinCheckSumDeploySize int64 `json:"min_checksum_deploy_size,omitempty"` } type FileRepresentation struct { diff --git a/artifactory/commands/transferfiles/fulltransfer.go b/artifactory/commands/transferfiles/fulltransfer.go index 4c7a38118..a60d48e41 100644 --- a/artifactory/commands/transferfiles/fulltransfer.go +++ b/artifactory/commands/transferfiles/fulltransfer.go @@ -175,7 +175,8 @@ func (m *fullTransferPhase) searchAndHandleFolderContents(params folderParams, p CheckExistenceInFilestore: m.checkExistenceInFilestore, // Skip file filtering in the Data Transfer plugin if it is already enabled in the JFrog CLI. // The local generated filter is enabled in the JFrog CLI for target Artifactory servers >= 7.55. - SkipFileFiltering: m.locallyGeneratedFilter.IsEnabled(), + SkipFileFiltering: m.locallyGeneratedFilter.IsEnabled(), + MinCheckSumDeploySize: m.minCheckSumDeploySize, } var result []servicesUtils.ResultItem diff --git a/artifactory/commands/transferfiles/phase.go b/artifactory/commands/transferfiles/phase.go index bb93adf87..99ced8985 100644 --- a/artifactory/commands/transferfiles/phase.go +++ b/artifactory/commands/transferfiles/phase.go @@ -38,6 +38,7 @@ type transferPhase interface { setPackageType(packageType string) setDisabledDistinctiveAql() setStopSignal(stopSignal chan os.Signal) + setMinCheckSumDeploySize(minCheckSumDeploySize int64) StopGracefully() } @@ -62,6 +63,7 @@ type phaseBase struct { stopSignal chan os.Signal // Optimization in Artifactory version 7.37 and above enables the exclusion of setting DISTINCT in SQL queries disabledDistinctiveAql bool + minCheckSumDeploySize int64 } func (pb *phaseBase) ShouldStop() bool { @@ -147,6 +149,10 @@ func (pb *phaseBase) setDisabledDistinctiveAql() { pb.disabledDistinctiveAql = true } +func (pb *phaseBase) setMinCheckSumDeploySize(minCheckSumDeploySize int64) { + pb.minCheckSumDeploySize = minCheckSumDeploySize +} + func (pb *phaseBase) setStopSignal(stopSignal chan os.Signal) { pb.stopSignal = stopSignal } diff --git a/artifactory/commands/transferfiles/transfer.go b/artifactory/commands/transferfiles/transfer.go index 62b451026..ed696c1d1 100644 --- a/artifactory/commands/transferfiles/transfer.go +++ b/artifactory/commands/transferfiles/transfer.go @@ -399,6 +399,10 @@ func (tdc *TransferFilesCommand) transferSingleRepo(sourceRepoKey string, target if err = tdc.initCurThreads(buildInfoRepo); err != nil { return } + minChecksumDeploySize, err := utils.GetMinChecksumDeploySize() + if err != nil { + return + } for currentPhaseId := 0; currentPhaseId < NumberOfPhases; currentPhaseId++ { if tdc.shouldStop() { return @@ -413,7 +417,7 @@ func (tdc *TransferFilesCommand) transferSingleRepo(sourceRepoKey string, target if err = tdc.stateManager.SetRepoPhase(currentPhaseId); err != nil { return } - if err = tdc.startPhase(newPhase, sourceRepoKey, buildInfoRepo, *repoSummary, srcUpService); err != nil { + if err = tdc.startPhase(newPhase, sourceRepoKey, buildInfoRepo, *repoSummary, srcUpService, minChecksumDeploySize); err != nil { return } } @@ -479,8 +483,8 @@ func (tdc *TransferFilesCommand) removeOldFilesIfNeeded(repos []string) error { return nil } -func (tdc *TransferFilesCommand) startPhase(newPhase *transferPhase, repo string, buildInfoRepo bool, repoSummary serviceUtils.RepositorySummary, srcUpService *srcUserPluginService) error { - tdc.initNewPhase(*newPhase, srcUpService, repoSummary, repo, buildInfoRepo) +func (tdc *TransferFilesCommand) startPhase(newPhase *transferPhase, repo string, buildInfoRepo bool, repoSummary serviceUtils.RepositorySummary, srcUpService *srcUserPluginService, minChecksumDeploySize int64) error { + tdc.initNewPhase(*newPhase, srcUpService, repoSummary, repo, buildInfoRepo, minChecksumDeploySize) skip, err := (*newPhase).shouldSkipPhase() if err != nil || skip { return err @@ -546,7 +550,7 @@ func (tdc *TransferFilesCommand) handleStop(srcUpService *srcUserPluginService) }, &newPhase } -func (tdc *TransferFilesCommand) initNewPhase(newPhase transferPhase, srcUpService *srcUserPluginService, repoSummary serviceUtils.RepositorySummary, repoKey string, buildInfoRepo bool) { +func (tdc *TransferFilesCommand) initNewPhase(newPhase transferPhase, srcUpService *srcUserPluginService, repoSummary serviceUtils.RepositorySummary, repoKey string, buildInfoRepo bool, minChecksumDeploySize int64) { newPhase.setContext(tdc.context) newPhase.setRepoKey(repoKey) newPhase.setCheckExistenceInFilestore(tdc.checkExistenceInFilestore) @@ -561,6 +565,7 @@ func (tdc *TransferFilesCommand) initNewPhase(newPhase transferPhase, srcUpServi newPhase.setPackageType(repoSummary.PackageType) newPhase.setLocallyGeneratedFilter(tdc.locallyGeneratedFilter) newPhase.setStopSignal(tdc.stopSignal) + newPhase.setMinCheckSumDeploySize(minChecksumDeploySize) } // Get all local and build-info repositories of the input server diff --git a/artifactory/commands/transferfiles/utils.go b/artifactory/commands/transferfiles/utils.go index a9b77f067..622f768e4 100644 --- a/artifactory/commands/transferfiles/utils.go +++ b/artifactory/commands/transferfiles/utils.go @@ -430,6 +430,7 @@ func uploadByChunks(files []api.FileRepresentation, uploadTokensChan chan Upload TargetAuth: createTargetAuth(base.targetRtDetails, base.proxyKey), CheckExistenceInFilestore: base.checkExistenceInFilestore, SkipFileFiltering: base.locallyGeneratedFilter.IsEnabled(), + MinCheckSumDeploySize: base.minCheckSumDeploySize, } for _, item := range files { diff --git a/artifactory/utils/upload.go b/artifactory/utils/upload.go index 11829a5ab..ed00f67f9 100644 --- a/artifactory/utils/upload.go +++ b/artifactory/utils/upload.go @@ -1,8 +1,13 @@ package utils import ( + "os" + "strconv" + "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-client-go/artifactory" + "github.com/jfrog/jfrog-client-go/artifactory/services" + "github.com/jfrog/jfrog-client-go/utils/errorutils" "github.com/jfrog/jfrog-client-go/utils/io" ) @@ -18,3 +23,16 @@ type UploadConfiguration struct { SplitCount int MinSplitSizeMB int64 } + +func GetMinChecksumDeploySize() (int64, error) { + minChecksumDeploySize := os.Getenv("JFROG_CLI_MIN_CHECKSUM_DEPLOY_SIZE_KB") + if minChecksumDeploySize == "" { + return services.DefaultMinChecksumDeploy, nil + } + minSize, err := strconv.ParseInt(minChecksumDeploySize, 10, 64) + err = errorutils.CheckError(err) + if err != nil { + return 0, err + } + return minSize * 1000, nil +} diff --git a/go.mod b/go.mod index 5d072cb22..6ae768550 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.20240318111807-75c3311549ab +replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240318124620-6267b7025659 -replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c +replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20240311081927-91b472899d7d // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc diff --git a/go.sum b/go.sum index 6bdaf3eda..a9fb9a01b 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.20240225113943-096bf22ca54c h1:M1QiuCYGCYN1IiGyxogrLzfetYGkkhE2pgDh5K4Wo9A= -github.com/jfrog/build-info-go v1.8.9-0.20240225113943-096bf22ca54c/go.mod h1:QHcKuesY4MrBVBuEwwBz4uIsX6mwYuMEDV09ng4AvAU= +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/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.20240318111807-75c3311549ab h1:A5VTYC5x9swhypyJt2j47WBRPiJjn+0mc7DMgcmdiSE= -github.com/jfrog/jfrog-client-go v1.28.1-0.20240318111807-75c3311549ab/go.mod h1:NB8tYFgkWtn+wHsKC+aYC75aLnS6yW81d8JAFTBxsi0= +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/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 3f0de94011d768b6ba02fdfc0a4d4a6db8282687 Mon Sep 17 00:00:00 2001 From: Robi Nino Date: Mon, 18 Mar 2024 16:48:14 +0200 Subject: [PATCH 07/16] 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 08/16] 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 09/16] 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 10/16] 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 11/16] 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 12/16] 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 13/16] 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 14/16] 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 15/16] 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 16/16] 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=