feat!: abra app env pull #708

Merged
decentral1se merged 2 commits from fix/497 into main 2025-10-31 20:33:31 +00:00
7 changed files with 975 additions and 205 deletions

View File

@ -1,28 +1,50 @@
package app package app
import ( import (
"context"
"fmt" "fmt"
"os"
"path"
"path/filepath"
"regexp"
"sort" "sort"
"strings" "strings"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/app"
appPkg "coopcloud.tech/abra/pkg/app"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
containerPkg "coopcloud.tech/abra/pkg/container"
contextPkg "coopcloud.tech/abra/pkg/context"
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/i18n" "coopcloud.tech/abra/pkg/i18n"
"coopcloud.tech/abra/pkg/log"
"coopcloud.tech/abra/pkg/upstream/stack"
"github.com/docker/docker/api/types/filters"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
// translators: `abra app env` aliases. use a comma separated list of aliases with // translators: `abra app env` aliases. use a comma separated list of aliases
// no spaces in between // with no spaces in between
var appEnvAliases = i18n.G("e") var appEnvAliases = i18n.G("e")
var AppEnvCommand = &cobra.Command{ // translators: `abra app env list` aliases. use a comma separated list of
// translators: `app env` command // aliases with no spaces in between
Use: i18n.G("env <domain> [flags]"), var appEnvListAliases = i18n.G("l,ls")
Aliases: strings.Split(appEnvAliases, ","),
// translators: Short description for `app env` command // translators: `abra app env pull` aliases. use a comma separated list of
Short: i18n.G("Show app .env values"), // aliases with no spaces in between
Example: i18n.G(" abra app env 1312.net"), var appEnvPullAliases = i18n.G("pl,p")
var AppEnvListCommand = &cobra.Command{
// translators: `app env list` command
Use: i18n.G("list <domain> [flags]"),
Aliases: strings.Split(appEnvListAliases, ","),
// translators: Short description for `app env list` command
Short: i18n.G("List all app environment values"),
Example: i18n.G(" abra app env list 1312.net"),
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
ValidArgsFunction: func( ValidArgsFunction: func(
cmd *cobra.Command, cmd *cobra.Command,
@ -49,3 +71,270 @@ var AppEnvCommand = &cobra.Command{
fmt.Println(overview) fmt.Println(overview)
}, },
} }
var AppEnvPullCommand = &cobra.Command{
// translators: `app pull` command
Use: i18n.G("pull <domain> [flags]"),
Aliases: strings.Split(appEnvPullAliases, ","),
// translators: Short description for `app env pull` command
Short: i18n.G("Pull app environment values from a deployed app"),
Long: i18n.G(`Pull app environment values from a deploymed app.
A convenient command for when you've lost your app environment file or want to
synchronize your local app environment values with what is deployed live.`),
Example: i18n.G(` # pull existing .env file and overwrite local values
abra app env pull 1312.net --force
# pull lost app .env file
abra app env pull my.gitea.net --server 1312.net`),
Args: cobra.MaximumNArgs(2),
ValidArgsFunction: func(
cmd *cobra.Command,
args []string,
toComplete string) ([]string, cobra.ShellCompDirective) {
return autocomplete.AppNameComplete()
},
Run: func(cmd *cobra.Command, args []string) {
appName := args[0]
appEnvPath := path.Join(config.ABRA_DIR, "servers", server, fmt.Sprintf("%s.env", appName))
if _, err := os.Stat(appEnvPath); !os.IsNotExist(err) {
log.Fatal(i18n.G("%s already exists?", appEnvPath))
}
if server == "" {
log.Fatal(i18n.G("unable to determine server of app %s, please pass --server/-s", appName))
}
serverDir := filepath.Join(config.SERVERS_DIR, server)
if _, err := os.Stat(serverDir); os.IsNotExist(err) {
log.Fatal(i18n.G("unknown server %s, run \"abra server add %s\"?", server, server))
}
store := contextPkg.NewDefaultDockerContextStore()
contexts, err := store.Store.List()
if err != nil {
log.Fatal(i18n.G("unable to look up server context for %s: %s", server, err))
}
var contextCreated bool
for _, context := range contexts {
if context.Name == server || server == "default" {
contextCreated = true
}
}
if !contextCreated {
log.Fatal(i18n.G("%s missing context, run \"abra server add %s\"?", server, server))
}
cl, err := client.New(server)
if err != nil {
log.Fatal(err)
}
deployMeta, err := stack.IsDeployed(context.Background(), cl, appPkg.StackName(appName))
if err != nil {
log.Fatal(err)
}
if !deployMeta.IsDeployed {
log.Fatal(i18n.G("%s is not deployed?", appName))
}
filters := filters.NewArgs()
filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(appName), "app"))
targetContainer, err := containerPkg.GetContainer(context.Background(), cl, filters, internal.NoInput)
if err != nil {
log.Fatal(i18n.G("unable to retrieve container for %s: %s", appName, err))
}
inspectResult, err := cl.ContainerInspect(context.Background(), targetContainer.ID)
if err != nil {
log.Fatal(i18n.G("unable to inspect container for %s: %s", appName, err))
}
deploymentEnv := make(map[string]string)
for _, envVar := range inspectResult.Config.Env {
split := strings.SplitN(envVar, "=", 2)
if len(split) != 2 {
log.Debug(i18n.G("no value attached to %s", envVar))
continue
}
key, val := split[0], split[1]
deploymentEnv[key] = val
}
log.Debug(i18n.G("pulled env values from %s deployment: %s", appName, deploymentEnv))
var (
recipeEnvVar string
recipeKey string
)
if r, ok := deploymentEnv["TYPE"]; ok {
recipeKey = "TYPE"
recipeEnvVar = r
}
if r, ok := deploymentEnv["RECIPE"]; ok {
recipeKey = "RECIPE"
recipeEnvVar = r
}
if recipeEnvVar == "" {
log.Fatal(i18n.G("unable to determine recipe type from %s, env: %v", appName, inspectResult.Config.Env))
}
var recipeName = recipeEnvVar
if strings.Contains(recipeEnvVar, ":") {
split := strings.Split(recipeEnvVar, ":")
recipeName = split[0]
}
recipe := internal.ValidateRecipe(
[]string{recipeName},
cmd.Name(),
)
version := deployMeta.Version
if deployMeta.IsChaos {
version = deployMeta.ChaosVersion
}
if _, err := recipe.EnsureVersion(version); err != nil {
log.Fatal(err)
}
mergedEnv, err := recipe.SampleEnv()
if err != nil {
log.Fatal(err)
}
log.Debug(i18n.G("retrieved env values from .env.sample of %s: %s", recipe.Name, mergedEnv))
for k, v := range deploymentEnv {
mergedEnv[k] = v
}
if !strings.Contains(recipeEnvVar, ":") {
mergedEnv[recipeKey] = fmt.Sprintf("%s:%s", mergedEnv[recipeKey], version)
}
log.Debug(i18n.G("final merged env values for %s are: %s", appName, mergedEnv))
envSample, err := os.ReadFile(recipe.SampleEnvPath)
if err != nil {
log.Fatal(err)
}
err = os.WriteFile(appEnvPath, envSample, 0o664)
if err != nil {
log.Fatal(i18n.G("unable to write new env %s: %s", appEnvPath, err))
}
read, err := os.ReadFile(appEnvPath)
if err != nil {
log.Fatal(i18n.G("unable to read new env %s: %s", appEnvPath, err))
}
sampleEnv, err := recipe.SampleEnv()
if err != nil {
log.Fatal(err)
}
var composeFileUpdated bool
newContents := string(read)
for key, val := range mergedEnv {
if sampleEnv[key] == val {
continue
}
if key == "COMPOSE_FILE" {
composeFileUpdated = true
continue
}
if m, _ := regexp.MatchString(fmt.Sprintf(`#%s=`, key), newContents); m {
log.Debug(i18n.G("uncommenting %s", key))
re := regexp.MustCompile(fmt.Sprintf(`#%s=`, key))
newContents = re.ReplaceAllString(newContents, fmt.Sprintf("%s=", key))
}
if m, _ := regexp.MatchString(fmt.Sprintf(`# %s=`, key), newContents); m {
log.Debug(i18n.G("uncommenting %s", key))
re := regexp.MustCompile(fmt.Sprintf(`# %s=`, key))
newContents = re.ReplaceAllString(newContents, fmt.Sprintf("%s=", key))
}
if m, _ := regexp.MatchString(fmt.Sprintf(`%s=".*"`, key), newContents); m {
log.Debug(i18n.G(`inserting %s="%s" (double quotes)`, key, val))
re := regexp.MustCompile(fmt.Sprintf(`%s=".*"`, key))
newContents = re.ReplaceAllString(newContents, fmt.Sprintf(`%s="%s"`, key, val))
continue
}
if m, _ := regexp.MatchString(fmt.Sprintf(`%s='.*'`, key), newContents); m {
log.Debug(i18n.G(`inserting %s='%s' (single quotes)`, key, val))
re := regexp.MustCompile(fmt.Sprintf(`%s='.*'`, key))
newContents = re.ReplaceAllString(newContents, fmt.Sprintf(`%s='%s'`, key, val))
continue
}
if m, _ := regexp.MatchString(fmt.Sprintf("%s=.*", key), newContents); m {
log.Debug(i18n.G("inserting %s=%s (no quotes)", key, val))
re := regexp.MustCompile(fmt.Sprintf("%s=.*", key))
newContents = re.ReplaceAllString(newContents, fmt.Sprintf("%s=%s", key, val))
}
}
err = os.WriteFile(appEnvPath, []byte(newContents), 0)
if err != nil {
log.Fatal(i18n.G("unable to write new env %s: %s", appEnvPath, err))
}
log.Info(i18n.G("%s successfully created", appEnvPath))
if composeFileUpdated {
log.Warn(i18n.G("manual update required: COMPOSE_FILE=\"%s\"", mergedEnv["COMPOSE_FILE"]))
}
},
}
var AppEnvCommand = &cobra.Command{
// translators: `app env` command group
Use: i18n.G("env [cmd] [args] [flags]"),
Aliases: strings.Split(appEnvAliases, ","),
// translators: Short description for `app env` command group
Short: i18n.G("Manage app environment values"),
}
var (
server string
)
func init() {
AppEnvPullCommand.Flags().BoolVarP(
&internal.Force,
i18n.G("force"),
i18n.G("f"),
false,
i18n.G("perform action without further prompt"),
)
AppEnvPullCommand.Flags().StringVarP(
&server,
i18n.G("server"),
i18n.G("s"),
"",
i18n.G("server associated with deployed app"),
)
AppEnvPullCommand.RegisterFlagCompletionFunc(
i18n.G("server"),
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return autocomplete.ServerNameComplete()
},
)
}

View File

@ -28,6 +28,7 @@ var AppUndeployCommand = &cobra.Command{
Use: i18n.G("undeploy <domain> [flags]"), Use: i18n.G("undeploy <domain> [flags]"),
// translators: Short description for `app undeploy` command // translators: Short description for `app undeploy` command
Aliases: strings.Split(appUndeployAliases, ","), Aliases: strings.Split(appUndeployAliases, ","),
Short: i18n.G("Undeploy a deployed app"),
Long: i18n.G(`This does not destroy any application data. Long: i18n.G(`This does not destroy any application data.
However, you should remain vigilant, as your swarm installation will consider However, you should remain vigilant, as your swarm installation will consider

View File

@ -283,6 +283,11 @@ Config:
app.AppBackupSnapshotsCommand, app.AppBackupSnapshotsCommand,
) )
app.AppEnvCommand.AddCommand(
app.AppEnvListCommand,
app.AppEnvPullCommand,
)
app.AppCommand.AddCommand( app.AppCommand.AddCommand(
app.AppBackupCommand, app.AppBackupCommand,
app.AppCheckCommand, app.AppCheckCommand,

View File

@ -7,7 +7,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: \n" msgstr "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n" "Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-10-23 09:14+0200\n" "POT-Creation-Date: 2025-10-31 21:31+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -92,6 +92,14 @@ msgid " # pass <cmd> args/flags without \"--\"\n"
" abra app cmd 1312.net my_cmd --local" " abra app cmd 1312.net my_cmd --local"
msgstr "" msgstr ""
#: ./cli/app/env.go:85
msgid " # pull existing .env file and overwrite local values\n"
" abra app env pull 1312.net --force\n"
"\n"
" # pull lost app .env file\n"
" abra app env pull my.gitea.net --server 1312.net"
msgstr ""
#: ./cli/app/restart.go:36 #: ./cli/app/restart.go:36
msgid " # restart a single app service\n" msgid " # restart a single app service\n"
" abra app restart 1312.net app\n" " abra app restart 1312.net app\n"
@ -125,8 +133,8 @@ msgid " # standard deployment\n"
" abra app deploy 1312.net 886db76d" " abra app deploy 1312.net 886db76d"
msgstr "" msgstr ""
#: ./cli/app/env.go:25 #: ./cli/app/env.go:47
msgid " abra app env 1312.net" msgid " abra app env list 1312.net"
msgstr "" msgstr ""
#: ./cli/app/remove.go:45 #: ./cli/app/remove.go:45
@ -201,7 +209,7 @@ msgstr ""
msgid "%s already exists" msgid "%s already exists"
msgstr "" msgstr ""
#: ./pkg/app/app.go:380 #: ./cli/app/env.go:102 ./pkg/app/app.go:380
#, c-format #, c-format
msgid "%s already exists?" msgid "%s already exists?"
msgstr "" msgstr ""
@ -341,7 +349,7 @@ msgstr ""
msgid "%s is not an upgrade for %s?" msgid "%s is not an upgrade for %s?"
msgstr "" msgstr ""
#: ./cli/app/logs.go:65 ./cli/app/ps.go:62 ./cli/app/restart.go:100 ./cli/app/services.go:55 ./cli/app/undeploy.go:65 ./cli/app/upgrade.go:447 #: ./cli/app/env.go:142 ./cli/app/logs.go:65 ./cli/app/ps.go:62 ./cli/app/restart.go:100 ./cli/app/services.go:55 ./cli/app/undeploy.go:66 ./cli/app/upgrade.go:447
#, c-format #, c-format
msgid "%s is not deployed?" msgid "%s is not deployed?"
msgstr "" msgstr ""
@ -356,6 +364,11 @@ msgstr ""
msgid "%s is still deployed. Run \"abra app undeploy %s\"" msgid "%s is still deployed. Run \"abra app undeploy %s\""
msgstr "" msgstr ""
#: ./cli/app/env.go:128
#, c-format
msgid "%s missing context, run \"abra server add %s\"?"
msgstr ""
#: ./cli/app/deploy.go:182 ./cli/app/upgrade.go:208 #: ./cli/app/deploy.go:182 ./cli/app/upgrade.go:208
#, c-format #, c-format
msgid "%s missing from %s.env" msgid "%s missing from %s.env"
@ -421,6 +434,11 @@ msgstr ""
msgid "%s successfully added" msgid "%s successfully added"
msgstr "" msgstr ""
#: ./cli/app/env.go:297
#, c-format
msgid "%s successfully created"
msgstr ""
#: ./cli/app/secret.go:254 #: ./cli/app/secret.go:254
#, c-format #, c-format
msgid "%s successfully stored on server" msgid "%s successfully stored on server"
@ -794,7 +812,7 @@ msgid "Downloads a backup.tar.gz to the current working directory.\n"
"\"backupbot.backup.path\" labels." "\"backupbot.backup.path\" labels."
msgstr "" msgstr ""
#: ./cli/app/env.go:48 #: ./cli/app/env.go:70
msgid "ENV OVERVIEW" msgid "ENV OVERVIEW"
msgstr "" msgstr ""
@ -939,6 +957,11 @@ msgstr ""
msgid "Lint a recipe" msgid "Lint a recipe"
msgstr "" msgstr ""
#. translators: Short description for `app env list` command
#: ./cli/app/env.go:46
msgid "List all app environment values"
msgstr ""
#. translators: Short description for `app cmd list` command #. translators: Short description for `app cmd list` command
#: ./cli/app/cmd.go:210 #: ./cli/app/cmd.go:210
msgid "List all available commands" msgid "List all available commands"
@ -993,6 +1016,11 @@ msgstr ""
msgid "Manage app backups" msgid "Manage app backups"
msgstr "" msgstr ""
#. translators: Short description for `app env` command group
#: ./cli/app/env.go:310
msgid "Manage app environment values"
msgstr ""
#. translators: Short description for `app secret` command group #. translators: Short description for `app secret` command group
#: ./cli/app/secret.go:537 #: ./cli/app/secret.go:537
msgid "Manage app secrets" msgid "Manage app secrets"
@ -1099,6 +1127,18 @@ msgid "Prunes unused containers, networks, and dangling images.\n"
"app. This can result in unwanted data loss if not used carefully." "app. This can result in unwanted data loss if not used carefully."
msgstr "" msgstr ""
#. translators: Short description for `app env pull` command
#: ./cli/app/env.go:80
msgid "Pull app environment values from a deployed app"
msgstr ""
#: ./cli/app/env.go:81
msgid "Pull app environment values from a deploymed app.\n"
"\n"
"A convenient command for when you've lost your app environment file or want to\n"
"synchronize your local app environment values with what is deployed live."
msgstr ""
#: ./pkg/lint/recipe.go:110 #: ./pkg/lint/recipe.go:110
msgid "README.md metadata filled in" msgid "README.md metadata filled in"
msgstr "" msgstr ""
@ -1268,11 +1308,6 @@ msgstr ""
msgid "Select recipe" msgid "Select recipe"
msgstr "" msgstr ""
#. translators: Short description for `app env` command
#: ./cli/app/env.go:24
msgid "Show app .env values"
msgstr ""
#. translators: Short description for `app labels` command #. translators: Short description for `app labels` command
#: ./cli/app/labels.go:32 #: ./cli/app/labels.go:32
msgid "Show deployment labels" msgid "Show deployment labels"
@ -1387,7 +1422,7 @@ msgid "This command rolls an app back to a previous version.\n"
"beforehand. See \"abra app backup\" for more." "beforehand. See \"abra app backup\" for more."
msgstr "" msgstr ""
#: ./cli/app/undeploy.go:31 #: ./cli/app/undeploy.go:32
msgid "This does not destroy any application data.\n" msgid "This does not destroy any application data.\n"
"\n" "\n"
"However, you should remain vigilant, as your swarm installation will consider\n" "However, you should remain vigilant, as your swarm installation will consider\n"
@ -1450,6 +1485,10 @@ msgstr ""
msgid "UPGRADE" msgid "UPGRADE"
msgstr "" msgstr ""
#: ./cli/app/undeploy.go:31
msgid "Undeploy a deployed app"
msgstr ""
#: ./cli/recipe/upgrade.go:50 #: ./cli/recipe/upgrade.go:50
msgid "Upgrade a given <recipe> configuration.\n" msgid "Upgrade a given <recipe> configuration.\n"
"\n" "\n"
@ -2029,7 +2068,7 @@ msgstr ""
msgid "check <domain> [flags]" msgid "check <domain> [flags]"
msgstr "" msgstr ""
#: ./cli/app/deploy.go:94 ./cli/app/undeploy.go:57 ./cli/app/upgrade.go:439 #: ./cli/app/deploy.go:94 ./cli/app/undeploy.go:58 ./cli/app/upgrade.go:439
#, c-format #, c-format
msgid "checking whether %s is already deployed" msgid "checking whether %s is already deployed"
msgstr "" msgstr ""
@ -2180,7 +2219,7 @@ msgstr ""
msgid "considering %s config(s) for tag update" msgid "considering %s config(s) for tag update"
msgstr "" msgstr ""
#: ./cli/app/undeploy.go:140 ./cli/server/prune.go:53 #: ./cli/app/undeploy.go:141 ./cli/server/prune.go:53
#, c-format #, c-format
msgid "containers pruned: %d; space reclaimed: %s" msgid "containers pruned: %d; space reclaimed: %s"
msgstr "" msgstr ""
@ -2567,9 +2606,9 @@ msgstr ""
msgid "duplicate secret target for %s not allowed" msgid "duplicate secret target for %s not allowed"
msgstr "" msgstr ""
#. translators: `abra app env` aliases. use a comma separated list of aliases with #. translators: `abra app env` aliases. use a comma separated list of aliases
#. no spaces in between #. with no spaces in between
#: ./cli/app/env.go:17 ./cli/recipe/lint.go:145 ./cli/recipe/new.go:131 #: ./cli/app/env.go:31 ./cli/recipe/lint.go:145 ./cli/recipe/new.go:131
msgid "e" msgid "e"
msgstr "" msgstr ""
@ -2608,9 +2647,9 @@ msgstr ""
msgid "enter / return to confirm, choose 'skip' to not upgrade this tag, vim mode is enabled" msgid "enter / return to confirm, choose 'skip' to not upgrade this tag, vim mode is enabled"
msgstr "" msgstr ""
#. translators: `app env` command #. translators: `app env` command group
#: ./cli/app/env.go:21 #: ./cli/app/env.go:307
msgid "env <domain> [flags]" msgid "env [cmd] [args] [flags]"
msgstr "" msgstr ""
#: ./pkg/app/app.go:248 #: ./pkg/app/app.go:248
@ -2687,7 +2726,7 @@ msgstr ""
#. translators: `abra recipe fetch` aliases. use a comma separated list of aliases #. translators: `abra recipe fetch` aliases. use a comma separated list of aliases
#. with no spaces in between #. with no spaces in between
#: ./cli/app/deploy.go:401 ./cli/app/remove.go:163 ./cli/app/rollback.go:349 ./cli/app/secret.go:593 ./cli/app/upgrade.go:459 ./cli/app/volume.go:217 ./cli/recipe/fetch.go:20 ./cli/recipe/fetch.go:138 #: ./cli/app/deploy.go:401 ./cli/app/env.go:321 ./cli/app/remove.go:163 ./cli/app/rollback.go:349 ./cli/app/secret.go:593 ./cli/app/upgrade.go:459 ./cli/app/volume.go:217 ./cli/recipe/fetch.go:20 ./cli/recipe/fetch.go:138
msgid "f" msgid "f"
msgstr "" msgstr ""
@ -2913,7 +2952,12 @@ msgstr ""
msgid "filter by recipe" msgid "filter by recipe"
msgstr "" msgstr ""
#: ./cli/app/deploy.go:400 ./cli/app/remove.go:162 ./cli/app/rollback.go:348 ./cli/app/upgrade.go:458 ./cli/app/volume.go:216 ./cli/recipe/fetch.go:137 #: ./cli/app/env.go:225
#, c-format
msgid "final merged env values for %s are: %s"
msgstr ""
#: ./cli/app/deploy.go:400 ./cli/app/env.go:320 ./cli/app/remove.go:162 ./cli/app/rollback.go:348 ./cli/app/upgrade.go:458 ./cli/app/volume.go:216 ./cli/recipe/fetch.go:137
msgid "force" msgid "force"
msgstr "" msgstr ""
@ -3131,7 +3175,7 @@ msgstr ""
msgid "ignore uncommitted recipes changes" msgid "ignore uncommitted recipes changes"
msgstr "" msgstr ""
#: ./cli/app/undeploy.go:155 ./cli/server/prune.go:74 #: ./cli/app/undeploy.go:156 ./cli/server/prune.go:74
#, c-format #, c-format
msgid "images pruned: %d; space reclaimed: %s" msgid "images pruned: %d; space reclaimed: %s"
msgstr "" msgstr ""
@ -3251,6 +3295,21 @@ msgstr ""
msgid "insert <domain> <secret> <version> [<data>] [flags]" msgid "insert <domain> <secret> <version> [<data>] [flags]"
msgstr "" msgstr ""
#: ./cli/app/env.go:286
#, c-format
msgid "inserting %s=%s (no quotes)"
msgstr ""
#: ./cli/app/env.go:279
#, c-format
msgid "inserting %s='%s' (single quotes)"
msgstr ""
#: ./cli/app/env.go:272
#, c-format
msgid "inserting %s=\"%s\" (double quotes)"
msgstr ""
#: ./cli/upgrade.go:62 #: ./cli/upgrade.go:62
msgid "install release candidate (may contain bugs)" msgid "install release candidate (may contain bugs)"
msgstr "" msgstr ""
@ -3314,6 +3373,12 @@ msgstr ""
msgid "l" msgid "l"
msgstr "" msgstr ""
#. translators: `abra app env list` aliases. use a comma separated list of
#. aliases with no spaces in between
#: ./cli/app/env.go:35
msgid "l,ls"
msgstr ""
#. translators: `app labels` command #. translators: `app labels` command
#: ./cli/app/labels.go:29 #: ./cli/app/labels.go:29
msgid "labels <domain> [flags]" msgid "labels <domain> [flags]"
@ -3361,8 +3426,9 @@ msgstr ""
#. translators: `app backup list` command #. translators: `app backup list` command
#. translators: `app cmd list` command #. translators: `app cmd list` command
#. translators: `app env list` command
#. translators: `app volume list` command #. translators: `app volume list` command
#: ./cli/app/backup.go:21 ./cli/app/cmd.go:207 ./cli/app/volume.go:25 #: ./cli/app/backup.go:21 ./cli/app/cmd.go:207 ./cli/app/env.go:43 ./cli/app/volume.go:25
msgid "list <domain> [flags]" msgid "list <domain> [flags]"
msgstr "" msgstr ""
@ -3474,6 +3540,11 @@ msgstr ""
msgid "man [flags]" msgid "man [flags]"
msgstr "" msgstr ""
#: ./cli/app/env.go:300
#, c-format
msgid "manual update required: COMPOSE_FILE=\"%s\""
msgstr ""
#: ./cli/app/move.go:200 #: ./cli/app/move.go:200
#, c-format #, c-format
msgid "migrating app config from %s to %s" msgid "migrating app config from %s to %s"
@ -3553,7 +3624,7 @@ msgstr ""
msgid "network %q is declared as external, but it is not in the right scope: %q instead of \"swarm\"" msgid "network %q is declared as external, but it is not in the right scope: %q instead of \"swarm\""
msgstr "" msgstr ""
#: ./cli/app/undeploy.go:147 ./cli/server/prune.go:60 #: ./cli/app/undeploy.go:148 ./cli/server/prune.go:60
#, c-format #, c-format
msgid "networks pruned: %d" msgid "networks pruned: %d"
msgstr "" msgstr ""
@ -3744,6 +3815,11 @@ msgstr ""
msgid "no unstable tags" msgid "no unstable tags"
msgstr "" msgstr ""
#: ./cli/app/env.go:161
#, c-format
msgid "no value attached to %s"
msgstr ""
#: ./cli/internal/recipe.go:72 ./cli/internal/recipe.go:87 #: ./cli/internal/recipe.go:72 ./cli/internal/recipe.go:87
msgid "no version bump type specififed?" msgid "no version bump type specififed?"
msgstr "" msgstr ""
@ -3838,7 +3914,7 @@ msgstr ""
#. with no spaces in between #. with no spaces in between
#. translators: `abra server prune` aliases. use a comma separated list of #. translators: `abra server prune` aliases. use a comma separated list of
#. aliases with no spaces in between #. aliases with no spaces in between
#: ./cli/app/backup.go:295 ./cli/app/new.go:381 ./cli/app/ps.go:29 ./cli/app/secret.go:561 ./cli/app/secret.go:585 ./cli/app/secret.go:625 ./cli/app/undeploy.go:168 ./cli/catalogue/catalogue.go:294 ./cli/recipe/list.go:112 ./cli/recipe/release.go:681 ./cli/server/prune.go:18 #: ./cli/app/backup.go:295 ./cli/app/new.go:381 ./cli/app/ps.go:29 ./cli/app/secret.go:561 ./cli/app/secret.go:585 ./cli/app/secret.go:625 ./cli/app/undeploy.go:169 ./cli/catalogue/catalogue.go:294 ./cli/recipe/list.go:112 ./cli/recipe/release.go:681 ./cli/server/prune.go:18
msgid "p" msgid "p"
msgstr "" msgstr ""
@ -3897,10 +3973,16 @@ msgstr ""
msgid "pattern" msgid "pattern"
msgstr "" msgstr ""
#: ./cli/app/deploy.go:403 ./cli/app/remove.go:165 ./cli/app/rollback.go:351 ./cli/app/upgrade.go:461 ./cli/app/volume.go:219 #: ./cli/app/deploy.go:403 ./cli/app/env.go:323 ./cli/app/remove.go:165 ./cli/app/rollback.go:351 ./cli/app/upgrade.go:461 ./cli/app/volume.go:219
msgid "perform action without further prompt" msgid "perform action without further prompt"
msgstr "" msgstr ""
#. translators: `abra app env pull` aliases. use a comma separated list of
#. aliases with no spaces in between
#: ./cli/app/env.go:39
msgid "pl,p"
msgstr ""
#: ./cli/recipe/release.go:634 #: ./cli/recipe/release.go:634
#, c-format #, c-format
msgid "please fix your synced label for %s and re-run this command" msgid "please fix your synced label for %s and re-run this command"
@ -3960,7 +4042,7 @@ msgstr ""
msgid "proposed images: %v" msgid "proposed images: %v"
msgstr "" msgstr ""
#: ./cli/app/undeploy.go:167 #: ./cli/app/undeploy.go:168
msgid "prune" msgid "prune"
msgstr "" msgstr ""
@ -3969,7 +4051,7 @@ msgstr ""
msgid "prune <server> [flags]" msgid "prune <server> [flags]"
msgstr "" msgstr ""
#: ./cli/app/undeploy.go:170 #: ./cli/app/undeploy.go:171
msgid "prune unused containers, networks, and dangling images" msgid "prune unused containers, networks, and dangling images"
msgstr "" msgstr ""
@ -3994,6 +4076,16 @@ msgstr ""
msgid "publish new release?" msgid "publish new release?"
msgstr "" msgstr ""
#. translators: `app pull` command
#: ./cli/app/env.go:77
msgid "pull <domain> [flags]"
msgstr ""
#: ./cli/app/env.go:169
#, c-format
msgid "pulled env values from %s deployment: %s"
msgstr ""
#: ./pkg/app/app.go:429 #: ./pkg/app/app.go:429
msgid "querying remote servers..." msgid "querying remote servers..."
msgstr "" msgstr ""
@ -4340,6 +4432,11 @@ msgstr ""
msgid "retrieved app statuses: %s" msgid "retrieved app statuses: %s"
msgstr "" msgstr ""
#: ./cli/app/env.go:215
#, c-format
msgid "retrieved env values from .env.sample of %s: %s"
msgstr ""
#: ./cli/recipe/version.go:46 #: ./cli/recipe/version.go:46
msgid "retrieved versions from local recipe repository" msgid "retrieved versions from local recipe repository"
msgstr "" msgstr ""
@ -4460,7 +4557,7 @@ msgstr ""
#. aliases with no spaces in between #. aliases with no spaces in between
#. translators: `abra server` aliases. use a comma separated list of aliases #. translators: `abra server` aliases. use a comma separated list of aliases
#. with no spaces in between #. with no spaces in between
#: ./cli/app/backup.go:198 ./cli/app/backup.go:263 ./cli/app/backup.go:287 ./cli/app/list.go:323 ./cli/app/logs.go:101 ./cli/app/new.go:358 ./cli/app/restore.go:114 ./cli/app/secret.go:535 ./cli/catalogue/catalogue.go:27 ./cli/catalogue/catalogue.go:310 ./cli/recipe/fetch.go:130 ./cli/recipe/sync.go:24 ./cli/server/server.go:12 #: ./cli/app/backup.go:198 ./cli/app/backup.go:263 ./cli/app/backup.go:287 ./cli/app/env.go:329 ./cli/app/list.go:323 ./cli/app/logs.go:101 ./cli/app/new.go:358 ./cli/app/restore.go:114 ./cli/app/secret.go:535 ./cli/catalogue/catalogue.go:27 ./cli/catalogue/catalogue.go:310 ./cli/recipe/fetch.go:130 ./cli/recipe/sync.go:24 ./cli/server/server.go:12
msgid "s" msgid "s"
msgstr "" msgstr ""
@ -4527,7 +4624,7 @@ msgid "secrets are %s shown again, please save them %s"
msgstr "" msgstr ""
#. translators: `abra server` command for autocompletion #. translators: `abra server` command for autocompletion
#: ./cli/app/list.go:322 ./cli/app/list.go:329 ./cli/app/new.go:357 ./cli/app/new.go:364 ./cli/run.go:101 #: ./cli/app/env.go:328 ./cli/app/env.go:335 ./cli/app/list.go:322 ./cli/app/list.go:329 ./cli/app/new.go:357 ./cli/app/new.go:364 ./cli/run.go:101
msgid "server" msgid "server"
msgstr "" msgstr ""
@ -4541,6 +4638,10 @@ msgstr ""
msgid "server [cmd] [args] [flags]" msgid "server [cmd] [args] [flags]"
msgstr "" msgstr ""
#: ./cli/app/env.go:331
msgid "server associated with deployed app"
msgstr ""
#: ./cli/server/add.go:191 #: ./cli/server/add.go:191
#, c-format #, c-format
msgid "server dir for %s already created" msgid "server dir for %s already created"
@ -5029,6 +5130,16 @@ msgstr ""
msgid "unable to delete tag %s: %s" msgid "unable to delete tag %s: %s"
msgstr "" msgstr ""
#: ./cli/app/env.go:187
#, c-format
msgid "unable to determine recipe type from %s, env: %v"
msgstr ""
#: ./cli/app/env.go:106
#, c-format
msgid "unable to determine server of app %s, please pass --server/-s"
msgstr ""
#: ./cli/recipe/upgrade.go:253 #: ./cli/recipe/upgrade.go:253
#, c-format #, c-format
msgid "unable to determine versioning semantics of %s, listing all tags" msgid "unable to determine versioning semantics of %s, listing all tags"
@ -5059,6 +5170,11 @@ msgstr ""
msgid "unable to git pull in %s: %s" msgid "unable to git pull in %s: %s"
msgstr "" msgstr ""
#: ./cli/app/env.go:154
#, c-format
msgid "unable to inspect container for %s: %s"
msgstr ""
#: ./pkg/lint/recipe.go:496 #: ./pkg/lint/recipe.go:496
#, c-format #, c-format
msgid "unable to list local tags for %s" msgid "unable to list local tags for %s"
@ -5068,6 +5184,11 @@ msgstr ""
msgid "unable to locate git command, cannot output diff" msgid "unable to locate git command, cannot output diff"
msgstr "" msgstr ""
#: ./cli/app/env.go:117
#, c-format
msgid "unable to look up server context for %s: %s"
msgstr ""
#: ./cli/recipe/fetch.go:77 ./pkg/git/read.go:26 ./pkg/lint/recipe.go:491 ./pkg/recipe/git.go:236 #: ./cli/recipe/fetch.go:77 ./pkg/git/read.go:26 ./pkg/lint/recipe.go:491 ./pkg/recipe/git.go:236
#, c-format #, c-format
msgid "unable to open %s: %s" msgid "unable to open %s: %s"
@ -5123,6 +5244,11 @@ msgstr ""
msgid "unable to query status of %s: %s" msgid "unable to query status of %s: %s"
msgstr "" msgstr ""
#: ./cli/app/env.go:239
#, c-format
msgid "unable to read new env %s: %s"
msgstr ""
#: ./pkg/recipe/git.go:241 #: ./pkg/recipe/git.go:241
#, c-format #, c-format
msgid "unable to read remotes in %s: %s" msgid "unable to read remotes in %s: %s"
@ -5173,6 +5299,11 @@ msgstr ""
msgid "unable to retrieve %s resources on %s: %s" msgid "unable to retrieve %s resources on %s: %s"
msgstr "" msgstr ""
#: ./cli/app/env.go:149
#, c-format
msgid "unable to retrieve container for %s: %s"
msgstr ""
#: ./cli/app/list.go:153 #: ./cli/app/list.go:153
#, c-format #, c-format
msgid "unable to retrieve tags for %s: %s" msgid "unable to retrieve tags for %s: %s"
@ -5203,6 +5334,16 @@ msgstr ""
msgid "unable to validate recipe: %s" msgid "unable to validate recipe: %s"
msgstr "" msgstr ""
#: ./cli/app/env.go:234 ./cli/app/env.go:294
#, c-format
msgid "unable to write new env %s: %s"
msgstr ""
#: ./cli/app/env.go:260 ./cli/app/env.go:266
#, c-format
msgid "uncommenting %s"
msgstr ""
#: ./pkg/upstream/convert/service.go:462 #: ./pkg/upstream/convert/service.go:462
#, c-format #, c-format
msgid "undefined config %q" msgid "undefined config %q"
@ -5228,7 +5369,7 @@ msgstr ""
msgid "undeploy <domain> [flags]" msgid "undeploy <domain> [flags]"
msgstr "" msgstr ""
#: ./cli/app/undeploy.go:116 #: ./cli/app/undeploy.go:117
msgid "undeploy succeeded 🟢" msgid "undeploy succeeded 🟢"
msgstr "" msgstr ""
@ -5284,6 +5425,11 @@ msgstr ""
msgid "unknown restart policy: %s" msgid "unknown restart policy: %s"
msgstr "" msgstr ""
#: ./cli/app/env.go:111
#, c-format
msgid "unknown server %s, run \"abra server add %s\"?"
msgstr ""
#: ./pkg/client/client.go:51 #: ./pkg/client/client.go:51
#, c-format #, c-format
msgid "unknown server, run \"abra server add %s\"?" msgid "unknown server, run \"abra server add %s\"?"
@ -5584,7 +5730,7 @@ msgstr ""
msgid "writer: %v, " msgid "writer: %v, "
msgstr "" msgstr ""
#: ./cli/app/deploy.go:275 ./cli/app/new.go:241 ./cli/app/rollback.go:252 ./cli/app/undeploy.go:119 ./cli/app/upgrade.go:298 #: ./cli/app/deploy.go:275 ./cli/app/new.go:241 ./cli/app/rollback.go:252 ./cli/app/undeploy.go:120 ./cli/app/upgrade.go:298
#, c-format #, c-format
msgid "writing recipe version failed: %s" msgid "writing recipe version failed: %s"
msgstr "" msgstr ""

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -28,17 +28,17 @@ teardown(){
} }
@test "validate app argument" { @test "validate app argument" {
run $ABRA app env run $ABRA app env list
assert_failure assert_failure
run $ABRA app env DOESNTEXIST run $ABRA app env list DOESNTEXIST
assert_failure assert_failure
} }
@test "show env version" { @test "show env version" {
latestRelease=$(_latest_release) latestRelease=$(_latest_release)
run $ABRA app env "$TEST_APP_DOMAIN" run $ABRA app env list "$TEST_APP_DOMAIN"
assert_success assert_success
assert_output --partial "$latestRelease" assert_output --partial "$latestRelease"
} }
@ -48,7 +48,7 @@ teardown(){
assert_success assert_success
assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo" assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo"
run $ABRA app env "$TEST_APP_DOMAIN" run $ABRA app env list "$TEST_APP_DOMAIN"
assert_success assert_success
assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo" assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo"
@ -57,3 +57,40 @@ teardown(){
run rm -rf "$ABRA_DIR/recipes/$TEST_RECIPE/foo" run rm -rf "$ABRA_DIR/recipes/$TEST_RECIPE/foo"
assert_not_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo" assert_not_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo"
} }
@test "app env pull explodes when no deployed app" {
run $ABRA app env pull "$TEST_APP_DOMAIN" -s "$TEST_SERVER"
assert_failure
}
# bats test_tags=slow
@test "app env pull recreates app env when missing" {
run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input
assert_success
run rm -rf "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
assert_success
assert_not_exists "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
run $ABRA app env pull "$TEST_APP_DOMAIN" -s "$TEST_SERVER"
assert_success
assert_exists "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
}
# bats test_tags=slow
@test "app env pull recreates correct version" {
run $ABRA app deploy "$TEST_APP_DOMAIN" "0.1.0+1.20.0" --no-input
assert_success
run rm -rf "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
assert_success
assert_not_exists "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
run $ABRA app env pull "$TEST_APP_DOMAIN" -s "$TEST_SERVER"
assert_success
assert_exists "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
run grep -q "TYPE=$TEST_RECIPE:0.1.0+1.20.0" \
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
assert_success
}