Skip to content

Commit ed64b7d

Browse files
authored
Create application command (#17)
* Create application command
1 parent 1645bf8 commit ed64b7d

File tree

15 files changed

+620
-31
lines changed

15 files changed

+620
-31
lines changed

.golangci.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ linters-settings:
3333
# https://staticcheck.io/docs/options#checks
3434
checks: [ "all","-SA1019","-SA1029" ]
3535
gosec:
36-
excludes: [ "G204", "G301", "G302", "G304", "G306", "G601", "G101", "G407" ]
36+
excludes: [ "G204", "G301", "G302", "G304", "G306", "G601", "G101" ]
3737
exclude-generated: true
38-
exclude-test-files: true
3938
config:
4039
global:
4140
nosec: true

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

0 commit comments

Comments
 (0)