From 5979ebb571c755650006c238ecf692cdb5e053ad Mon Sep 17 00:00:00 2001 From: Eyal Delarea Date: Tue, 12 Mar 2024 17:10:07 +0200 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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) {