Skip to content

Commit

Permalink
RBC command - Turn spec flag optional, adding support in buildName an…
Browse files Browse the repository at this point in the history
…d buildNumber
  • Loading branch information
oshratZairi committed Nov 27, 2024
1 parent 9e8e64f commit 5fe48da
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 30 deletions.
13 changes: 8 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.6
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
Expand Down Expand Up @@ -167,9 +167,12 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)

//replace github.com/jfrog/jfrog-cli-core/v2 => ../jfrog-cli-core/
//replace github.com/jfrog/jfrog-cli-core/v2 => .github.com/jfrog/jfrog-cli-core dev

// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20241113152357-24197a744331

// replace github.com/jfrog/jfrog-cli-security => github.com/jfrog/jfrog-cli-security v1.12.5-0.20241107141149-42cf964808a1
replace github.com/jfrog/jfrog-cli-security => github.com/attiasas/jfrog-cli-security v0.0.0-20241127094042-0a28e03bc754

// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240918081224-1c584cc334c7

Expand Down
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -30,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=
Expand Down Expand Up @@ -161,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.10.5 h1:cW03JlPlKv7RMUU896uLUxyLWXAmCgR5Y5QX0fwgz0Q=
github.com/jfrog/build-info-go v1.10.5/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=
Expand All @@ -171,14 +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.6 h1:bMfJsrLQJw0dZp4nqUf1xOmtY0rpCatW/I5q88x+fhQ=
github.com/jfrog/jfrog-cli-artifactory v0.1.6/go.mod h1:jbNb22ebtupcjdhrdGq0VBew2vWG6VUK04xxGNDfynE=
github.com/jfrog/jfrog-cli-core/v2 v2.56.8 h1:UexulAwRVN20VmYACijkTFYKqtUq5myE4okEgmUrorw=
github.com/jfrog/jfrog-cli-core/v2 v2.56.8/go.mod h1:RY74eDpw1WBxruSfZ0HO1ax7c1NAj+rbBgA/hVOJNME=
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-cli-security v1.12.5 h1:2JHPyapXuHQw/qEaElGxBUGrJCZlVFLXDdxkqhf10vE=
github.com/jfrog/jfrog-cli-security v1.12.5/go.mod h1:5LBGwth7TXkEH8MO0JJXvpoRktMAV2BK7Q5nQePNrv4=
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=
Expand Down
77 changes: 68 additions & 9 deletions lifecycle/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
)

Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down
67 changes: 67 additions & 0 deletions lifecycle/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
}
78 changes: 71 additions & 7 deletions lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -24,6 +25,7 @@ import (
"os"
"path"
"path/filepath"
"strconv"
"testing"
"time"
)
Expand Down Expand Up @@ -160,7 +162,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)
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
Expand Down Expand Up @@ -208,22 +227,67 @@ func createRbFromSpec(t *testing.T, specName, rbName, rbVersion string, sync boo
createRb(t, specFile, "spec", rbName, rbVersion, sync, withoutKey)
}

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) {
argsAndOptions := []string{
"rbc",
rbName,
rbVersion,
options := []string{
getOption(sourceOption, specFilePath),
}

if !withoutKey {
argsAndOptions = append(argsAndOptions, getOption(cliutils.SigningKey, gpgKeyPairName))
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...))
}

Expand Down
4 changes: 3 additions & 1 deletion utils/cliutils/commandsflags.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,8 @@ const (
ReleaseBundles = "release-bundles"
lcReleaseBundles = lifecyclePrefix + ReleaseBundles
SigningKey = "signing-key"
BuildName = "build-name"
BuildNumber = "build-number"
lcSigningKey = lifecyclePrefix + SigningKey
PathMappingPattern = "mapping-pattern"
lcPathMappingPattern = lifecyclePrefix + PathMappingPattern
Expand Down Expand Up @@ -2015,7 +2017,7 @@ var commandFlags = map[string][]string{
},
ReleaseBundleCreate: {
platformUrl, user, password, accessToken, serverId, lcSigningKey, lcSync, lcProject, lcBuilds, lcReleaseBundles,
specFlag, specVars,
specFlag, specVars, buildName, buildNumber,
},
ReleaseBundlePromote: {
platformUrl, user, password, accessToken, serverId, lcSigningKey, lcSync, lcProject, lcIncludeRepos, lcExcludeRepos,
Expand Down
Loading

0 comments on commit 5fe48da

Please sign in to comment.