Skip to content

Commit 402ea93

Browse files
committed
Create application command
1 parent 1645bf8 commit 402ea93

File tree

14 files changed

+492
-29
lines changed

14 files changed

+492
-29
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ prereq::
4949
GOBIN=${TOOLS_DIR} $(GOCMD) install go.uber.org/mock/[email protected]
5050
${TOOLS_DIR}/mockgen --version
5151

52-
build::
52+
build:: clean generate-mock
5353
$(GOCMD) env GOOS GOARCH
5454
$(GOCMD) build -ldflags="${LINKERFLAGS}" -gcflags ${COMPILERFLAGS} -o ${BINARY_CLI}/application-cli-plugin main.go
5555

application/app/context.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
package app
22

33
import (
4+
"github.com/jfrog/jfrog-cli-application/application/service/applications"
45
"github.com/jfrog/jfrog-cli-application/application/service/systems"
56
"github.com/jfrog/jfrog-cli-application/application/service/versions"
67
)
78

89
type Context interface {
10+
GetApplicationService() applications.ApplicationService
911
GetVersionService() versions.VersionService
1012
GetSystemService() systems.SystemService
1113
GetConfig() interface{}
1214
}
1315

1416
type context struct {
15-
versionService versions.VersionService
16-
systemService systems.SystemService
17+
applicationService applications.ApplicationService
18+
versionService versions.VersionService
19+
systemService systems.SystemService
1720
}
1821

1922
func NewAppContext() Context {
2023
return &context{
21-
versionService: versions.NewVersionService(),
22-
systemService: systems.NewSystemService(),
24+
applicationService: applications.NewApplicationService(),
25+
versionService: versions.NewVersionService(),
26+
systemService: systems.NewSystemService(),
2327
}
2428
}
2529

30+
func (c *context) GetApplicationService() applications.ApplicationService {
31+
return c.applicationService
32+
}
33+
2634
func (c *context) GetVersionService() versions.VersionService {
2735
return c.versionService
2836
}

application/app/context_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package app
33
import (
44
"testing"
55

6+
mockapplications "github.com/jfrog/jfrog-cli-application/application/service/applications/mocks"
67
mocksystems "github.com/jfrog/jfrog-cli-application/application/service/systems/mocks"
78
mockversions "github.com/jfrog/jfrog-cli-application/application/service/versions/mocks"
89

@@ -12,10 +13,19 @@ import (
1213
func TestNewAppContext(t *testing.T) {
1314
ctx := NewAppContext()
1415
assert.NotNil(t, ctx)
16+
assert.NotNil(t, ctx.GetApplicationService())
1517
assert.NotNil(t, ctx.GetVersionService())
1618
assert.NotNil(t, ctx.GetSystemService())
1719
}
1820

21+
func TestGetApplicationService(t *testing.T) {
22+
mockApplicationService := &mockapplications.MockApplicationService{}
23+
ctx := &context{
24+
applicationService: mockApplicationService,
25+
}
26+
assert.Equal(t, mockApplicationService, ctx.GetApplicationService())
27+
}
28+
1929
func TestGetVersionService(t *testing.T) {
2030
mockVersionService := &mockversions.MockVersionService{}
2131
ctx := &context{

application/cli/cli.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cli
22

33
import (
44
"github.com/jfrog/jfrog-cli-application/application/app"
5+
"github.com/jfrog/jfrog-cli-application/application/commands/application"
56
"github.com/jfrog/jfrog-cli-application/application/commands/system"
67
"github.com/jfrog/jfrog-cli-application/application/commands/version"
78
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
@@ -38,6 +39,7 @@ func GetJfrogApplicationCli() components.App {
3839
system.GetPingCommand(appContext),
3940
version.GetCreateAppVersionCommand(appContext),
4041
version.GetPromoteAppVersionCommand(appContext),
42+
application.GetCreateAppCommand(appContext),
4143
},
4244
)
4345
return appEntity
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package application
2+
3+
import (
4+
"github.com/jfrog/jfrog-cli-application/application/commands/utils"
5+
"github.com/jfrog/jfrog-cli-application/application/model"
6+
"github.com/jfrog/jfrog-cli-application/application/service"
7+
commonCLiCommands "github.com/jfrog/jfrog-cli-core/v2/common/commands"
8+
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
9+
coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
10+
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
11+
"github.com/jfrog/jfrog-client-go/utils/errorutils"
12+
"slices"
13+
14+
"github.com/jfrog/jfrog-cli-application/application/app"
15+
"github.com/jfrog/jfrog-cli-application/application/commands"
16+
"github.com/jfrog/jfrog-cli-application/application/common"
17+
"github.com/jfrog/jfrog-cli-application/application/service/applications"
18+
)
19+
20+
type createAppCommand struct {
21+
serverDetails *coreConfig.ServerDetails
22+
applicationService applications.ApplicationService
23+
requestBody *model.CreateAppRequest
24+
}
25+
26+
func (cac *createAppCommand) Run() error {
27+
ctx, err := service.NewContext(*cac.serverDetails)
28+
if err != nil {
29+
return err
30+
}
31+
32+
return cac.applicationService.CreateApplication(ctx, cac.requestBody)
33+
}
34+
35+
func (cac *createAppCommand) ServerDetails() (*coreConfig.ServerDetails, error) {
36+
return cac.serverDetails, nil
37+
}
38+
39+
func (cac *createAppCommand) CommandName() string {
40+
return commands.CreateApp
41+
}
42+
43+
func (cac *createAppCommand) buildRequestPayload(ctx *components.Context) (*model.CreateAppRequest, error) {
44+
appKey := ctx.Arguments[0]
45+
displayName := ctx.GetStringFlagValue(commands.DisplayNameFlag)
46+
if displayName == "" {
47+
// Default to the application key if display name is not provided
48+
displayName = appKey
49+
}
50+
51+
project := ctx.GetStringFlagValue(commands.ProjectFlag)
52+
if project == "" {
53+
return nil, errorutils.CheckErrorf("--%s is mandatory", commands.ProjectFlag)
54+
}
55+
56+
businessCriticality := ctx.GetStringFlagValue(commands.BusinessCriticalityFlag)
57+
if businessCriticality == "" {
58+
// Default to "unspecified" if not provided
59+
businessCriticality = model.BusinessCriticalityValues[0]
60+
} else if !slices.Contains(model.BusinessCriticalityValues, businessCriticality) {
61+
return nil, errorutils.CheckErrorf("invalid value for --%s: '%s'. Allowed values: %s", commands.BusinessCriticalityFlag, businessCriticality, coreutils.ListToText(model.BusinessCriticalityValues))
62+
}
63+
64+
maturityLevel := ctx.GetStringFlagValue(commands.MaturityLevelFlag)
65+
if maturityLevel == "" {
66+
// Default to "unspecified" if not provided
67+
maturityLevel = model.MaturityLevelValues[0]
68+
} else if !slices.Contains(model.MaturityLevelValues, maturityLevel) {
69+
return nil, errorutils.CheckErrorf("invalid value for --%s: '%s'. Allowed values: %s", commands.MaturityLevelFlag, maturityLevel, coreutils.ListToText(model.MaturityLevelValues))
70+
}
71+
72+
description := ctx.GetStringFlagValue(commands.DescriptionFlag)
73+
userOwners := utils.ParseSliceFlag(ctx.GetStringFlagValue(commands.UserOwnersFlag))
74+
groupOwners := utils.ParseSliceFlag(ctx.GetStringFlagValue(commands.GroupOwnersFlag))
75+
labelsMap, err := utils.ParseMapFlag(ctx.GetStringFlagValue(commands.LabelsFlag))
76+
if err != nil {
77+
return nil, err
78+
}
79+
80+
return &model.CreateAppRequest{
81+
ApplicationName: displayName,
82+
ApplicationKey: appKey,
83+
Description: description,
84+
ProjectKey: project,
85+
MaturityLevel: maturityLevel,
86+
BusinessCriticality: businessCriticality,
87+
Labels: labelsMap,
88+
UserOwners: userOwners,
89+
GroupOwners: groupOwners,
90+
}, nil
91+
}
92+
93+
func (cac *createAppCommand) prepareAndRunCommand(ctx *components.Context) error {
94+
if len(ctx.Arguments) < 1 {
95+
return errorutils.CheckErrorf("application key is required")
96+
}
97+
98+
var err error
99+
cac.requestBody, err = cac.buildRequestPayload(ctx)
100+
if err != nil {
101+
return err
102+
}
103+
104+
cac.serverDetails, err = utils.ServerDetailsByFlags(ctx)
105+
if err != nil {
106+
return err
107+
}
108+
109+
return commonCLiCommands.Exec(cac)
110+
}
111+
112+
func GetCreateAppCommand(appContext app.Context) components.Command {
113+
cmd := &createAppCommand{
114+
applicationService: appContext.GetApplicationService(),
115+
}
116+
return components.Command{
117+
Name: "create",
118+
Description: "Create a new application",
119+
Category: common.CategoryApplication,
120+
Aliases: []string{"ca"},
121+
Arguments: []components.Argument{
122+
{
123+
Name: "application-key",
124+
Description: "The key of the application to create",
125+
Optional: false,
126+
},
127+
},
128+
Flags: commands.GetCommandFlags(commands.CreateApp),
129+
Action: cmd.prepareAndRunCommand,
130+
}
131+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package application
2+
3+
import (
4+
"errors"
5+
"testing"
6+
7+
"github.com/jfrog/jfrog-cli-application/application/model"
8+
mockapps "github.com/jfrog/jfrog-cli-application/application/service/applications/mocks"
9+
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
10+
"github.com/stretchr/testify/assert"
11+
"go.uber.org/mock/gomock"
12+
)
13+
14+
func TestCreateAppCommand_Run(t *testing.T) {
15+
ctrl := gomock.NewController(t)
16+
defer ctrl.Finish()
17+
18+
serverDetails := &config.ServerDetails{Url: "https://example.com"}
19+
requestPayload := &model.CreateAppRequest{
20+
ApplicationKey: "app-key",
21+
ApplicationName: "app-name",
22+
ProjectKey: "proj-key",
23+
}
24+
25+
mockAppService := mockapps.NewMockApplicationService(ctrl)
26+
mockAppService.EXPECT().CreateApplication(gomock.Any(), requestPayload).Return(nil).Times(1)
27+
28+
cmd := &createAppCommand{
29+
applicationService: mockAppService,
30+
serverDetails: serverDetails,
31+
requestBody: requestPayload,
32+
}
33+
34+
err := cmd.Run()
35+
assert.NoError(t, err)
36+
}
37+
38+
func TestCreateAppCommand_Run_Error(t *testing.T) {
39+
ctrl := gomock.NewController(t)
40+
defer ctrl.Finish()
41+
42+
serverDetails := &config.ServerDetails{Url: "https://example.com"}
43+
requestPayload := &model.CreateAppRequest{
44+
ApplicationKey: "app-key",
45+
ApplicationName: "app-name",
46+
ProjectKey: "proj-key",
47+
}
48+
49+
mockAppService := mockapps.NewMockApplicationService(ctrl)
50+
mockAppService.EXPECT().CreateApplication(gomock.Any(), requestPayload).Return(errors.New("failed to create an application. Status code: 500")).Times(1)
51+
52+
cmd := &createAppCommand{
53+
applicationService: mockAppService,
54+
serverDetails: serverDetails,
55+
requestBody: requestPayload,
56+
}
57+
58+
err := cmd.Run()
59+
assert.Error(t, err)
60+
assert.Equal(t, "failed to create an application. Status code: 500", err.Error())
61+
}

0 commit comments

Comments
 (0)