refactor!: vertical render & UI/UX fixes
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
See coop-cloud/abra#454
This commit is contained in:
parent
b6573720ec
commit
97959ef5da
@ -46,7 +46,10 @@ ${FOO:<default>} syntax). "check" does not confirm or deny this for you.`,
|
||||
}
|
||||
|
||||
table.
|
||||
Headers("RECIPE ENV SAMPLE", "APP ENV").
|
||||
Headers(
|
||||
fmt.Sprintf("%s .env.sample", app.Recipe.Name),
|
||||
fmt.Sprintf("%s.env", app.Name),
|
||||
).
|
||||
StyleFunc(func(row, col int) lipgloss.Style {
|
||||
switch {
|
||||
case col == 1:
|
||||
@ -71,7 +74,9 @@ ${FOO:<default>} syntax). "check" does not confirm or deny this for you.`,
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(table)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -110,19 +110,19 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
// is because we need to deal with GetComposeFiles under the hood and these
|
||||
// files change from version to version which therefore affects which
|
||||
// secrets might be generated
|
||||
version := deployMeta.Version
|
||||
toDeployVersion := deployMeta.Version
|
||||
if specificVersion != "" {
|
||||
version = specificVersion
|
||||
log.Debugf("choosing %s as version to deploy", version)
|
||||
toDeployVersion = specificVersion
|
||||
log.Debugf("choosing %s as version to deploy", toDeployVersion)
|
||||
|
||||
var err error
|
||||
isChaosCommit, err = app.Recipe.EnsureVersion(version)
|
||||
isChaosCommit, err = app.Recipe.EnsureVersion(toDeployVersion)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if isChaosCommit {
|
||||
log.Debugf("assuming '%s' is a chaos commit", version)
|
||||
log.Debugf("assuming '%s' is a chaos commit", toDeployVersion)
|
||||
internal.Chaos = true
|
||||
}
|
||||
}
|
||||
@ -138,12 +138,8 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
}
|
||||
}
|
||||
|
||||
if deployMeta.IsDeployed {
|
||||
if internal.Force || internal.Chaos {
|
||||
warnMessages = append(warnMessages, fmt.Sprintf("%s is already deployed", app.Name))
|
||||
} else {
|
||||
log.Fatalf("%s is already deployed", app.Name)
|
||||
}
|
||||
if deployMeta.IsDeployed && !(internal.Force || internal.Chaos) {
|
||||
log.Fatalf("%s is already deployed", app.Name)
|
||||
}
|
||||
|
||||
if !internal.Chaos && specificVersion == "" {
|
||||
@ -153,9 +149,9 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
}
|
||||
|
||||
if len(versions) > 0 && !internal.Chaos {
|
||||
version = versions[len(versions)-1]
|
||||
log.Debugf("choosing %s as version to deploy", version)
|
||||
if _, err := app.Recipe.EnsureVersion(version); err != nil {
|
||||
toDeployVersion = versions[len(versions)-1]
|
||||
log.Debugf("choosing %s as version to deploy", toDeployVersion)
|
||||
if _, err := app.Recipe.EnsureVersion(toDeployVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
@ -163,25 +159,22 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
version = formatter.SmallSHA(head.String())
|
||||
warnMessages = append(warnMessages, fmt.Sprintf("no versions detected, using latest commit"))
|
||||
toDeployVersion = formatter.SmallSHA(head.String())
|
||||
}
|
||||
}
|
||||
|
||||
chaosVersion := config.CHAOS_DEFAULT
|
||||
toDeployChaosVersion := config.CHAOS_DEFAULT
|
||||
if internal.Chaos {
|
||||
warnMessages = append(warnMessages, "chaos mode engaged")
|
||||
|
||||
if isChaosCommit {
|
||||
chaosVersion = specificVersion
|
||||
toDeployChaosVersion = specificVersion
|
||||
versionLabelLocal, err := app.Recipe.GetVersionLabelLocal()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
version = versionLabelLocal
|
||||
toDeployVersion = versionLabelLocal
|
||||
} else {
|
||||
var err error
|
||||
chaosVersion, err = app.Recipe.ChaosVersion()
|
||||
toDeployChaosVersion, err = app.Recipe.ChaosVersion()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -216,7 +209,7 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
appPkg.ExposeAllEnv(stackName, compose, app.Env)
|
||||
appPkg.SetRecipeLabel(compose, stackName, app.Recipe.Name)
|
||||
appPkg.SetChaosLabel(compose, stackName, internal.Chaos)
|
||||
appPkg.SetChaosVersionLabel(compose, stackName, chaosVersion)
|
||||
appPkg.SetChaosVersionLabel(compose, stackName, toDeployChaosVersion)
|
||||
appPkg.SetUpdateLabel(compose, stackName, app.Env)
|
||||
|
||||
envVars, err := appPkg.CheckEnv(app)
|
||||
@ -239,13 +232,24 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
warnMessages = append(warnMessages, "skipping domain checks as no DOMAIN=... configured for app")
|
||||
log.Debug("skipping domain checks as no DOMAIN=... configured for app")
|
||||
}
|
||||
} else {
|
||||
warnMessages = append(warnMessages, "skipping domain checks as requested")
|
||||
log.Debug("skipping domain checks as requested")
|
||||
}
|
||||
|
||||
if err := internal.DeployOverview(app, warnMessages, version, chaosVersion); err != nil {
|
||||
deployedVersion := "N/A"
|
||||
if deployMeta.IsDeployed {
|
||||
deployedVersion = deployMeta.Version
|
||||
}
|
||||
|
||||
if err := internal.DeployOverview(
|
||||
app,
|
||||
warnMessages,
|
||||
deployedVersion,
|
||||
deployMeta.ChaosVersion,
|
||||
toDeployVersion,
|
||||
toDeployChaosVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@ -267,9 +271,9 @@ Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
}
|
||||
}
|
||||
|
||||
app.Recipe.Version = version
|
||||
if chaosVersion != config.CHAOS_DEFAULT {
|
||||
app.Recipe.Version = chaosVersion
|
||||
app.Recipe.Version = toDeployVersion
|
||||
if toDeployChaosVersion != config.CHAOS_DEFAULT {
|
||||
app.Recipe.Version = toDeployChaosVersion
|
||||
}
|
||||
log.Debugf("choosing %s as version to save to env file", app.Recipe.Version)
|
||||
if err := app.WriteRecipeVersion(app.Recipe.Version, false); err != nil {
|
||||
|
@ -208,7 +208,7 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
|
||||
serverStat := allStats[app.Server]
|
||||
|
||||
headers := []string{"RECIPE", "DOMAIN"}
|
||||
headers := []string{"RECIPE", "DOMAIN", "SERVER"}
|
||||
if status {
|
||||
headers = append(headers, []string{
|
||||
"STATUS",
|
||||
@ -228,7 +228,7 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
|
||||
var rows [][]string
|
||||
for _, appStat := range serverStat.Apps {
|
||||
row := []string{appStat.Recipe, appStat.Domain}
|
||||
row := []string{appStat.Recipe, appStat.Domain, appStat.Server}
|
||||
if status {
|
||||
chaosStatus := appStat.Chaos
|
||||
if chaosStatus != "unknown" {
|
||||
@ -256,20 +256,8 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
table.Rows(rows...)
|
||||
|
||||
if len(rows) > 0 {
|
||||
fmt.Println(table)
|
||||
|
||||
if status {
|
||||
fmt.Println(fmt.Sprintf(
|
||||
"SERVER: %s | TOTAL APPS: %v | VERSIONED: %v | UNVERSIONED: %v | LATEST : %v | UPGRADE: %v",
|
||||
app.Server,
|
||||
serverStat.AppCount,
|
||||
serverStat.VersionCount,
|
||||
serverStat.UnversionedCount,
|
||||
serverStat.LatestCount,
|
||||
serverStat.UpgradeCount,
|
||||
))
|
||||
} else {
|
||||
log.Infof("SERVER: %s TOTAL APPS: %v", app.Server, serverStat.AppCount)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(allStats) > 1 && len(rows) > 0 {
|
||||
@ -279,12 +267,6 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
|
||||
alreadySeen[app.Server] = true
|
||||
}
|
||||
|
||||
if len(allStats) > 1 {
|
||||
totalServers := formatter.BoldStyle.Render("TOTAL SERVERS")
|
||||
totalApps := formatter.BoldStyle.Render("TOTAL APPS")
|
||||
log.Infof("%s: %v | %s: %v ", totalServers, totalServersCount, totalApps, totalAppsCount)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
102
cli/app/new.go
102
cli/app/new.go
@ -64,7 +64,6 @@ var AppNewCommand = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
recipe := internal.ValidateRecipe(args, cmd.Name())
|
||||
|
||||
var recipeVersion string
|
||||
if !internal.Chaos {
|
||||
if err := recipe.EnsureIsClean(); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -74,41 +73,47 @@ var AppNewCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(args) == 2 {
|
||||
recipeVersion = args[1]
|
||||
}
|
||||
var recipeVersion string
|
||||
if len(args) == 2 {
|
||||
recipeVersion = args[1]
|
||||
}
|
||||
|
||||
if recipeVersion == "" {
|
||||
recipeVersions, err := recipe.GetRecipeVersions()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if len(recipeVersions) > 0 {
|
||||
latest := recipeVersions[len(recipeVersions)-1]
|
||||
for tag := range latest {
|
||||
recipeVersion = tag
|
||||
}
|
||||
|
||||
if _, err := recipe.EnsureVersion(recipeVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
if err := recipe.EnsureLatest(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, err := recipe.EnsureVersion(recipeVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
var recipeVersions recipePkg.RecipeVersions
|
||||
if recipeVersion == "" {
|
||||
var err error
|
||||
recipeVersions, err = recipe.GetRecipeVersions()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if internal.Chaos && recipeVersion == "" {
|
||||
if len(recipeVersions) > 0 {
|
||||
latest := recipeVersions[len(recipeVersions)-1]
|
||||
for tag := range latest {
|
||||
recipeVersion = tag
|
||||
}
|
||||
|
||||
if _, err := recipe.EnsureVersion(recipeVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
if err := recipe.EnsureLatest(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if !internal.Chaos && recipeVersion != "" {
|
||||
if _, err := recipe.EnsureVersion(recipeVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
chaosVersion := config.CHAOS_DEFAULT
|
||||
if internal.Chaos {
|
||||
var err error
|
||||
recipeVersion, err = recipe.ChaosVersion()
|
||||
chaosVersion, err = recipe.ChaosVersion()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -187,37 +192,20 @@ var AppNewCommand = &cobra.Command{
|
||||
newAppServer = "local"
|
||||
}
|
||||
|
||||
table, err := formatter.CreateTable()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
headers := []string{"SERVER", "DOMAIN", "RECIPE", "VERSION"}
|
||||
table.Headers(headers...)
|
||||
|
||||
table.Row(newAppServer, appDomain, recipe.Name, recipeVersion)
|
||||
|
||||
log.Infof("new app '%s' created 🌞", recipe.Name)
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println(table)
|
||||
fmt.Println("")
|
||||
|
||||
fmt.Println("Configure this app:")
|
||||
fmt.Println(fmt.Sprintf("\n abra app config %s", appDomain))
|
||||
|
||||
fmt.Println("")
|
||||
fmt.Println("Deploy this app:")
|
||||
fmt.Println(fmt.Sprintf("\n abra app deploy %s", appDomain))
|
||||
log.Infof("%s created successfully (version: %s, chaos: %s)", appDomain, recipeVersion, chaosVersion)
|
||||
|
||||
if len(appSecrets) > 0 {
|
||||
fmt.Println("")
|
||||
fmt.Println("Generated secrets:")
|
||||
fmt.Println("")
|
||||
fmt.Println(secretsTable)
|
||||
rows := [][]string{}
|
||||
for k, v := range appSecrets {
|
||||
rows = append(rows, []string{k, v})
|
||||
}
|
||||
|
||||
overview := formatter.CreateOverview("SECRETS OVERVIEW", rows)
|
||||
|
||||
fmt.Println(overview)
|
||||
|
||||
log.Warnf(
|
||||
"generated secrets %s shown again, please take note of them %s",
|
||||
"secrets are %s shown again, please save them %s",
|
||||
formatter.BoldStyle.Render("NOT"),
|
||||
formatter.BoldStyle.Render("NOW"),
|
||||
)
|
||||
|
@ -128,24 +128,35 @@ func showPSOutput(app appPkg.App, cl *dockerClient.Client, deployedVersion, chao
|
||||
|
||||
allContainerStats[containerStats["service"]] = containerStats
|
||||
|
||||
// NOTE(d1): don't clobber these variables for --machine output
|
||||
dVersion := deployedVersion
|
||||
cVersion := chaosVersion
|
||||
|
||||
if containerStats["service"] != "app" {
|
||||
// NOTE(d1): don't repeat info which only relevant for the "app" service
|
||||
dVersion = ""
|
||||
cVersion = ""
|
||||
}
|
||||
|
||||
row := []string{
|
||||
containerStats["service"],
|
||||
containerStats["image"],
|
||||
containerStats["created"],
|
||||
dVersion,
|
||||
cVersion,
|
||||
containerStats["status"],
|
||||
containerStats["state"],
|
||||
containerStats["ports"],
|
||||
}
|
||||
|
||||
rows = append(rows, row)
|
||||
}
|
||||
|
||||
if internal.MachineReadable {
|
||||
jsonstring, err := json.Marshal(allContainerStats)
|
||||
rendered, err := json.Marshal(allContainerStats)
|
||||
if err != nil {
|
||||
log.Fatal("unable to convert to JSON: %s", err)
|
||||
}
|
||||
fmt.Println(string(jsonstring))
|
||||
|
||||
fmt.Println(string(rendered))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -157,19 +168,18 @@ func showPSOutput(app appPkg.App, cl *dockerClient.Client, deployedVersion, chao
|
||||
headers := []string{
|
||||
"SERVICE",
|
||||
"IMAGE",
|
||||
"CREATED",
|
||||
"VERSION",
|
||||
"CHAOS",
|
||||
"STATUS",
|
||||
"STATE",
|
||||
"PORTS",
|
||||
}
|
||||
|
||||
table.
|
||||
Headers(headers...).
|
||||
Rows(rows...)
|
||||
|
||||
fmt.Println(table)
|
||||
|
||||
log.Infof("VERSION: %s CHAOS: %s", deployedVersion, chaosVersion)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -127,7 +127,9 @@ var AppSecretGenerateCommand = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(table)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Warnf(
|
||||
"generated secrets %s shown again, please take note of them %s",
|
||||
@ -394,7 +396,10 @@ var AppSecretLsCommand = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(table)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ var AppServicesCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
headers := []string{"SERVICE (SHORT)", "SERVICE (LONG)", "IMAGE"}
|
||||
headers := []string{"SERVICE (SHORT)", "SERVICE (LONG)"}
|
||||
table.Headers(headers...)
|
||||
|
||||
var rows [][]string
|
||||
@ -80,7 +80,6 @@ var AppServicesCommand = &cobra.Command{
|
||||
row := []string{
|
||||
serviceShortName,
|
||||
serviceLongName,
|
||||
formatter.RemoveSha(container.Image),
|
||||
}
|
||||
|
||||
rows = append(rows, row)
|
||||
@ -89,7 +88,9 @@ var AppServicesCommand = &cobra.Command{
|
||||
table.Rows(rows...)
|
||||
|
||||
if len(rows) > 0 {
|
||||
fmt.Println(table)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -59,7 +59,10 @@ Passing "--prune/-p" does not remove those volumes.`,
|
||||
chaosVersion = deployMeta.ChaosVersion
|
||||
}
|
||||
|
||||
if err := internal.DeployOverview(app, []string{}, deployMeta.Version, chaosVersion); err != nil {
|
||||
if err := internal.UndeployOverview(
|
||||
app,
|
||||
deployMeta.Version,
|
||||
chaosVersion); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
@ -43,7 +42,7 @@ var AppVolumeListCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
headers := []string{"name", "created", "mounted"}
|
||||
headers := []string{"NAME", "ON SERVER"}
|
||||
|
||||
table, err := formatter.CreateTable()
|
||||
if err != nil {
|
||||
@ -54,14 +53,16 @@ var AppVolumeListCommand = &cobra.Command{
|
||||
|
||||
var rows [][]string
|
||||
for _, volume := range volumes {
|
||||
row := []string{volume.Name, volume.CreatedAt, volume.Mountpoint}
|
||||
row := []string{volume.Name, volume.Mountpoint}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
|
||||
table.Rows(rows...)
|
||||
|
||||
if len(rows) > 0 {
|
||||
fmt.Println(table)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
@ -20,7 +21,8 @@ var borderStyle = lipgloss.NewStyle().
|
||||
|
||||
var headerStyle = lipgloss.NewStyle().
|
||||
Underline(true).
|
||||
Bold(true)
|
||||
Bold(true).
|
||||
PaddingBottom(1)
|
||||
|
||||
var leftStyle = lipgloss.NewStyle().
|
||||
Bold(true)
|
||||
@ -51,6 +53,11 @@ func NewVersionOverview(
|
||||
server = "local"
|
||||
}
|
||||
|
||||
domain := app.Domain
|
||||
if domain == "" {
|
||||
domain = "N/A"
|
||||
}
|
||||
|
||||
body := strings.Builder{}
|
||||
body.WriteString(
|
||||
borderStyle.Render(
|
||||
@ -60,7 +67,7 @@ func NewVersionOverview(
|
||||
lipgloss.JoinVertical(
|
||||
lipgloss.Left,
|
||||
horizontal(leftStyle.Render("SERVER"), " ", rightStyle.Render(server)),
|
||||
horizontal(leftStyle.Render("DOMAIN"), " ", rightStyle.Render(app.Domain)),
|
||||
horizontal(leftStyle.Render("DOMAIN"), " ", rightStyle.Render(domain)),
|
||||
horizontal(leftStyle.Render("RECIPE"), " ", rightStyle.Render(app.Recipe.Name)),
|
||||
horizontal(leftStyle.Render("CONFIG"), " ", rightStyle.Render(deployConfig)),
|
||||
horizontal(leftStyle.Render("VERSION"), " ", rightStyle.Render(currentVersion)),
|
||||
@ -101,7 +108,13 @@ func NewVersionOverview(
|
||||
}
|
||||
|
||||
// DeployOverview shows a deployment overview
|
||||
func DeployOverview(app appPkg.App, warnMessages []string, version, chaosVersion string) error {
|
||||
func DeployOverview(
|
||||
app appPkg.App,
|
||||
warnMessages []string,
|
||||
deployedVersion string,
|
||||
deployedChaosVersion string,
|
||||
toDeployVersion,
|
||||
toDeployChaosVersion string) error {
|
||||
deployConfig := "compose.yml"
|
||||
if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok {
|
||||
deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n")
|
||||
@ -112,25 +125,25 @@ func DeployOverview(app appPkg.App, warnMessages []string, version, chaosVersion
|
||||
server = "local"
|
||||
}
|
||||
|
||||
body := strings.Builder{}
|
||||
body.WriteString(
|
||||
borderStyle.Render(
|
||||
lipgloss.JoinVertical(
|
||||
lipgloss.Center,
|
||||
headerStyle.Render("DEPLOY OVERVIEW"),
|
||||
lipgloss.JoinVertical(
|
||||
lipgloss.Left,
|
||||
horizontal(leftStyle.Render("SERVER"), " ", rightStyle.Render(server)),
|
||||
horizontal(leftStyle.Render("DOMAIN"), " ", rightStyle.Render(app.Domain)),
|
||||
horizontal(leftStyle.Render("RECIPE"), " ", rightStyle.Render(app.Recipe.Name)),
|
||||
horizontal(leftStyle.Render("CONFIG"), " ", rightStyle.Render(deployConfig)),
|
||||
horizontal(leftStyle.Render("VERSION"), " ", rightStyle.Render(version)),
|
||||
horizontal(leftStyle.Render("CHAOS"), " ", rightStyle.Padding(0).Render(chaosVersion)),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
fmt.Println(body.String())
|
||||
domain := app.Domain
|
||||
if domain == "" {
|
||||
domain = "N/A"
|
||||
}
|
||||
|
||||
rows := [][]string{
|
||||
[]string{"APP", domain},
|
||||
[]string{"RECIPE", app.Recipe.Name},
|
||||
[]string{"SERVER", server},
|
||||
[]string{"DEPLOYED", deployedVersion},
|
||||
[]string{"CURRENT CHAOS ", deployedChaosVersion},
|
||||
[]string{"TO DEPLOY", toDeployVersion},
|
||||
[]string{"NEW CHAOS", toDeployChaosVersion},
|
||||
[]string{"CONFIG", deployConfig},
|
||||
}
|
||||
|
||||
overview := formatter.CreateOverview("DEPLOY OVERVIEW", rows)
|
||||
|
||||
fmt.Println(overview)
|
||||
|
||||
for _, msg := range warnMessages {
|
||||
log.Warn(msg)
|
||||
@ -153,6 +166,56 @@ func DeployOverview(app appPkg.App, warnMessages []string, version, chaosVersion
|
||||
return nil
|
||||
}
|
||||
|
||||
// UndeployOverview shows an undeployment overview
|
||||
func UndeployOverview(
|
||||
app appPkg.App,
|
||||
version,
|
||||
chaosVersion string) error {
|
||||
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"
|
||||
}
|
||||
|
||||
domain := app.Domain
|
||||
if domain == "" {
|
||||
domain = "N/A"
|
||||
}
|
||||
|
||||
rows := [][]string{
|
||||
[]string{"APP", domain},
|
||||
[]string{"RECIPE", app.Recipe.Name},
|
||||
[]string{"SERVER", server},
|
||||
[]string{"DEPLOYED", version},
|
||||
[]string{"CHAOS", chaosVersion},
|
||||
[]string{"CONFIG", deployConfig},
|
||||
}
|
||||
|
||||
overview := formatter.CreateOverview("UNDEPLOY OVERVIEW", rows)
|
||||
|
||||
fmt.Println(overview)
|
||||
|
||||
if NoInput {
|
||||
return nil
|
||||
}
|
||||
|
||||
response := false
|
||||
prompt := &survey.Confirm{Message: "proceed?"}
|
||||
if err := survey.AskOne(prompt, &response); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !response {
|
||||
log.Fatal("undeploy cancelled")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostCmds parses a string of commands and executes them inside of the respective services
|
||||
// the commands string must have the following format:
|
||||
// "<service> <command> <arguments>|<service> <command> <arguments>|... "
|
||||
|
@ -1,8 +1,6 @@
|
||||
package recipe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
@ -104,7 +102,9 @@ var RecipeLintCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if len(rows) > 0 {
|
||||
fmt.Println(table)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, warnMsg := range warnMessages {
|
||||
log.Warn(warnMsg)
|
||||
|
@ -79,8 +79,9 @@ var RecipeListCommand = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(table)
|
||||
log.Infof("total recipes: %v", len(rows))
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -55,15 +55,32 @@ var RecipeVersionCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
table.Headers("SERVICE", "NAME", "TAG")
|
||||
table.Headers("SERVICE", "IMAGE", "TAG", "VERSION")
|
||||
|
||||
for version, meta := range recipeMeta.Versions[i] {
|
||||
var allRows [][]string
|
||||
var rows [][]string
|
||||
|
||||
for service, serviceMeta := range meta {
|
||||
rows = append(rows, []string{service, serviceMeta.Image, serviceMeta.Tag})
|
||||
allRows = append(allRows, []string{version, service, serviceMeta.Image, serviceMeta.Tag})
|
||||
recipeVersion := version
|
||||
if service != "app" {
|
||||
recipeVersion = ""
|
||||
}
|
||||
|
||||
rows = append(rows, []string{
|
||||
service,
|
||||
serviceMeta.Image,
|
||||
serviceMeta.Tag,
|
||||
recipeVersion,
|
||||
})
|
||||
|
||||
allRows = append(allRows, []string{
|
||||
version,
|
||||
service,
|
||||
serviceMeta.Image,
|
||||
serviceMeta.Tag,
|
||||
recipeVersion,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(rows, sortServiceByName(rows))
|
||||
@ -71,8 +88,9 @@ var RecipeVersionCommand = &cobra.Command{
|
||||
table.Rows(rows...)
|
||||
|
||||
if !internal.MachineReadable {
|
||||
fmt.Println(table)
|
||||
log.Infof("VERSION: %s", version)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println()
|
||||
continue
|
||||
}
|
||||
@ -100,11 +118,7 @@ var RecipeVersionCommand = &cobra.Command{
|
||||
|
||||
func sortServiceByName(versions [][]string) func(i, j int) bool {
|
||||
return func(i, j int) bool {
|
||||
// NOTE(d1): corresponds to the `tableCol` definition below
|
||||
if versions[i][1] == "app" {
|
||||
return true
|
||||
}
|
||||
return versions[i][1] < versions[j][1]
|
||||
return versions[i][0] < versions[j][0]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,9 @@ var ServerListCommand = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(table)
|
||||
if err := formatter.PrintTable(table); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -615,7 +615,7 @@ func (a App) WriteRecipeVersion(version string, dryRun bool) error {
|
||||
}
|
||||
|
||||
if !skipped {
|
||||
log.Infof("version %s saved to %s.env", version, a.Domain)
|
||||
log.Debugf("version %s saved to %s.env", version, a.Domain)
|
||||
} else {
|
||||
log.Debugf("skipping version %s write as already exists in %s.env", version, a.Domain)
|
||||
}
|
||||
|
@ -43,33 +43,122 @@ func HumanDuration(timestamp int64) string {
|
||||
|
||||
// CreateTable prepares a table layout for output.
|
||||
func CreateTable() (*table.Table, error) {
|
||||
var (
|
||||
renderer = lipgloss.NewRenderer(os.Stdout)
|
||||
headerStyle = renderer.NewStyle().Bold(true).Align(lipgloss.Center)
|
||||
cellStyle = renderer.NewStyle().Padding(0, 1)
|
||||
borderStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("63"))
|
||||
)
|
||||
|
||||
table := table.New().
|
||||
Border(lipgloss.ThickBorder()).
|
||||
BorderStyle(
|
||||
lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("63")),
|
||||
)
|
||||
BorderStyle(borderStyle).
|
||||
StyleFunc(func(row, col int) lipgloss.Style {
|
||||
var style lipgloss.Style
|
||||
|
||||
switch {
|
||||
case row == table.HeaderRow:
|
||||
return headerStyle
|
||||
default:
|
||||
style = cellStyle
|
||||
}
|
||||
|
||||
return style
|
||||
})
|
||||
|
||||
return table, nil
|
||||
}
|
||||
|
||||
func PrintTable(t *table.Table) error {
|
||||
if isAbraCI, ok := os.LookupEnv("ABRA_CI"); ok && isAbraCI == "1" {
|
||||
// NOTE(d1): no width limits for CI testing since we test against outputs
|
||||
log.Debug("detected ABRA_CI=1")
|
||||
return table, nil
|
||||
fmt.Println(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
tWidth, _ := lipgloss.Size(t.String())
|
||||
|
||||
width, _, err := term.GetSize(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if width-10 < 79 {
|
||||
// NOTE(d1): maintain standard minimum width
|
||||
table.Width(79)
|
||||
} else {
|
||||
// NOTE(d1): tests show that this produces stable border drawing
|
||||
table.Width(width - 10)
|
||||
if tWidth > width {
|
||||
t.Width(width - 10)
|
||||
}
|
||||
|
||||
return table, nil
|
||||
fmt.Println(t)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// horizontal is a JoinHorizontal helper function.
|
||||
func horizontal(left, mid, right string) string {
|
||||
return lipgloss.JoinHorizontal(lipgloss.Right, left, mid, right)
|
||||
}
|
||||
|
||||
func CreateOverview(header string, rows [][]string) string {
|
||||
var borderStyle = lipgloss.NewStyle().
|
||||
BorderStyle(lipgloss.ThickBorder()).
|
||||
Padding(0, 1, 0, 1).
|
||||
MaxWidth(79).
|
||||
BorderForeground(lipgloss.Color("63"))
|
||||
|
||||
var headerStyle = lipgloss.NewStyle().
|
||||
Underline(true).
|
||||
Bold(true).
|
||||
PaddingBottom(1)
|
||||
|
||||
var leftStyle = lipgloss.NewStyle().
|
||||
Bold(true)
|
||||
|
||||
var rightStyle = lipgloss.NewStyle()
|
||||
|
||||
var longest int
|
||||
for _, row := range rows {
|
||||
if len(row[0]) > longest {
|
||||
longest = len(row[0])
|
||||
}
|
||||
}
|
||||
|
||||
var renderedRows []string
|
||||
for _, row := range rows {
|
||||
if len(row) > 2 {
|
||||
panic("CreateOverview: only accepts rows of len == 2")
|
||||
}
|
||||
|
||||
lenOffset := 4
|
||||
if len(row[0]) < longest {
|
||||
lenOffset += longest - len(row[0])
|
||||
}
|
||||
|
||||
offset := ""
|
||||
for range lenOffset {
|
||||
offset = offset + " "
|
||||
}
|
||||
|
||||
renderedRows = append(
|
||||
renderedRows,
|
||||
horizontal(leftStyle.Render(row[0]), offset, rightStyle.Render(row[1])),
|
||||
)
|
||||
}
|
||||
|
||||
body := strings.Builder{}
|
||||
body.WriteString(
|
||||
borderStyle.Render(
|
||||
lipgloss.JoinVertical(
|
||||
lipgloss.Center,
|
||||
headerStyle.Render(header),
|
||||
lipgloss.JoinVertical(
|
||||
lipgloss.Left,
|
||||
renderedRows...,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
return body.String()
|
||||
}
|
||||
|
||||
// ToJSON converts a lipgloss.Table to JSON representation. It's not a robust
|
||||
|
@ -247,7 +247,7 @@ func (r Recipe) ChaosVersion() (string, error) {
|
||||
}
|
||||
|
||||
if !isClean {
|
||||
version = fmt.Sprintf("%s + unstaged changes", version)
|
||||
version = fmt.Sprintf("%s+U", version)
|
||||
}
|
||||
|
||||
return version, nil
|
||||
|
Loading…
x
Reference in New Issue
Block a user