forked from toolshed/abra
		
	refactor: app new cmd to be easier to read
This commit is contained in:
		
							
								
								
									
										275
									
								
								cli/app/new.go
									
									
									
									
									
								
							
							
						
						
									
										275
									
								
								cli/app/new.go
									
									
									
									
									
								
							@ -16,10 +16,9 @@ import (
 | 
			
		||||
	"github.com/urfave/cli/v2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var appNewCommand = &cli.Command{
 | 
			
		||||
	Name:  "new",
 | 
			
		||||
	Usage: "Create a new app",
 | 
			
		||||
	Description: `
 | 
			
		||||
type Secrets map[string]string
 | 
			
		||||
 | 
			
		||||
var appNewDescription = `
 | 
			
		||||
This command takes an app recipe and uses it to create a new app. This new app
 | 
			
		||||
configuration is stored in your ~/.abra directory under the appropriate server.
 | 
			
		||||
 | 
			
		||||
@ -37,7 +36,12 @@ store them somewhere safe.
 | 
			
		||||
You can use the "--pass/-P" to store these generated passwords locally in a
 | 
			
		||||
pass store (see passwordstore.org for more). The pass command must be available
 | 
			
		||||
on your $PATH.
 | 
			
		||||
`,
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
var appNewCommand = &cli.Command{
 | 
			
		||||
	Name:        "new",
 | 
			
		||||
	Usage:       "Create a new app",
 | 
			
		||||
	Description: appNewDescription,
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.ServerFlag,
 | 
			
		||||
		internal.DomainFlag,
 | 
			
		||||
@ -46,108 +50,161 @@ on your $PATH.
 | 
			
		||||
		internal.SecretsFlag,
 | 
			
		||||
	},
 | 
			
		||||
	ArgsUsage: "<type>",
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		appType := c.Args().First()
 | 
			
		||||
		if appType == "" {
 | 
			
		||||
			internal.ShowSubcommandHelpAndError(c, errors.New("no app type provided"))
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		config.EnsureAbraDirExists()
 | 
			
		||||
 | 
			
		||||
		appFiles, err := config.LoadAppFiles(internal.Server)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		catl, err := catalogue.ReadAppsCatalogue()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		app := catl[appType]
 | 
			
		||||
		app.EnsureExists()
 | 
			
		||||
 | 
			
		||||
		latestVersion := app.LatestVersion()
 | 
			
		||||
		if err := app.EnsureVersion(latestVersion); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		servers := appFiles.GetServers()
 | 
			
		||||
		if internal.Server == "" {
 | 
			
		||||
			prompt := &survey.Select{
 | 
			
		||||
				Message: "Select app server:",
 | 
			
		||||
				Options: servers,
 | 
			
		||||
			}
 | 
			
		||||
			if err := survey.AskOne(prompt, &internal.Server); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if internal.Domain == "" {
 | 
			
		||||
			prompt := &survey.Input{
 | 
			
		||||
				Message: "Specify app domain",
 | 
			
		||||
			}
 | 
			
		||||
			if err := survey.AskOne(prompt, &internal.Domain); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if internal.AppName == "" {
 | 
			
		||||
			prompt := &survey.Input{
 | 
			
		||||
				Message: "Specify app name:",
 | 
			
		||||
				Default: strings.ReplaceAll(internal.Domain, ".", "_"),
 | 
			
		||||
			}
 | 
			
		||||
			if err := survey.AskOne(prompt, &internal.AppName); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sanitisedAppName := strings.ReplaceAll(internal.AppName, ".", "_")
 | 
			
		||||
		if len(sanitisedAppName) > 45 {
 | 
			
		||||
			logrus.Fatal(fmt.Errorf("'%s' cannot be longer than 45 characters", sanitisedAppName))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := config.CopyAppEnvSample(appType, internal.AppName, internal.Server); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		secrets := make(map[string]string)
 | 
			
		||||
		if internal.Secrets {
 | 
			
		||||
			appEnvPath := path.Join(config.ABRA_DIR, "servers", internal.Server, fmt.Sprintf("%s.env", sanitisedAppName))
 | 
			
		||||
			appEnv, err := config.ReadEnv(appEnvPath)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
			secretEnvVars := secret.ReadSecretEnvVars(appEnv)
 | 
			
		||||
			secrets, err = secret.GenerateSecrets(secretEnvVars, sanitisedAppName, internal.Server)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
			if internal.Pass {
 | 
			
		||||
				for secretName := range secrets {
 | 
			
		||||
					secretValue := secrets[secretName]
 | 
			
		||||
					if err := secret.PassInsertSecret(secretValue, secretName, sanitisedAppName, internal.Server); err != nil {
 | 
			
		||||
						logrus.Fatal(err)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tableCol := []string{"Name", "Domain", "Type", "Server"}
 | 
			
		||||
		table := abraFormatter.CreateTable(tableCol)
 | 
			
		||||
		table.Append([]string{sanitisedAppName, internal.Domain, appType, internal.Server})
 | 
			
		||||
		table.Render()
 | 
			
		||||
 | 
			
		||||
		if internal.Secrets {
 | 
			
		||||
			secretCols := []string{"Name", "Value"}
 | 
			
		||||
			secretTable := abraFormatter.CreateTable(secretCols)
 | 
			
		||||
			for secret := range secrets {
 | 
			
		||||
				secretTable.Append([]string{secret, secrets[secret]})
 | 
			
		||||
			}
 | 
			
		||||
			secretTable.Render()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
	Action:    action,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sanitiseAppName(name string) string {
 | 
			
		||||
	return strings.ReplaceAll(name, ".", "_")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func appLookup(appType string) (catalogue.App, error) {
 | 
			
		||||
	catl, err := catalogue.ReadAppsCatalogue()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return catalogue.App{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app, ok := catl[appType]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return catalogue.App{}, fmt.Errorf("app type does not exist: %s", appType)
 | 
			
		||||
	}
 | 
			
		||||
	if err := app.EnsureExists(); err != nil {
 | 
			
		||||
		return catalogue.App{}, err
 | 
			
		||||
	}
 | 
			
		||||
	return app, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ensureDomainFlag checks if the domain flag was used. if not, asks the user for it
 | 
			
		||||
func ensureDomainFlag() error {
 | 
			
		||||
	if internal.Domain == "" {
 | 
			
		||||
		prompt := &survey.Input{
 | 
			
		||||
			Message: "Specify app domain",
 | 
			
		||||
		}
 | 
			
		||||
		if err := survey.AskOne(prompt, &internal.Domain); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ensureServerFlag checks if the server flag was used. if not, asks the user for it
 | 
			
		||||
func ensureServerFlag() error {
 | 
			
		||||
	appFiles, err := config.LoadAppFiles(internal.Server)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	servers := appFiles.GetServers()
 | 
			
		||||
	if internal.Server == "" {
 | 
			
		||||
		prompt := &survey.Select{
 | 
			
		||||
			Message: "Select app server:",
 | 
			
		||||
			Options: servers,
 | 
			
		||||
		}
 | 
			
		||||
		if err := survey.AskOne(prompt, &internal.Server); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ensureServerFlag checks if the AppName flag was used. if not, asks the user for it
 | 
			
		||||
func ensureAppNameFlag() error {
 | 
			
		||||
	if internal.AppName == "" {
 | 
			
		||||
		prompt := &survey.Input{
 | 
			
		||||
			Message: "Specify app name:",
 | 
			
		||||
			Default: sanitiseAppName(internal.Domain),
 | 
			
		||||
		}
 | 
			
		||||
		if err := survey.AskOne(prompt, &internal.AppName); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createSecrets(sanitisedAppName string) (Secrets, error) {
 | 
			
		||||
	appEnvPath := path.Join(config.ABRA_DIR, "servers", internal.Server, fmt.Sprintf("%s.env", sanitisedAppName))
 | 
			
		||||
	appEnv, err := config.ReadEnv(appEnvPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	secretEnvVars := secret.ReadSecretEnvVars(appEnv)
 | 
			
		||||
	secrets, err := secret.GenerateSecrets(secretEnvVars, sanitisedAppName, internal.Server)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if internal.Pass {
 | 
			
		||||
		for secretName := range secrets {
 | 
			
		||||
			secretValue := secrets[secretName]
 | 
			
		||||
			if err := secret.PassInsertSecret(secretValue, secretName, sanitisedAppName, internal.Server); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return secrets, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func action(c *cli.Context) error {
 | 
			
		||||
	appType := c.Args().First()
 | 
			
		||||
	if appType == "" {
 | 
			
		||||
		internal.ShowSubcommandHelpAndError(c, errors.New("no app type provided"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := config.EnsureAbraDirExists(); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	app, err := appLookup(appType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	latestVersion := app.LatestVersion()
 | 
			
		||||
	if err := app.EnsureVersion(latestVersion); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// These use the flag from internal.x to check and edit so no need to return anything
 | 
			
		||||
	if err := ensureServerFlag(); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := ensureDomainFlag(); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := ensureAppNameFlag(); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sanitisedAppName := sanitiseAppName(internal.AppName)
 | 
			
		||||
	if len(sanitisedAppName) > 45 {
 | 
			
		||||
		logrus.Fatalf("'%s' cannot be longer than 45 characters", sanitisedAppName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := config.CopyAppEnvSample(appType, internal.AppName, internal.Server); err != nil {
 | 
			
		||||
		logrus.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if internal.Secrets {
 | 
			
		||||
		secrets, err := createSecrets(sanitisedAppName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		secretCols := []string{"Name", "Value"}
 | 
			
		||||
		secretTable := abraFormatter.CreateTable(secretCols)
 | 
			
		||||
		for secret := range secrets {
 | 
			
		||||
			secretTable.Append([]string{secret, secrets[secret]})
 | 
			
		||||
		}
 | 
			
		||||
		// Defer secret table first so it is last no matter what
 | 
			
		||||
		defer secretTable.Render()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tableCol := []string{"Name", "Domain", "Type", "Server"}
 | 
			
		||||
	table := abraFormatter.CreateTable(tableCol)
 | 
			
		||||
	table.Append([]string{sanitisedAppName, internal.Domain, appType, internal.Server})
 | 
			
		||||
	defer table.Render()
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user