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