package internal import ( "fmt" "io/ioutil" "os" "path" "strings" "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/formatter" "github.com/AlecAivazis/survey/v2" dockerClient "github.com/docker/docker/client" "github.com/sirupsen/logrus" ) // NewVersionOverview shows an upgrade or downgrade overview func NewVersionOverview(app config.App, currentVersion, newVersion, releaseNotes string) error { tableCol := []string{"server", "recipe", "config", "domain", "current version", "to be deployed"} table := formatter.CreateTable(tableCol) deployConfig := "compose.yml" if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok { deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n") } server := app.Server if app.Server == "default" { server = "local" } table.Append([]string{server, app.Recipe, deployConfig, app.Domain, currentVersion, newVersion}) table.Render() if releaseNotes == "" { var err error releaseNotes, err = GetReleaseNotes(app.Recipe, newVersion) if err != nil { return err } } if releaseNotes != "" && newVersion != "" { fmt.Println() fmt.Println(fmt.Sprintf("%s release notes:\n\n%s", newVersion, releaseNotes)) } else { logrus.Warnf("no release notes available for %s", newVersion) } if NoInput { return nil } response := false prompt := &survey.Confirm{ Message: "continue with deployment?", } if err := survey.AskOne(prompt, &response); err != nil { return err } if !response { logrus.Fatal("exiting as requested") } return nil } // GetReleaseNotes prints release notes for a recipe version func GetReleaseNotes(recipeName, version string) (string, error) { if version == "" { return "", nil } fpath := path.Join(config.RECIPES_DIR, recipeName, "release", version) if _, err := os.Stat(fpath); !os.IsNotExist(err) { releaseNotes, err := ioutil.ReadFile(fpath) if err != nil { return "", err } return string(releaseNotes), nil } return "", nil } // PostCmds parses a string of commands and executes them inside of the respective services // the commands string must have the following format: // " | |... " func PostCmds(cl *dockerClient.Client, app config.App, commands string) error { abraSh := path.Join(config.RECIPES_DIR, app.Recipe, "abra.sh") if _, err := os.Stat(abraSh); err != nil { if os.IsNotExist(err) { return fmt.Errorf(fmt.Sprintf("%s does not exist for %s?", abraSh, app.Name)) } return err } for _, command := range strings.Split(commands, "|") { commandParts := strings.Split(command, " ") if len(commandParts) < 2 { return fmt.Errorf(fmt.Sprintf("not enough arguments: %s", command)) } targetServiceName := commandParts[0] cmdName := commandParts[1] parsedCmdArgs := "" if len(commandParts) > 2 { parsedCmdArgs = fmt.Sprintf("%s ", strings.Join(commandParts[2:], " ")) } logrus.Infof("running post-command '%s %s' in container %s", cmdName, parsedCmdArgs, targetServiceName) if err := EnsureCommand(abraSh, app.Recipe, cmdName); err != nil { return err } serviceNames, err := config.GetAppServiceNames(app.Name) if err != nil { return err } matchingServiceName := false for _, serviceName := range serviceNames { if serviceName == targetServiceName { matchingServiceName = true } } if !matchingServiceName { return fmt.Errorf(fmt.Sprintf("no service %s for %s?", targetServiceName, app.Name)) } logrus.Debugf("running command %s %s within the context of %s_%s", cmdName, parsedCmdArgs, app.StackName(), targetServiceName) Tty = true if err := RunCmdRemote(cl, app, abraSh, targetServiceName, cmdName, parsedCmdArgs); err != nil { return err } } return nil } // DeployOverview shows a deployment overview func DeployOverview(app config.App, version, message string) error { tableCol := []string{"server", "recipe", "config", "domain", "version"} table := formatter.CreateTable(tableCol) deployConfig := "compose.yml" if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok { deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n") } server := app.Server if app.Server == "default" { server = "local" } table.Append([]string{server, app.Recipe, deployConfig, app.Domain, version}) table.Render() if NoInput { return nil } response := false prompt := &survey.Confirm{ Message: message, } if err := survey.AskOne(prompt, &response); err != nil { return err } if !response { logrus.Fatal("exiting as requested") } return nil }