feat: translation support
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
See #483
This commit is contained in:
@ -1,12 +1,12 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/leonelquinteros/gotext"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var AppCommand = &cobra.Command{
|
||||
Use: "app [cmd] [args] [flags]",
|
||||
Aliases: []string{"a"},
|
||||
Short: gotext.Get("Manage apps"),
|
||||
Use: i18n.G("app [cmd] [args] [flags]"),
|
||||
Aliases: []string{i18n.G("a")},
|
||||
Short: i18n.G("Manage apps"),
|
||||
}
|
||||
|
@ -6,14 +6,15 @@ import (
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var AppBackupListCommand = &cobra.Command{
|
||||
Use: "list <domain> [flags]",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List the contents of a snapshot",
|
||||
Use: i18n.G("list <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("ls")},
|
||||
Short: i18n.G("List the contents of a snapshot"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -40,17 +41,17 @@ var AppBackupListCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if snapshot != "" {
|
||||
log.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
|
||||
log.Debug(i18n.G("including SNAPSHOT=%s in backupbot exec invocation", snapshot))
|
||||
execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
|
||||
}
|
||||
|
||||
if showAllPaths {
|
||||
log.Debugf("including SHOW_ALL=%v in backupbot exec invocation", showAllPaths)
|
||||
log.Debug(i18n.G("including SHOW_ALL=%v in backupbot exec invocation", showAllPaths))
|
||||
execEnv = append(execEnv, fmt.Sprintf("SHOW_ALL=%v", showAllPaths))
|
||||
}
|
||||
|
||||
if timestamps {
|
||||
log.Debugf("including TIMESTAMPS=%v in backupbot exec invocation", timestamps)
|
||||
log.Debug(i18n.G("including TIMESTAMPS=%v in backupbot exec invocation", timestamps))
|
||||
execEnv = append(execEnv, fmt.Sprintf("TIMESTAMPS=%v", timestamps))
|
||||
}
|
||||
|
||||
@ -61,13 +62,13 @@ var AppBackupListCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
var AppBackupDownloadCommand = &cobra.Command{
|
||||
Use: "download <domain> [flags]",
|
||||
Aliases: []string{"d"},
|
||||
Short: "Download a snapshot",
|
||||
Long: `Downloads a backup.tar.gz to the current working directory.
|
||||
Use: i18n.G("download <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("d")},
|
||||
Short: i18n.G("Download a snapshot"),
|
||||
Long: i18n.G(`Downloads a backup.tar.gz to the current working directory.
|
||||
|
||||
"--volumes/-v" includes data contained in volumes alongide paths specified in
|
||||
"backupbot.backup.path" labels.`,
|
||||
"backupbot.backup.path" labels.`),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -98,22 +99,22 @@ var AppBackupDownloadCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if snapshot != "" {
|
||||
log.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
|
||||
log.Debug(i18n.G("including SNAPSHOT=%s in backupbot exec invocation", snapshot))
|
||||
execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
|
||||
}
|
||||
|
||||
if includePath != "" {
|
||||
log.Debugf("including INCLUDE_PATH=%s in backupbot exec invocation", includePath)
|
||||
log.Debug(i18n.G("including INCLUDE_PATH=%s in backupbot exec invocation", includePath))
|
||||
execEnv = append(execEnv, fmt.Sprintf("INCLUDE_PATH=%s", includePath))
|
||||
}
|
||||
|
||||
if includeSecrets {
|
||||
log.Debugf("including SECRETS=%v in backupbot exec invocation", includeSecrets)
|
||||
log.Debug(i18n.G("including SECRETS=%v in backupbot exec invocation", includeSecrets))
|
||||
execEnv = append(execEnv, fmt.Sprintf("SECRETS=%v", includeSecrets))
|
||||
}
|
||||
|
||||
if includeVolumes {
|
||||
log.Debugf("including VOLUMES=%v in backupbot exec invocation", includeVolumes)
|
||||
log.Debug(i18n.G("including VOLUMES=%v in backupbot exec invocation", includeVolumes))
|
||||
execEnv = append(execEnv, fmt.Sprintf("VOLUMES=%v", includeVolumes))
|
||||
}
|
||||
|
||||
@ -130,9 +131,9 @@ var AppBackupDownloadCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
var AppBackupCreateCommand = &cobra.Command{
|
||||
Use: "create <domain> [flags]",
|
||||
Aliases: []string{"c"},
|
||||
Short: "Create a new snapshot",
|
||||
Use: i18n.G("create <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("c")},
|
||||
Short: i18n.G("Create a new snapshot"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -163,7 +164,7 @@ var AppBackupCreateCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if retries != "" {
|
||||
log.Debugf("including RETRIES=%s in backupbot exec invocation", retries)
|
||||
log.Debug(i18n.G("including RETRIES=%s in backupbot exec invocation", retries))
|
||||
execEnv = append(execEnv, fmt.Sprintf("RETRIES=%s", retries))
|
||||
}
|
||||
|
||||
@ -174,9 +175,9 @@ var AppBackupCreateCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
var AppBackupSnapshotsCommand = &cobra.Command{
|
||||
Use: "snapshots <domain> [flags]",
|
||||
Aliases: []string{"s"},
|
||||
Short: "List all snapshots",
|
||||
Use: i18n.G("snapshots <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("s")},
|
||||
Short: i18n.G("List all snapshots"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -209,9 +210,9 @@ var AppBackupSnapshotsCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
var AppBackupCommand = &cobra.Command{
|
||||
Use: "backup [cmd] [args] [flags]",
|
||||
Aliases: []string{"b"},
|
||||
Short: "Manage app backups",
|
||||
Use: i18n.G("backup [cmd] [args] [flags]"),
|
||||
Aliases: []string{i18n.G("b")},
|
||||
Short: i18n.G("Manage app backups"),
|
||||
}
|
||||
|
||||
var (
|
||||
@ -227,81 +228,81 @@ var (
|
||||
func init() {
|
||||
AppBackupListCommand.Flags().StringVarP(
|
||||
&snapshot,
|
||||
"snapshot",
|
||||
"s",
|
||||
i18n.G("snapshot"),
|
||||
i18n.G("s"),
|
||||
"",
|
||||
"list specific snapshot",
|
||||
i18n.G("list specific snapshot"),
|
||||
)
|
||||
|
||||
AppBackupListCommand.Flags().BoolVarP(
|
||||
&showAllPaths,
|
||||
"all",
|
||||
"a",
|
||||
i18n.G("all"),
|
||||
i18n.G("a"),
|
||||
false,
|
||||
"show all paths",
|
||||
i18n.G("show all paths"),
|
||||
)
|
||||
|
||||
AppBackupListCommand.Flags().BoolVarP(
|
||||
×tamps,
|
||||
"timestamps",
|
||||
"t",
|
||||
i18n.G("timestamps"),
|
||||
i18n.G("t"),
|
||||
false,
|
||||
"include timestamps",
|
||||
i18n.G("include timestamps"),
|
||||
)
|
||||
|
||||
AppBackupDownloadCommand.Flags().StringVarP(
|
||||
&snapshot,
|
||||
"snapshot",
|
||||
"s",
|
||||
i18n.G("snapshot"),
|
||||
i18n.G("s"),
|
||||
"",
|
||||
"list specific snapshot",
|
||||
i18n.G("list specific snapshot"),
|
||||
)
|
||||
|
||||
AppBackupDownloadCommand.Flags().StringVarP(
|
||||
&includePath,
|
||||
"path",
|
||||
"p",
|
||||
i18n.G("path"),
|
||||
i18n.G("p"),
|
||||
"",
|
||||
"volumes path",
|
||||
i18n.G("volumes path"),
|
||||
)
|
||||
|
||||
AppBackupDownloadCommand.Flags().BoolVarP(
|
||||
&includeSecrets,
|
||||
"secrets",
|
||||
"S",
|
||||
i18n.G("secrets"),
|
||||
i18n.G("S"),
|
||||
false,
|
||||
"include secrets",
|
||||
i18n.G("include secrets"),
|
||||
)
|
||||
|
||||
AppBackupDownloadCommand.Flags().BoolVarP(
|
||||
&includeVolumes,
|
||||
"volumes",
|
||||
"v",
|
||||
i18n.G("volumes"),
|
||||
i18n.G("v"),
|
||||
false,
|
||||
"include volumes",
|
||||
i18n.G("include volumes"),
|
||||
)
|
||||
|
||||
AppBackupDownloadCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
|
||||
AppBackupCreateCommand.Flags().StringVarP(
|
||||
&retries,
|
||||
"retries",
|
||||
"r",
|
||||
i18n.G("retries"),
|
||||
i18n.G("r"),
|
||||
"1",
|
||||
"number of retry attempts",
|
||||
i18n.G("number of retry attempts"),
|
||||
)
|
||||
|
||||
AppBackupCreateCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
}
|
||||
|
@ -7,16 +7,17 @@ import (
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var AppCheckCommand = &cobra.Command{
|
||||
Use: "check <domain> [flags]",
|
||||
Aliases: []string{"chk"},
|
||||
Short: "Ensure an app is well configured",
|
||||
Long: `Compare env vars in both the app ".env" and recipe ".env.sample" file.
|
||||
Use: i18n.G("check <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("chk")},
|
||||
Short: i18n.G("Ensure an app is well configured"),
|
||||
Long: i18n.G(`Compare env vars in both the app ".env" and recipe ".env.sample" file.
|
||||
|
||||
The goal is to ensure that recipe ".env.sample" env vars are defined in your
|
||||
app ".env" file. Only env var definitions in the ".env.sample" which are
|
||||
@ -25,7 +26,7 @@ these env vars, then "check" will complain.
|
||||
|
||||
Recipe maintainers may or may not provide defaults for env vars within their
|
||||
recipes regardless of commenting or not (e.g. through the use of
|
||||
${FOO:<default>} syntax). "check" does not confirm or deny this for you.`,
|
||||
${FOO:<default>} syntax). "check" does not confirm or deny this for you.`),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -83,9 +84,9 @@ ${FOO:<default>} syntax). "check" does not confirm or deny this for you.`,
|
||||
func init() {
|
||||
AppCheckCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
}
|
||||
|
@ -13,15 +13,16 @@ import (
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var AppCmdCommand = &cobra.Command{
|
||||
Use: "command <domain> [service | --local] <cmd> [[args] [flags] | [flags] -- [args]]",
|
||||
Aliases: []string{"cmd"},
|
||||
Short: "Run app commands",
|
||||
Long: `Run an app specific command.
|
||||
Use: i18n.G("command <domain> [service | --local] <cmd> [[args] [flags] | [flags] -- [args]]"),
|
||||
Aliases: []string{i18n.G("cmd")},
|
||||
Short: i18n.G("Run app commands"),
|
||||
Long: i18n.G(`Run an app specific command.
|
||||
|
||||
These commands are bash functions, defined in the abra.sh of the recipe itself.
|
||||
They can be run within the context of a service (e.g. app) or locally on your
|
||||
@ -30,24 +31,24 @@ work station by passing "--local/-l".
|
||||
N.B. If using the "--" style to pass arguments, flags (e.g. "--local/-l") must
|
||||
be passed *before* the "--". It is possible to pass arguments without the "--"
|
||||
as long as no dashes are present (i.e. "foo" works without "--", "-foo"
|
||||
does not).`,
|
||||
Example: ` # pass <cmd> args/flags without "--"
|
||||
does not).`),
|
||||
Example: i18n.G(` # pass <cmd> args/flags without "--"
|
||||
abra app cmd 1312.net app my_cmd_arg foo --user bar
|
||||
|
||||
# pass <cmd> args/flags with "--"
|
||||
abra app cmd 1312.net app my_cmd_args --user bar -- foo -vvv
|
||||
|
||||
# drop the [service] arg if using "--local/-l"
|
||||
abra app cmd 1312.net my_cmd --local`,
|
||||
abra app cmd 1312.net my_cmd --local`),
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if local {
|
||||
if !(len(args) >= 2) {
|
||||
return errors.New("requires at least 2 arguments with --local/-l")
|
||||
return errors.New(i18n.G("requires at least 2 arguments with --local/-l"))
|
||||
}
|
||||
|
||||
if slices.Contains(os.Args, "--") {
|
||||
if cmd.ArgsLenAtDash() > 2 {
|
||||
return errors.New("accepts at most 2 args with --local/-l")
|
||||
return errors.New(i18n.G("accepts at most 2 args with --local/-l"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +64,7 @@ does not).`,
|
||||
}
|
||||
|
||||
if !(len(args) >= 3) {
|
||||
return errors.New("requires at least 3 arguments")
|
||||
return errors.New(i18n.G("requires at least 3 arguments"))
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -97,14 +98,14 @@ does not).`,
|
||||
}
|
||||
|
||||
if local && remoteUser != "" {
|
||||
log.Fatal("cannot use --local & --user together")
|
||||
log.Fatal(i18n.G("cannot use --local & --user together"))
|
||||
}
|
||||
|
||||
hasCmdArgs, parsedCmdArgs := parseCmdArgs(args, local)
|
||||
|
||||
if _, err := os.Stat(app.Recipe.AbraShPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.Fatalf("%s does not exist for %s?", app.Recipe.AbraShPath, app.Name)
|
||||
log.Fatal(i18n.G("%s does not exist for %s?", app.Recipe.AbraShPath, app.Name))
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -115,7 +116,7 @@ does not).`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("--local detected, running %s on local work station", cmdName)
|
||||
log.Debug(i18n.G("--local detected, running %s on local work station", cmdName))
|
||||
|
||||
var exportEnv string
|
||||
for k, v := range app.Env {
|
||||
@ -124,16 +125,16 @@ does not).`,
|
||||
|
||||
var sourceAndExec string
|
||||
if hasCmdArgs {
|
||||
log.Debugf("parsed following command arguments: %s", parsedCmdArgs)
|
||||
log.Debug(i18n.G("parsed following command arguments: %s", parsedCmdArgs))
|
||||
sourceAndExec = fmt.Sprintf("TARGET=local; APP_NAME=%s; STACK_NAME=%s; %s . %s; %s %s", app.Name, app.StackName(), exportEnv, app.Recipe.AbraShPath, cmdName, parsedCmdArgs)
|
||||
} else {
|
||||
log.Debug("did not detect any command arguments")
|
||||
log.Debug(i18n.G("did not detect any command arguments"))
|
||||
sourceAndExec = fmt.Sprintf("TARGET=local; APP_NAME=%s; STACK_NAME=%s; %s . %s; %s", app.Name, app.StackName(), exportEnv, app.Recipe.AbraShPath, cmdName)
|
||||
}
|
||||
|
||||
shell := "/bin/bash"
|
||||
if _, err := os.Stat(shell); errors.Is(err, os.ErrNotExist) {
|
||||
log.Debugf("%s does not exist locally, use /bin/sh as fallback", shell)
|
||||
log.Debug(i18n.G("%s does not exist locally, use /bin/sh as fallback", shell))
|
||||
shell = "/bin/sh"
|
||||
}
|
||||
cmd := exec.Command(shell, "-c", sourceAndExec)
|
||||
@ -164,15 +165,15 @@ does not).`,
|
||||
}
|
||||
|
||||
if !matchingServiceName {
|
||||
log.Fatalf("no service %s for %s?", targetServiceName, app.Name)
|
||||
log.Fatal(i18n.G("no service %s for %s?", targetServiceName, app.Name))
|
||||
}
|
||||
|
||||
log.Debugf("running command %s within the context of %s_%s", cmdName, app.StackName(), targetServiceName)
|
||||
log.Debug(i18n.G("running command %s within the context of %s_%s", cmdName, app.StackName(), targetServiceName))
|
||||
|
||||
if hasCmdArgs {
|
||||
log.Debugf("parsed following command arguments: %s", parsedCmdArgs)
|
||||
log.Debug(i18n.G("parsed following command arguments: %s", parsedCmdArgs))
|
||||
} else {
|
||||
log.Debug("did not detect any command arguments")
|
||||
log.Debug(i18n.G("did not detect any command arguments"))
|
||||
}
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
@ -192,9 +193,9 @@ does not).`,
|
||||
}
|
||||
|
||||
var AppCmdListCommand = &cobra.Command{
|
||||
Use: "list <domain> [flags]",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List all available commands",
|
||||
Use: i18n.G("list <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("ls")},
|
||||
Short: i18n.G("List all available commands"),
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
app := internal.ValidateApp(args)
|
||||
@ -244,33 +245,33 @@ var (
|
||||
func init() {
|
||||
AppCmdCommand.Flags().BoolVarP(
|
||||
&local,
|
||||
"local",
|
||||
"l",
|
||||
i18n.G("local"),
|
||||
i18n.G("l"),
|
||||
false,
|
||||
"run command locally",
|
||||
i18n.G("run command locally"),
|
||||
)
|
||||
|
||||
AppCmdCommand.Flags().StringVarP(
|
||||
&remoteUser,
|
||||
"user",
|
||||
"u",
|
||||
i18n.G("user"),
|
||||
i18n.G("u"),
|
||||
"",
|
||||
"request remote user",
|
||||
i18n.G("request remote user"),
|
||||
)
|
||||
|
||||
AppCmdCommand.Flags().BoolVarP(
|
||||
&disableTTY,
|
||||
"tty",
|
||||
"T",
|
||||
i18n.G("tty"),
|
||||
i18n.G("T"),
|
||||
false,
|
||||
"disable remote TTY",
|
||||
i18n.G("disable remote TTY"),
|
||||
)
|
||||
|
||||
AppCmdCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
}
|
||||
|
@ -6,16 +6,17 @@ import (
|
||||
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var AppConfigCommand = &cobra.Command{
|
||||
Use: "config <domain> [flags]",
|
||||
Aliases: []string{"cfg"},
|
||||
Short: "Edit app config",
|
||||
Example: " abra config 1312.net",
|
||||
Use: i18n.G("config <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("cfg")},
|
||||
Short: i18n.G("Edit app config"),
|
||||
Example: i18n.G(" abra config 1312.net"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -32,13 +33,13 @@ var AppConfigCommand = &cobra.Command{
|
||||
appName := args[0]
|
||||
appFile, exists := files[appName]
|
||||
if !exists {
|
||||
log.Fatalf("cannot find app with name %s", appName)
|
||||
log.Fatal(i18n.G("cannot find app with name %s", appName))
|
||||
}
|
||||
|
||||
ed, ok := os.LookupEnv("EDITOR")
|
||||
if !ok {
|
||||
edPrompt := &survey.Select{
|
||||
Message: "which editor do you wish to use?",
|
||||
Message: i18n.G("which editor do you wish to use?"),
|
||||
Options: []string{"vi", "vim", "nvim", "nano", "pico", "emacs"},
|
||||
}
|
||||
if err := survey.AskOne(edPrompt, &ed); err != nil {
|
||||
|
@ -3,7 +3,6 @@ package app
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
@ -15,6 +14,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
containerPkg "coopcloud.tech/abra/pkg/container"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/container"
|
||||
"github.com/docker/cli/cli/command"
|
||||
@ -26,14 +26,14 @@ import (
|
||||
)
|
||||
|
||||
var AppCpCommand = &cobra.Command{
|
||||
Use: "cp <domain> <src> <dst> [flags]",
|
||||
Aliases: []string{"c"},
|
||||
Short: "Copy files to/from a deployed app service",
|
||||
Example: ` # copy myfile.txt to the root of the app service
|
||||
Use: i18n.G("cp <domain> <src> <dst> [flags]"),
|
||||
Aliases: []string{i18n.G("c")},
|
||||
Short: i18n.G("Copy files to/from a deployed app service"),
|
||||
Example: i18n.G(` # copy myfile.txt to the root of the app service
|
||||
abra app cp 1312.net myfile.txt app:/
|
||||
|
||||
# copy that file back to your current working directory locally
|
||||
abra app cp 1312.net app:/myfile.txt ./`,
|
||||
abra app cp 1312.net app:/myfile.txt ./`),
|
||||
Args: cobra.ExactArgs(3),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -69,7 +69,7 @@ var AppCpCommand = &cobra.Command{
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Debugf("retrieved %s as target container on %s", formatter.ShortenID(container.ID), app.Server)
|
||||
log.Debug(i18n.G("retrieved %s as target container on %s", formatter.ShortenID(container.ID), app.Server))
|
||||
|
||||
if toContainer {
|
||||
err = CopyToContainer(cl, container.ID, srcPath, dstPath)
|
||||
@ -82,7 +82,7 @@ var AppCpCommand = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var errServiceMissing = errors.New("one of <src>/<dest> arguments must take $SERVICE:$PATH form")
|
||||
var errServiceMissing = errors.New(i18n.G("one of <src>/<dest> arguments must take $SERVICE:$PATH form"))
|
||||
|
||||
// parseSrcAndDst parses src and dest string. One of src or dst must be of the form $SERVICE:$PATH
|
||||
func parseSrcAndDst(src, dst string) (srcPath string, dstPath string, service string, toContainer bool, err error) {
|
||||
@ -105,7 +105,7 @@ func parseSrcAndDst(src, dst string) (srcPath string, dstPath string, service st
|
||||
func CopyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath string) error {
|
||||
srcStat, err := os.Stat(srcPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("local %s ", err)
|
||||
return errors.New(i18n.G("local %s ", err))
|
||||
}
|
||||
|
||||
dstStat, err := cl.ContainerStatPath(context.Background(), containerID, dstPath)
|
||||
@ -114,7 +114,7 @@ func CopyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath stri
|
||||
if errdefs.IsNotFound(err) {
|
||||
dstExists = false
|
||||
} else {
|
||||
return fmt.Errorf("remote path: %s", err)
|
||||
return errors.New(i18n.G("remote path: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ func CopyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath stri
|
||||
Detach: false,
|
||||
Tty: true,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("create remote directory: %s", err)
|
||||
return errors.New(i18n.G("create remote directory: %s", err))
|
||||
}
|
||||
case CopyModeFileToFile:
|
||||
// Remove the file component from the path, since docker can only copy
|
||||
@ -161,7 +161,7 @@ func CopyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath stri
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("copy %s from local to %s on container", srcPath, dstPath)
|
||||
log.Debug(i18n.G("copy %s from local to %s on container", srcPath, dstPath))
|
||||
copyOpts := containertypes.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false}
|
||||
if err := cl.CopyToContainer(context.Background(), containerID, dstPath, content, copyOpts); err != nil {
|
||||
return err
|
||||
@ -181,7 +181,7 @@ func CopyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath stri
|
||||
Detach: false,
|
||||
Tty: true,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("create remote directory: %s", err)
|
||||
return errors.New(i18n.G("create remote directory: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,9 +194,9 @@ func CopyFromContainer(cl *dockerClient.Client, containerID, srcPath, dstPath st
|
||||
srcStat, err := cl.ContainerStatPath(context.Background(), containerID, srcPath)
|
||||
if err != nil {
|
||||
if errdefs.IsNotFound(err) {
|
||||
return fmt.Errorf("remote: %s does not exist", srcPath)
|
||||
return errors.New(i18n.G("remote: %s does not exist", srcPath))
|
||||
} else {
|
||||
return fmt.Errorf("remote path: %s", err)
|
||||
return errors.New(i18n.G("remote path: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,7 +207,7 @@ func CopyFromContainer(cl *dockerClient.Client, containerID, srcPath, dstPath st
|
||||
if os.IsNotExist(err) {
|
||||
dstExists = false
|
||||
} else {
|
||||
return fmt.Errorf("remote path: %s", err)
|
||||
return errors.New(i18n.G("remote path: %s", err))
|
||||
}
|
||||
} else {
|
||||
dstMode = dstStat.Mode()
|
||||
@ -242,7 +242,7 @@ func CopyFromContainer(cl *dockerClient.Client, containerID, srcPath, dstPath st
|
||||
|
||||
content, _, err := cl.CopyFromContainer(context.Background(), containerID, srcPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("copy: %s", err)
|
||||
return errors.New(i18n.G("copy: %s", err))
|
||||
}
|
||||
defer content.Close()
|
||||
if err := archive.Untar(content, dstPath, &archive.TarOptions{
|
||||
@ -250,7 +250,7 @@ func CopyFromContainer(cl *dockerClient.Client, containerID, srcPath, dstPath st
|
||||
Compression: archive.Gzip,
|
||||
NoLchown: true,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("untar: %s", err)
|
||||
return errors.New(i18n.G("untar: %s", err))
|
||||
}
|
||||
|
||||
if moveDstFile != "" {
|
||||
@ -269,8 +269,8 @@ func CopyFromContainer(cl *dockerClient.Client, containerID, srcPath, dstPath st
|
||||
}
|
||||
|
||||
var (
|
||||
ErrCopyDirToFile = fmt.Errorf("can't copy dir to file")
|
||||
ErrDstDirNotExist = fmt.Errorf("destination directory does not exist")
|
||||
ErrCopyDirToFile = errors.New(i18n.G("can't copy dir to file"))
|
||||
ErrDstDirNotExist = errors.New(i18n.G("destination directory does not exist"))
|
||||
)
|
||||
|
||||
type CopyMode int
|
||||
@ -375,9 +375,9 @@ func moveFile(sourcePath, destPath string) error {
|
||||
func init() {
|
||||
AppCpCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
@ -16,6 +16,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/dns"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/lint"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||
@ -24,15 +25,15 @@ import (
|
||||
)
|
||||
|
||||
var AppDeployCommand = &cobra.Command{
|
||||
Use: "deploy <domain> [version] [flags]",
|
||||
Aliases: []string{"d"},
|
||||
Short: "Deploy an app",
|
||||
Long: `Deploy an app.
|
||||
Use: i18n.G("deploy <domain> [version] [flags]"),
|
||||
Aliases: []string{i18n.G("d")},
|
||||
Short: i18n.G("Deploy an app"),
|
||||
Long: i18n.G(`Deploy an app.
|
||||
|
||||
This command supports chaos operations. Use "--chaos/-C" to deploy your recipe
|
||||
checkout as-is. Recipe commit hashes are also supported as values for
|
||||
"[version]". Please note, "upgrade"/"rollback" do not support chaos operations.`,
|
||||
Example: ` # standard deployment
|
||||
"[version]". Please note, "upgrade"/"rollback" do not support chaos operations.`),
|
||||
Example: i18n.G(` # standard deployment
|
||||
abra app deploy 1312.net
|
||||
|
||||
# chaos deployment
|
||||
@ -42,7 +43,7 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
abra app deploy 1312.net 2.0.0+1.2.3
|
||||
|
||||
# deploy a specific git hash
|
||||
abra app deploy 1312.net 886db76d`,
|
||||
abra app deploy 1312.net 886db76d`),
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -55,7 +56,7 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
case 1:
|
||||
app, err := appPkg.Get(args[0])
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("autocomplete failed: %s", err)
|
||||
errMsg := i18n.G("autocomplete failed: %s", err)
|
||||
return []string{errMsg}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
return autocomplete.RecipeVersionComplete(app.Recipe.Name)
|
||||
@ -84,7 +85,7 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("checking whether %s is already deployed", app.StackName())
|
||||
log.Debug(i18n.G("checking whether %s is already deployed", app.StackName()))
|
||||
|
||||
deployMeta, err := stack.IsDeployed(context.Background(), cl, app.StackName())
|
||||
if err != nil {
|
||||
@ -92,18 +93,18 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
}
|
||||
|
||||
if deployMeta.IsDeployed && !(internal.Force || internal.Chaos) {
|
||||
log.Fatalf("%s is already deployed", app.Name)
|
||||
log.Fatal(i18n.G("%s is already deployed", app.Name))
|
||||
}
|
||||
|
||||
toDeployVersion, err = getDeployVersion(args, deployMeta, app)
|
||||
if err != nil {
|
||||
log.Fatal(fmt.Errorf("get deploy version: %s", err))
|
||||
log.Fatal(i18n.G("get deploy version: %s", err))
|
||||
}
|
||||
|
||||
if !internal.Chaos {
|
||||
_, err = app.Recipe.EnsureVersion(toDeployVersion)
|
||||
if err != nil {
|
||||
log.Fatalf("ensure recipe: %s", err)
|
||||
log.Fatal(i18n.G("ensure recipe: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,7 +163,7 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
for _, envVar := range envVars {
|
||||
if !envVar.Present {
|
||||
deployWarnMessages = append(deployWarnMessages,
|
||||
fmt.Sprintf("%s missing from %s.env", envVar.Name, app.Domain),
|
||||
i18n.G("%s missing from %s.env", envVar.Name, app.Domain),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -173,10 +174,10 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
log.Debug("skipping domain checks, no DOMAIN=... configured")
|
||||
log.Debug(i18n.G("skipping domain checks, no DOMAIN=... configured"))
|
||||
}
|
||||
} else {
|
||||
log.Debug("skipping domain checks")
|
||||
log.Debug(i18n.G("skipping domain checks"))
|
||||
}
|
||||
|
||||
deployedVersion := config.NO_VERSION_DEFAULT
|
||||
@ -199,7 +200,7 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("set waiting timeout to %d second(s)", stack.WaitTimeout)
|
||||
log.Debug(i18n.G("set waiting timeout to %d second(s)", stack.WaitTimeout))
|
||||
|
||||
serviceNames, err := appPkg.GetAppServiceNames(app.Name)
|
||||
if err != nil {
|
||||
@ -225,14 +226,14 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
||||
|
||||
postDeployCmds, ok := app.Env["POST_DEPLOY_CMDS"]
|
||||
if ok && !internal.DontWaitConverge {
|
||||
log.Debugf("run the following post-deploy commands: %s", postDeployCmds)
|
||||
log.Debug(i18n.G("run the following post-deploy commands: %s", postDeployCmds))
|
||||
if err := internal.PostCmds(cl, app, postDeployCmds); err != nil {
|
||||
log.Fatalf("attempting to run post deploy commands, saw: %s", err)
|
||||
log.Fatal(i18n.G("attempting to run post deploy commands, saw: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
if err := app.WriteRecipeVersion(toDeployVersion, false); err != nil {
|
||||
log.Fatalf("writing recipe version failed: %s", err)
|
||||
log.Fatal(i18n.G("writing recipe version failed: %s", err))
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -258,7 +259,7 @@ func getLatestVersionOrCommit(app app.App) (string, error) {
|
||||
// validateArgsAndFlags ensures compatible args/flags.
|
||||
func validateArgsAndFlags(args []string) error {
|
||||
if len(args) == 2 && args[1] != "" && internal.Chaos {
|
||||
return fmt.Errorf("cannot use [version] and --chaos together")
|
||||
return errors.New(i18n.G("cannot use [version] and --chaos together"))
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -272,7 +273,7 @@ func validateSecrets(cl *dockerClient.Client, app app.App) error {
|
||||
|
||||
for _, secStat := range secStats {
|
||||
if !secStat.CreatedOnRemote {
|
||||
return fmt.Errorf("secret not generated: %s", secStat.LocalName)
|
||||
return errors.New(i18n.G("secret not generated: %s", secStat.LocalName))
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,33 +287,33 @@ func getDeployVersion(cliArgs []string, deployMeta stack.DeployMeta, app app.App
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
log.Debugf("version: taking chaos version: %s", v)
|
||||
log.Debug(i18n.G("version: taking chaos version: %s", v))
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Check if the deploy version is set with a cli argument
|
||||
if len(cliArgs) == 2 && cliArgs[1] != "" {
|
||||
log.Debugf("version: taking version from cli arg: %s", cliArgs[1])
|
||||
log.Debug(i18n.G("version: taking version from cli arg: %s", cliArgs[1]))
|
||||
return cliArgs[1], nil
|
||||
}
|
||||
|
||||
// Check if the recipe has a version in the .env file
|
||||
if app.Recipe.EnvVersion != "" && !internal.IgnoreEnvVersion {
|
||||
if strings.HasSuffix(app.Recipe.EnvVersionRaw, "+U") {
|
||||
return "", fmt.Errorf("version: can not redeploy chaos version %s", app.Recipe.EnvVersionRaw)
|
||||
return "", errors.New(i18n.G("version: can not redeploy chaos version %s", app.Recipe.EnvVersionRaw))
|
||||
}
|
||||
log.Debugf("version: taking version from .env file: %s", app.Recipe.EnvVersion)
|
||||
log.Debug(i18n.G("version: taking version from .env file: %s", app.Recipe.EnvVersion))
|
||||
return app.Recipe.EnvVersion, nil
|
||||
}
|
||||
|
||||
// Take deployed version
|
||||
if deployMeta.IsDeployed {
|
||||
log.Debugf("version: taking deployed version: %s", deployMeta.Version)
|
||||
log.Debug(i18n.G("version: taking deployed version: %s", deployMeta.Version))
|
||||
return deployMeta.Version, nil
|
||||
}
|
||||
|
||||
v, err := getLatestVersionOrCommit(app)
|
||||
log.Debugf("version: taking new recipe version: %s", v)
|
||||
log.Debug(i18n.G("version: taking new recipe version: %s", v))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -322,33 +323,33 @@ func getDeployVersion(cliArgs []string, deployMeta stack.DeployMeta, app app.App
|
||||
func init() {
|
||||
AppDeployCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
|
||||
AppDeployCommand.Flags().BoolVarP(
|
||||
&internal.Force,
|
||||
"force",
|
||||
"f",
|
||||
i18n.G("force"),
|
||||
i18n.G("f"),
|
||||
false,
|
||||
"perform action without further prompt",
|
||||
i18n.G("perform action without further prompt"),
|
||||
)
|
||||
|
||||
AppDeployCommand.Flags().BoolVarP(
|
||||
&internal.NoDomainChecks,
|
||||
"no-domain-checks",
|
||||
"D",
|
||||
i18n.G("no-domain-checks"),
|
||||
i18n.G("D"),
|
||||
false,
|
||||
"disable public DNS checks",
|
||||
i18n.G("disable public DNS checks"),
|
||||
)
|
||||
|
||||
AppDeployCommand.Flags().BoolVarP(
|
||||
&internal.DontWaitConverge,
|
||||
"no-converge-checks",
|
||||
"c",
|
||||
i18n.G("no-converge-checks"),
|
||||
i18n.G("c"),
|
||||
false,
|
||||
"disable converge logic checks",
|
||||
i18n.G("disable converge logic checks"),
|
||||
)
|
||||
}
|
||||
|
@ -7,14 +7,15 @@ import (
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var AppEnvCommand = &cobra.Command{
|
||||
Use: "env <domain> [flags]",
|
||||
Aliases: []string{"e"},
|
||||
Short: "Show app .env values",
|
||||
Example: " abra app env 1312.net",
|
||||
Use: i18n.G("env <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("e")},
|
||||
Short: i18n.G("Show app .env values"),
|
||||
Example: i18n.G(" abra app env 1312.net"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -37,7 +38,7 @@ var AppEnvCommand = &cobra.Command{
|
||||
rows = append(rows, []string{k, app.Env[k]})
|
||||
}
|
||||
|
||||
overview := formatter.CreateOverview("ENV OVERVIEW", rows)
|
||||
overview := formatter.CreateOverview(i18n.G("ENV OVERVIEW"), rows)
|
||||
fmt.Println(overview)
|
||||
},
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/convert"
|
||||
composetypes "github.com/docker/cli/cli/compose/types"
|
||||
@ -19,11 +20,11 @@ import (
|
||||
)
|
||||
|
||||
var AppLabelsCommand = &cobra.Command{
|
||||
Use: "labels <domain> [flags]",
|
||||
Aliases: []string{"lb"},
|
||||
Short: "Show deployment labels",
|
||||
Long: "Both local recipe and live deployment labels are shown.",
|
||||
Example: " abra app labels 1312.net",
|
||||
Use: i18n.G("labels <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("lb")},
|
||||
Short: i18n.G("Show deployment labels"),
|
||||
Long: i18n.G("Both local recipe and live deployment labels are shown."),
|
||||
Example: i18n.G(" abra app labels 1312.net"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -49,7 +50,7 @@ var AppLabelsCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
rows := [][]string{
|
||||
{"DEPLOYED LABELS", "---"},
|
||||
{i18n.G("DEPLOYED LABELS"), "---"},
|
||||
}
|
||||
|
||||
remoteLabelKeys := make([]string, 0, len(remoteLabels))
|
||||
@ -67,10 +68,10 @@ var AppLabelsCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if len(remoteLabelKeys) == 0 {
|
||||
rows = append(rows, []string{"unknown"})
|
||||
rows = append(rows, []string{i18n.G("unknown")})
|
||||
}
|
||||
|
||||
rows = append(rows, []string{"RECIPE LABELS", "---"})
|
||||
rows = append(rows, []string{i18n.G("RECIPE LABELS"), "---"})
|
||||
|
||||
config, err := app.Recipe.GetComposeConfig(app.Env)
|
||||
if err != nil {
|
||||
@ -98,7 +99,7 @@ var AppLabelsCommand = &cobra.Command{
|
||||
})
|
||||
}
|
||||
|
||||
overview := formatter.CreateOverview("LABELS OVERVIEW", rows)
|
||||
overview := formatter.CreateOverview(i18n.G("LABELS OVERVIEW"), rows)
|
||||
fmt.Println(overview)
|
||||
},
|
||||
}
|
||||
@ -131,9 +132,9 @@ func getLabels(cl *dockerClient.Client, stackName string) (map[string]string, er
|
||||
func init() {
|
||||
AppLabelsCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/tagcmp"
|
||||
"github.com/spf13/cobra"
|
||||
@ -39,20 +40,20 @@ type serverStatus struct {
|
||||
}
|
||||
|
||||
var AppListCommand = &cobra.Command{
|
||||
Use: "list [flags]",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List all managed apps",
|
||||
Long: `Generate a report of all managed apps.
|
||||
Use: i18n.G("list [flags]"),
|
||||
Aliases: []string{i18n.G("ls")},
|
||||
Short: i18n.G("List all managed apps"),
|
||||
Long: i18n.G(`Generate a report of all managed apps.
|
||||
|
||||
Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
Example: ` # list apps of all servers without live status
|
||||
Use "--status/-S" flag to query all servers for the live deployment status.`),
|
||||
Example: i18n.G(` # list apps of all servers without live status
|
||||
abra app ls
|
||||
|
||||
# list apps of a specific server with live status
|
||||
abra app ls -s 1312.net -S
|
||||
|
||||
# list apps of all servers which match a specific recipe
|
||||
abra app ls -r gitea`,
|
||||
abra app ls -r gitea`),
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
appFiles, err := appPkg.LoadAppFiles(listAppServer)
|
||||
@ -107,11 +108,11 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
totalAppsCount++
|
||||
|
||||
if status {
|
||||
status := "unknown"
|
||||
version := "unknown"
|
||||
chaos := "unknown"
|
||||
chaosVersion := "unknown"
|
||||
autoUpdate := "unknown"
|
||||
status := i18n.G("unknown")
|
||||
version := i18n.G("unknown")
|
||||
chaos := i18n.G("unknown")
|
||||
chaosVersion := i18n.G("unknown")
|
||||
autoUpdate := i18n.G("unknown")
|
||||
if statusMeta, ok := statuses[app.StackName()]; ok {
|
||||
if currentVersion, exists := statusMeta["version"]; exists {
|
||||
if currentVersion != "" {
|
||||
@ -144,12 +145,12 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
var newUpdates []string
|
||||
if version != "unknown" && chaos == "false" {
|
||||
if err := app.Recipe.EnsureExists(); err != nil {
|
||||
log.Fatalf("unable to clone %s: %s", app.Name, err)
|
||||
log.Fatal(i18n.G("unable to clone %s: %s", app.Name, err))
|
||||
}
|
||||
|
||||
updates, err := app.Recipe.Tags()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to retrieve tags for %s: %s", app.Name, err)
|
||||
log.Fatal(i18n.G("unable to retrieve tags for %s: %s", app.Name, err))
|
||||
}
|
||||
|
||||
parsedVersion, err := tagcmp.Parse(version)
|
||||
@ -171,9 +172,9 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
|
||||
if len(newUpdates) == 0 {
|
||||
if version == "unknown" {
|
||||
appStats.Upgrade = "unknown"
|
||||
appStats.Upgrade = i18n.G("unknown")
|
||||
} else {
|
||||
appStats.Upgrade = "latest"
|
||||
appStats.Upgrade = i18n.G("latest")
|
||||
stats.LatestCount++
|
||||
}
|
||||
} else {
|
||||
@ -212,14 +213,15 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
|
||||
|
||||
serverStat := allStats[app.Server]
|
||||
|
||||
headers := []string{"RECIPE", "DOMAIN", "SERVER"}
|
||||
headers := []string{i18n.G("RECIPE"), i18n.G("DOMAIN"), i18n.G("SERVER")}
|
||||
if status {
|
||||
headers = append(headers, []string{
|
||||
"STATUS",
|
||||
"CHAOS",
|
||||
"VERSION",
|
||||
"UPGRADE",
|
||||
"AUTOUPDATE"}...,
|
||||
i18n.G("STATUS"),
|
||||
i18n.G("CHAOS"),
|
||||
i18n.G("VERSION"),
|
||||
i18n.G("UPGRADE"),
|
||||
i18n.G("AUTOUPDATE"),
|
||||
}...,
|
||||
)
|
||||
}
|
||||
|
||||
@ -283,22 +285,22 @@ var (
|
||||
func init() {
|
||||
AppListCommand.Flags().BoolVarP(
|
||||
&status,
|
||||
"status",
|
||||
"S",
|
||||
i18n.G("status"),
|
||||
i18n.G("S"),
|
||||
false,
|
||||
"show app deployment status",
|
||||
i18n.G("show app deployment status"),
|
||||
)
|
||||
|
||||
AppListCommand.Flags().StringVarP(
|
||||
&recipeFilter,
|
||||
"recipe",
|
||||
"r",
|
||||
i18n.G("recipe"),
|
||||
i18n.G("r"),
|
||||
"",
|
||||
"show apps of a specific recipe",
|
||||
i18n.G("show apps of a specific recipe"),
|
||||
)
|
||||
|
||||
AppListCommand.RegisterFlagCompletionFunc(
|
||||
"recipe",
|
||||
i18n.G("recipe"),
|
||||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return autocomplete.RecipeNameComplete()
|
||||
},
|
||||
@ -306,22 +308,22 @@ func init() {
|
||||
|
||||
AppListCommand.Flags().BoolVarP(
|
||||
&internal.MachineReadable,
|
||||
"machine",
|
||||
"m",
|
||||
i18n.G("machine"),
|
||||
i18n.G("m"),
|
||||
false,
|
||||
"print machine-readable output",
|
||||
i18n.G("print machine-readable output"),
|
||||
)
|
||||
|
||||
AppListCommand.Flags().StringVarP(
|
||||
&listAppServer,
|
||||
"server",
|
||||
"s",
|
||||
i18n.G("server"),
|
||||
i18n.G("s"),
|
||||
"",
|
||||
"show apps of a specific server",
|
||||
i18n.G("show apps of a specific server"),
|
||||
)
|
||||
|
||||
AppListCommand.RegisterFlagCompletionFunc(
|
||||
"server",
|
||||
i18n.G("server"),
|
||||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return autocomplete.ServerNameComplete()
|
||||
},
|
||||
|
@ -2,12 +2,12 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/logs"
|
||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||
@ -15,9 +15,9 @@ import (
|
||||
)
|
||||
|
||||
var AppLogsCommand = &cobra.Command{
|
||||
Use: "logs <domain> [service] [flags]",
|
||||
Aliases: []string{"l"},
|
||||
Short: "Tail app logs",
|
||||
Use: i18n.G("logs <domain> [service] [flags]"),
|
||||
Aliases: []string{i18n.G("l")},
|
||||
Short: i18n.G("Tail app logs"),
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -29,8 +29,7 @@ var AppLogsCommand = &cobra.Command{
|
||||
case 1:
|
||||
app, err := appPkg.Get(args[0])
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("autocomplete failed: %s", err)
|
||||
return []string{errMsg}, cobra.ShellCompDirectiveError
|
||||
return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
return autocomplete.ServiceNameComplete(app.Name)
|
||||
default:
|
||||
@ -56,7 +55,7 @@ var AppLogsCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if !deployMeta.IsDeployed {
|
||||
log.Fatalf("%s is not deployed?", app.Name)
|
||||
log.Fatal(i18n.G("%s is not deployed?", app.Name))
|
||||
}
|
||||
|
||||
var serviceNames []string
|
||||
@ -91,17 +90,17 @@ var (
|
||||
func init() {
|
||||
AppLogsCommand.Flags().BoolVarP(
|
||||
&stdErr,
|
||||
"stderr",
|
||||
"s",
|
||||
i18n.G("stderr"),
|
||||
i18n.G("s"),
|
||||
false,
|
||||
"only tail stderr",
|
||||
i18n.G("only tail stderr"),
|
||||
)
|
||||
|
||||
AppLogsCommand.Flags().StringVarP(
|
||||
&sinceLogs,
|
||||
"since",
|
||||
"S",
|
||||
i18n.G("since"),
|
||||
i18n.G("S"),
|
||||
"",
|
||||
"tail logs since YYYY-MM-DDTHH:MM:SSZ",
|
||||
i18n.G("tail logs since YYYY-MM-DDTHH:MM:SSZ"),
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
@ -10,6 +11,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
recipePkg "coopcloud.tech/abra/pkg/recipe"
|
||||
"coopcloud.tech/abra/pkg/secret"
|
||||
@ -19,7 +21,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var appNewDescription = `Creates a new app from a default recipe.
|
||||
var appNewDescription = i18n.G(`Creates a new app from a default recipe.
|
||||
|
||||
This new app configuration is stored in your $ABRA_DIR directory under the
|
||||
appropriate server.
|
||||
@ -39,12 +41,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.`
|
||||
on your $PATH.`)
|
||||
|
||||
var AppNewCommand = &cobra.Command{
|
||||
Use: "new [recipe] [version] [flags]",
|
||||
Aliases: []string{"n"},
|
||||
Short: "Create a new app",
|
||||
Use: i18n.G("new [recipe] [version] [flags]"),
|
||||
Aliases: []string{i18n.G("n")},
|
||||
Short: i18n.G("Create a new app"),
|
||||
Long: appNewDescription,
|
||||
Args: cobra.RangeArgs(0, 2),
|
||||
ValidArgsFunction: func(
|
||||
@ -65,7 +67,7 @@ var AppNewCommand = &cobra.Command{
|
||||
recipe := internal.ValidateRecipe(args, cmd.Name())
|
||||
|
||||
if len(args) == 2 && internal.Chaos {
|
||||
log.Fatal("cannot use [version] and --chaos together")
|
||||
log.Fatal(i18n.G("cannot use [version] and --chaos together"))
|
||||
}
|
||||
|
||||
var recipeVersion string
|
||||
@ -113,7 +115,7 @@ var AppNewCommand = &cobra.Command{
|
||||
if recipeVersion == "" {
|
||||
head, err := recipe.Head()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to retrieve latest commit for %s: %s", recipe.Name, err)
|
||||
log.Fatal(i18n.G("failed to retrieve latest commit for %s: %s", recipe.Name, err))
|
||||
}
|
||||
|
||||
recipeVersion = formatter.SmallSHA(head.String())
|
||||
@ -130,7 +132,7 @@ var AppNewCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
sanitisedAppName := appPkg.SanitiseAppName(appDomain)
|
||||
log.Debugf("%s sanitised as %s for new app", appDomain, sanitisedAppName)
|
||||
log.Debug(i18n.G("%s sanitised as %s for new app", appDomain, sanitisedAppName))
|
||||
|
||||
if err := appPkg.TemplateAppEnvSample(
|
||||
recipe,
|
||||
@ -182,7 +184,7 @@ var AppNewCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
headers := []string{"NAME", "VALUE"}
|
||||
headers := []string{i18n.G("NAME"), i18n.G("VALUE")}
|
||||
secretsTable.Headers(headers...)
|
||||
|
||||
for name, val := range appSecrets {
|
||||
@ -194,7 +196,7 @@ var AppNewCommand = &cobra.Command{
|
||||
newAppServer = "local"
|
||||
}
|
||||
|
||||
log.Infof("%s created (version: %s)", appDomain, recipeVersion)
|
||||
log.Info(i18n.G("%s created (version: %s)", appDomain, recipeVersion))
|
||||
|
||||
if len(appSecrets) > 0 {
|
||||
rows := [][]string{}
|
||||
@ -202,15 +204,15 @@ var AppNewCommand = &cobra.Command{
|
||||
rows = append(rows, []string{k, v})
|
||||
}
|
||||
|
||||
overview := formatter.CreateOverview("SECRETS OVERVIEW", rows)
|
||||
overview := formatter.CreateOverview(i18n.G("SECRETS OVERVIEW"), rows)
|
||||
|
||||
fmt.Println(overview)
|
||||
|
||||
log.Warnf(
|
||||
log.Warn(i18n.G(
|
||||
"secrets are %s shown again, please save them %s",
|
||||
formatter.BoldUnderlineStyle.Render("NOT"),
|
||||
formatter.BoldUnderlineStyle.Render("NOW"),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
app, err := app.Get(appDomain)
|
||||
@ -219,7 +221,7 @@ var AppNewCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if err := app.WriteRecipeVersion(recipeVersion, false); err != nil {
|
||||
log.Fatalf("writing recipe version failed: %s", err)
|
||||
log.Fatal(i18n.G("writing recipe version failed: %s", err))
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -231,7 +233,7 @@ type AppSecrets map[string]string
|
||||
func createSecrets(cl *dockerClient.Client, secretsConfig map[string]secret.Secret, sanitisedAppName string) (AppSecrets, error) {
|
||||
// NOTE(d1): trim to match app.StackName() implementation
|
||||
if len(sanitisedAppName) > config.MAX_SANITISED_APP_NAME_LENGTH {
|
||||
log.Debugf("trimming %s to %s to avoid runtime limits", sanitisedAppName, sanitisedAppName[:config.MAX_SANITISED_APP_NAME_LENGTH])
|
||||
log.Debug(i18n.G("trimming %s to %s to avoid runtime limits", sanitisedAppName, sanitisedAppName[:config.MAX_SANITISED_APP_NAME_LENGTH]))
|
||||
sanitisedAppName = sanitisedAppName[:config.MAX_SANITISED_APP_NAME_LENGTH]
|
||||
}
|
||||
|
||||
@ -261,7 +263,7 @@ func createSecrets(cl *dockerClient.Client, secretsConfig map[string]secret.Secr
|
||||
func ensureDomainFlag(recipe recipePkg.Recipe, server string) error {
|
||||
if appDomain == "" && !internal.NoInput {
|
||||
prompt := &survey.Input{
|
||||
Message: "Specify app domain",
|
||||
Message: i18n.G("Specify app domain"),
|
||||
Default: fmt.Sprintf("%s.%s", recipe.Name, server),
|
||||
}
|
||||
if err := survey.AskOne(prompt, &appDomain); err != nil {
|
||||
@ -270,7 +272,7 @@ func ensureDomainFlag(recipe recipePkg.Recipe, server string) error {
|
||||
}
|
||||
|
||||
if appDomain == "" {
|
||||
return fmt.Errorf("no domain provided")
|
||||
return errors.New(i18n.G("no domain provided"))
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -279,13 +281,13 @@ func ensureDomainFlag(recipe recipePkg.Recipe, server string) error {
|
||||
// promptForSecrets asks if we should generate secrets for a new app.
|
||||
func promptForSecrets(recipeName string, secretsConfig map[string]secret.Secret) error {
|
||||
if len(secretsConfig) == 0 {
|
||||
log.Debugf("%s has no secrets to generate, skipping...", recipeName)
|
||||
log.Debug(i18n.G("%s has no secrets to generate, skipping...", recipeName))
|
||||
return nil
|
||||
}
|
||||
|
||||
if !generateSecrets && !internal.NoInput {
|
||||
prompt := &survey.Confirm{
|
||||
Message: "Generate app secrets?",
|
||||
Message: i18n.G("Generate app secrets?"),
|
||||
}
|
||||
if err := survey.AskOne(prompt, &generateSecrets); err != nil {
|
||||
return err
|
||||
@ -304,13 +306,13 @@ func ensureServerFlag() error {
|
||||
|
||||
if len(servers) == 1 {
|
||||
newAppServer = servers[0]
|
||||
log.Infof("single server detected, choosing %s automatically", newAppServer)
|
||||
log.Info(i18n.G("single server detected, choosing %s automatically", newAppServer))
|
||||
return nil
|
||||
}
|
||||
|
||||
if newAppServer == "" && !internal.NoInput {
|
||||
prompt := &survey.Select{
|
||||
Message: "Select app server:",
|
||||
Message: i18n.G("Select app server:"),
|
||||
Options: servers,
|
||||
}
|
||||
if err := survey.AskOne(prompt, &newAppServer); err != nil {
|
||||
@ -319,7 +321,7 @@ func ensureServerFlag() error {
|
||||
}
|
||||
|
||||
if newAppServer == "" {
|
||||
return fmt.Errorf("no server provided")
|
||||
return errors.New(i18n.G("no server provided"))
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -335,14 +337,14 @@ var (
|
||||
func init() {
|
||||
AppNewCommand.Flags().StringVarP(
|
||||
&newAppServer,
|
||||
"server",
|
||||
"s",
|
||||
i18n.G("server"),
|
||||
i18n.G("s"),
|
||||
"",
|
||||
"specify server for new app",
|
||||
i18n.G("specify server for new app"),
|
||||
)
|
||||
|
||||
AppNewCommand.RegisterFlagCompletionFunc(
|
||||
"server",
|
||||
i18n.G("server"),
|
||||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
return autocomplete.ServerNameComplete()
|
||||
},
|
||||
@ -350,34 +352,34 @@ func init() {
|
||||
|
||||
AppNewCommand.Flags().StringVarP(
|
||||
&appDomain,
|
||||
"domain",
|
||||
"D",
|
||||
i18n.G("domain"),
|
||||
i18n.G("D"),
|
||||
"",
|
||||
"domain name for app",
|
||||
i18n.G("domain name for app"),
|
||||
)
|
||||
|
||||
AppNewCommand.Flags().BoolVarP(
|
||||
&saveInPass,
|
||||
"pass",
|
||||
"p",
|
||||
i18n.G("pass"),
|
||||
i18n.G("p"),
|
||||
false,
|
||||
"store secrets in a local pass store",
|
||||
i18n.G("store secrets in a local pass store"),
|
||||
)
|
||||
|
||||
AppNewCommand.Flags().BoolVarP(
|
||||
&generateSecrets,
|
||||
"secrets",
|
||||
"S",
|
||||
i18n.G("secrets"),
|
||||
i18n.G("S"),
|
||||
false,
|
||||
"automatically generate secrets",
|
||||
i18n.G("automatically generate secrets"),
|
||||
)
|
||||
|
||||
AppNewCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
abraService "coopcloud.tech/abra/pkg/service"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
@ -24,9 +25,9 @@ import (
|
||||
)
|
||||
|
||||
var AppPsCommand = &cobra.Command{
|
||||
Use: "ps <domain> [flags]",
|
||||
Aliases: []string{"p"},
|
||||
Short: "Check app deployment status",
|
||||
Use: i18n.G("ps <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("p")},
|
||||
Short: i18n.G("Check app deployment status"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -52,7 +53,7 @@ var AppPsCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if !deployMeta.IsDeployed {
|
||||
log.Fatalf("%s is not deployed?", app.Name)
|
||||
log.Fatal(i18n.G("%s is not deployed?", app.Name))
|
||||
}
|
||||
|
||||
chaosVersion := config.CHAOS_DEFAULT
|
||||
@ -115,11 +116,11 @@ func showPSOutput(app appPkg.App, cl *dockerClient.Client, deployedVersion, chao
|
||||
"version": deployedVersion,
|
||||
"chaos": chaosVersion,
|
||||
"service": service.Name,
|
||||
"image": "unknown",
|
||||
"created": "unknown",
|
||||
"status": "unknown",
|
||||
"state": "unknown",
|
||||
"ports": "unknown",
|
||||
"image": i18n.G("unknown"),
|
||||
"created": i18n.G("unknown"),
|
||||
"status": i18n.G("unknown"),
|
||||
"state": i18n.G("unknown"),
|
||||
"ports": i18n.G("unknown"),
|
||||
}
|
||||
} else {
|
||||
container := containers[0]
|
||||
@ -161,7 +162,7 @@ func showPSOutput(app appPkg.App, cl *dockerClient.Client, deployedVersion, chao
|
||||
if internal.MachineReadable {
|
||||
rendered, err := json.Marshal(allContainerStats)
|
||||
if err != nil {
|
||||
log.Fatal("unable to convert to JSON: %s", err)
|
||||
log.Fatal(i18n.G("unable to convert to JSON: %s", err))
|
||||
}
|
||||
|
||||
fmt.Println(string(rendered))
|
||||
@ -175,11 +176,11 @@ func showPSOutput(app appPkg.App, cl *dockerClient.Client, deployedVersion, chao
|
||||
}
|
||||
|
||||
headers := []string{
|
||||
"SERVICE",
|
||||
"STATUS",
|
||||
"IMAGE",
|
||||
"VERSION",
|
||||
"CHAOS",
|
||||
i18n.G("SERVICE"),
|
||||
i18n.G("STATUS"),
|
||||
i18n.G("IMAGE"),
|
||||
i18n.G("VERSION"),
|
||||
i18n.G("CHAOS"),
|
||||
}
|
||||
|
||||
table.
|
||||
@ -194,17 +195,17 @@ func showPSOutput(app appPkg.App, cl *dockerClient.Client, deployedVersion, chao
|
||||
func init() {
|
||||
AppPsCommand.Flags().BoolVarP(
|
||||
&internal.MachineReadable,
|
||||
"machine",
|
||||
"m",
|
||||
i18n.G("machine"),
|
||||
i18n.G("m"),
|
||||
false,
|
||||
"print machine-readable output",
|
||||
i18n.G("print machine-readable output"),
|
||||
)
|
||||
|
||||
AppPsCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
@ -16,10 +16,10 @@ import (
|
||||
)
|
||||
|
||||
var AppRemoveCommand = &cobra.Command{
|
||||
Use: "remove <domain> [flags]",
|
||||
Aliases: []string{"rm"},
|
||||
Short: "Remove all app data, locally and remotely",
|
||||
Long: `Remove everything related to an app which is already undeployed.
|
||||
Use: i18n.G("remove <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("rm")},
|
||||
Short: i18n.G("Remove all app data, locally and remotely"),
|
||||
Long: i18n.G(`Remove everything related to an app which is already undeployed.
|
||||
|
||||
By default, it will prompt for confirmation before proceeding. All secrets,
|
||||
volumes and the local app env file will be deleted.
|
||||
@ -34,8 +34,8 @@ Please note, if you delete the local app env file without removing volumes and
|
||||
secrets first, Abra will *not* be able to help you remove them afterwards.
|
||||
|
||||
To delete everything without prompt, use the "--force/-f" or the "--no-input/n"
|
||||
flag.`,
|
||||
Example: " abra app remove 1312.net",
|
||||
flag.`),
|
||||
Example: i18n.G(" abra app remove 1312.net"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -47,16 +47,16 @@ flag.`,
|
||||
app := internal.ValidateApp(args)
|
||||
|
||||
if !internal.Force && !internal.NoInput {
|
||||
log.Warnf("ALERTA ALERTA: deleting %s data and config (local/remote)", app.Name)
|
||||
log.Warn(i18n.G("ALERTA ALERTA: deleting %s data and config (local/remote)", app.Name))
|
||||
|
||||
response := false
|
||||
prompt := &survey.Confirm{Message: "are you sure?"}
|
||||
prompt := &survey.Confirm{Message: i18n.G("are you sure?")}
|
||||
if err := survey.AskOne(prompt, &response); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if !response {
|
||||
log.Fatal("aborting as requested")
|
||||
log.Fatal(i18n.G("aborting as requested"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ flag.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
if deployMeta.IsDeployed {
|
||||
log.Fatalf("%s is still deployed. Run \"abra app undeploy %s\"", app.Name, app.Name)
|
||||
log.Fatal(i18n.G("%s is still deployed. Run \"abra app undeploy %s\"", app.Name, app.Name))
|
||||
}
|
||||
|
||||
fs, err := app.Filters(false, false)
|
||||
@ -86,12 +86,12 @@ flag.`,
|
||||
|
||||
if len(configNames) > 0 {
|
||||
if err := client.RemoveConfigs(cl, context.Background(), configNames, internal.Force); err != nil {
|
||||
log.Fatalf("removing configs failed: %s", err)
|
||||
log.Fatal(i18n.G("removing configs failed: %s", err))
|
||||
}
|
||||
|
||||
log.Infof("%d config(s) removed successfully", len(configNames))
|
||||
log.Info(i18n.G("%d config(s) removed successfully", len(configNames)))
|
||||
} else {
|
||||
log.Info("no configs to remove")
|
||||
log.Info(i18n.G("no configs to remove"))
|
||||
}
|
||||
|
||||
secretList, err := cl.SecretList(context.Background(), types.SecretListOptions{Filters: fs})
|
||||
@ -113,10 +113,10 @@ flag.`,
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Info(fmt.Sprintf("secret: %s removed", name))
|
||||
log.Info(i18n.G("secret: %s removed", name))
|
||||
}
|
||||
} else {
|
||||
log.Info("no secrets to remove")
|
||||
log.Info(i18n.G("no secrets to remove"))
|
||||
}
|
||||
|
||||
fs, err = app.Filters(false, true)
|
||||
@ -133,28 +133,28 @@ flag.`,
|
||||
if len(volumeNames) > 0 {
|
||||
err := client.RemoveVolumes(cl, context.Background(), volumeNames, internal.Force, 5)
|
||||
if err != nil {
|
||||
log.Fatalf("removing volumes failed: %s", err)
|
||||
log.Fatal(i18n.G("removing volumes failed: %s", err))
|
||||
}
|
||||
|
||||
log.Infof("%d volume(s) removed successfully", len(volumeNames))
|
||||
log.Info(i18n.G("%d volume(s) removed successfully", len(volumeNames)))
|
||||
} else {
|
||||
log.Info("no volumes to remove")
|
||||
log.Info(i18n.G("no volumes to remove"))
|
||||
}
|
||||
|
||||
if err = os.Remove(app.Path); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Info(fmt.Sprintf("file: %s removed", app.Path))
|
||||
log.Info(i18n.G("file: %s removed", app.Path))
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AppRemoveCommand.Flags().BoolVarP(
|
||||
&internal.Force,
|
||||
"force",
|
||||
"f",
|
||||
i18n.G("force"),
|
||||
i18n.G("f"),
|
||||
false,
|
||||
"perform action without further prompt",
|
||||
i18n.G("perform action without further prompt"),
|
||||
)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/ui"
|
||||
upstream "coopcloud.tech/abra/pkg/upstream/service"
|
||||
@ -17,19 +18,19 @@ import (
|
||||
)
|
||||
|
||||
var AppRestartCommand = &cobra.Command{
|
||||
Use: "restart <domain> [[service] | --all-services] [flags]",
|
||||
Aliases: []string{"re"},
|
||||
Short: "Restart an app",
|
||||
Long: `This command restarts services within a deployed app.
|
||||
Use: i18n.G("restart <domain> [[service] | --all-services] [flags]"),
|
||||
Aliases: []string{i18n.G("re")},
|
||||
Short: i18n.G("Restart an app"),
|
||||
Long: i18n.G(`This command restarts services within a deployed app.
|
||||
|
||||
Run "abra app ps <domain>" to see a list of service names.
|
||||
|
||||
Pass "--all-services/-a" to restart all services.`,
|
||||
Example: ` # restart a single app service
|
||||
Pass "--all-services/-a" to restart all services.`),
|
||||
Example: i18n.G(` # restart a single app service
|
||||
abra app restart 1312.net app
|
||||
|
||||
# restart all app services
|
||||
abra app restart 1312.net -a`,
|
||||
abra app restart 1312.net -a`),
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -60,11 +61,11 @@ Pass "--all-services/-a" to restart all services.`,
|
||||
}
|
||||
|
||||
if serviceName == "" && !allServices {
|
||||
log.Fatal("missing [service]")
|
||||
log.Fatal(i18n.G("missing [service]"))
|
||||
}
|
||||
|
||||
if serviceName != "" && allServices {
|
||||
log.Fatal("cannot use [service] and --all-services/-a together")
|
||||
log.Fatal(i18n.G("cannot use [service] and --all-services/-a together"))
|
||||
}
|
||||
|
||||
var serviceNames []string
|
||||
@ -89,7 +90,7 @@ Pass "--all-services/-a" to restart all services.`,
|
||||
}
|
||||
|
||||
if !deployMeta.IsDeployed {
|
||||
log.Fatalf("%s is not deployed?", app.Name)
|
||||
log.Fatal(i18n.G("%s is not deployed?", app.Name))
|
||||
}
|
||||
|
||||
for _, serviceName := range serviceNames {
|
||||
@ -104,7 +105,7 @@ Pass "--all-services/-a" to restart all services.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("attempting to scale %s to 0", stackServiceName)
|
||||
log.Debug(i18n.G("attempting to scale %s to 0", stackServiceName))
|
||||
|
||||
if err := upstream.RunServiceScale(context.Background(), cl, stackServiceName, 0); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -128,8 +129,8 @@ Pass "--all-services/-a" to restart all services.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("%s has been scaled to 0", stackServiceName)
|
||||
log.Debugf("attempting to scale %s to 1", stackServiceName)
|
||||
log.Debug(i18n.G("%s has been scaled to 0", stackServiceName))
|
||||
log.Debug(i18n.G("attempting to scale %s to 1", stackServiceName))
|
||||
|
||||
if err := upstream.RunServiceScale(context.Background(), cl, stackServiceName, 1); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -139,8 +140,8 @@ Pass "--all-services/-a" to restart all services.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("%s has been scaled to 1", stackServiceName)
|
||||
log.Infof("%s service successfully restarted", serviceName)
|
||||
log.Debug(i18n.G("%s has been scaled to 1", stackServiceName))
|
||||
log.Info(i18n.G("%s service successfully restarted", serviceName))
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -150,16 +151,16 @@ var allServices bool
|
||||
func init() {
|
||||
AppRestartCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
AppRestartCommand.Flags().BoolVarP(
|
||||
&allServices,
|
||||
"all-services",
|
||||
"a",
|
||||
i18n.G("all-services"),
|
||||
i18n.G("a"),
|
||||
false,
|
||||
"restart all services",
|
||||
i18n.G("restart all services"),
|
||||
)
|
||||
}
|
||||
|
@ -7,17 +7,18 @@ import (
|
||||
"coopcloud.tech/abra/cli/internal"
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var AppRestoreCommand = &cobra.Command{
|
||||
Use: "restore <domain> [flags]",
|
||||
Aliases: []string{"rs"},
|
||||
Short: "Restore a snapshot",
|
||||
Long: `Snapshots are restored while apps are deployed.
|
||||
Use: i18n.G("restore <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("rs")},
|
||||
Short: i18n.G("Restore a snapshot"),
|
||||
Long: i18n.G(`Snapshots are restored while apps are deployed.
|
||||
|
||||
Some restore scenarios may require service / app restarts.`,
|
||||
Some restore scenarios may require service / app restarts.`),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -48,34 +49,34 @@ Some restore scenarios may require service / app restarts.`,
|
||||
}
|
||||
|
||||
if snapshot != "" {
|
||||
log.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
|
||||
log.Debug(i18n.G("including SNAPSHOT=%s in backupbot exec invocation", snapshot))
|
||||
execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
|
||||
}
|
||||
|
||||
if targetPath != "" {
|
||||
log.Debugf("including TARGET=%s in backupbot exec invocation", targetPath)
|
||||
log.Debug(i18n.G("including TARGET=%s in backupbot exec invocation", targetPath))
|
||||
execEnv = append(execEnv, fmt.Sprintf("TARGET=%s", targetPath))
|
||||
}
|
||||
|
||||
if internal.NoInput {
|
||||
log.Debugf("including NONINTERACTIVE=%v in backupbot exec invocation", internal.NoInput)
|
||||
log.Debug(i18n.G("including NONINTERACTIVE=%v in backupbot exec invocation", internal.NoInput))
|
||||
execEnv = append(execEnv, fmt.Sprintf("NONINTERACTIVE=%v", internal.NoInput))
|
||||
}
|
||||
|
||||
if len(volumes) > 0 {
|
||||
allVolumes := strings.Join(volumes, ",")
|
||||
log.Debugf("including VOLUMES=%s in backupbot exec invocation", allVolumes)
|
||||
log.Debug(i18n.G("including VOLUMES=%s in backupbot exec invocation", allVolumes))
|
||||
execEnv = append(execEnv, fmt.Sprintf("VOLUMES=%s", allVolumes))
|
||||
}
|
||||
|
||||
if len(services) > 0 {
|
||||
allServices := strings.Join(services, ",")
|
||||
log.Debugf("including CONTAINER=%s in backupbot exec invocation", allServices)
|
||||
log.Debug(i18n.G("including CONTAINER=%s in backupbot exec invocation", allServices))
|
||||
execEnv = append(execEnv, fmt.Sprintf("CONTAINER=%s", allServices))
|
||||
}
|
||||
|
||||
if hooks {
|
||||
log.Debugf("including NO_COMMANDS=%v in backupbot exec invocation", false)
|
||||
log.Debug(i18n.G("including NO_COMMANDS=%v in backupbot exec invocation", false))
|
||||
execEnv = append(execEnv, fmt.Sprintf("NO_COMMANDS=%v", false))
|
||||
}
|
||||
|
||||
@ -95,41 +96,41 @@ var (
|
||||
func init() {
|
||||
AppRestoreCommand.Flags().StringVarP(
|
||||
&targetPath,
|
||||
"target",
|
||||
"t",
|
||||
i18n.G("target"),
|
||||
i18n.G("t"),
|
||||
"/",
|
||||
"target path",
|
||||
i18n.G("target path"),
|
||||
)
|
||||
|
||||
AppRestoreCommand.Flags().StringArrayVarP(
|
||||
&services,
|
||||
"services",
|
||||
"s",
|
||||
i18n.G("services"),
|
||||
i18n.G("s"),
|
||||
[]string{},
|
||||
"restore specific services",
|
||||
i18n.G("restore specific services"),
|
||||
)
|
||||
|
||||
AppRestoreCommand.Flags().StringArrayVarP(
|
||||
&volumes,
|
||||
"volumes",
|
||||
"v",
|
||||
i18n.G("volumes"),
|
||||
i18n.G("v"),
|
||||
[]string{},
|
||||
"restore specific volumes",
|
||||
i18n.G("restore specific volumes"),
|
||||
)
|
||||
|
||||
AppRestoreCommand.Flags().BoolVarP(
|
||||
&hooks,
|
||||
"hooks",
|
||||
"H",
|
||||
i18n.G("hooks"),
|
||||
i18n.G("H"),
|
||||
false,
|
||||
"enable pre/post-hook command execution",
|
||||
i18n.G("enable pre/post-hook command execution"),
|
||||
)
|
||||
|
||||
AppRestoreCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"errors"
|
||||
|
||||
"coopcloud.tech/abra/pkg/app"
|
||||
appPkg "coopcloud.tech/abra/pkg/app"
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/envfile"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/lint"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"coopcloud.tech/tagcmp"
|
||||
@ -21,10 +22,10 @@ import (
|
||||
)
|
||||
|
||||
var AppRollbackCommand = &cobra.Command{
|
||||
Use: "rollback <domain> [version] [flags]",
|
||||
Aliases: []string{"rl"},
|
||||
Short: "Roll an app back to a previous version",
|
||||
Long: `This command rolls an app back to a previous version.
|
||||
Use: i18n.G("rollback <domain> [version] [flags]"),
|
||||
Aliases: []string{i18n.G("rl")},
|
||||
Short: i18n.G("Roll an app back to a previous version"),
|
||||
Long: i18n.G(`This command rolls an app back to a previous version.
|
||||
|
||||
Unlike "abra app deploy", chaos operations are not supported here. Only recipe
|
||||
versions are supported values for "[version]".
|
||||
@ -37,12 +38,12 @@ are available. The live deployment version is the "source of truth" in this
|
||||
case. The stored .env version is not consulted.
|
||||
|
||||
A downgrade can be destructive, please ensure you have a copy of your app data
|
||||
beforehand. See "abra app backup" for more.`,
|
||||
Example: ` # standard rollback
|
||||
beforehand. See "abra app backup" for more.`),
|
||||
Example: i18n.G(` # standard rollback
|
||||
abra app rollback 1312.net
|
||||
|
||||
# rollback to specific version
|
||||
abra app rollback 1312.net 2.0.0+1.2.3`,
|
||||
abra app rollback 1312.net 2.0.0+1.2.3`),
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -54,8 +55,7 @@ beforehand. See "abra app backup" for more.`,
|
||||
case 1:
|
||||
app, err := appPkg.Get(args[0])
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("autocomplete failed: %s", err)
|
||||
return []string{errMsg}, cobra.ShellCompDirectiveError
|
||||
return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
return autocomplete.RecipeVersionComplete(app.Recipe.Name)
|
||||
default:
|
||||
@ -117,7 +117,7 @@ beforehand. See "abra app backup" for more.`,
|
||||
}
|
||||
|
||||
if !downgradeAvailable {
|
||||
log.Info("no available downgrades")
|
||||
log.Info(i18n.G("no available downgrades"))
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -139,10 +139,10 @@ beforehand. See "abra app backup" for more.`,
|
||||
}
|
||||
|
||||
if chosenDowngrade == "" {
|
||||
log.Fatal("unknown deployed version, unable to downgrade")
|
||||
log.Fatal(i18n.G("unknown deployed version, unable to downgrade"))
|
||||
}
|
||||
|
||||
log.Debugf("choosing %s as version to rollback", chosenDowngrade)
|
||||
log.Debug(i18n.G("choosing %s as version to rollback", chosenDowngrade))
|
||||
|
||||
if _, err := app.Recipe.EnsureVersion(chosenDowngrade); err != nil {
|
||||
log.Fatal(err)
|
||||
@ -199,7 +199,7 @@ beforehand. See "abra app backup" for more.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("set waiting timeout to %d second(s)", stack.WaitTimeout)
|
||||
log.Debug(i18n.G("set waiting timeout to %d second(s)", stack.WaitTimeout))
|
||||
|
||||
serviceNames, err := appPkg.GetAppServiceNames(app.Name)
|
||||
if err != nil {
|
||||
@ -224,7 +224,7 @@ beforehand. See "abra app backup" for more.`,
|
||||
}
|
||||
|
||||
if err := app.WriteRecipeVersion(chosenDowngrade, false); err != nil {
|
||||
log.Fatalf("writing recipe version failed: %s", err)
|
||||
log.Fatal(i18n.G("writing recipe version failed: %s", err))
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -235,12 +235,12 @@ func chooseDowngrade(
|
||||
deployMeta stack.DeployMeta,
|
||||
chosenDowngrade *string,
|
||||
) error {
|
||||
msg := fmt.Sprintf("please select a downgrade (version: %s):", deployMeta.Version)
|
||||
msg := i18n.G("please select a downgrade (version: %s):", deployMeta.Version)
|
||||
|
||||
if deployMeta.IsChaos {
|
||||
chaosVersion := formatter.BoldDirtyDefault(deployMeta.ChaosVersion)
|
||||
|
||||
msg = fmt.Sprintf(
|
||||
msg = i18n.G(
|
||||
"please select a downgrade (version: %s, chaos: %s):",
|
||||
deployMeta.Version,
|
||||
chaosVersion,
|
||||
@ -267,21 +267,21 @@ func validateDowngradeVersionArg(
|
||||
) error {
|
||||
parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("current deployment '%s' is not a known version for %s", deployMeta.Version, app.Recipe.Name)
|
||||
return errors.New(i18n.G("current deployment '%s' is not a known version for %s", deployMeta.Version, app.Recipe.Name))
|
||||
}
|
||||
|
||||
parsedSpecificVersion, err := tagcmp.Parse(specificVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("'%s' is not a known version for %s", specificVersion, app.Recipe.Name)
|
||||
return errors.New(i18n.G("'%s' is not a known version for %s", specificVersion, app.Recipe.Name))
|
||||
}
|
||||
|
||||
if parsedSpecificVersion.IsGreaterThan(parsedDeployedVersion) &&
|
||||
!parsedSpecificVersion.Equals(parsedDeployedVersion) {
|
||||
return fmt.Errorf("%s is not a downgrade for %s?", deployMeta.Version, specificVersion)
|
||||
return errors.New(i18n.G("%s is not a downgrade for %s?", deployMeta.Version, specificVersion))
|
||||
}
|
||||
|
||||
if parsedSpecificVersion.Equals(parsedDeployedVersion) && !internal.Force {
|
||||
return fmt.Errorf("%s is not a downgrade for %s?", deployMeta.Version, specificVersion)
|
||||
return errors.New(i18n.G("%s is not a downgrade for %s?", deployMeta.Version, specificVersion))
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -320,24 +320,25 @@ func ensureDowngradesAvailable(
|
||||
func init() {
|
||||
AppRollbackCommand.Flags().BoolVarP(
|
||||
&internal.Force,
|
||||
"force",
|
||||
"f",
|
||||
i18n.G("force"),
|
||||
i18n.G("f"),
|
||||
false,
|
||||
"perform action without further prompt",
|
||||
i18n.G("perform action without further prompt"),
|
||||
)
|
||||
|
||||
AppRollbackCommand.Flags().BoolVarP(
|
||||
&internal.NoDomainChecks,
|
||||
"no-domain-checks",
|
||||
"D",
|
||||
i18n.G("no-domain-checks"),
|
||||
i18n.G("D"),
|
||||
false,
|
||||
"disable public DNS checks",
|
||||
i18n.G("disable public DNS checks"),
|
||||
)
|
||||
|
||||
AppRollbackCommand.Flags().BoolVarP(
|
||||
&internal.DontWaitConverge, "no-converge-checks",
|
||||
"c",
|
||||
&internal.DontWaitConverge,
|
||||
i18n.G("no-converge-checks"),
|
||||
i18n.G("c"),
|
||||
false,
|
||||
"disable converge logic checks",
|
||||
i18n.G("disable converge logic checks"),
|
||||
)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
containerPkg "coopcloud.tech/abra/pkg/container"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/container"
|
||||
"github.com/docker/cli/cli/command"
|
||||
@ -17,17 +18,17 @@ import (
|
||||
)
|
||||
|
||||
var AppRunCommand = &cobra.Command{
|
||||
Use: "run <domain> <service> <cmd> [[args] [flags] | [flags] -- [args]]",
|
||||
Aliases: []string{"r"},
|
||||
Short: "Run a command inside a service container",
|
||||
Example: ` # run <cmd> with args/flags
|
||||
Use: i18n.G("run <domain> <service> <cmd> [[args] [flags] | [flags] -- [args]]"),
|
||||
Aliases: []string{i18n.G("r")},
|
||||
Short: i18n.G("Run a command inside a service container"),
|
||||
Example: i18n.G(` # run <cmd> with args/flags
|
||||
abra app run 1312.net app -- ls -lha
|
||||
|
||||
# run <cmd> without args/flags
|
||||
abra app run 1312.net app bash --user nobody
|
||||
|
||||
# run <cmd> with both kinds of args/flags
|
||||
abra app run 1312.net app --user nobody -- ls -lha`,
|
||||
abra app run 1312.net app --user nobody -- ls -lha`),
|
||||
Args: cobra.MinimumNArgs(3),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -98,17 +99,17 @@ var (
|
||||
|
||||
func init() {
|
||||
AppRunCommand.Flags().BoolVarP(&noTTY,
|
||||
"no-tty",
|
||||
"t",
|
||||
i18n.G("no-tty"),
|
||||
i18n.G("t"),
|
||||
false,
|
||||
"do not request a TTY",
|
||||
i18n.G("do not request a TTY"),
|
||||
)
|
||||
|
||||
AppRunCommand.Flags().StringVarP(
|
||||
&runAsUser,
|
||||
"user",
|
||||
"u",
|
||||
i18n.G("user"),
|
||||
i18n.G("u"),
|
||||
"",
|
||||
"run command as user",
|
||||
i18n.G("run command as user"),
|
||||
)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/secret"
|
||||
"github.com/docker/docker/api/types"
|
||||
@ -20,9 +21,9 @@ import (
|
||||
)
|
||||
|
||||
var AppSecretGenerateCommand = &cobra.Command{
|
||||
Use: "generate <domain> [[secret] [version] | --all] [flags]",
|
||||
Aliases: []string{"g"},
|
||||
Short: "Generate secrets",
|
||||
Use: i18n.G("generate <domain> [[secret] [version] | --all] [flags]"),
|
||||
Aliases: []string{i18n.G("g")},
|
||||
Short: i18n.G("Generate secrets"),
|
||||
Args: cobra.RangeArgs(1, 3),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -34,8 +35,7 @@ var AppSecretGenerateCommand = &cobra.Command{
|
||||
case 1:
|
||||
app, err := appPkg.Get(args[0])
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("autocomplete failed: %s", err)
|
||||
return []string{errMsg}, cobra.ShellCompDirectiveError
|
||||
return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
return autocomplete.SecretComplete(app.Recipe.Name)
|
||||
default:
|
||||
@ -50,11 +50,11 @@ var AppSecretGenerateCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if len(args) <= 2 && !generateAllSecrets {
|
||||
log.Fatal("missing arguments [secret]/[version] or '--all'")
|
||||
log.Fatal(i18n.G("missing arguments [secret]/[version] or '--all'"))
|
||||
}
|
||||
|
||||
if len(args) > 2 && generateAllSecrets {
|
||||
log.Fatal("cannot use '[secret] [version]' and '--all' together")
|
||||
log.Fatal(i18n.G("cannot use '[secret] [version]' and '--all' together"))
|
||||
}
|
||||
|
||||
composeFiles, err := app.Recipe.GetComposeFiles(app.Env)
|
||||
@ -72,7 +72,7 @@ var AppSecretGenerateCommand = &cobra.Command{
|
||||
secretVersion := args[2]
|
||||
s, ok := secrets[secretName]
|
||||
if !ok {
|
||||
log.Fatalf("%s doesn't exist in the env config?", secretName)
|
||||
log.Fatal(i18n.G("%s doesn't exist in the env config?", secretName))
|
||||
}
|
||||
s.Version = secretVersion
|
||||
secrets = map[string]secret.Secret{
|
||||
@ -99,11 +99,11 @@ var AppSecretGenerateCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if len(secretVals) == 0 {
|
||||
log.Warn("no secrets generated")
|
||||
log.Warn(i18n.G("no secrets generated"))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
headers := []string{"NAME", "VALUE"}
|
||||
headers := []string{i18n.G("NAME"), i18n.G("VALUE")}
|
||||
table, err := formatter.CreateTable()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -121,7 +121,7 @@ var AppSecretGenerateCommand = &cobra.Command{
|
||||
if internal.MachineReadable {
|
||||
out, err := formatter.ToJSON(headers, rows)
|
||||
if err != nil {
|
||||
log.Fatal("unable to render to JSON: %s", err)
|
||||
log.Fatal(i18n.G("unable to render to JSON: %s", err))
|
||||
}
|
||||
fmt.Println(out)
|
||||
return
|
||||
@ -131,31 +131,31 @@ var AppSecretGenerateCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Warnf(
|
||||
log.Warn(i18n.G(
|
||||
"generated secrets %s shown again, please take note of them %s",
|
||||
formatter.BoldStyle.Render("NOT"),
|
||||
formatter.BoldStyle.Render("NOW"),
|
||||
)
|
||||
formatter.BoldStyle.Render(i18n.G("NOT")),
|
||||
formatter.BoldStyle.Render(i18n.G("NOW")),
|
||||
))
|
||||
},
|
||||
}
|
||||
|
||||
var AppSecretInsertCommand = &cobra.Command{
|
||||
Use: "insert <domain> <secret> <version> <data> [flags]",
|
||||
Aliases: []string{"i"},
|
||||
Short: "Insert secret",
|
||||
Long: `This command inserts a secret into an app environment.
|
||||
Use: i18n.G("insert <domain> <secret> <version> <data> [flags]"),
|
||||
Aliases: []string{i18n.G("i")},
|
||||
Short: i18n.G("Insert secret"),
|
||||
Long: i18n.G(`This command inserts a secret into an app environment.
|
||||
|
||||
Arbitrary secret insertion is not supported. Secrets that are inserted must
|
||||
match those configured in the recipe beforehand.
|
||||
|
||||
This can be useful when you want to manually generate secrets for an app
|
||||
environment. Typically, you can let Abra generate them for you on app creation
|
||||
(see "abra app new --secrets/-S" for more).`,
|
||||
Example: ` # insert regular secret
|
||||
(see "abra app new --secrets/-S" for more).`),
|
||||
Example: i18n.G(` # insert regular secret
|
||||
abra app secret insert 1312.net my_secret v1 mySuperSecret
|
||||
|
||||
# insert secret as file
|
||||
abra app secret insert 1312.net my_secret v1 secret.txt -f`,
|
||||
abra app secret insert 1312.net my_secret v1 secret.txt -f`),
|
||||
Args: cobra.MinimumNArgs(4),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -167,8 +167,7 @@ environment. Typically, you can let Abra generate them for you on app creation
|
||||
case 1:
|
||||
app, err := appPkg.Get(args[0])
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("autocomplete failed: %s", err)
|
||||
return []string{errMsg}, cobra.ShellCompDirectiveError
|
||||
return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
return autocomplete.SecretComplete(app.Recipe.Name)
|
||||
default:
|
||||
@ -208,13 +207,13 @@ environment. Typically, you can let Abra generate them for you on app creation
|
||||
}
|
||||
}
|
||||
if !isRecipeSecret {
|
||||
log.Fatalf("no secret %s available for recipe %s?", name, app.Recipe.Name)
|
||||
log.Fatal(i18n.G("no secret %s available for recipe %s?", name, app.Recipe.Name))
|
||||
}
|
||||
|
||||
if insertFromFile {
|
||||
raw, err := os.ReadFile(data)
|
||||
if err != nil {
|
||||
log.Fatalf("reading secret from file: %s", err)
|
||||
log.Fatal(i18n.G("reading secret from file: %s", err))
|
||||
}
|
||||
data = string(raw)
|
||||
}
|
||||
@ -228,7 +227,7 @@ environment. Typically, you can let Abra generate them for you on app creation
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Infof("%s successfully stored on server", secretName)
|
||||
log.Info(i18n.G("%s successfully stored on server", secretName))
|
||||
|
||||
if storeInPass {
|
||||
if err := secret.PassInsertSecret(data, name, app.Name, app.Server); err != nil {
|
||||
@ -244,28 +243,28 @@ func secretRm(cl *dockerClient.Client, app appPkg.App, secretName, parsed string
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("deleted %s successfully from server", secretName)
|
||||
log.Info(i18n.G("deleted %s successfully from server", secretName))
|
||||
|
||||
if removeFromPass {
|
||||
if err := secret.PassRmSecret(parsed, app.StackName(), app.Server); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("deleted %s successfully from local pass store", secretName)
|
||||
log.Info(i18n.G("deleted %s successfully from local pass store", secretName))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var AppSecretRmCommand = &cobra.Command{
|
||||
Use: "remove <domain> [[secret] | --all] [flags]",
|
||||
Aliases: []string{"rm"},
|
||||
Short: "Remove a secret",
|
||||
Long: `This command removes a secret from an app environment.
|
||||
Use: i18n.G("remove <domain> [[secret] | --all] [flags]"),
|
||||
Aliases: []string{i18n.G("rm")},
|
||||
Short: i18n.G("Remove a secret"),
|
||||
Long: i18n.G(`This command removes a secret from an app environment.
|
||||
|
||||
Arbitrary secret removal is not supported. Secrets that are removed must
|
||||
match those configured in the recipe beforehand.`,
|
||||
Example: " abra app secret rm 1312.net oauth_key",
|
||||
match those configured in the recipe beforehand.`),
|
||||
Example: i18n.G(" abra app secret rm 1312.net oauth_key"),
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -278,8 +277,7 @@ match those configured in the recipe beforehand.`,
|
||||
if !rmAllSecrets {
|
||||
app, err := appPkg.Get(args[0])
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("autocomplete failed: %s", err)
|
||||
return []string{errMsg}, cobra.ShellCompDirectiveError
|
||||
return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
return autocomplete.SecretComplete(app.Recipe.Name)
|
||||
}
|
||||
@ -306,11 +304,11 @@ match those configured in the recipe beforehand.`,
|
||||
}
|
||||
|
||||
if len(args) == 2 && rmAllSecrets {
|
||||
log.Fatal("cannot use [secret] and --all/-a together")
|
||||
log.Fatal(i18n.G("cannot use [secret] and --all/-a together"))
|
||||
}
|
||||
|
||||
if len(args) != 2 && !rmAllSecrets {
|
||||
log.Fatal("no secret(s) specified?")
|
||||
log.Fatal(i18n.G("no secret(s) specified?"))
|
||||
}
|
||||
|
||||
cl, err := client.New(app.Server)
|
||||
@ -361,19 +359,19 @@ match those configured in the recipe beforehand.`,
|
||||
}
|
||||
|
||||
if !match && secretToRm != "" {
|
||||
log.Fatalf("%s doesn't exist on server?", secretToRm)
|
||||
log.Fatal(i18n.G("%s doesn't exist on server?", secretToRm))
|
||||
}
|
||||
|
||||
if !match {
|
||||
log.Fatal("no secrets to remove?")
|
||||
log.Fatal(i18n.G("no secrets to remove?"))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var AppSecretLsCommand = &cobra.Command{
|
||||
Use: "list <domain>",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List all secrets",
|
||||
Use: i18n.G("list <domain>"),
|
||||
Aliases: []string{i18n.G("ls")},
|
||||
Short: i18n.G("List all secrets"),
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -393,7 +391,7 @@ var AppSecretLsCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
headers := []string{"NAME", "VERSION", "GENERATED NAME", "CREATED ON SERVER"}
|
||||
headers := []string{i18n.G("NAME"), i18n.G("VERSION"), i18n.G("GENERATED NAME"), i18n.G("CREATED ON SERVER")}
|
||||
table, err := formatter.CreateTable()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -423,7 +421,7 @@ var AppSecretLsCommand = &cobra.Command{
|
||||
if internal.MachineReadable {
|
||||
out, err := formatter.ToJSON(headers, rows)
|
||||
if err != nil {
|
||||
log.Fatal("unable to render to JSON: %s", err)
|
||||
log.Fatal(i18n.G("unable to render to JSON: %s", err))
|
||||
}
|
||||
fmt.Println(out)
|
||||
return
|
||||
@ -436,14 +434,14 @@ var AppSecretLsCommand = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
log.Warnf("no secrets stored for %s", app.Name)
|
||||
log.Warn(i18n.G("no secrets stored for %s", app.Name))
|
||||
},
|
||||
}
|
||||
|
||||
var AppSecretCommand = &cobra.Command{
|
||||
Use: "secret [cmd] [args] [flags]",
|
||||
Aliases: []string{"s"},
|
||||
Short: "Manage app secrets",
|
||||
Use: i18n.G("secret [cmd] [args] [flags]"),
|
||||
Aliases: []string{i18n.G("s")},
|
||||
Short: i18n.G("Manage app secrets"),
|
||||
}
|
||||
|
||||
var (
|
||||
@ -458,105 +456,105 @@ var (
|
||||
func init() {
|
||||
AppSecretGenerateCommand.Flags().BoolVarP(
|
||||
&internal.MachineReadable,
|
||||
"machine",
|
||||
"m",
|
||||
i18n.G("machine"),
|
||||
i18n.G("m"),
|
||||
false,
|
||||
"print machine-readable output",
|
||||
i18n.G("print machine-readable output"),
|
||||
)
|
||||
|
||||
AppSecretGenerateCommand.Flags().BoolVarP(
|
||||
&storeInPass,
|
||||
"pass",
|
||||
"p",
|
||||
i18n.G("pass"),
|
||||
i18n.G("p"),
|
||||
false,
|
||||
"store generated secrets in a local pass store",
|
||||
i18n.G("store generated secrets in a local pass store"),
|
||||
)
|
||||
|
||||
AppSecretGenerateCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
|
||||
AppSecretGenerateCommand.Flags().BoolVarP(
|
||||
&generateAllSecrets,
|
||||
"all",
|
||||
"a",
|
||||
i18n.G("all"),
|
||||
i18n.G("a"),
|
||||
false,
|
||||
"generate all secrets",
|
||||
i18n.G("generate all secrets"),
|
||||
)
|
||||
|
||||
AppSecretInsertCommand.Flags().BoolVarP(
|
||||
&storeInPass,
|
||||
"pass",
|
||||
"p",
|
||||
i18n.G("pass"),
|
||||
i18n.G("p"),
|
||||
false,
|
||||
"store generated secrets in a local pass store",
|
||||
i18n.G("store generated secrets in a local pass store"),
|
||||
)
|
||||
|
||||
AppSecretInsertCommand.Flags().BoolVarP(
|
||||
&insertFromFile,
|
||||
"file",
|
||||
"f",
|
||||
i18n.G("file"),
|
||||
i18n.G("f"),
|
||||
false,
|
||||
"treat input as a file",
|
||||
i18n.G("treat input as a file"),
|
||||
)
|
||||
|
||||
AppSecretInsertCommand.Flags().BoolVarP(
|
||||
&trimInput,
|
||||
"trim",
|
||||
"t",
|
||||
i18n.G("trim"),
|
||||
i18n.G("t"),
|
||||
false,
|
||||
"trim input",
|
||||
i18n.G("trim input"),
|
||||
)
|
||||
|
||||
AppSecretInsertCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
|
||||
AppSecretRmCommand.Flags().BoolVarP(
|
||||
&rmAllSecrets,
|
||||
"all",
|
||||
"a",
|
||||
i18n.G("all"),
|
||||
i18n.G("a"),
|
||||
false,
|
||||
"remove all secrets",
|
||||
i18n.G("remove all secrets"),
|
||||
)
|
||||
|
||||
AppSecretRmCommand.Flags().BoolVarP(
|
||||
&removeFromPass,
|
||||
"pass",
|
||||
"p",
|
||||
i18n.G("pass"),
|
||||
i18n.G("p"),
|
||||
false,
|
||||
"remove generated secrets from a local pass store",
|
||||
i18n.G("remove generated secrets from a local pass store"),
|
||||
)
|
||||
|
||||
AppSecretRmCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
|
||||
AppSecretLsCommand.Flags().BoolVarP(
|
||||
&internal.Chaos,
|
||||
"chaos",
|
||||
"C",
|
||||
i18n.G("chaos"),
|
||||
i18n.G("C"),
|
||||
false,
|
||||
"ignore uncommitted recipes changes",
|
||||
i18n.G("ignore uncommitted recipes changes"),
|
||||
)
|
||||
|
||||
AppSecretLsCommand.Flags().BoolVarP(
|
||||
&internal.MachineReadable,
|
||||
"machine",
|
||||
"m",
|
||||
i18n.G("machine"),
|
||||
i18n.G("m"),
|
||||
false,
|
||||
"print machine-readable output",
|
||||
i18n.G("print machine-readable output"),
|
||||
)
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/service"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
@ -17,9 +18,9 @@ import (
|
||||
)
|
||||
|
||||
var AppServicesCommand = &cobra.Command{
|
||||
Use: "services <domain> [flags]",
|
||||
Aliases: []string{"sr"},
|
||||
Short: "Display all services of an app",
|
||||
Use: i18n.G("services <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("sr")},
|
||||
Short: i18n.G("Display all services of an app"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -45,7 +46,7 @@ var AppServicesCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
if !deployMeta.IsDeployed {
|
||||
log.Fatalf("%s is not deployed?", app.Name)
|
||||
log.Fatal(i18n.G("%s is not deployed?", app.Name))
|
||||
}
|
||||
|
||||
filters, err := app.Filters(true, true)
|
||||
@ -63,7 +64,7 @@ var AppServicesCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
headers := []string{"SERVICE (SHORT)", "SERVICE (LONG)"}
|
||||
headers := []string{i18n.G("SERVICE (SHORT)"), i18n.G("SERVICE (LONG)")}
|
||||
table.Headers(headers...)
|
||||
|
||||
var rows [][]string
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
stack "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
@ -18,15 +19,15 @@ import (
|
||||
)
|
||||
|
||||
var AppUndeployCommand = &cobra.Command{
|
||||
Use: "undeploy <domain> [flags]",
|
||||
Aliases: []string{"un"},
|
||||
Short: "Undeploy an app",
|
||||
Long: `This does not destroy any application data.
|
||||
Use: i18n.G("undeploy <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("un")},
|
||||
Short: i18n.G("Undeploy an app"),
|
||||
Long: i18n.G(`This does not destroy any application data.
|
||||
|
||||
However, you should remain vigilant, as your swarm installation will consider
|
||||
any previously attached volumes as eligible for pruning once undeployed.
|
||||
|
||||
Passing "--prune/-p" does not remove those volumes.`,
|
||||
Passing "--prune/-p" does not remove those volumes.`),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -47,7 +48,7 @@ Passing "--prune/-p" does not remove those volumes.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("checking whether %s is already deployed", stackName)
|
||||
log.Debug(i18n.G("checking whether %s is already deployed", stackName))
|
||||
|
||||
deployMeta, err := stack.IsDeployed(context.Background(), cl, stackName)
|
||||
if err != nil {
|
||||
@ -55,7 +56,7 @@ Passing "--prune/-p" does not remove those volumes.`,
|
||||
}
|
||||
|
||||
if !deployMeta.IsDeployed {
|
||||
log.Fatalf("%s is not deployed?", app.Name)
|
||||
log.Fatal(i18n.G("%s is not deployed?", app.Name))
|
||||
}
|
||||
|
||||
if err := internal.DeployOverview(
|
||||
@ -84,7 +85,7 @@ Passing "--prune/-p" does not remove those volumes.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Info("initialising undeploy")
|
||||
log.Info(i18n.G("initialising undeploy"))
|
||||
|
||||
rmOpts := stack.Remove{
|
||||
Namespaces: []string{stackName},
|
||||
@ -100,10 +101,10 @@ Passing "--prune/-p" does not remove those volumes.`,
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("undeploy succeeded 🟢")
|
||||
log.Info(i18n.G("undeploy succeeded 🟢"))
|
||||
|
||||
if err := app.WriteRecipeVersion(deployMeta.Version, false); err != nil {
|
||||
log.Fatalf("writing recipe version failed: %s", err)
|
||||
log.Fatal(i18n.G("writing recipe version failed: %s", err))
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -124,14 +125,14 @@ func pruneApp(cl *dockerClient.Client, app appPkg.App) error {
|
||||
}
|
||||
|
||||
cntSpaceReclaimed := formatter.ByteCountSI(cr.SpaceReclaimed)
|
||||
log.Infof("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed)
|
||||
log.Info(i18n.G("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed))
|
||||
|
||||
nr, err := cl.NetworksPrune(ctx, pruneFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("networks pruned: %d", len(nr.NetworksDeleted))
|
||||
log.Info(i18n.G("networks pruned: %d", len(nr.NetworksDeleted)))
|
||||
|
||||
ir, err := cl.ImagesPrune(ctx, pruneFilters)
|
||||
if err != nil {
|
||||
@ -139,7 +140,7 @@ func pruneApp(cl *dockerClient.Client, app appPkg.App) error {
|
||||
}
|
||||
|
||||
imgSpaceReclaimed := formatter.ByteCountSI(ir.SpaceReclaimed)
|
||||
log.Infof("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed)
|
||||
log.Info(i18n.G("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed))
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -151,9 +152,9 @@ var (
|
||||
func init() {
|
||||
AppUndeployCommand.Flags().BoolVarP(
|
||||
&prune,
|
||||
"prune",
|
||||
"p",
|
||||
i18n.G("prune"),
|
||||
i18n.G("p"),
|
||||
false,
|
||||
"prune unused containers, networks, and dangling images",
|
||||
i18n.G("prune unused containers, networks, and dangling images"),
|
||||
)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@ -13,6 +14,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/config"
|
||||
"coopcloud.tech/abra/pkg/envfile"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/lint"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/recipe"
|
||||
@ -24,10 +26,10 @@ import (
|
||||
)
|
||||
|
||||
var AppUpgradeCommand = &cobra.Command{
|
||||
Use: "upgrade <domain> [version] [flags]",
|
||||
Aliases: []string{"up"},
|
||||
Short: "Upgrade an app",
|
||||
Long: `Upgrade an app.
|
||||
Use: i18n.G("upgrade <domain> [version] [flags]"),
|
||||
Aliases: []string{i18n.G("up")},
|
||||
Short: i18n.G("Upgrade an app"),
|
||||
Long: i18n.G(`Upgrade an app.
|
||||
|
||||
Unlike "abra app deploy", chaos operations are not supported here. Only recipe
|
||||
versions are supported values for "[version]".
|
||||
@ -40,7 +42,7 @@ are available. The live deployment version is the "source of truth" in this
|
||||
case. The stored .env version is not consulted.
|
||||
|
||||
An upgrade can be destructive, please ensure you have a copy of your app data
|
||||
beforehand. See "abra app backup" for more.`,
|
||||
beforehand. See "abra app backup" for more.`),
|
||||
Args: cobra.RangeArgs(1, 2),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -53,8 +55,7 @@ beforehand. See "abra app backup" for more.`,
|
||||
case 1:
|
||||
app, err := appPkg.Get(args[0])
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("autocomplete failed: %s", err)
|
||||
return []string{errMsg}, cobra.ShellCompDirectiveError
|
||||
return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
|
||||
}
|
||||
return autocomplete.RecipeVersionComplete(app.Recipe.Name)
|
||||
default:
|
||||
@ -123,7 +124,7 @@ beforehand. See "abra app backup" for more.`,
|
||||
}
|
||||
|
||||
if !upgradeAvailable {
|
||||
log.Info("no available upgrades")
|
||||
log.Info(i18n.G("no available upgrades"))
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -145,10 +146,10 @@ beforehand. See "abra app backup" for more.`,
|
||||
}
|
||||
|
||||
if chosenUpgrade == "" {
|
||||
log.Fatal("unknown deployed version, unable to upgrade")
|
||||
log.Fatal(i18n.G("unknown deployed version, unable to upgrade"))
|
||||
}
|
||||
|
||||
log.Debugf("choosing %s as version to upgrade", chosenUpgrade)
|
||||
log.Debug(i18n.G("choosing %s as version to upgrade", chosenUpgrade))
|
||||
|
||||
// Get the release notes before checking out the new version in the
|
||||
// recipe. This enables us to get release notes, that were added after
|
||||
@ -204,7 +205,7 @@ beforehand. See "abra app backup" for more.`,
|
||||
for _, envVar := range envVars {
|
||||
if !envVar.Present {
|
||||
upgradeWarnMessages = append(upgradeWarnMessages,
|
||||
fmt.Sprintf("%s missing from %s.env", envVar.Name, app.Domain),
|
||||
i18n.G("%s missing from %s.env", envVar.Name, app.Domain),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -236,7 +237,7 @@ beforehand. See "abra app backup" for more.`,
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Debugf("set waiting timeout to %d second(s)", stack.WaitTimeout)
|
||||
log.Debug(i18n.G("set waiting timeout to %d second(s)", stack.WaitTimeout))
|
||||
|
||||
serviceNames, err := appPkg.GetAppServiceNames(app.Name)
|
||||
if err != nil {
|
||||
@ -262,15 +263,15 @@ beforehand. See "abra app backup" for more.`,
|
||||
|
||||
postDeployCmds, ok := app.Env["POST_UPGRADE_CMDS"]
|
||||
if ok && !internal.DontWaitConverge {
|
||||
log.Debugf("run the following post-deploy commands: %s", postDeployCmds)
|
||||
log.Debug(i18n.G("run the following post-deploy commands: %s", postDeployCmds))
|
||||
|
||||
if err := internal.PostCmds(cl, app, postDeployCmds); err != nil {
|
||||
log.Fatalf("attempting to run post deploy commands, saw: %s", err)
|
||||
log.Fatal(i18n.G("attempting to run post deploy commands, saw: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
if err := app.WriteRecipeVersion(chosenUpgrade, false); err != nil {
|
||||
log.Fatalf("writing recipe version failed: %s", err)
|
||||
log.Fatal(i18n.G("writing recipe version failed: %s", err))
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -281,12 +282,12 @@ func chooseUpgrade(
|
||||
deployMeta stack.DeployMeta,
|
||||
chosenUpgrade *string,
|
||||
) error {
|
||||
msg := fmt.Sprintf("please select an upgrade (version: %s):", deployMeta.Version)
|
||||
msg := i18n.G("please select an upgrade (version: %s):", deployMeta.Version)
|
||||
|
||||
if deployMeta.IsChaos {
|
||||
chaosVersion := formatter.BoldDirtyDefault(deployMeta.ChaosVersion)
|
||||
|
||||
msg = fmt.Sprintf(
|
||||
msg = i18n.G(
|
||||
"please select an upgrade (version: %s, chaos: %s):",
|
||||
deployMeta.Version,
|
||||
chaosVersion,
|
||||
@ -314,18 +315,18 @@ func getReleaseNotes(
|
||||
) error {
|
||||
parsedChosenUpgrade, err := tagcmp.Parse(chosenUpgrade)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing chosen upgrade version failed: %s", err)
|
||||
return errors.New(i18n.G("parsing chosen upgrade version failed: %s", err))
|
||||
}
|
||||
|
||||
parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing deployment version failed: %s", err)
|
||||
return errors.New(i18n.G("parsing deployment version failed: %s", err))
|
||||
}
|
||||
|
||||
for _, version := range internal.SortVersionsDesc(versions) {
|
||||
parsedVersion, err := tagcmp.Parse(version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing recipe version failed: %s", err)
|
||||
return errors.New(i18n.G("parsing recipe version failed: %s", err))
|
||||
}
|
||||
|
||||
if parsedVersion.IsGreaterThan(parsedDeployedVersion) &&
|
||||
@ -358,13 +359,13 @@ func ensureUpgradesAvailable(
|
||||
) (bool, error) {
|
||||
parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("parsing deployed version failed: %s", err)
|
||||
return false, errors.New(i18n.G("parsing deployed version failed: %s", err))
|
||||
}
|
||||
|
||||
for _, version := range versions {
|
||||
parsedVersion, err := tagcmp.Parse(version)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("parsing recipe version failed: %s", err)
|
||||
return false, errors.New(i18n.G("parsing recipe version failed: %s", err))
|
||||
}
|
||||
|
||||
if parsedVersion.IsGreaterThan(parsedDeployedVersion) &&
|
||||
@ -388,21 +389,21 @@ func validateUpgradeVersionArg(
|
||||
) error {
|
||||
parsedSpecificVersion, err := tagcmp.Parse(specificVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("'%s' is not a known version for %s", specificVersion, app.Recipe.Name)
|
||||
return errors.New(i18n.G("'%s' is not a known version for %s", specificVersion, app.Recipe.Name))
|
||||
}
|
||||
|
||||
parsedDeployedVersion, err := tagcmp.Parse(deployMeta.Version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("'%s' is not a known version", deployMeta.Version)
|
||||
return errors.New(i18n.G("'%s' is not a known version", deployMeta.Version))
|
||||
}
|
||||
|
||||
if parsedSpecificVersion.IsLessThan(parsedDeployedVersion) &&
|
||||
!parsedSpecificVersion.Equals(parsedDeployedVersion) {
|
||||
return fmt.Errorf("%s is not an upgrade for %s?", deployMeta.Version, specificVersion)
|
||||
return errors.New(i18n.G("%s is not an upgrade for %s?", deployMeta.Version, specificVersion))
|
||||
}
|
||||
|
||||
if parsedSpecificVersion.Equals(parsedDeployedVersion) && !internal.Force {
|
||||
return fmt.Errorf("%s is not an upgrade for %s?", deployMeta.Version, specificVersion)
|
||||
return errors.New(i18n.G("%s is not an upgrade for %s?", deployMeta.Version, specificVersion))
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -411,7 +412,7 @@ func validateUpgradeVersionArg(
|
||||
// ensureDeployed ensures the app is deployed and if so, returns deployment
|
||||
// meta info.
|
||||
func ensureDeployed(cl *dockerClient.Client, app app.App) (stack.DeployMeta, error) {
|
||||
log.Debugf("checking whether %s is already deployed", app.StackName())
|
||||
log.Debug(i18n.G("checking whether %s is already deployed", app.StackName()))
|
||||
|
||||
deployMeta, err := stack.IsDeployed(context.Background(), cl, app.StackName())
|
||||
if err != nil {
|
||||
@ -419,7 +420,7 @@ func ensureDeployed(cl *dockerClient.Client, app app.App) (stack.DeployMeta, err
|
||||
}
|
||||
|
||||
if !deployMeta.IsDeployed {
|
||||
return stack.DeployMeta{}, fmt.Errorf("%s is not deployed?", app.Name)
|
||||
return stack.DeployMeta{}, errors.New(i18n.G("%s is not deployed?", app.Name))
|
||||
}
|
||||
|
||||
return deployMeta, nil
|
||||
@ -430,32 +431,33 @@ var showReleaseNotes bool
|
||||
func init() {
|
||||
AppUpgradeCommand.Flags().BoolVarP(
|
||||
&internal.Force,
|
||||
"force",
|
||||
"f",
|
||||
i18n.G("force"),
|
||||
i18n.G("f"),
|
||||
false,
|
||||
"perform action without further prompt",
|
||||
i18n.G("perform action without further prompt"),
|
||||
)
|
||||
|
||||
AppUpgradeCommand.Flags().BoolVarP(
|
||||
&internal.NoDomainChecks,
|
||||
"no-domain-checks",
|
||||
"D",
|
||||
i18n.G("no-domain-checks"),
|
||||
i18n.G("D"),
|
||||
false,
|
||||
"disable public DNS checks",
|
||||
i18n.G("disable public DNS checks"),
|
||||
)
|
||||
|
||||
AppUpgradeCommand.Flags().BoolVarP(
|
||||
&internal.DontWaitConverge, "no-converge-checks",
|
||||
"c",
|
||||
&internal.DontWaitConverge,
|
||||
i18n.G("no-converge-checks"),
|
||||
i18n.G("c"),
|
||||
false,
|
||||
"disable converge logic checks",
|
||||
i18n.G("disable converge logic checks"),
|
||||
)
|
||||
|
||||
AppUpgradeCommand.Flags().BoolVarP(
|
||||
&showReleaseNotes,
|
||||
"releasenotes",
|
||||
"r",
|
||||
i18n.G("releasenotes"),
|
||||
i18n.G("r"),
|
||||
false,
|
||||
"only show release notes",
|
||||
i18n.G("only show release notes"),
|
||||
)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/autocomplete"
|
||||
"coopcloud.tech/abra/pkg/client"
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
"coopcloud.tech/abra/pkg/i18n"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
@ -15,9 +16,9 @@ import (
|
||||
)
|
||||
|
||||
var AppVolumeListCommand = &cobra.Command{
|
||||
Use: "list <domain> [flags]",
|
||||
Aliases: []string{"ls"},
|
||||
Short: "List volumes associated with an app",
|
||||
Use: i18n.G("list <domain> [flags]"),
|
||||
Aliases: []string{i18n.G("ls")},
|
||||
Short: i18n.G("List volumes associated with an app"),
|
||||
Args: cobra.ExactArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -43,7 +44,7 @@ var AppVolumeListCommand = &cobra.Command{
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
headers := []string{"NAME", "ON SERVER"}
|
||||
headers := []string{i18n.G("NAME"), i18n.G("ON SERVER")}
|
||||
|
||||
table, err := formatter.CreateTable()
|
||||
if err != nil {
|
||||
@ -67,14 +68,14 @@ var AppVolumeListCommand = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
log.Warnf("no volumes created for %s", app.Name)
|
||||
log.Warn(i18n.G("no volumes created for %s", app.Name))
|
||||
},
|
||||
}
|
||||
|
||||
var AppVolumeRemoveCommand = &cobra.Command{
|
||||
Use: "remove <domain> [volume] [flags]",
|
||||
Short: "Remove volume(s) associated with an app",
|
||||
Long: `Remove volumes associated with an app.
|
||||
Use: i18n.G("remove <domain> [volume] [flags]"),
|
||||
Short: i18n.G("Remove volume(s) associated with an app"),
|
||||
Long: i18n.G(`Remove volumes associated with an app.
|
||||
|
||||
The app in question must be undeployed before you try to remove volumes. See
|
||||
"abra app undeploy <domain>" for more.
|
||||
@ -83,13 +84,13 @@ The command is interactive and will show a multiple select input which allows
|
||||
you to make a seclection. Use the "?" key to see more help on navigating this
|
||||
interface.
|
||||
|
||||
Passing "--force/-f" will select all volumes for removal. Be careful.`,
|
||||
Example: ` # delete volumes interactively
|
||||
Passing "--force/-f" will select all volumes for removal. Be careful.`),
|
||||
Example: i18n.G(` # delete volumes interactively
|
||||
abra app volume rm 1312.net
|
||||
|
||||
# delete specific volume
|
||||
abra app volume rm 1312.net my_volume`,
|
||||
Aliases: []string{"rm"},
|
||||
abra app volume rm 1312.net my_volume`),
|
||||
Aliases: []string{i18n.G("rm")},
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
ValidArgsFunction: func(
|
||||
cmd *cobra.Command,
|
||||
@ -116,7 +117,7 @@ Passing "--force/-f" will select all volumes for removal. Be careful.`,
|
||||
}
|
||||
|
||||
if deployMeta.IsDeployed {
|
||||
log.Fatalf("%s is still deployed. Run \"abra app undeploy %s\"", app.Name, app.Name)
|
||||
log.Fatal(i18n.G("%s is still deployed. Run \"abra app undeploy %s\"", app.Name, app.Name))
|
||||
}
|
||||
|
||||
filters, err := app.Filters(false, true)
|
||||
@ -141,15 +142,15 @@ Passing "--force/-f" will select all volumes for removal. Be careful.`,
|
||||
}
|
||||
|
||||
if !exactMatch {
|
||||
log.Fatalf("unable to remove volume: no volume with name '%s'?", volumeToDelete)
|
||||
log.Fatal(i18n.G("unable to remove volume: no volume with name '%s'?", volumeToDelete))
|
||||
}
|
||||
|
||||
err := client.RemoveVolumes(cl, context.Background(), []string{fullVolumeToDeleteName}, internal.Force, 5)
|
||||
if err != nil {
|
||||
log.Fatalf("removing volume %s failed: %s", volumeToDelete, err)
|
||||
log.Fatal(i18n.G("removing volume %s failed: %s", volumeToDelete, err))
|
||||
}
|
||||
|
||||
log.Infof("volume %s removed successfully", volumeToDelete)
|
||||
log.Info(i18n.G("volume %s removed successfully", volumeToDelete))
|
||||
|
||||
return
|
||||
}
|
||||
@ -157,8 +158,8 @@ Passing "--force/-f" will select all volumes for removal. Be careful.`,
|
||||
var volumesToRemove []string
|
||||
if !internal.Force && !internal.NoInput {
|
||||
volumesPrompt := &survey.MultiSelect{
|
||||
Message: "which volumes do you want to remove?",
|
||||
Help: "'x' indicates selected, enter / return to confirm, ctrl-c to exit, vim mode is enabled",
|
||||
Message: i18n.G("which volumes do you want to remove?"),
|
||||
Help: i18n.G("'x' indicates selected, enter / return to confirm, ctrl-c to exit, vim mode is enabled"),
|
||||
VimMode: true,
|
||||
Options: volumeNames,
|
||||
Default: volumeNames,
|
||||
@ -175,28 +176,28 @@ Passing "--force/-f" will select all volumes for removal. Be careful.`,
|
||||
if len(volumesToRemove) > 0 {
|
||||
err := client.RemoveVolumes(cl, context.Background(), volumesToRemove, internal.Force, 5)
|
||||
if err != nil {
|
||||
log.Fatalf("removing volumes failed: %s", err)
|
||||
log.Fatal(i18n.G("removing volumes failed: %s", err))
|
||||
}
|
||||
|
||||
log.Infof("%d volumes removed successfully", len(volumesToRemove))
|
||||
log.Info(i18n.G("%d volumes removed successfully", len(volumesToRemove)))
|
||||
} else {
|
||||
log.Info("no volumes removed")
|
||||
log.Info(i18n.G("no volumes removed"))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var AppVolumeCommand = &cobra.Command{
|
||||
Use: "volume [cmd] [args] [flags]",
|
||||
Aliases: []string{"vl"},
|
||||
Short: "Manage app volumes",
|
||||
Use: i18n.G("volume [cmd] [args] [flags]"),
|
||||
Aliases: []string{i18n.G("vl")},
|
||||
Short: i18n.G("Manage app volumes"),
|
||||
}
|
||||
|
||||
func init() {
|
||||
AppVolumeRemoveCommand.Flags().BoolVarP(
|
||||
&internal.Force,
|
||||
"force",
|
||||
"f",
|
||||
i18n.G("force"),
|
||||
i18n.G("f"),
|
||||
false,
|
||||
"perform action without further prompt",
|
||||
i18n.G("perform action without further prompt"),
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user