Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): support backend app for "app init" #873

Merged
merged 4 commits into from
Apr 24, 2020
Merged
Show file tree
Hide file tree
Changes from 3 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
52 changes: 44 additions & 8 deletions internal/pkg/cli/app_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package cli

import (
"encoding"
"fmt"
"strconv"
"strings"
Expand All @@ -24,9 +25,12 @@ import (
)

var (
appInitAppTypePrompt = "Which type of " + color.Emphasize("infrastructure pattern") + " best represents your application?"
appInitAppTypeHelpPrompt = `Your application's architecture. Most applications need additional AWS resources to run.
To help setup the infrastructure resources, select what "kind" or "type" of application you want to build.`
appInitAppTypePrompt = "Which type of " + color.Emphasize("infrastructure pattern") + " best represents your application?"
fmtAppInitAppTypeHelpPrompt = `A %s is a public, internet-facing, HTTP server that's behind a load balancer.
To learn more see: https://git.io/JfIpv

A %s is a private, non internet-facing service.
To learn more see: https://git.io/JfIpT`

fmtAppInitAppNamePrompt = "What do you want to " + color.Emphasize("name") + " this %s?"
fmtAppInitAppNameHelpPrompt = `The name will uniquely identify this application within your %s project.
Expand Down Expand Up @@ -198,7 +202,7 @@ func (o *initAppOpts) Execute() error {
}

func (o *initAppOpts) createManifest() (string, error) {
manifest, err := o.createLoadBalancedAppManifest()
manifest, err := o.newManifest()
if err != nil {
return "", err
}
Expand Down Expand Up @@ -229,7 +233,18 @@ func (o *initAppOpts) createManifest() (string, error) {
return manifestPath, nil
}

func (o *initAppOpts) createLoadBalancedAppManifest() (*manifest.LoadBalancedWebApp, error) {
func (o *initAppOpts) newManifest() (encoding.BinaryMarshaler, error) {
switch o.AppType {
case manifest.LoadBalancedWebApplication:
return o.newLoadBalancedWebAppManifest()
case manifest.BackendApplication:
return o.newBackendAppManifest()
default:
return nil, fmt.Errorf("application type %s doesn't have a manifest", o.AppType)
}
}

func (o *initAppOpts) newLoadBalancedWebAppManifest() (*manifest.LoadBalancedWebApp, error) {
props := &manifest.LoadBalancedWebAppProps{
AppProps: &manifest.AppProps{
AppName: o.AppName,
Expand All @@ -253,12 +268,26 @@ func (o *initAppOpts) createLoadBalancedAppManifest() (*manifest.LoadBalancedWeb
return manifest.NewLoadBalancedWebApp(props), nil
}

func (o *initAppOpts) newBackendAppManifest() (*manifest.BackendApp, error) {
return manifest.NewBackendApp(manifest.BackendAppProps{
AppProps: manifest.AppProps{
AppName: o.AppName,
Dockerfile: o.DockerfilePath,
},
Port: o.AppPort,
}), nil
}

func (o *initAppOpts) askAppType() error {
if o.AppType != "" {
return nil
}

t, err := o.prompt.SelectOne(appInitAppTypePrompt, appInitAppTypeHelpPrompt, manifest.AppTypes)
help := fmt.Sprintf(fmtAppInitAppTypeHelpPrompt,
manifest.LoadBalancedWebApplication,
manifest.BackendApplication,
)
t, err := o.prompt.SelectOne(appInitAppTypePrompt, help, manifest.AppTypes)
if err != nil {
return fmt.Errorf("failed to get type selection: %w", err)
}
Expand Down Expand Up @@ -384,8 +413,11 @@ func BuildAppInitCmd() *cobra.Command {
Long: `Creates a new application in a project.
This command is also run as part of "ecs-preview init".`,
Example: `
Create a "frontend" web application.
/code $ ecs-preview app init --name frontend --app-type "Load Balanced Web App" --dockerfile ./frontend/Dockerfile`,
Create a "frontend" load balanced web application.
/code $ ecs-preview app init --name frontend --app-type "Load Balanced Web App" --dockerfile ./frontend/Dockerfile

Create an "subscribers" backend application.
/code $ ecs-preview app init --name subscribers --app-type "Backend App"`,
RunE: runCmdE(func(cmd *cobra.Command, args []string) error {
opts, err := newInitAppOpts(vars)
if err != nil {
Expand Down Expand Up @@ -422,11 +454,15 @@ This command is also run as part of "ecs-preview init".`,
lbWebAppFlags := pflag.NewFlagSet(manifest.LoadBalancedWebApplication, pflag.ContinueOnError)
lbWebAppFlags.AddFlag(cmd.Flags().Lookup(appPortFlag))

backendAppFlags := pflag.NewFlagSet(manifest.BackendApplication, pflag.ContinueOnError)
backendAppFlags.AddFlag(cmd.Flags().Lookup(appPortFlag))

cmd.Annotations = map[string]string{
// The order of the sections we want to display.
"sections": fmt.Sprintf(`Required,%s`, strings.Join(manifest.AppTypes, ",")),
"Required": requiredFlags.FlagUsages(),
manifest.LoadBalancedWebApplication: lbWebAppFlags.FlagUsages(),
manifest.BackendApplication: lbWebAppFlags.FlagUsages(),
}
cmd.SetUsageTemplate(`{{h1 "Usage"}}{{if .Runnable}}
{{.UseLine}}{{end}}{{$annotations := .Annotations}}{{$sections := split .Annotations.sections ","}}{{if gt (len $sections) 0}}
Expand Down
8 changes: 4 additions & 4 deletions internal/pkg/cli/app_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestAppInitOpts_Validate(t *testing.T) {
"invalid app type": {
inProjectName: "phonetool",
inAppType: "TestAppType",
wantedErr: errors.New(`invalid app type TestAppType: must be one of "Load Balanced Web App"`),
wantedErr: errors.New(`invalid app type TestAppType: must be one of "Load Balanced Web App", "Backend App"`),
},
"invalid app name": {
inProjectName: "phonetool",
Expand Down Expand Up @@ -116,7 +116,7 @@ func TestAppInitOpts_Ask(t *testing.T) {

mockFileSystem: func(mockFS afero.Fs) {},
mockPrompt: func(m *climocks.Mockprompter) {
m.EXPECT().SelectOne(gomock.Eq("Which type of infrastructure pattern best represents your application?"), appInitAppTypeHelpPrompt, gomock.Eq(manifest.AppTypes)).
m.EXPECT().SelectOne(gomock.Eq("Which type of infrastructure pattern best represents your application?"), gomock.Any(), gomock.Eq(manifest.AppTypes)).
Return(wantedAppType, nil)
},
mockDockerfile: func(m *climocks.MockdockerfileParser) {},
Expand Down Expand Up @@ -354,7 +354,7 @@ func TestAppInitOpts_Execute(t *testing.T) {
mockDependencies func(*gomock.Controller, *initAppOpts)
wantedErr error
}{
"writes manifest, and creates repositories successfully": {
"writes load balanced web app manifest, and creates repositories successfully": {
inAppType: manifest.LoadBalancedWebApplication,
inProjectName: "project",
inAppName: "frontend",
Expand Down Expand Up @@ -646,7 +646,7 @@ func TestAppInitOpts_createLoadBalancedAppManifest(t *testing.T) {
}
tc.mockDependencies(ctrl, &opts)
// WHEN
manifest, err := opts.createLoadBalancedAppManifest()
manifest, err := opts.newLoadBalancedWebAppManifest()

// THEN
if tc.wantedErr == nil {
Expand Down
1 change: 1 addition & 0 deletions internal/pkg/manifest/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
// AppTypes are the supported manifest types.
var AppTypes = []string{
LoadBalancedWebApplication,
BackendApplication,
}

// App holds the basic data that every application manifest file needs to have.
Expand Down