Skip to content

Commit b669f49

Browse files
authored
Align CLI commands with updated spec and API (#32)
* Align CLI commands with updated spec and API
1 parent b83aa2b commit b669f49

File tree

7 files changed

+485
-256
lines changed

7 files changed

+485
-256
lines changed

apptrust/commands/flags.go

Lines changed: 50 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,29 @@ const (
2828
accessToken = "access-token"
2929
ProjectFlag = "project"
3030

31-
ApplicationKeyFlag = "application-key"
32-
PackageTypeFlag = "package-type"
33-
PackageNameFlag = "package-name"
34-
PackageVersionFlag = "package-version"
35-
PackageRepositoryFlag = "package-repository"
36-
SpecFlag = "spec"
37-
SpecVarsFlag = "spec-vars"
38-
StageVarsFlag = "stage"
39-
ApplicationNameFlag = "application-name"
40-
DescriptionFlag = "desc"
41-
BusinessCriticalityFlag = "business-criticality"
42-
MaturityLevelFlag = "maturity-level"
43-
LabelsFlag = "labels"
44-
UserOwnersFlag = "user-owners"
45-
GroupOwnersFlag = "group-owners"
46-
SigningKeyFlag = "signing-key"
47-
SyncFlag = "sync"
48-
PromotionTypeFlag = "promotion-type"
49-
DryRunFlag = "dry-run"
50-
ExcludeReposFlag = "exclude-repos"
51-
IncludeReposFlag = "include-repos"
52-
PropsFlag = "props"
53-
TagFlag = "tag"
54-
BuildsFlag = "builds"
55-
ReleaseBundlesFlag = "release-bundles"
56-
SourceVersionFlag = "source-version"
57-
PackagesFlag = "packages"
58-
PropertiesFlag = "properties"
59-
DeletePropertyFlag = "delete-property"
31+
ApplicationKeyFlag = "application-key"
32+
SpecFlag = "spec"
33+
SpecVarsFlag = "spec-vars"
34+
StageVarsFlag = "stage"
35+
ApplicationNameFlag = "application-name"
36+
DescriptionFlag = "desc"
37+
BusinessCriticalityFlag = "business-criticality"
38+
MaturityLevelFlag = "maturity-level"
39+
LabelsFlag = "labels"
40+
UserOwnersFlag = "user-owners"
41+
GroupOwnersFlag = "group-owners"
42+
SyncFlag = "sync"
43+
PromotionTypeFlag = "promotion-type"
44+
DryRunFlag = "dry-run"
45+
ExcludeReposFlag = "exclude-repos"
46+
IncludeReposFlag = "include-repos"
47+
PropsFlag = "props"
48+
TagFlag = "tag"
49+
SourceTypeBuildsFlag = "source-type-builds"
50+
SourceTypeReleaseBundlesFlag = "source-type-release-bundles"
51+
SourceTypeApplicationVersionsFlag = "source-type-application-versions"
52+
PropertiesFlag = "properties"
53+
DeletePropertyFlag = "delete-property"
6054
)
6155

6256
// Flag keys mapped to their corresponding components.Flag definition.
@@ -66,37 +60,31 @@ var flagsMap = map[string]components.Flag{
6660
url: components.NewStringFlag(url, "JFrog Platform URL.", func(f *components.StringFlag) { f.Mandatory = false }),
6761
user: components.NewStringFlag(user, "JFrog username.", func(f *components.StringFlag) { f.Mandatory = false }),
6862
accessToken: components.NewStringFlag(accessToken, "JFrog access token.", func(f *components.StringFlag) { f.Mandatory = false }),
69-
ProjectFlag: components.NewStringFlag(ProjectFlag, "Project key associated with the application.", func(f *components.StringFlag) { f.Mandatory = false }),
63+
ProjectFlag: components.NewStringFlag(ProjectFlag, "Project key associated with the application. This flag is mandatory when the --spec flag is not provided.", func(f *components.StringFlag) { f.Mandatory = false }),
7064

71-
ApplicationKeyFlag: components.NewStringFlag(ApplicationKeyFlag, "Application key.", func(f *components.StringFlag) { f.Mandatory = false }),
72-
PackageTypeFlag: components.NewStringFlag(PackageTypeFlag, "Package type.", func(f *components.StringFlag) { f.Mandatory = false }),
73-
PackageNameFlag: components.NewStringFlag(PackageNameFlag, "Package name.", func(f *components.StringFlag) { f.Mandatory = false }),
74-
PackageVersionFlag: components.NewStringFlag(PackageVersionFlag, "Package version.", func(f *components.StringFlag) { f.Mandatory = false }),
75-
PackageRepositoryFlag: components.NewStringFlag(PackageRepositoryFlag, "Package storing repository.", func(f *components.StringFlag) { f.Mandatory = false }),
76-
SpecFlag: components.NewStringFlag(SpecFlag, "A path to the specification file.", func(f *components.StringFlag) { f.Mandatory = false }),
77-
SpecVarsFlag: components.NewStringFlag(SpecVarsFlag, "List of semicolon-separated (;) variables in the form of \"key1=value1;key2=value2;...\" (wrapped by quotes) to be replaced in the File Spec. In the File Spec, the variables should be used as follows: ${key1}.", func(f *components.StringFlag) { f.Mandatory = false }),
78-
StageVarsFlag: components.NewStringFlag(StageVarsFlag, "Promotion stage.", func(f *components.StringFlag) { f.Mandatory = true }),
79-
ApplicationNameFlag: components.NewStringFlag(ApplicationNameFlag, "The display name of the application.", func(f *components.StringFlag) { f.Mandatory = false }),
80-
DescriptionFlag: components.NewStringFlag(DescriptionFlag, "The description of the application.", func(f *components.StringFlag) { f.Mandatory = false }),
81-
BusinessCriticalityFlag: components.NewStringFlag(BusinessCriticalityFlag, "The business criticality level. The following values are supported: "+coreutils.ListToText(model.BusinessCriticalityValues), func(f *components.StringFlag) { f.Mandatory = false }),
82-
MaturityLevelFlag: components.NewStringFlag(MaturityLevelFlag, "The maturity level.", func(f *components.StringFlag) { f.Mandatory = false }),
83-
LabelsFlag: components.NewStringFlag(LabelsFlag, "List of semicolon-separated (;) labels in the form of \"key1=value1;key2=value2;...\" (wrapped by quotes).", func(f *components.StringFlag) { f.Mandatory = false }),
84-
UserOwnersFlag: components.NewStringFlag(UserOwnersFlag, "Comma-separated list of user owners.", func(f *components.StringFlag) { f.Mandatory = false }),
85-
GroupOwnersFlag: components.NewStringFlag(GroupOwnersFlag, "Comma-separated list of group owners.", func(f *components.StringFlag) { f.Mandatory = false }),
86-
SigningKeyFlag: components.NewStringFlag(SigningKeyFlag, "The GPG/RSA key-pair name given in Artifactory.", func(f *components.StringFlag) { f.Mandatory = false }),
87-
SyncFlag: components.NewBoolFlag(SyncFlag, "Whether to synchronize the operation.", components.WithBoolDefaultValueTrue()),
88-
PromotionTypeFlag: components.NewStringFlag(PromotionTypeFlag, "The promotion type. The following values are supported: "+coreutils.ListToText(model.PromotionTypeValues), func(f *components.StringFlag) { f.Mandatory = false; f.DefaultValue = model.PromotionTypeCopy }),
89-
DryRunFlag: components.NewBoolFlag(DryRunFlag, "Perform a simulation of the operation.", components.WithBoolDefaultValueFalse()),
90-
ExcludeReposFlag: components.NewStringFlag(ExcludeReposFlag, "Semicolon-separated list of repositories to exclude.", func(f *components.StringFlag) { f.Mandatory = false }),
91-
IncludeReposFlag: components.NewStringFlag(IncludeReposFlag, "Semicolon-separated list of repositories to include.", func(f *components.StringFlag) { f.Mandatory = false }),
92-
PropsFlag: components.NewStringFlag(PropsFlag, "Semicolon-separated list of properties in the form of 'key1=value1;key2=value2;...' to be added to each artifact.", func(f *components.StringFlag) { f.Mandatory = false }),
93-
TagFlag: components.NewStringFlag(TagFlag, "A tag to associate with the version. Must contain only alphanumeric characters, hyphens (-), underscores (_), and dots (.).", func(f *components.StringFlag) { f.Mandatory = false }),
94-
BuildsFlag: components.NewStringFlag(BuildsFlag, "List of builds in format 'name1:number1[:timestamp1];name2:number2[:timestamp2]'", func(f *components.StringFlag) { f.Mandatory = false }),
95-
ReleaseBundlesFlag: components.NewStringFlag(ReleaseBundlesFlag, "List of release bundles in format 'name1:version1;name2:version2'", func(f *components.StringFlag) { f.Mandatory = false }),
96-
SourceVersionFlag: components.NewStringFlag(SourceVersionFlag, "Source versions in format 'app1:version1;app2:version2'", func(f *components.StringFlag) { f.Mandatory = false }),
97-
PackagesFlag: components.NewStringFlag(PackagesFlag, "List of packages in format 'name1;name2'", func(f *components.StringFlag) { f.Mandatory = false }),
98-
PropertiesFlag: components.NewStringFlag(PropertiesFlag, "Sets or updates custom properties for the application version in format 'key1=value1[,value2,...];key2=value3[,value4,...]'", func(f *components.StringFlag) { f.Mandatory = false }),
99-
DeletePropertyFlag: components.NewStringFlag(DeletePropertyFlag, "Remove a property key and all its values", func(f *components.StringFlag) { f.Mandatory = false }),
65+
ApplicationKeyFlag: components.NewStringFlag(ApplicationKeyFlag, "Application key.", func(f *components.StringFlag) { f.Mandatory = false }),
66+
SpecFlag: components.NewStringFlag(SpecFlag, "A path to the specification file.", func(f *components.StringFlag) { f.Mandatory = false }),
67+
SpecVarsFlag: components.NewStringFlag(SpecVarsFlag, "List of semicolon-separated (;) variables in the form of \"key1=value1;key2=value2;...\" (wrapped by quotes) to be replaced in the File Spec. In the File Spec, the variables should be used as follows: ${key1}.", func(f *components.StringFlag) { f.Mandatory = false }),
68+
StageVarsFlag: components.NewStringFlag(StageVarsFlag, "Promotion stage.", func(f *components.StringFlag) { f.Mandatory = true }),
69+
ApplicationNameFlag: components.NewStringFlag(ApplicationNameFlag, "The display name of the application.", func(f *components.StringFlag) { f.Mandatory = false }),
70+
DescriptionFlag: components.NewStringFlag(DescriptionFlag, "The description of the application.", func(f *components.StringFlag) { f.Mandatory = false }),
71+
BusinessCriticalityFlag: components.NewStringFlag(BusinessCriticalityFlag, "The business criticality level. The following values are supported: "+coreutils.ListToText(model.BusinessCriticalityValues), func(f *components.StringFlag) { f.Mandatory = false }),
72+
MaturityLevelFlag: components.NewStringFlag(MaturityLevelFlag, "The maturity level.", func(f *components.StringFlag) { f.Mandatory = false }),
73+
LabelsFlag: components.NewStringFlag(LabelsFlag, "List of semicolon-separated (;) labels in the form of \"key1=value1;key2=value2;...\" (wrapped by quotes).", func(f *components.StringFlag) { f.Mandatory = false }),
74+
UserOwnersFlag: components.NewStringFlag(UserOwnersFlag, "Comma-separated list of user owners.", func(f *components.StringFlag) { f.Mandatory = false }),
75+
GroupOwnersFlag: components.NewStringFlag(GroupOwnersFlag, "Comma-separated list of group owners.", func(f *components.StringFlag) { f.Mandatory = false }),
76+
SyncFlag: components.NewBoolFlag(SyncFlag, "Whether to synchronize the operation.", components.WithBoolDefaultValueTrue()),
77+
PromotionTypeFlag: components.NewStringFlag(PromotionTypeFlag, "The promotion type. The following values are supported: "+coreutils.ListToText(model.PromotionTypeValues), func(f *components.StringFlag) { f.Mandatory = false; f.DefaultValue = model.PromotionTypeCopy }),
78+
DryRunFlag: components.NewBoolFlag(DryRunFlag, "Perform a simulation of the operation.", components.WithBoolDefaultValueFalse()),
79+
ExcludeReposFlag: components.NewStringFlag(ExcludeReposFlag, "Semicolon-separated list of repositories to exclude.", func(f *components.StringFlag) { f.Mandatory = false }),
80+
IncludeReposFlag: components.NewStringFlag(IncludeReposFlag, "Semicolon-separated list of repositories to include.", func(f *components.StringFlag) { f.Mandatory = false }),
81+
PropsFlag: components.NewStringFlag(PropsFlag, "Semicolon-separated list of properties in the form of 'key1=value1;key2=value2;...' to be added to each artifact.", func(f *components.StringFlag) { f.Mandatory = false }),
82+
TagFlag: components.NewStringFlag(TagFlag, "A tag to associate with the version. Must contain only alphanumeric characters, hyphens (-), underscores (_), and dots (.).", func(f *components.StringFlag) { f.Mandatory = false }),
83+
SourceTypeBuildsFlag: components.NewStringFlag(SourceTypeBuildsFlag, "List of semicolon-separated (;) builds in the form of 'name=buildName1, id=runID1, [include-deps=true]; name=buildName2, id=runID2, [include-deps=true]' to be included in the new version.", func(f *components.StringFlag) { f.Mandatory = false }),
84+
SourceTypeReleaseBundlesFlag: components.NewStringFlag(SourceTypeReleaseBundlesFlag, "List of semicolon-separated (;) release bundles in the form of 'name=releaseBundleName1, version=version1; name=releaseBundleName2, version=version2' to be included in the new version.", func(f *components.StringFlag) { f.Mandatory = false }),
85+
SourceTypeApplicationVersionsFlag: components.NewStringFlag(SourceTypeApplicationVersionsFlag, "List of semicolon-separated (;) application versions in the form of 'application-key=app1, version=version1; application-key=app2, version=version2' to be included in the new version.", func(f *components.StringFlag) { f.Mandatory = false }),
86+
PropertiesFlag: components.NewStringFlag(PropertiesFlag, "Sets or updates custom properties for the application version in format 'key1=value1[,value2,...];key2=value3[,value4,...]'", func(f *components.StringFlag) { f.Mandatory = false }),
87+
DeletePropertyFlag: components.NewStringFlag(DeletePropertyFlag, "Remove a property key and all its values", func(f *components.StringFlag) { f.Mandatory = false }),
10088
}
10189

10290
var commandFlags = map[string][]string{
@@ -105,14 +93,10 @@ var commandFlags = map[string][]string{
10593
user,
10694
accessToken,
10795
serverId,
108-
ApplicationKeyFlag,
10996
TagFlag,
110-
PackagesFlag,
111-
PackageTypeFlag,
112-
PackageRepositoryFlag,
113-
BuildsFlag,
114-
ReleaseBundlesFlag,
115-
SourceVersionFlag,
97+
SourceTypeBuildsFlag,
98+
SourceTypeReleaseBundlesFlag,
99+
SourceTypeApplicationVersionsFlag,
116100
SpecFlag,
117101
SpecVarsFlag,
118102
},
@@ -161,17 +145,13 @@ var commandFlags = map[string][]string{
161145
accessToken,
162146
serverId,
163147
ApplicationKeyFlag,
164-
PackagesFlag,
165-
PackageTypeFlag,
166148
},
167149
PackageUnbind: {
168150
url,
169151
user,
170152
accessToken,
171153
serverId,
172154
ApplicationKeyFlag,
173-
PackagesFlag,
174-
PackageTypeFlag,
175155
},
176156

177157
Ping: {
@@ -194,7 +174,6 @@ var commandFlags = map[string][]string{
194174
LabelsFlag,
195175
UserOwnersFlag,
196176
GroupOwnersFlag,
197-
SigningKeyFlag,
198177
SpecFlag,
199178
SpecVarsFlag,
200179
},
@@ -211,9 +190,6 @@ var commandFlags = map[string][]string{
211190
LabelsFlag,
212191
UserOwnersFlag,
213192
GroupOwnersFlag,
214-
SigningKeyFlag,
215-
SpecFlag,
216-
SpecVarsFlag,
217193
},
218194

219195
AppDelete: {

apptrust/commands/utils/utils.go

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,15 @@ func ParseSliceFlag(flagValue string) []string {
5656
// ParseMapFlag parses a semicolon-separated string of key=value pairs into a map[string]string.
5757
// Returns an error if any pair does not contain exactly one '='.
5858
func ParseMapFlag(flagValue string) (map[string]string, error) {
59-
if flagValue == "" {
59+
return ParseKeyValueString(flagValue, ";")
60+
}
61+
62+
func ParseKeyValueString(value, separator string) (map[string]string, error) {
63+
if value == "" {
6064
return nil, nil
6165
}
6266
result := make(map[string]string)
63-
pairs := strings.Split(flagValue, ";")
67+
pairs := strings.Split(value, separator)
6468
for _, pair := range pairs {
6569
keyValue := strings.SplitN(pair, "=", 2)
6670
if len(keyValue) != 2 {
@@ -87,25 +91,6 @@ func ValidateEnumFlag(flagName, value string, defaultValue string, allowedValues
8791
flagName, value, coreutils.ListToText(allowedValues))
8892
}
8993

90-
// ParsePackagesFlag parses a comma-separated list of package name:version pairs into a slice of maps.
91-
// Each map contains keys "name" and "version". Returns an error if any entry is not in the expected format.
92-
// Example input: "pkg1:1.0.0,pkg2:2.0.0" => []map[string]string{{"name": "pkg1", "version": "1.0.0"}, {"name": "pkg2", "version": "2.0.0"}}
93-
func ParsePackagesFlag(flagValue string) ([]map[string]string, error) {
94-
if flagValue == "" {
95-
return nil, nil
96-
}
97-
pairs := strings.Split(flagValue, ",")
98-
var result []map[string]string
99-
for _, pair := range pairs {
100-
parts := strings.SplitN(strings.TrimSpace(pair), PartSeparator, 2)
101-
if len(parts) != 2 {
102-
return nil, fmt.Errorf("invalid package format: %s (expected <name>:<version>)", pair)
103-
}
104-
result = append(result, map[string]string{"name": parts[0], "version": parts[1]})
105-
}
106-
return result, nil
107-
}
108-
10994
// ParseDelimitedSlice splits a delimited string into a slice of string slices.
11095
// Example: input "a:1;b:2" returns [][]string{{"a","1"},{"b","2"}}
11196
func ParseDelimitedSlice(input string) [][]string {

apptrust/commands/utils/utils_test.go

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -115,40 +115,6 @@ func TestValidateEnumFlag(t *testing.T) {
115115
}
116116
}
117117

118-
func TestParsePackagesFlag(t *testing.T) {
119-
tests := []struct {
120-
name string
121-
input string
122-
expected []map[string]string
123-
expectErr bool
124-
}{
125-
{"empty string", "", nil, false},
126-
{"single package", "foo:1.0.0", []map[string]string{{"name": "foo", "version": "1.0.0"}}, false},
127-
{"multiple packages", "foo:1.0.0,bar:2.0.0", []map[string]string{{"name": "foo", "version": "1.0.0"}, {"name": "bar", "version": "2.0.0"}}, false},
128-
{"spaces", " foo:1.0.0 , bar:2.0.0 ", []map[string]string{{"name": "foo", "version": "1.0.0"}, {"name": "bar", "version": "2.0.0"}}, false},
129-
{"invalid format", "foo", nil, true},
130-
{"missing version", "foo:", []map[string]string{{"name": "foo", "version": ""}}, false},
131-
{"missing name", ":1.0.0", []map[string]string{{"name": "", "version": "1.0.0"}}, false},
132-
}
133-
for _, tt := range tests {
134-
t.Run(tt.name, func(t *testing.T) {
135-
result, err := ParsePackagesFlag(tt.input)
136-
if tt.expectErr {
137-
if err == nil {
138-
t.Errorf("expected error for input %q, got nil", tt.input)
139-
}
140-
return
141-
}
142-
if err != nil {
143-
t.Errorf("unexpected error for input %q: %v", tt.input, err)
144-
}
145-
if !reflect.DeepEqual(result, tt.expected) {
146-
t.Errorf("ParsePackagesFlag(%q) = %v, want %v", tt.input, result, tt.expected)
147-
}
148-
})
149-
}
150-
}
151-
152118
func TestParseDelimitedSlice(t *testing.T) {
153119
tests := []struct {
154120
name string

0 commit comments

Comments
 (0)