Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
RBC command - Turn spec flag optional, adding support in buildName an…
Browse files Browse the repository at this point in the history
…d buildNumber
oshratZairi committed Nov 27, 2024
1 parent 3bf322b commit 57f6280
Showing 8 changed files with 244 additions and 37 deletions.
18 changes: 8 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
@@ -16,13 +16,13 @@ require (
github.com/docker/docker v27.3.1+incompatible
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1
github.com/jfrog/archiver/v3 v3.6.1
github.com/jfrog/build-info-go v1.10.5
github.com/jfrog/build-info-go v1.10.6
github.com/jfrog/gofrog v1.7.6
github.com/jfrog/jfrog-cli-artifactory v0.1.7
github.com/jfrog/jfrog-cli-core/v2 v2.56.8
github.com/jfrog/jfrog-cli-core/v2 v2.57.0
github.com/jfrog/jfrog-cli-platform-services v1.4.0
github.com/jfrog/jfrog-cli-security v1.12.5
github.com/jfrog/jfrog-client-go v1.48.0
github.com/jfrog/jfrog-cli-security v1.13.1
github.com/jfrog/jfrog-client-go v1.48.1
github.com/jszwec/csvutil v1.10.0
github.com/manifoldco/promptui v0.9.0
github.com/stretchr/testify v1.9.0
@@ -167,12 +167,10 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)

replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20241121163158-04daeb8132c3

replace github.com/jfrog/jfrog-cli-security => github.com/EyalDelarea/jfrog-cli-security v0.0.0-20241121103043-02719f295f02
replace github.com/jfrog/jfrog-cli-security => github.com/attiasas/jfrog-cli-security v0.0.0-20241127094042-0a28e03bc754

//replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20241121163158-04daeb8132c3
//replace github.com/jfrog/jfrog-cli-security => github.com/EyalDelarea/jfrog-cli-security v0.0.0-20241121103043-02719f295f02
// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240918081224-1c584cc334c7

replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20241121100855-e7a75ceee2bd

//replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20241121100855-e7a75ceee2bd
// replace github.com/jfrog/gofrog => github.com/jfrog/gofrog dev
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
@@ -10,8 +10,6 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/CycloneDX/cyclonedx-go v0.9.0 h1:inaif7qD8bivyxp7XLgxUYtOXWtDez7+j72qKTMQTb8=
github.com/CycloneDX/cyclonedx-go v0.9.0/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw=
github.com/EyalDelarea/jfrog-cli-security v0.0.0-20241121103043-02719f295f02 h1:oyTvu0FWw+qlEcinSd/8/U+JWR00uQSSa9y0fO+ZVAo=
github.com/EyalDelarea/jfrog-cli-security v0.0.0-20241121103043-02719f295f02/go.mod h1:5LBGwth7TXkEH8MO0JJXvpoRktMAV2BK7Q5nQePNrv4=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
@@ -32,6 +30,8 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/attiasas/jfrog-cli-security v0.0.0-20241127094042-0a28e03bc754 h1:tnraoKqMyE6GsJtQ+Rotmh5dhACF/Zks+zBxgr7GEGg=
github.com/attiasas/jfrog-cli-security v0.0.0-20241127094042-0a28e03bc754/go.mod h1:0oEKO2/vVvBC3m9SSWcKx4tWG6sPmvy4Mn4RD2zlSEQ=
github.com/beevik/etree v1.4.0 h1:oz1UedHRepuY3p4N5OjE0nK1WLCqtzHf25bxplKOHLs=
github.com/beevik/etree v1.4.0/go.mod h1:cyWiXwGoasx60gHvtnEh5x8+uIjUVnjWqBvEnhnqKDA=
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
@@ -163,8 +163,8 @@ github.com/jedib0t/go-pretty/v6 v6.6.1 h1:iJ65Xjb680rHcikRj6DSIbzCex2huitmc7bDtx
github.com/jedib0t/go-pretty/v6 v6.6.1/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
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.20241121100855-e7a75ceee2bd h1:PzxnJ1mjHIL4bAC4RPm87WnJ1TZXFBicyOhtIHRQH6g=
github.com/jfrog/build-info-go v1.8.9-0.20241121100855-e7a75ceee2bd/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE=
github.com/jfrog/build-info-go v1.10.6 h1:zH1ZhXlVfi5DlFyunygHjrdOcnv5qxfeLqmsfD4+lc4=
github.com/jfrog/build-info-go v1.10.6/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/gofrog v1.7.6 h1:QmfAiRzVyaI7JYGsB7cxfAJePAZTzFz0gRWZSE27c6s=
@@ -173,12 +173,12 @@ 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.7 h1:/PBDO6nS6cf3PK+GRkd6BJtZnvYasi1PrQhRiayirso=
github.com/jfrog/jfrog-cli-artifactory v0.1.7/go.mod h1:M5pZTHnsYNDmml/FAnoxxt4QiHOIUHPx91th30AtwfM=
github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20241121163158-04daeb8132c3 h1:cJSPTMflqE+ucC/h2/BB6BkVxz3BG8PnivCb00Dxt/Y=
github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20241121163158-04daeb8132c3/go.mod h1:zVyWxMkBpZwy/AvTohefIlaZzYKBMFje+gKKKlkunNo=
github.com/jfrog/jfrog-cli-core/v2 v2.57.0 h1:3ON0J6Sjc2+4HZrzh4eSbdciXx3sJsJUIJ3TPQXh/5c=
github.com/jfrog/jfrog-cli-core/v2 v2.57.0/go.mod h1:SThaC/fniC96oN8YgCsHjvOxp5rBM7IppuIybn1oxT0=
github.com/jfrog/jfrog-cli-platform-services v1.4.0 h1:g6A30+tOfXd1h6VASeNwH+5mhs5bPQJ0MFzZs/4nlvs=
github.com/jfrog/jfrog-cli-platform-services v1.4.0/go.mod h1:Ky4SDXuMeaiNP/5zMT1YSzIuXG+cNYYOl8BaEA7Awbc=
github.com/jfrog/jfrog-client-go v1.48.0 h1:hx5B7+Wnobmzq4aFVZtALtbEVDFcjpn0Wb4q2m6H4KU=
github.com/jfrog/jfrog-client-go v1.48.0/go.mod h1:1a7bmQHkRmPEza9wva2+WVrYzrGbosrMymq57kyG5gU=
github.com/jfrog/jfrog-client-go v1.48.1 h1:R6x6gazy0F196XXDhDdRAxmNplSJ5SrJfEmmNBgks/8=
github.com/jfrog/jfrog-client-go v1.48.1/go.mod h1:1a7bmQHkRmPEza9wva2+WVrYzrGbosrMymq57kyG5gU=
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=
77 changes: 68 additions & 9 deletions lifecycle/cli.go
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ package lifecycle

import (
"errors"
"fmt"
commonCliUtils "github.com/jfrog/jfrog-cli-core/v2/common/cliutils"
"github.com/jfrog/jfrog-cli-core/v2/common/commands"
"github.com/jfrog/jfrog-cli-core/v2/common/spec"
@@ -24,6 +25,7 @@ import (
"github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/urfave/cli"
"os"
"strings"
)

@@ -131,21 +133,56 @@ func validateCreateReleaseBundleContext(c *cli.Context) error {
}

func assertValidCreationMethod(c *cli.Context) error {
// Determine the methods provided
methods := []bool{
c.IsSet("spec"), c.IsSet(cliutils.Builds), c.IsSet(cliutils.ReleaseBundles)}
if coreutils.SumTrueValues(methods) > 1 {
return errorutils.CheckErrorf("exactly one creation source must be supplied: --%s, --%s or --%s.\n"+
"Opt to use the --%s option as the --%s and --%s are deprecated",
c.IsSet("spec"),
c.IsSet(cliutils.Builds),
c.IsSet(cliutils.ReleaseBundles),
}
methodCount := coreutils.SumTrueValues(methods)

// Validate that only one creation method is provided
if err := validateSingleCreationMethod(methodCount); err != nil {
return err
}

if err := validateCreationValuesPresence(c, methodCount); err != nil {
return err
}
return nil
}

func validateSingleCreationMethod(methodCount int) error {
if methodCount > 1 {
return errorutils.CheckErrorf(
"exactly one creation source must be supplied: --%s, --%s, or --%s.\n"+
"Opt to use the --%s option as the --%s and --%s are deprecated",
"spec", cliutils.Builds, cliutils.ReleaseBundles,
"spec", cliutils.Builds, cliutils.ReleaseBundles,
"spec", cliutils.Builds, cliutils.ReleaseBundles)
)
}
// If the user did not provide a source, we suggest only the recommended spec approach.
if coreutils.SumTrueValues(methods) == 0 {
return errorutils.CheckErrorf("the --spec option is mandatory")
return nil
}

func validateCreationValuesPresence(c *cli.Context, methodCount int) error {
if methodCount == 0 {
if !areBuildFlagsSet(c) && !areBuildEnvVarsSet() {
return errorutils.CheckErrorf("Either --build-name or JFROG_CLI_BUILD_NAME, and --build-number or JFROG_CLI_BUILD_NUMBER must be defined")
}
}
return nil
}

// areBuildFlagsSet checks if build-name or build-number flags are set.
func areBuildFlagsSet(c *cli.Context) bool {
return c.IsSet(cliutils.BuildName) || c.IsSet(cliutils.BuildNumber)
}

// areBuildEnvVarsSet checks if build environment variables are set.
func areBuildEnvVarsSet() bool {
return os.Getenv("JFROG_CLI_BUILD_NUMBER") != "" && os.Getenv("JFROG_CLI_BUILD_NAME") != ""
}

func create(c *cli.Context) (err error) {
if err = validateCreateReleaseBundleContext(c); err != nil {
return err
@@ -169,10 +206,32 @@ func create(c *cli.Context) (err error) {
}

func getReleaseBundleCreationSpec(c *cli.Context) (*spec.SpecFiles, error) {
if c.IsSet(cliutils.Builds) || c.IsSet(cliutils.ReleaseBundles) {
return nil, nil
}

// Check if the "spec" flag is set
if c.IsSet("spec") {
return cliutils.GetSpec(c, true, false)
}
return nil, nil

// Retrieve build name and build number from command line flags or environment variables
buildName := getStringFlagOrEnv(c, "build-name", "JFROG_CLI_BUILD_NAME")
buildNumber := getStringFlagOrEnv(c, "build-number", "JFROG_CLI_BUILD_NUMBER")

// If both buildName and buildNumber are provided, generate the spec
if buildName != "" && buildNumber != "" {
return cliutils.GetSpecFromVariables(buildNumber, buildName)
}

return nil, fmt.Errorf("either the 'spec' flag must be set, or both '--build-name' and '--build-number' or the corresponding environment variables 'JFROG_CLI_BUILD_NAME' and 'JFROG_CLI_BUILD_NUMBER' must be defined")
}

func getStringFlagOrEnv(c *cli.Context, flag string, envVar string) string {
if c.IsSet(flag) {
return c.String(flag)
}
return os.Getenv(envVar)
}

func promote(c *cli.Context) error {
67 changes: 67 additions & 0 deletions lifecycle/cli_test.go
Original file line number Diff line number Diff line change
@@ -56,3 +56,70 @@ func TestCreateReleaseBundleSpecWithProject(t *testing.T) {
creationSpec.Get(0).Project = ""
assert.Equal(t, projectKey, cliutils.GetProject(context))
}

func TestGetReleaseBundleCreationSpec(t *testing.T) {

t.Run("Spec Flag Set", func(t *testing.T) {
specFile := filepath.Join("testdata", "specfile.json")
ctx, _ := tests.CreateContext(t, []string{"spec=" + specFile}, []string{})

spec, err := getReleaseBundleCreationSpec(ctx)

assert.NoError(t, err)
assert.NotNil(t, spec)
})

t.Run("Build Name and Number Set via Flags", func(t *testing.T) {
ctx, _ := tests.CreateContext(t, []string{"build-name=Common-builds", "build-number=1.0.0"}, []string{})

spec, err := getReleaseBundleCreationSpec(ctx)

assert.NoError(t, err)
assert.NotNil(t, spec)
assert.Equal(t, "Common-builds/1.0.0", spec.Files[0].Build)
})

t.Run("Build Name and Number Set via Env Variables", func(t *testing.T) {
t.Setenv("JFROG_CLI_BUILD_NAME", "Common-builds")
t.Setenv("JFROG_CLI_BUILD_NUMBER", "2.0.0")

ctx, _ := tests.CreateContext(t, []string{}, []string{})

spec, err := getReleaseBundleCreationSpec(ctx)

assert.NoError(t, err)
assert.NotNil(t, spec)
assert.Equal(t, "Common-builds/2.0.0", spec.Files[0].Build)
})

t.Run("Missing Build Name and Number", func(t *testing.T) {
ctx, _ := tests.CreateContext(t, []string{}, []string{})

spec, err := getReleaseBundleCreationSpec(ctx)

assert.Error(t, err)
assert.Nil(t, spec)
assert.EqualError(t, err, "either the 'spec' flag must be set, or both '--build-name' and '--build-number' or the corresponding environment variables 'JFROG_CLI_BUILD_NAME' and 'JFROG_CLI_BUILD_NUMBER' must be defined")
})

t.Run("Only One Build Variable Set", func(t *testing.T) {
ctx, _ := tests.CreateContext(t, []string{"build-name=Common-builds"}, []string{})

spec, err := getReleaseBundleCreationSpec(ctx)

assert.Error(t, err)
assert.Nil(t, spec)
assert.EqualError(t, err, "either the 'spec' flag must be set, or both '--build-name' and '--build-number' or the corresponding environment variables 'JFROG_CLI_BUILD_NAME' and 'JFROG_CLI_BUILD_NUMBER' must be defined")
})

t.Run("One Env Variable One Flag", func(t *testing.T) {
ctx, _ := tests.CreateContext(t, []string{"build-name=Common-builds"}, []string{})
t.Setenv("JFROG_CLI_BUILD_NUMBER", "2.0.0")

spec, err := getReleaseBundleCreationSpec(ctx)

assert.NoError(t, err)
assert.NotNil(t, spec)
assert.Equal(t, "Common-builds/2.0.0", spec.Files[0].Build)
})
}
83 changes: 74 additions & 9 deletions lifecycle_test.go
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/jfrog/gofrog/io"
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
"github.com/jfrog/jfrog-cli-core/v2/common/spec"
configUtils "github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests"
@@ -24,6 +25,7 @@ import (
"os"
"path"
"path/filepath"
"strconv"
"testing"
"time"
)
@@ -167,7 +169,24 @@ func TestLifecycleFullFlow(t *testing.T) {
// Verify the artifacts were distributed correctly by the provided path mappings.
assertExpectedArtifacts(t, tests.SearchAllDevRepo, tests.GetExpectedLifecycleDistributedArtifacts())
*/
}

func TestCreateBundleWithoutSpec(t *testing.T) {
cleanCallback := initLifecycleTest(t, artifactoryLifecycleMinVersion)
defer cleanCallback()

lcManager := getLcServiceManager(t)

deleteBuilds := uploadBuilds(t)
defer deleteBuilds()

createRbFromBuildNameAndNumber(t, tests.LifecycleBuilds12, tests.LcRbName1, number1, true, false)
defer deleteReleaseBundle(t, lcManager, tests.LcRbName1, number1)
assertStatusCompleted(t, lcManager, tests.LcRbName1, number1, "")

createRbFromBuildNameAndNumber(t, tests.LifecycleBuilds12, tests.LcRbName1, number2, true, true)
defer deleteReleaseBundle(t, lcManager, tests.LcRbName1, number2)
assertStatusCompleted(t, lcManager, tests.LcRbName1, number2, "")
}

// Import bundles only work on onPerm platforms
@@ -215,21 +234,67 @@ func createRbFromSpec(t *testing.T, specName, rbName, rbVersion string, sync boo
createRb(t, specFile, "spec", rbName, rbVersion, sync, withoutSigningKey)
}

func createRb(t *testing.T, specFilePath, sourceOption, rbName, rbVersion string, sync bool, withoutSigningKey bool) {
argsAndOptions := []string{
"rbc",
rbName,
rbVersion,
func createRbFromBuildNameAndNumber(t *testing.T, specName, rbName, rbVersion string, sync bool, withoutKey bool) {
filePath, err := tests.CreateSpec(specName)
assert.NoError(t, err)

specFile, err := os.Open(filePath)
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer specFile.Close()
var specData spec.SpecFiles
decoder := json.NewDecoder(specFile)
if err := decoder.Decode(&specData); err != nil {
fmt.Println("Error decoding JSON:", err)
return
}

buildInfo := specData.Files[0].Build
buildName, buildNumber, err := tests.ExtractBuildInfo(buildInfo)
assert.NoError(t, err)

options := []string{
getOption(cliutils.BuildName, buildName),
getOption(cliutils.BuildNumber, buildNumber),
}

if !withoutKey {
options = append(options, getOption(cliutils.SigningKey, gpgKeyPairName))
}

if sync {
options = append(options, getOption(cliutils.Sync, strconv.FormatBool(sync)))
}

createRbWithOptions(t, rbName, rbVersion, options...)
}

func createRb(t *testing.T, specFilePath, sourceOption, rbName, rbVersion string, sync bool, withoutKey bool) {
options := []string{
getOption(sourceOption, specFilePath),
}

if !withoutSigningKey {
argsAndOptions = append(argsAndOptions, getOption(cliutils.SigningKey, gpgKeyPairName))
if !withoutKey {
options = append(options, getOption(cliutils.SigningKey, gpgKeyPairName))
}
// Add the --sync option only if requested, to test the default value.

if sync {
argsAndOptions = append(argsAndOptions, getOption(cliutils.Sync, "true"))
options = append(options, getOption(cliutils.Sync, "true"))
}

createRbWithOptions(t, rbName, rbVersion, options...)
}

func createRbWithOptions(t *testing.T, rbName, rbVersion string, options ...string) {
argsAndOptions := []string{
"rbc",
rbName,
rbVersion,
}

argsAndOptions = append(argsAndOptions, options...)
assert.NoError(t, lcCli.Exec(argsAndOptions...))
}

Loading

0 comments on commit 57f6280

Please sign in to comment.