diff --git a/go.mod b/go.mod index 18dec2a78..cf7c28a24 100644 --- a/go.mod +++ b/go.mod @@ -191,8 +191,8 @@ require ( replace github.com/jfrog/jfrog-cli-artifactory => github.com/jfrog/jfrog-cli-artifactory v0.1.13-0.20250221101554-05889536ad05 -replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250226093426-131ae1505b58 +replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250226094621-9317a4bcdfc4 -replace github.com/jfrog/build-info-go => github.com/fluxxBot/build-info-go v1.8.9-0.20250203111011-4ff16d3d42be +replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20250226102210-d57860372195 replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20250221062042-87cb5136765e diff --git a/go.sum b/go.sum index 69af25fd9..b4c8cd887 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,6 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxxBot/build-info-go v1.8.9-0.20250203111011-4ff16d3d42be h1:K9d43ZYkRj9Y0XI78KZvHlCWdZ7O24np+Xv9C7PKJwk= -github.com/fluxxBot/build-info-go v1.8.9-0.20250203111011-4ff16d3d42be/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE= 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= @@ -177,6 +175,8 @@ github.com/jedib0t/go-pretty/v6 v6.6.5 h1:9PgMJOVBedpgYLI56jQRJYqngxYAAzfEUua+3N github.com/jedib0t/go-pretty/v6 v6.6.5/go.mod h1:Uq/HrbhuFty5WSVNfjpQQe47x16RwVGXIveNGEyGtHs= github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI= github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw= +github.com/jfrog/build-info-go v1.8.9-0.20250226102210-d57860372195 h1:rH+VDEIBZt5jTx0KYuMINYQwEMzhJFgY0Fr/0w+aLtI= +github.com/jfrog/build-info-go v1.8.9-0.20250226102210-d57860372195/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE= github.com/jfrog/froggit-go v1.16.2 h1:F//S83iXH14qsCwYzv0zB2JtjS2pJVEsUoEmYA+37dQ= github.com/jfrog/froggit-go v1.16.2/go.mod h1:5VpdQfAcbuyFl9x/x8HGm7kVk719kEtW/8YJFvKcHPA= github.com/jfrog/go-mockhttp v0.3.1 h1:/wac8v4GMZx62viZmv4wazB5GNKs+GxawuS1u3maJH8= @@ -187,8 +187,8 @@ 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.13-0.20250221101554-05889536ad05 h1:UV9W1ZImGWLks4+w+zg9hMtySvEIU+WxO73lsO6NIyY= github.com/jfrog/jfrog-cli-artifactory v0.1.13-0.20250221101554-05889536ad05/go.mod h1:223EqxDx7Ogrj7zJZkKAoFuQJStC5qtPXjwsf+r6d/A= -github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250226093426-131ae1505b58 h1:r8aE1Amm8CLbMLMCbNhivs7WqhoLlj+cBhzStohBYOU= -github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250226093426-131ae1505b58/go.mod h1:8uzry1RGoxmw2aeJVE/8kLIFTXCE23ApLUNRUGFRu90= +github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250226094621-9317a4bcdfc4 h1:MyrLOJQzdSENA1bEI4Dz7idpPv9i+MVkIcu94JH3vvw= +github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250226094621-9317a4bcdfc4/go.mod h1:8uzry1RGoxmw2aeJVE/8kLIFTXCE23ApLUNRUGFRu90= github.com/jfrog/jfrog-cli-platform-services v1.7.0 h1:u0AOyG4JX3VT7xhEeA9gDpBgW8tYILONpQURtzR3FkI= github.com/jfrog/jfrog-cli-platform-services v1.7.0/go.mod h1:u3lMRG7XC8MeUy/OPkHkZnsgCMIi0br4sjk2/W1Pm8I= github.com/jfrog/jfrog-cli-security v1.15.0 h1:TYNIID231X/AivYtptDCF25JyH8qTQht6ISHRfwejL8= diff --git a/lifecycle/cli.go b/lifecycle/cli.go index 0e7b03181..9d3cbe5d5 100644 --- a/lifecycle/cli.go +++ b/lifecycle/cli.go @@ -222,7 +222,7 @@ func getReleaseBundleCreationSpec(c *cli.Context) (*spec.SpecFiles, error) { buildNumber := getStringFlagOrEnv(c, cliutils.BuildNumber, coreutils.BuildNumber) if buildName != "" && buildNumber != "" { - return speccore.CreateSpecFromBuildNameAndNumber(buildName, buildNumber) + return speccore.CreateSpecFromBuildNameNumberAndProject(buildName, buildNumber, cliutils.GetProject(c)) } return nil, fmt.Errorf("either the --spec flag must be provided, " + diff --git a/lifecycle_test.go b/lifecycle_test.go index 976c8e67d..389b50251 100644 --- a/lifecycle_test.go +++ b/lifecycle_test.go @@ -218,16 +218,27 @@ func uploadBuilds(t *testing.T) func() { } } +func uploadBuildsWithProject(t *testing.T) func() { + uploadBuildWithArtifactsAndProject(t, tests.UploadDevSpecA, tests.LcBuildName1, number1, tests.ProjectKey) + uploadBuildWithArtifactsAndProject(t, tests.UploadDevSpecB, tests.LcBuildName2, number2, tests.ProjectKey) + uploadBuildWithDepsAndProject(t, tests.LcBuildName3, number3, tests.ProjectKey) + return func() { + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.LcBuildName1, artHttpDetails) + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.LcBuildName2, artHttpDetails) + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.LcBuildName3, artHttpDetails) + } +} + func createRbBackwardCompatible(t *testing.T, specName, sourceOption, rbName, rbVersion string, sync bool) { specFile, err := getSpecFile(specName) assert.NoError(t, err) - createRbWithFlags(t, specFile, sourceOption, "", "", rbName, rbVersion, sync, false) + createRbWithFlags(t, specFile, sourceOption, "", "", rbName, rbVersion, "", sync, false) } func createRbFromSpec(t *testing.T, specName, rbName, rbVersion string, sync bool, withoutSigningKey bool) { specFile, err := tests.CreateSpec(specName) assert.NoError(t, err) - createRbWithFlags(t, specFile, "spec", "", "", rbName, rbVersion, sync, withoutSigningKey) + createRbWithFlags(t, specFile, "spec", "", "", rbName, rbVersion, "", sync, withoutSigningKey) } func TestCreateBundleWithoutSpec(t *testing.T) { @@ -239,16 +250,34 @@ func TestCreateBundleWithoutSpec(t *testing.T) { deleteBuilds := uploadBuilds(t) defer deleteBuilds() - createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, false, false) + createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, "", false, false) assertStatusCompleted(t, lcManager, tests.LcRbName1, number1, "") defer deleteReleaseBundle(t, lcManager, tests.LcRbName1, number1) - createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, false, true) + createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, "", false, true) assertStatusCompleted(t, lcManager, tests.LcRbName2, number2, "") defer deleteReleaseBundle(t, lcManager, tests.LcRbName2, number2) } -func createRbWithFlags(t *testing.T, specFilePath, sourceOption, buildName, buildNumber, rbName, rbVersion string, +func TestCreateBundleWithoutSpecAndWithProject(t *testing.T) { + cleanCallback := initLifecycleTest(t, signingKeyOptionalArtifactoryMinVersion) + defer cleanCallback() + deleteProject := createTestProject(t) + defer func() { + if err := deleteProject(); err != nil { + t.Error(err) + } + }() + lcManager := getLcServiceManager(t) + deleteBuilds := uploadBuildsWithProject(t) + defer deleteBuilds() + + createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey, false, false) + assertStatusCompletedWithProject(t, lcManager, tests.LcRbName1, number1, "", tests.ProjectKey) + defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName1, number1, tests.ProjectKey) +} + +func createRbWithFlags(t *testing.T, specFilePath, sourceOption, buildName, buildNumber, rbName, rbVersion, project string, sync, withoutSigningKey bool) { argsAndOptions := []string{ "rbc", @@ -273,6 +302,10 @@ func createRbWithFlags(t *testing.T, specFilePath, sourceOption, buildName, buil argsAndOptions = append(argsAndOptions, getOption(cliutils.Sync, "true")) } + if project != "" { + argsAndOptions = append(argsAndOptions, getOption(cliutils.Project, project)) + } + assert.NoError(t, lcCli.Exec(argsAndOptions...)) } @@ -335,6 +368,15 @@ func assertStatusCompleted(t *testing.T, lcManager *lifecycle.LifecycleServicesM assert.Equal(t, services.Completed, resp.Status) } +// If createdMillis is provided, assert status for promotion. If blank, assert for creation. +func assertStatusCompletedWithProject(t *testing.T, lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion, createdMillis, projectKey string) { + resp, err := getStatusWithProject(lcManager, rbName, rbVersion, createdMillis, projectKey) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, services.Completed, resp.Status) +} + func getLcServiceManager(t *testing.T) *lifecycle.LifecycleServicesManager { lcManager, err := utils.CreateLifecycleServiceManager(lcDetails, false) assert.NoError(t, err) @@ -371,6 +413,18 @@ func getStatus(lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion, return lcManager.GetReleaseBundlePromotionStatus(rbDetails, "", createdMillis, true) } +func getStatusWithProject(lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion, createdMillis, projectKey string) (services.ReleaseBundleStatusResponse, error) { + rbDetails := services.ReleaseBundleDetails{ + ReleaseBundleName: rbName, + ReleaseBundleVersion: rbVersion, + } + + if createdMillis == "" { + return lcManager.GetReleaseBundleCreationStatus(rbDetails, projectKey, true) + } + return lcManager.GetReleaseBundlePromotionStatus(rbDetails, projectKey, createdMillis, true) +} + func getReleaseBundleSpecification(lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion string) (services.ReleaseBundleSpecResponse, error) { rbDetails := services.ReleaseBundleDetails{ ReleaseBundleName: rbName, @@ -391,6 +445,17 @@ func deleteReleaseBundle(t *testing.T, lcManager *lifecycle.LifecycleServicesMan time.Sleep(5 * time.Second) } +func deleteReleaseBundleWithProject(t *testing.T, lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion, projectKey string) { + rbDetails := services.ReleaseBundleDetails{ + ReleaseBundleName: rbName, + ReleaseBundleVersion: rbVersion, + } + + assert.NoError(t, lcManager.DeleteReleaseBundleVersion(rbDetails, services.CommonOptionalQueryParams{Async: false, ProjectKey: projectKey})) + // Wait after remote deleting. Can be removed once remote deleting supports sync. + time.Sleep(5 * time.Second) +} + /* func remoteDeleteReleaseBundle(t *testing.T, lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion string) { params := distribution.NewDistributeReleaseBundleParams(rbName, rbVersion) @@ -428,6 +493,27 @@ func uploadBuildWithDeps(t *testing.T, buildName, buildNumber string) { runRt(t, "build-publish", buildName, buildNumber) } +func uploadBuildWithArtifactsAndProject(t *testing.T, specFileName, buildName, buildNumber, projectKey string) { + specFile, err := tests.CreateSpec(specFileName) + assert.NoError(t, err) + + runRt(t, "upload", "--spec="+specFile, "--build-name="+buildName, "--build-number="+buildNumber, "--project="+projectKey) + runRt(t, "build-publish", buildName, buildNumber, "--project="+projectKey) +} + +func uploadBuildWithDepsAndProject(t *testing.T, buildName, buildNumber, projectKey string) { + err := fileutils.CreateDirIfNotExist(tests.Out) + assert.NoError(t, err) + + randFile, err := io.CreateRandFile(filepath.Join(tests.Out, "dep-file"), 1000) + assert.NoError(t, err) + + runRt(t, "upload", randFile.Name(), tests.RtDevRepo, "--flat", "--project="+projectKey) + assert.NoError(t, lcCli.WithoutCredentials().Exec("rt", "bad", buildName, buildNumber, tests.RtDevRepo+"/dep-file", "--from-rt")) + + runRt(t, "build-publish", buildName, buildNumber, "--project="+projectKey) +} + func initLifecycleTest(t *testing.T, minVersion string) (cleanCallback func()) { if !*tests.TestLifecycle { t.Skip("Skipping lifecycle test. To run release bundle test add the '-test.lc=true' option.")