Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance download functionality to support RBV2 #2805

Merged
merged 2 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletion artifactory/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ import (
buildinfocmd "github.com/jfrog/jfrog-client-go/artifactory/buildinfo"
"github.com/jfrog/jfrog-client-go/artifactory/services"
clientutils "github.com/jfrog/jfrog-client-go/utils"
utilsForLC "github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/jszwec/csvutil"
Expand All @@ -133,6 +134,7 @@ const (
userCategory = "User Management"
transferCategory = "Transfer Between Artifactory Instances"
otherCategory = "Other"
releaseBundlesV2 = "release-bundles-v2"
)

func GetCommands() []cli.Command {
Expand Down Expand Up @@ -1269,14 +1271,17 @@ func prepareDownloadCommand(c *cli.Context) (*spec.SpecFiles, error) {

var downloadSpec *spec.SpecFiles
var err error

if c.IsSet("spec") {
downloadSpec, err = cliutils.GetSpec(c, true, true)
} else {
downloadSpec, err = createDefaultDownloadSpec(c)
}

if err != nil {
return nil, err
}

setTransitiveInDownloadSpec(downloadSpec)
err = spec.ValidateSpec(downloadSpec.Files, false, true)
if err != nil {
Expand All @@ -1290,6 +1295,7 @@ func downloadCmd(c *cli.Context) error {
if err != nil {
return err
}

fixWinPathsForDownloadCmd(downloadSpec, c)
configuration, err := cliutils.CreateDownloadConfiguration(c)
if err != nil {
Expand Down Expand Up @@ -1330,6 +1336,54 @@ func downloadCmd(c *cli.Context) error {
return cliutils.GetCliError(err, result.SuccessCount(), result.FailCount(), cliutils.IsFailNoOp(c))
}

func checkRbExistenceInV2(c *cli.Context) (bool, error) {
bundleNameAndVersion := c.String("bundle")
parts := strings.Split(bundleNameAndVersion, "/")
rbName := parts[0]
rbVersion := parts[1]

lcDetails, err := createLifecycleDetailsByFlags(c)
if err != nil {
return false, err
}

lcServicesManager, err := utils.CreateLifecycleServiceManager(lcDetails, false)
if err != nil {
return false, err
}

return lcServicesManager.IsReleaseBundleExist(rbName, rbVersion, c.String("project"))
}

func createLifecycleDetailsByFlags(c *cli.Context) (*coreConfig.ServerDetails, error) {
lcDetails, err := cliutils.CreateServerDetailsWithConfigOffer(c, true, commonCliUtils.Platform)
if err != nil {
return nil, err
}
if lcDetails.Url == "" {
return nil, errors.New("platform URL is mandatory for lifecycle commands")
}
PlatformToLifecycleUrls(lcDetails)
return lcDetails, nil
}

func PlatformToLifecycleUrls(lcDetails *coreConfig.ServerDetails) {
// For tests only. in prod - this "if" will always return false
if strings.Contains(lcDetails.Url, "artifactory/") {
lcDetails.ArtifactoryUrl = utilsForLC.AddTrailingSlashIfNeeded(lcDetails.Url)
lcDetails.LifecycleUrl = strings.Replace(
utilsForLC.AddTrailingSlashIfNeeded(lcDetails.Url),
"artifactory/",
"lifecycle/",
1,
)
} else {
lcDetails.ArtifactoryUrl = utilsForLC.AddTrailingSlashIfNeeded(lcDetails.Url) + "artifactory/"
lcDetails.LifecycleUrl = utilsForLC.AddTrailingSlashIfNeeded(lcDetails.Url) + "lifecycle/"
}
lcDetails.Url = ""
}

func uploadCmd(c *cli.Context) (err error) {
if c.NArg() > 0 && c.IsSet("spec") {
return cliutils.PrintHelpAndReturnError("No arguments should be sent when the spec option is used.", c)
Expand Down Expand Up @@ -2648,8 +2702,9 @@ func createDefaultDownloadSpec(c *cli.Context) (*spec.SpecFiles, error) {
if err != nil {
return nil, err
}

EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved
return spec.NewBuilder().
Pattern(strings.TrimPrefix(c.Args().Get(0), "/")).
Pattern(getSourcePattern(c)).
Props(c.String("props")).
ExcludeProps(c.String("exclude-props")).
Build(c.String("build")).
Expand All @@ -2674,6 +2729,53 @@ func createDefaultDownloadSpec(c *cli.Context) (*spec.SpecFiles, error) {
BuildSpec(), nil
}

func getSourcePattern(c *cli.Context) string {
var source string
var isRbv2 bool
var err error

if c.IsSet("bundle") {
// If the bundle flag is set, we need to check if the bundle exists in rbv2
isRbv2, err = checkRbExistenceInV2(c)
if err != nil {
log.Error("Error occurred while checking if the bundle exists in rbv2:", err.Error())
}
}

if isRbv2 {
// RB2 will be downloaded like a regular artifact, path: projectKey-release-bundles-v2/rbName/rbVersion
source, err = buildSourceForRbv2(c)
if err != nil {
log.Error("Error occurred while building source path for rbv2:", err.Error())
return ""
}
} else {
source = strings.TrimPrefix(c.Args().Get(0), "/")
}

return source
}

func buildSourceForRbv2(c *cli.Context) (string, error) {
bundleNameAndVersion := c.String("bundle")
projectKey := c.String("project")
source := projectKey

// Reset bundle flag
err := c.Set("bundle", "")
if err != nil {
return "", err
}

// If projectKey is not empty, append "-" to it
if projectKey != "" {
source += "-"
}
// Build RB path: projectKey-release-bundles-v2/rbName/rbVersion/
source += releaseBundlesV2 + "/" + bundleNameAndVersion + "/"
return source, nil
}

func setTransitiveInDownloadSpec(downloadSpec *spec.SpecFiles) {
transitive := os.Getenv(coreutils.TransitiveDownload)
if transitive == "" {
Expand Down
38 changes: 35 additions & 3 deletions artifactory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ import (
// https://jira.jfrog.org/browse/JA-2620
// Minimum Artifactory version with Terraform support
const terraformMinArtifactoryVersion = "7.38.4"
const deleteReleaseBundleV1ApiUrl = "artifactory/api/release/bundles/"
const deleteReleaseBundleV2ApiUrl = "lifecycle/api/v2/release_bundle/records/"

// JFrog CLI for Artifactory sub-commands (jfrog rt ...)
var artifactoryCli *coretests.JfrogCli
Expand Down Expand Up @@ -223,10 +225,11 @@ func TestArtifactorySimpleUploadSpecUsingConfig(t *testing.T) {
inttestutils.VerifyExistInArtifactory(tests.GetSimpleUploadExpectedRepo1(), searchFilePath, serverDetails, t)
cleanArtifactoryTest()
}

func TestReleaseBundleImportOnPrem(t *testing.T) {
// Cleanup
defer func() {
deleteReceivedReleaseBundle(t, "cli-tests", "2")
deleteReceivedReleaseBundle(t, deleteReleaseBundleV1ApiUrl, "cli-tests", "2")
cleanArtifactoryTest()
}()
initArtifactoryTest(t, "")
Expand All @@ -240,6 +243,35 @@ func TestReleaseBundleImportOnPrem(t *testing.T) {
assert.NoError(t, lcCli.Exec("rbi", testFilePath))
}

func TestReleaseBundleV2Download(t *testing.T) {
buildNumber := "5"
defer func() {
deleteReceivedReleaseBundle(t, deleteReleaseBundleV2ApiUrl, tests.LcRbName1, buildNumber)
inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.RtBuildName1, artHttpDetails)
cleanArtifactoryTest()
}()
initArtifactoryTest(t, "")
initLifecycleTest(t, signingKeyOptionalArtifactoryMinVersion)

runRt(t, "upload", "testdata/a/a1.in", tests.RtRepo1, "--build-name="+tests.RtBuildName1, "--build-number="+buildNumber)
runRt(t, "build-publish", tests.RtBuildName1, buildNumber)

// Create RBV2
err := lcCli.Exec("rbc", tests.LcRbName1, buildNumber, "--build-name="+tests.RtBuildName1, "--build-number="+buildNumber)
assert.NoError(t, err)

runRt(t, "download", "--bundle="+tests.LcRbName1+"/"+buildNumber)

wd, err := os.Getwd()
assert.NoError(t, err, "Failed to get current dir")
exists, err := fileutils.IsDirExists(filepath.Join(wd, tests.LcRbName1), false)

assert.NoError(t, err)
assert.True(t, exists)

clientTestUtils.RemoveAllAndAssert(t, filepath.Join(wd, tests.LcRbName1))
}

func TestArtifactoryUploadPathWithSpecialCharsAsNoRegex(t *testing.T) {
initArtifactoryTest(t, "")
filePath := getSpecialCharFilePath()
Expand Down Expand Up @@ -5654,10 +5686,10 @@ func sendArtifactoryTrustedPublicKey(t *testing.T, artHttpDetails httputils.Http
assert.NoError(t, err)
}

func deleteReceivedReleaseBundle(t *testing.T, bundleName, bundleVersion string) {
func deleteReceivedReleaseBundle(t *testing.T, url, bundleName, bundleVersion string) {
client, err := httpclient.ClientBuilder().Build()
assert.NoError(t, err)
deleteApi := path.Join("artifactory/api/release/bundles/", bundleName, bundleVersion)
deleteApi := path.Join(url, bundleName, bundleVersion)
_, _, err = client.SendDelete(*tests.JfrogUrl+deleteApi, []byte{}, artHttpDetails, "Deleting release bundle")
assert.NoError(t, err)
}
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,7 @@ require (
// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20241220065541-91828d43d8b9

// replace github.com/jfrog/gofrog => github.com/jfrog/gofrog dev

replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250101110857-b26e9a6644c6

replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20250112155823-f3d607f5d854
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,14 @@ github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYL
github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w=
github.com/jfrog/jfrog-cli-artifactory v0.1.11 h1:tYGQpkGZVHwYxApKhMXgY1V25QaLFaTbjsoq0l3Bf4w=
github.com/jfrog/jfrog-cli-artifactory v0.1.11/go.mod h1:rVBTbanRnG9CXyAYRJ2O6h2fJMa+fsGB+3swUB/qEt0=
github.com/jfrog/jfrog-cli-core/v2 v2.57.6 h1:kI5BqDW8Q4R5HkTUPSAObTqyIgQ9z7DqeFYGOEC1zPk=
github.com/jfrog/jfrog-cli-core/v2 v2.57.6/go.mod h1:h5pzOZUb5ChGcGrXCYr3nPyXcTZjeGW2Rm1Zceo8Afg=
github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250101110857-b26e9a6644c6 h1:/i1sIQS0q0gRN531ChVToQWcjaVZOKZ4KuGk7j7vDTc=
github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250101110857-b26e9a6644c6/go.mod h1:LfKvCRXbvwgE0V6aX3/GabkzCedghXq0Y6lmsEuxr44=
github.com/jfrog/jfrog-cli-platform-services v1.6.0 h1:2fBIDxnQaFWStZqMEUI2I3nkNjDmknxxHcmpeLxtocc=
github.com/jfrog/jfrog-cli-platform-services v1.6.0/go.mod h1:u3lMRG7XC8MeUy/OPkHkZnsgCMIi0br4sjk2/W1Pm8I=
github.com/jfrog/jfrog-cli-security v1.14.0 h1:mGm/ya0Qh0YdBS7ATgmQi1r8MEkbM8Hh/ml4UPkuu/4=
github.com/jfrog/jfrog-cli-security v1.14.0/go.mod h1:KGfZVb4je4fiWm+OTNWdyi8V3c2TAkNDZHxsUUEM2GE=
github.com/jfrog/jfrog-client-go v1.49.0 h1:NaTK6+LQBEJafL//6ntnS/eVx1dZMJnxydALwWHKORQ=
github.com/jfrog/jfrog-client-go v1.49.0/go.mod h1:ohIfKpMBCQsE9kunrKQ1wvoExpqsPLaluRFO186B5EM=
github.com/jfrog/jfrog-client-go v1.28.1-0.20250112155823-f3d607f5d854 h1:PlskEOWetCRH7NfEMbgC2/sOFPciXj42exbadxX3HT4=
github.com/jfrog/jfrog-client-go v1.28.1-0.20250112155823-f3d607f5d854/go.mod h1:ohIfKpMBCQsE9kunrKQ1wvoExpqsPLaluRFO186B5EM=
github.com/jszwec/csvutil v1.10.0 h1:upMDUxhQKqZ5ZDCs/wy+8Kib8rZR8I8lOR34yJkdqhI=
github.com/jszwec/csvutil v1.10.0/go.mod h1:/E4ONrmGkwmWsk9ae9jpXnv9QT8pLHEPcCirMFhxG9I=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
Expand Down
Loading