Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ linters-settings:
# https://staticcheck.io/docs/options#checks
checks: [ "all","-SA1019","-SA1029" ]
gosec:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

G407 is not supported anymore so it can't be excluded. Also, exclude-test-files is not supported (and probably not wanted in the first place).

excludes: [ "G204", "G301", "G302", "G304", "G306", "G601", "G101", "G407" ]
excludes: [ "G204", "G301", "G302", "G304", "G306", "G601", "G101" ]
exclude-generated: true
exclude-test-files: true
config:
global:
nosec: true
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ prereq::
GOBIN=${TOOLS_DIR} $(GOCMD) install go.uber.org/mock/[email protected]
${TOOLS_DIR}/mockgen --version

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

Expand Down
16 changes: 12 additions & 4 deletions application/app/context.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
package app

import (
"github.com/jfrog/jfrog-cli-application/application/service/applications"
"github.com/jfrog/jfrog-cli-application/application/service/systems"
"github.com/jfrog/jfrog-cli-application/application/service/versions"
)

type Context interface {
GetApplicationService() applications.ApplicationService
GetVersionService() versions.VersionService
GetSystemService() systems.SystemService
GetConfig() interface{}
}

type context struct {
versionService versions.VersionService
systemService systems.SystemService
applicationService applications.ApplicationService
versionService versions.VersionService
systemService systems.SystemService
}

func NewAppContext() Context {
return &context{
versionService: versions.NewVersionService(),
systemService: systems.NewSystemService(),
applicationService: applications.NewApplicationService(),
versionService: versions.NewVersionService(),
systemService: systems.NewSystemService(),
}
}

func (c *context) GetApplicationService() applications.ApplicationService {
return c.applicationService
}

func (c *context) GetVersionService() versions.VersionService {
return c.versionService
}
Expand Down
10 changes: 10 additions & 0 deletions application/app/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app
import (
"testing"

mockapplications "github.com/jfrog/jfrog-cli-application/application/service/applications/mocks"
mocksystems "github.com/jfrog/jfrog-cli-application/application/service/systems/mocks"
mockversions "github.com/jfrog/jfrog-cli-application/application/service/versions/mocks"

Expand All @@ -12,10 +13,19 @@ import (
func TestNewAppContext(t *testing.T) {
ctx := NewAppContext()
assert.NotNil(t, ctx)
assert.NotNil(t, ctx.GetApplicationService())
assert.NotNil(t, ctx.GetVersionService())
assert.NotNil(t, ctx.GetSystemService())
}

func TestGetApplicationService(t *testing.T) {
mockApplicationService := &mockapplications.MockApplicationService{}
ctx := &context{
applicationService: mockApplicationService,
}
assert.Equal(t, mockApplicationService, ctx.GetApplicationService())
}

func TestGetVersionService(t *testing.T) {
mockVersionService := &mockversions.MockVersionService{}
ctx := &context{
Expand Down
2 changes: 2 additions & 0 deletions application/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"github.com/jfrog/jfrog-cli-application/application/app"
"github.com/jfrog/jfrog-cli-application/application/commands/application"
"github.com/jfrog/jfrog-cli-application/application/commands/system"
"github.com/jfrog/jfrog-cli-application/application/commands/version"
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
Expand Down Expand Up @@ -38,6 +39,7 @@ func GetJfrogApplicationCli() components.App {
system.GetPingCommand(appContext),
version.GetCreateAppVersionCommand(appContext),
version.GetPromoteAppVersionCommand(appContext),
application.GetCreateAppCommand(appContext),
},
)
return appEntity
Expand Down
134 changes: 134 additions & 0 deletions application/commands/application/create_app_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package application

import (
pluginsCommon "github.com/jfrog/jfrog-cli-core/v2/plugins/common"

"github.com/jfrog/jfrog-cli-application/application/commands/utils"
"github.com/jfrog/jfrog-cli-application/application/model"
"github.com/jfrog/jfrog-cli-application/application/service"
commonCLiCommands "github.com/jfrog/jfrog-cli-core/v2/common/commands"
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/utils/errorutils"

"github.com/jfrog/jfrog-cli-application/application/app"
"github.com/jfrog/jfrog-cli-application/application/commands"
"github.com/jfrog/jfrog-cli-application/application/common"
"github.com/jfrog/jfrog-cli-application/application/service/applications"
)

type createAppCommand struct {
serverDetails *coreConfig.ServerDetails
applicationService applications.ApplicationService
requestBody *model.CreateAppRequest
}

func (cac *createAppCommand) Run() error {
ctx, err := service.NewContext(*cac.serverDetails)
if err != nil {
return err
}

return cac.applicationService.CreateApplication(ctx, cac.requestBody)
}

func (cac *createAppCommand) ServerDetails() (*coreConfig.ServerDetails, error) {
return cac.serverDetails, nil
}

func (cac *createAppCommand) CommandName() string {
return commands.CreateApp
}

func (cac *createAppCommand) buildRequestPayload(ctx *components.Context) (*model.CreateAppRequest, error) {
applicationKey := ctx.Arguments[0]
applicationName := ctx.GetStringFlagValue(commands.ApplicationNameFlag)
if applicationName == "" {
// Default to the application key if application name is not provided
applicationName = applicationKey
}

project := ctx.GetStringFlagValue(commands.ProjectFlag)
if project == "" {
return nil, errorutils.CheckErrorf("--%s is mandatory", commands.ProjectFlag)
}

businessCriticalityStr := ctx.GetStringFlagValue(commands.BusinessCriticalityFlag)
businessCriticality, err := utils.ValidateEnumFlag(
commands.BusinessCriticalityFlag,
businessCriticalityStr,
model.BusinessCriticalityUnspecified,
model.BusinessCriticalityValues)
if err != nil {
return nil, err
}

maturityLevelStr := ctx.GetStringFlagValue(commands.MaturityLevelFlag)
maturityLevel, err := utils.ValidateEnumFlag(
commands.MaturityLevelFlag,
maturityLevelStr,
model.MaturityLevelUnspecified,
model.MaturityLevelValues)
if err != nil {
return nil, err
}

description := ctx.GetStringFlagValue(commands.DescriptionFlag)
userOwners := utils.ParseSliceFlag(ctx.GetStringFlagValue(commands.UserOwnersFlag))
groupOwners := utils.ParseSliceFlag(ctx.GetStringFlagValue(commands.GroupOwnersFlag))
labelsMap, err := utils.ParseMapFlag(ctx.GetStringFlagValue(commands.LabelsFlag))
if err != nil {
return nil, err
}

return &model.CreateAppRequest{
ApplicationName: applicationName,
ApplicationKey: applicationKey,
Description: description,
ProjectKey: project,
MaturityLevel: maturityLevel,
BusinessCriticality: businessCriticality,
Labels: labelsMap,
UserOwners: userOwners,
GroupOwners: groupOwners,
}, nil
}

func (cac *createAppCommand) prepareAndRunCommand(ctx *components.Context) error {
if len(ctx.Arguments) != 1 {
return pluginsCommon.WrongNumberOfArgumentsHandler(ctx)
}

var err error
cac.requestBody, err = cac.buildRequestPayload(ctx)
if err != nil {
return err
}

cac.serverDetails, err = utils.ServerDetailsByFlags(ctx)
if err != nil {
return err
}

return commonCLiCommands.Exec(cac)
}

func GetCreateAppCommand(appContext app.Context) components.Command {
cmd := &createAppCommand{
applicationService: appContext.GetApplicationService(),
}
return components.Command{
Name: "create",
Description: "Create a new application",
Category: common.CategoryApplication,
Arguments: []components.Argument{
{
Name: "application-key",
Description: "The key of the application to create",
Optional: false,
},
},
Flags: commands.GetCommandFlags(commands.CreateApp),
Action: cmd.prepareAndRunCommand,
}
}
86 changes: 86 additions & 0 deletions application/commands/application/create_app_cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package application

import (
"errors"
"flag"
"testing"

"github.com/urfave/cli"

"github.com/jfrog/jfrog-cli-application/application/model"
mockapps "github.com/jfrog/jfrog-cli-application/application/service/applications/mocks"
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
)

func TestCreateAppCommand_Run(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

serverDetails := &config.ServerDetails{Url: "https://example.com"}
requestPayload := &model.CreateAppRequest{
ApplicationKey: "app-key",
ApplicationName: "app-name",
ProjectKey: "proj-key",
}

mockAppService := mockapps.NewMockApplicationService(ctrl)
mockAppService.EXPECT().CreateApplication(gomock.Any(), requestPayload).Return(nil).Times(1)

cmd := &createAppCommand{
applicationService: mockAppService,
serverDetails: serverDetails,
requestBody: requestPayload,
}

err := cmd.Run()
assert.NoError(t, err)
}

func TestCreateAppCommand_Error(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

serverDetails := &config.ServerDetails{Url: "https://example.com"}
requestPayload := &model.CreateAppRequest{
ApplicationKey: "app-key",
ApplicationName: "app-name",
ProjectKey: "proj-key",
}

mockAppService := mockapps.NewMockApplicationService(ctrl)
mockAppService.EXPECT().CreateApplication(gomock.Any(), requestPayload).Return(errors.New("failed to create an application. Status code: 500")).Times(1)

cmd := &createAppCommand{
applicationService: mockAppService,
serverDetails: serverDetails,
requestBody: requestPayload,
}

err := cmd.Run()
assert.Error(t, err)
assert.Equal(t, "failed to create an application. Status code: 500", err.Error())
}

func TestCreateAppCommand_WrongNumberOfArguments(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
ctx := cli.NewContext(app, set, nil)

mockAppService := mockapps.NewMockApplicationService(ctrl)
cmd := &createAppCommand{
applicationService: mockAppService,
}

// Test with no arguments
context, err := components.ConvertContext(ctx)
assert.NoError(t, err)

err = cmd.prepareAndRunCommand(context)
assert.Error(t, err)
assert.Contains(t, err.Error(), "Wrong number of arguments")
}
Loading