Skip to content

Commit

Permalink
add prompt for configuring new project
Browse files Browse the repository at this point in the history
  • Loading branch information
spatocode committed Sep 13, 2023
1 parent 55cae9c commit c2fec9f
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 47 deletions.
2 changes: 1 addition & 1 deletion cloud/aws/access.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func NewIAM(cfg *config.Config, awsConfig aws.Config) *IAM {
return &IAM{
config: cfg,
awsConfig: awsConfig,
roleName: fmt.Sprintf("%s-JermLambdaServiceExecutionRole", cfg.Name),
roleName: fmt.Sprintf("%s-JermLambdaServiceExecutionRole", cfg.GetFunctionName()),
policyName: "jerm-permissions",
}
}
Expand Down
28 changes: 14 additions & 14 deletions cloud/aws/apigateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (a *ApiGateway) setup(functionArn *string) error {
template := cf.NewTemplate()
template.Description = "Auto generated by Jerm"
restApi := &cfApigateway.RestApi{
Name: aws.String(a.config.Name),
Name: aws.String(a.config.GetFunctionName()),
Description: aws.String("Automatically created by Jerm"),
}
template.Resources["Api"] = restApi
Expand Down Expand Up @@ -64,7 +64,7 @@ func (a *ApiGateway) setup(functionArn *string) error {
return err
}

log.PrintInfo(fmt.Sprintf("Project %s is now live at %s", a.config.Name, apiUrl))
log.PrintInfo(fmt.Sprintf("Project %s is now live at %s", a.config.GetFunctionName(), apiUrl))

return nil
}
Expand Down Expand Up @@ -130,7 +130,7 @@ func (a *ApiGateway) getRestApis() ([]*string, error) {
Limit: aws.Int32(500),
})
for _, item := range resp.Items {
if *item.Name == a.config.Name {
if *item.Name == a.config.GetFunctionName() {
apiIds = append(apiIds, item.Id)
}
}
Expand All @@ -140,7 +140,7 @@ func (a *ApiGateway) getRestApis() ([]*string, error) {
func (a *ApiGateway) getApiId() (*string, error) {
cloudformationClient := cloudformation.NewFromConfig(a.awsConfig)
resp, err := cloudformationClient.DescribeStackResource(context.TODO(), &cloudformation.DescribeStackResourceInput{
StackName: aws.String(a.config.Name),
StackName: aws.String(a.config.GetFunctionName()),
LogicalResourceId: aws.String("Api"),
})
if err != nil {
Expand All @@ -157,7 +157,7 @@ func (a *ApiGateway) getApiId() (*string, error) {
}

func (a *ApiGateway) createCFStack() error {
template := fmt.Sprintf("%s-template-%v.json", a.config.Name, time.Now().Unix())
template := fmt.Sprintf("%s-template-%v.json", a.config.GetFunctionName(), time.Now().Unix())
data, err := a.cfTemplate.JSON()
if err != nil {
return err
Expand All @@ -180,18 +180,18 @@ func (a *ApiGateway) createCFStack() error {

client := cloudformation.NewFromConfig(a.awsConfig)
_, err = client.DescribeStacks(context.TODO(), &cloudformation.DescribeStacksInput{
StackName: aws.String(a.config.Name),
StackName: aws.String(a.config.GetFunctionName()),
})
if err != nil {
log.Debug("creating cloud formation stack...")
tags := []cfTypes.Tag{
{
Key: aws.String("JermProject"),
Value: aws.String(a.config.Name),
Value: aws.String(a.config.GetFunctionName()),
},
}
_, err := client.CreateStack(context.TODO(), &cloudformation.CreateStackInput{
StackName: aws.String(a.config.Name),
StackName: aws.String(a.config.GetFunctionName()),
TemplateURL: aws.String(url),
Tags: tags,
Capabilities: make([]cfTypes.Capability, 0),
Expand All @@ -201,7 +201,7 @@ func (a *ApiGateway) createCFStack() error {
}
} else {
client.UpdateStack(context.TODO(), &cloudformation.UpdateStackInput{
StackName: aws.String(a.config.Name),
StackName: aws.String(a.config.GetFunctionName()),
TemplateURL: aws.String(url),
Capabilities: make([]cfTypes.Capability, 0),
})
Expand All @@ -210,7 +210,7 @@ func (a *ApiGateway) createCFStack() error {
for {
time.Sleep(time.Second * 3)
resp, _ := client.DescribeStacks(context.TODO(), &cloudformation.DescribeStacksInput{
StackName: aws.String(a.config.Name),
StackName: aws.String(a.config.GetFunctionName()),
})
if resp.Stacks == nil {
continue
Expand Down Expand Up @@ -245,20 +245,20 @@ func (a *ApiGateway) createCFStack() error {
func (a *ApiGateway) deleteStack() error {
client := cloudformation.NewFromConfig(a.awsConfig)
resp, err := client.DescribeStacks(context.TODO(), &cloudformation.DescribeStacksInput{
StackName: aws.String(a.config.Name),
StackName: aws.String(a.config.GetFunctionName()),
})
if err != nil {
log.Debug(fmt.Sprintf("unable to find stack %s\n", a.config.Name))
log.Debug(fmt.Sprintf("unable to find stack %s\n", a.config.GetFunctionName()))
return err
}
tags := make(map[string]string)
for _, tag := range resp.Stacks[0].Tags {
tags[*tag.Key] = *tag.Value
}
if tags["JermProject"] == a.config.Name {
if tags["JermProject"] == a.config.GetFunctionName() {
log.Debug("deleting cloud formation stack...")
_, err := client.DeleteStack(context.TODO(), &cloudformation.DeleteStackInput{
StackName: aws.String(a.config.Name),
StackName: aws.String(a.config.GetFunctionName()),
})
if err != nil {
return err
Expand Down
18 changes: 9 additions & 9 deletions cloud/aws/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func (l *Lambda) Deploy(zipPath string) (bool, error) {
func (l *Lambda) waitTillFunctionBecomesActive() error {
client := lambda.NewFunctionActiveV2Waiter(lambda.NewFromConfig(l.awsConfig))
err := client.Wait(context.TODO(), &lambda.GetFunctionInput{
FunctionName: aws.String(l.config.Name),
FunctionName: aws.String(l.config.GetFunctionName()),
}, time.Second*l.maxWaiterDuration)
if err != nil {
return err
Expand All @@ -175,7 +175,7 @@ func (l *Lambda) waitTillFunctionBecomesActive() error {
func (l *Lambda) waitTillFunctionBecomesUpdated() {
client := lambda.NewFunctionUpdatedV2Waiter(lambda.NewFromConfig(l.awsConfig))
err := client.Wait(context.TODO(), &lambda.GetFunctionInput{
FunctionName: aws.String(l.config.Name),
FunctionName: aws.String(l.config.GetFunctionName()),
}, time.Second*l.maxWaiterDuration)
if err != nil {
log.Debug(err.Error())
Expand Down Expand Up @@ -203,7 +203,7 @@ func (l *Lambda) Update(zipPath string) error {
return err
}

_, err = l.getLambdaFunction(l.config.Name)
_, err = l.getLambdaFunction(l.config.GetFunctionName())
if err != nil {
return err
}
Expand Down Expand Up @@ -267,7 +267,7 @@ func (l *Lambda) deleteLambdaFunction() {
log.Debug("deleting lambda function...")
client := lambda.NewFromConfig(l.awsConfig)
client.DeleteFunction(context.TODO(), &lambda.DeleteFunctionInput{
FunctionName: aws.String(l.config.Name),
FunctionName: aws.String(l.config.GetFunctionName()),
})
}

Expand Down Expand Up @@ -302,7 +302,7 @@ func (l *Lambda) Rollback(steps int) error {
return revisions[i] > revisions[j]
})

name := fmt.Sprintf("%s:%v", l.config.Name, revisions[steps])
name := fmt.Sprintf("%s:%v", l.config.GetFunctionName(), revisions[steps])
function, err := l.getLambdaFunction(name)
if err != nil {
var rnfErr *lambdaTypes.ResourceNotFoundException
Expand All @@ -321,7 +321,7 @@ func (l *Lambda) Rollback(steps int) error {
}

if res.StatusCode != 200 {
msg := fmt.Sprintf("Unable to get version %v of project %s", revisions[steps], l.config.Name)
msg := fmt.Sprintf("Unable to get version %v of project %s", revisions[steps], l.config.GetFunctionName())
return errors.New(msg)
}
defer res.Body.Close()
Expand All @@ -340,7 +340,7 @@ func (l *Lambda) listLambdaVersions() ([]lambdaTypes.FunctionConfiguration, erro
log.Debug("list lambda versions by function...")
client := lambda.NewFromConfig(l.awsConfig)
response, err := client.ListVersionsByFunction(context.TODO(), &lambda.ListVersionsByFunctionInput{
FunctionName: aws.String(l.config.Name),
FunctionName: aws.String(l.config.GetFunctionName()),
})
if err != nil {
return nil, err
Expand Down Expand Up @@ -380,7 +380,7 @@ func (l *Lambda) isAlreadyDeployed() (bool, error) {
}

func (l *Lambda) createLambdaFunction(zipPath string) (*string, error) {
name := l.config.Name
name := l.config.GetFunctionName()
function, err := l.getLambdaFunction(name)
if err == nil {
return function.Configuration.FunctionArn, nil
Expand Down Expand Up @@ -423,7 +423,7 @@ func (l *Lambda) updateLambdaFunction(content []byte) (*string, error) {
log.Debug("updating lambda function code...")
client := lambda.NewFromConfig(l.awsConfig)
resp, err := client.UpdateFunctionCode(context.TODO(), &lambda.UpdateFunctionCodeInput{
FunctionName: aws.String(l.config.Name),
FunctionName: aws.String(l.config.GetFunctionName()),
ZipFile: content,
Publish: true,
})
Expand Down
4 changes: 2 additions & 2 deletions cloud/aws/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (c *CloudWatch) getLogs(startTime int64) ([]cwTypes.FilteredLogEvent, error
logEvents []cwTypes.FilteredLogEvent
)

name := fmt.Sprintf("/aws/lambda/%s", c.config.Name)
name := fmt.Sprintf("/aws/lambda/%s", c.config.GetFunctionName())
streams, err := c.getLogStreams(name)
if err != nil {
var rnfErr *cwTypes.ResourceNotFoundException
Expand Down Expand Up @@ -157,6 +157,6 @@ func (c *CloudWatch) deleteLogGroup(groupName string) {
}

func (c *CloudWatch) DeleteLog() {
groupName := fmt.Sprintf("/aws/lambda/%s", c.config.Name)
groupName := fmt.Sprintf("/aws/lambda/%s", c.config.GetFunctionName())
c.deleteLogGroup(groupName)
}
8 changes: 3 additions & 5 deletions cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ Copyright © 2023 Ekene Izukanne <ekeneizukanne@gmail.com>
package cmd

import (
"errors"
"os"

"github.com/spf13/cobra"

"github.com/spatocode/jerm"
Expand All @@ -23,9 +20,10 @@ var deployCmd = &cobra.Command{

config, err := jerm.ReadConfig(jerm.DefaultConfigFile)
if err != nil {
var pErr *os.PathError
if !errors.As(err, &pErr) {
config, err = jerm.PromptConfig()
if err != nil {
log.PrintError(err.Error())
return
}
}

Expand Down
67 changes: 57 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ package config
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"strings"
"time"

"github.com/aws/aws-sdk-go-v2/config"
"github.com/spatocode/jerm/internal/log"
"github.com/spatocode/jerm/internal/utils"
)

const (
Dev Stage = "dev"
Production Stage = "production"
Staging Stage = "staging"
DefaultRegion = "us-west-2"
DefaultStage Stage = Dev
)

type Stage string
Expand All @@ -32,6 +35,10 @@ type Config struct {
Entry string `json:"entry"`
}

func (c *Config) GetFunctionName() string {
return fmt.Sprintf("%s-%s", c.Name, c.Stage)
}

// Defaults extracts the default configuration
func (c *Config) Defaults() error {
if err := c.detectRegion(); err != nil {
Expand Down Expand Up @@ -86,12 +93,16 @@ func (c *Config) init() error {
log.Debug(err.Error())
return err
}
splitPath := strings.Split(workDir, "/")
projectName := splitPath[len(splitPath)-1]

workspace, err := utils.GetWorkspaceName()
if err != nil {
log.Debug(err.Error())
return err
}

c.Stage = string(Dev)
c.Bucket = fmt.Sprintf("jerm-%d", time.Now().Unix())
c.Name = fmt.Sprintf("%s-%s", projectName, string(Dev))
c.Name = workspace
c.Dir = workDir

if err := c.Defaults(); err != nil {
Expand All @@ -101,17 +112,53 @@ func (c *Config) init() error {
return nil
}

func PrompConfig() (*Config, error) {
c := &Config{}
c.init()

name, err := utils.GetStdIn(fmt.Sprintf("Project name [%s]: <enter alternate name or press enter>", c.Name))
if err != nil {
return nil, errors.New("unexpected error occured")
}
if name != "" {
c.Name = name
}

stage, err := utils.GetStdIn(fmt.Sprintf("Deployment stage [%s]: <enter alternate stage or press enter>", DefaultStage))
if err != nil {
return nil, errors.New("unexpected error occured")
}
if stage != "" {
// TODO: Check is correct name
c.Stage = stage
}

region, err := utils.GetStdIn(fmt.Sprintf("Region [%s]: <enter alternate region or press enter>", c.Region))
if err != nil {
return nil, errors.New("unexpected error occured")
}
if region != "" {
c.Region = region
}

bucket, err := utils.GetStdIn(fmt.Sprintf("Bucket [%s]: <enter alternate bucket or press enter>", fmt.Sprintf("jerm-%d", time.Now().Unix())))
if err != nil {
return nil, errors.New("unexpected error occured")
}
if bucket != "" {
// TODO: Enforce bucket naming restrictions
// https://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html#bucketnamingrules
c.Bucket = strings.TrimSpace(bucket)
}

return c, nil
}

// ReadConfig reads a configuration file
func ReadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
cfg := &Config{}
err := cfg.init()
if err != nil {
return nil, err
}

return cfg, nil
return nil, err
}
return ParseConfig(data)
}
Expand Down
14 changes: 12 additions & 2 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package utils
import (
"bufio"
"context"
"fmt"
"net/http"
"os"
"os/exec"
Expand Down Expand Up @@ -43,6 +42,7 @@ func GetShellCommandOutput(command string, args ...string) (string, error) {
return string(out), err
}

// GetStdIn gets a stdin prompt from user
func GetStdIn(prompt string) (string, error) {
if prompt != "" {
log.PrintInfo(prompt)
Expand All @@ -52,6 +52,16 @@ func GetStdIn(prompt string) (string, error) {
if err != nil {
return "", err
}
fmt.Println()
return strings.TrimSpace(value), nil
}

func GetWorkspaceName() (string, error) {
workDir, err := os.Getwd()
if err != nil {
log.Debug(err.Error())
return "", err
}
splitPath := strings.Split(workDir, "/")
workspaceName := splitPath[len(splitPath)-1]
return workspaceName, err
}
Loading

0 comments on commit c2fec9f

Please sign in to comment.