Skip to content
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
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ require (
github.com/jfrog/build-info-go v1.13.1-0.20260130140656-2d0d5593fccf
github.com/jfrog/gofrog v1.7.6
github.com/jfrog/jfrog-cli-application v1.0.2-0.20260127112223-c5078af84b5a
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260129054930-035e3ed7e30d
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260203090305-f5f8aed71eaf
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260128134755-624b659a398e
github.com/jfrog/jfrog-cli-evidence v0.8.3-0.20260125120022-1c6f4f382dbb
github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20251205121610-171eb9b0000e
github.com/jfrog/jfrog-cli-security v1.26.0
github.com/jfrog/jfrog-client-go v1.55.1-0.20260128141727-bd34d78a3e48
github.com/jfrog/jfrog-client-go v1.55.1-0.20260202100450-1b20bddfdb3f
github.com/jszwec/csvutil v1.10.0
github.com/manifoldco/promptui v0.9.0
github.com/spf13/viper v1.21.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1218,8 +1218,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-application v1.0.2-0.20260127112223-c5078af84b5a h1:Yvl7XuMoI1cXk3jzB1oWcZvFy5K3aUAIin9o5GRaqzE=
github.com/jfrog/jfrog-cli-application v1.0.2-0.20260127112223-c5078af84b5a/go.mod h1:xum2HquWO5uExa/A7MQs3TgJJVEeoqTR+6Z4mfBr1Xw=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260129054930-035e3ed7e30d h1:jyBD9kqAL8eHerZvGmxiTZECA+sYuH3TpodGnnpnPSs=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260129054930-035e3ed7e30d/go.mod h1:ANFZOB4AX+Voo24l1BO8bVvN76m3ZViR1QaK5u3QDgE=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260203090305-f5f8aed71eaf h1:3W7qIxrkJkC1K0vB/By3fVyCkU3qgY9SdHQs7o5RNRo=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260203090305-f5f8aed71eaf/go.mod h1:DkLAN+AvZ4v6jcuUStufi9DuhAS1dvSRJhILJyRa9kg=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260128134755-624b659a398e h1:jGtYjWMMfCINDl1JbRtvAijtVwD+j+yvR5BuYMZvRrA=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260128134755-624b659a398e/go.mod h1:+Hnaikp/xCSPD/q7txxRy4Zc0wzjW/usrCSf+6uONSQ=
github.com/jfrog/jfrog-cli-evidence v0.8.3-0.20260125120022-1c6f4f382dbb h1:4nGzxRxVcXxkFg95jr+zMjESisZGqSYecXfHsA37rpA=
Expand All @@ -1228,8 +1228,8 @@ github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20251205121610-171eb9b000
github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20251205121610-171eb9b0000e/go.mod h1:qbu4iqBST9x8LgD8HhzUm91iOB3vHqtoGmaxOnmw0ok=
github.com/jfrog/jfrog-cli-security v1.26.0 h1:FcLshS1Ahm0++nV5q7UluFTCVRxH2wEIbqO7ZBag++I=
github.com/jfrog/jfrog-cli-security v1.26.0/go.mod h1:r9E0BdlNy6mq6gkRGslZRZaYe6WeGhLkpUm8+oEUOvU=
github.com/jfrog/jfrog-client-go v1.55.1-0.20260128141727-bd34d78a3e48 h1:HY4b9DsUe0Lox1rScYHKmfIZY9PQvy0kfkOefqc/QdQ=
github.com/jfrog/jfrog-client-go v1.55.1-0.20260128141727-bd34d78a3e48/go.mod h1:sCE06+GngPoyrGO0c+vmhgMoVSP83UMNiZnIuNPzU8U=
github.com/jfrog/jfrog-client-go v1.55.1-0.20260202100450-1b20bddfdb3f h1:A/5DenqKB4zv9jWhG777/UwhoGL8hCzIndKj0sJ7QSM=
github.com/jfrog/jfrog-client-go v1.55.1-0.20260202100450-1b20bddfdb3f/go.mod h1:sCE06+GngPoyrGO0c+vmhgMoVSP83UMNiZnIuNPzU8U=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY=
Expand Down
143 changes: 133 additions & 10 deletions lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
artifactoryLifecycleMinVersion = "7.68.3"
signingKeyOptionalArtifactoryMinVersion = "7.104.1"
promotionTypeFlagArtifactoryMinVersion = "7.106.1"
draftBundleArtifactoryMinVersion = "7.136.0"
gpgKeyPairName = "lc-tests-key-pair"
lcTestdataPath = "lifecycle"
releaseBundlesSpec = "release-bundles-spec.json"
Expand Down Expand Up @@ -167,7 +168,7 @@ func TestReleaseBundleCreationFromMultiBundlesUsingCommandFlagWithProject(t *tes
defer deleteBuilds()

// Create first release bundle from builds with project
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey, true, true)
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey, true, true, false)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName1, number1, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName1, number1, "", tests.ProjectKey)

Expand All @@ -177,7 +178,7 @@ func TestReleaseBundleCreationFromMultiBundlesUsingCommandFlagWithProject(t *tes
assert.True(t, isExist, "Release bundle %s/%s should exist in project %s", tests.LcRbName1, number1, tests.ProjectKey)

// Create second release bundle from builds with project
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, tests.ProjectKey, true, true)
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, tests.ProjectKey, true, true, false)
defer deleteReleaseBundleWithProject(t, lcManager, tests.LcRbName2, number2, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, tests.LcRbName2, number2, "", tests.ProjectKey)

Expand Down Expand Up @@ -489,6 +490,85 @@ func TestPromoteReleaseBundleWithPromotionTypeFlag(t *testing.T) {
assertStatusCompleted(t, lcManager, tests.LcRbName1, number1, "")
}

func TestReleaseBundleCreationWithDraftFlagFromSpec(t *testing.T) {
cleanCallback := initLifecycleTest(t, draftBundleArtifactoryMinVersion)
defer cleanCallback()
lcManager := getLcServiceManager(t)

deleteBuilds := uploadBuilds(t)
defer deleteBuilds()

// Create draft bundle from spec
createRbFromSpecWithDraft(t, tests.LifecycleBuilds12, tests.LcRbName1, number1, true, true, true)
defer deleteReleaseBundle(t, lcManager, tests.LcRbName1, number1)
assertStatusDraft(t, lcManager, tests.LcRbName1, number1)
}

func TestReleaseBundleCreationWithDraftFlagFromFlags(t *testing.T) {
cleanCallback := initLifecycleTest(t, draftBundleArtifactoryMinVersion)
defer cleanCallback()
lcManager := getLcServiceManager(t)

deleteBuilds := uploadBuilds(t)
defer deleteBuilds()

// Create draft bundle using build-name/build-number flags
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, "default", true, true, true)
defer deleteReleaseBundle(t, lcManager, tests.LcRbName2, number2)
assertStatusDraft(t, lcManager, tests.LcRbName2, number2)
}

func TestReleaseBundleUpdateWithSpec(t *testing.T) {
cleanCallback := initLifecycleTest(t, draftBundleArtifactoryMinVersion)
defer cleanCallback()
lcManager := getLcServiceManager(t)

deleteBuilds := uploadBuilds(t)
defer deleteBuilds()

// Create a draft bundle from build 1
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, "default", true, true, true)
defer deleteReleaseBundle(t, lcManager, tests.LcRbName1, number1)
assertStatusDraft(t, lcManager, tests.LcRbName1, number1)
assertRbArtifacts(t, lcManager, tests.LcRbName1, number1, tests.GetExpectedLifecycleBuild1Artifacts())

// Update the draft bundle by adding build 3 (which includes dependencies) using spec file
updateSpecFile, err := tests.CreateSpec(tests.LifecycleBuilds3)
assert.NoError(t, err)
updateRbWithFlags(t, updateSpecFile, tests.LcRbName1, number1, "default", "", true)

// Verify the bundle is still in DRAFT status after update
assertStatusDraft(t, lcManager, tests.LcRbName1, number1)

// Verify the bundle now contains artifacts from both build 1 and build 3
assertRbArtifacts(t, lcManager, tests.LcRbName1, number1, tests.GetExpectedLifecycleUpdateArtifacts())
}

func TestReleaseBundleUpdateWithFlags(t *testing.T) {
cleanCallback := initLifecycleTest(t, draftBundleArtifactoryMinVersion)
defer cleanCallback()
lcManager := getLcServiceManager(t)

deleteBuilds := uploadBuilds(t)
defer deleteBuilds()

// Create a draft bundle from build 2
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, "default", true, true, true)
defer deleteReleaseBundle(t, lcManager, tests.LcRbName2, number2)
assertStatusDraft(t, lcManager, tests.LcRbName2, number2)
assertRbArtifacts(t, lcManager, tests.LcRbName2, number2, tests.GetExpectedLifecycleBuild2Artifacts())

// Update draft using --source-type-builds flag to add build 3
sourceBuildsFlag := fmt.Sprintf("name=%s,id=%s,include-deps=true", tests.LcBuildName3, number3)
updateRbWithFlags(t, "", tests.LcRbName2, number2, "default", sourceBuildsFlag, true)

// Verify the bundle is still in DRAFT status after update
assertStatusDraft(t, lcManager, tests.LcRbName2, number2)

// Verify the bundle now contains artifacts from both build 2 and build 3
assertRbArtifacts(t, lcManager, tests.LcRbName2, number2, tests.GetExpectedLifecycleUpdateBuild2Artifacts())
}

/*func deleteExportedReleaseBundle(t *testing.T, rbName string) {
assert.NoError(t, os.RemoveAll(rbName))
}*/
Expand Down Expand Up @@ -524,13 +604,19 @@ func uploadBuildsWithProject(t *testing.T) func() {
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, 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, false)
}

func createRbFromSpecWithDraft(t *testing.T, specName, rbName, rbVersion string, sync, withoutSigningKey, draft bool) {
specFile, err := tests.CreateSpec(specName)
assert.NoError(t, err)
createRbWithFlags(t, specFile, "spec", "", "", rbName, rbVersion, "", sync, withoutSigningKey, draft)
}

func TestCreateBundleWithoutSpec(t *testing.T) {
Expand All @@ -542,11 +628,11 @@ func TestCreateBundleWithoutSpec(t *testing.T) {
deleteBuilds := uploadBuilds(t)
defer deleteBuilds()

createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, "default", false, false)
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, "default", false, false, false)
assertStatusCompleted(t, lcManager, tests.LcRbName1, number1, "")
defer deleteReleaseBundle(t, lcManager, tests.LcRbName1, number1)

createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, "default", false, true)
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, tests.LcRbName2, number2, "default", false, true, false)
assertStatusCompleted(t, lcManager, tests.LcRbName2, number2, "")
defer deleteReleaseBundle(t, lcManager, tests.LcRbName2, number2)
}
Expand All @@ -566,13 +652,13 @@ func TestCreateBundleWithoutSpecAndWithProject(t *testing.T) {
deleteBuilds := uploadBuildsWithProject(t)
defer deleteBuilds()

createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey, false, false)
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, tests.LcRbName1, number1, tests.ProjectKey, false, 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,
sync, withoutSigningKey, draft bool,
) {
argsAndOptions := []string{
"rbc",
Expand Down Expand Up @@ -601,6 +687,35 @@ func createRbWithFlags(t *testing.T, specFilePath, sourceOption, buildName, buil
argsAndOptions = append(argsAndOptions, getOption(cliutils.Project, project))
}

if draft {
argsAndOptions = append(argsAndOptions, getOption(cliutils.Draft, "true"))
}

assert.NoError(t, lcCli.Exec(argsAndOptions...))
}

func updateRbWithFlags(t *testing.T, specFilePath, rbName, rbVersion, project, sourceTypeBuilds string, sync bool) {
argsAndOptions := []string{
"rbu",
rbName,
rbVersion,
"--add", // Mandatory flag for rbu
}

if specFilePath != "" {
argsAndOptions = append(argsAndOptions, getOption("spec", specFilePath))
}

if sourceTypeBuilds != "" {
argsAndOptions = append(argsAndOptions, getOption("source-type-builds", sourceTypeBuilds))
}

if project != "" {
argsAndOptions = append(argsAndOptions, getOption(cliutils.Project, project))
}

argsAndOptions = append(argsAndOptions, getOption(cliutils.Sync, strconv.FormatBool(sync)))

assert.NoError(t, lcCli.Exec(argsAndOptions...))
}

Expand Down Expand Up @@ -665,6 +780,14 @@ func assertStatusCompleted(t *testing.T, lcManager *lifecycle.LifecycleServicesM
assert.Equal(t, services.Completed, resp.Status)
}

func assertStatusDraft(t *testing.T, lcManager *lifecycle.LifecycleServicesManager, rbName, rbVersion string) {
resp, err := getStatus(lcManager, rbName, rbVersion, "")
if !assert.NoError(t, err) {
return
}
assert.Equal(t, services.Draft, resp.Status)
}

// If createdMillis is provided, assert status for promotion. If blank, assert for creation.
//
//nolint:unparam // createdMillis parameter is kept for API consistency with existing tests
Expand Down Expand Up @@ -1204,13 +1327,13 @@ func TestReleaseBundlesSearchVersions(t *testing.T) {
}

// Create release bundles with project
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, projectRbName, projectVersionA, tests.ProjectKey, true, false)
createRbWithFlags(t, "", "", tests.LcBuildName1, number1, projectRbName, projectVersionA, tests.ProjectKey, true, false, false)
defer deleteReleaseBundleWithProject(t, lcManager, projectRbName, projectVersionA, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, projectRbName, projectVersionA, "", tests.ProjectKey)

time.Sleep(1 * time.Second)

createRbWithFlags(t, "", "", tests.LcBuildName2, number2, projectRbName, projectVersionB, tests.ProjectKey, true, false)
createRbWithFlags(t, "", "", tests.LcBuildName2, number2, projectRbName, projectVersionB, tests.ProjectKey, true, false, false)
defer deleteReleaseBundleWithProject(t, lcManager, projectRbName, projectVersionB, tests.ProjectKey)
assertStatusCompletedWithProject(t, lcManager, projectRbName, projectVersionB, "", tests.ProjectKey)

Expand Down
1 change: 1 addition & 0 deletions utils/cliutils/commandsflags.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ const (
SigningKey = "signing-key"
setupRepo = repo
PromotionType = "promotion-type"
Draft = "draft"
)

var flagsMap = map[string]cli.Flag{
Expand Down
40 changes: 40 additions & 0 deletions utils/tests/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2157,6 +2157,46 @@ func GetExpectedLifecycleCreationByAql() []string {
}
}

// GetExpectedLifecycleBuild1Artifacts returns expected artifacts from build 1 only.
func GetExpectedLifecycleBuild1Artifacts() []string {
return []string{
RtDevRepo + "/a1.in",
RtDevRepo + "/a2.in",
RtDevRepo + "/a3.in",
}
}

// GetExpectedLifecycleUpdateArtifacts returns expected artifacts after updating a draft bundle
// that was created from build 1 (a1.in, a2.in, a3.in) with build 3 (dep-file as dependency).
func GetExpectedLifecycleUpdateArtifacts() []string {
return []string{
RtDevRepo + "/a1.in",
RtDevRepo + "/a2.in",
RtDevRepo + "/a3.in",
RtDevRepo + "/dep-file",
}
}

// GetExpectedLifecycleBuild2Artifacts returns expected artifacts from build 2 only.
func GetExpectedLifecycleBuild2Artifacts() []string {
return []string{
RtDevRepo + "/b1.in",
RtDevRepo + "/b2.in",
RtDevRepo + "/b3.in",
}
}

// GetExpectedLifecycleUpdateBuild2Artifacts returns expected artifacts after updating a draft bundle
// that was created from build 2 (b1.in, b2.in, b3.in) with build 3 (dep-file as dependency).
func GetExpectedLifecycleUpdateBuild2Artifacts() []string {
return []string{
RtDevRepo + "/b1.in",
RtDevRepo + "/b2.in",
RtDevRepo + "/b3.in",
RtDevRepo + "/dep-file",
}
}

func GetExpectedLifecycleArtifacts() []string {
return []string{
RtProdRepo1 + "/a1.in",
Expand Down
Loading