forked from toolshed/abra
Compare commits
16 Commits
fix-crash-
...
local-reci
| Author | SHA1 | Date | |
|---|---|---|---|
| 8cbf118f66 | |||
| cc8703310c | |||
|
fcd5bd863d
|
|||
|
e6af2da9dd
|
|||
| 4b688825e0 | |||
| b0cf2a1f8e | |||
| 6b7020d457 | |||
| efdac610bd | |||
| cd6021f116 | |||
| ee8de8ef5c | |||
|
e5a653c002
|
|||
|
2cca04de90
|
|||
| f2f79e2df8 | |||
|
dd83741a9f
|
|||
|
dc2cd85d91
|
|||
|
96e59cf196
|
@ -152,7 +152,6 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
appPkg.ExposeAllEnv(stackName, compose, app.Env)
|
|
||||||
appPkg.SetRecipeLabel(compose, stackName, app.Recipe.Name)
|
appPkg.SetRecipeLabel(compose, stackName, app.Recipe.Name)
|
||||||
appPkg.SetChaosLabel(compose, stackName, internal.Chaos)
|
appPkg.SetChaosLabel(compose, stackName, internal.Chaos)
|
||||||
if internal.Chaos {
|
if internal.Chaos {
|
||||||
@ -171,6 +170,9 @@ checkout as-is. Recipe commit hashes are also supported as values for
|
|||||||
}
|
}
|
||||||
appPkg.SetVersionLabel(compose, stackName, versionLabel)
|
appPkg.SetVersionLabel(compose, stackName, versionLabel)
|
||||||
|
|
||||||
|
newRecipeWithDeployVersion := fmt.Sprintf("%s:%s", app.Recipe.Name, toDeployVersion)
|
||||||
|
appPkg.ExposeAllEnv(stackName, compose, app.Env, newRecipeWithDeployVersion)
|
||||||
|
|
||||||
envVars, err := appPkg.CheckEnv(app)
|
envVars, err := appPkg.CheckEnv(app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|||||||
311
cli/app/env.go
311
cli/app/env.go
@ -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,274 @@ 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
|
||||||
|
if server == "default" {
|
||||||
|
contextCreated = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, context := range contexts {
|
||||||
|
if context.Name == server {
|
||||||
|
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()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@ -128,6 +128,10 @@ Use "--dry-run/-r" to see which secrets and volumes will be moved.`),
|
|||||||
secretName := strings.Join(sname[:len(sname)-1], "_")
|
secretName := strings.Join(sname[:len(sname)-1], "_")
|
||||||
data := resources.Secrets[secretName]
|
data := resources.Secrets[secretName]
|
||||||
if err := client.StoreSecret(newServerClient, s.Spec.Name, data); err != nil {
|
if err := client.StoreSecret(newServerClient, s.Spec.Name, data); err != nil {
|
||||||
|
if strings.Contains(err.Error(), "already exists") {
|
||||||
|
log.Info(i18n.G("skipping secret (because it already exists) on %s: %s", s.Spec.Name, newServer))
|
||||||
|
continue
|
||||||
|
}
|
||||||
log.Fatal(i18n.G("failed to store secret on %s: %s", err, newServer))
|
log.Fatal(i18n.G("failed to store secret on %s: %s", err, newServer))
|
||||||
}
|
}
|
||||||
log.Info(i18n.G("created secret on %s: %s", s.Spec.Name, newServer))
|
log.Info(i18n.G("created secret on %s: %s", s.Spec.Name, newServer))
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
appPkg "coopcloud.tech/abra/pkg/app"
|
appPkg "coopcloud.tech/abra/pkg/app"
|
||||||
@ -177,7 +178,9 @@ beforehand. See "abra app backup" for more.`),
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
appPkg.ExposeAllEnv(stackName, compose, app.Env)
|
newRecipeWithDowngradeVersion := fmt.Sprintf("%s:%s", app.Recipe.Name, chosenDowngrade)
|
||||||
|
appPkg.ExposeAllEnv(stackName, compose, app.Env, newRecipeWithDowngradeVersion)
|
||||||
|
|
||||||
appPkg.SetRecipeLabel(compose, stackName, app.Recipe.Name)
|
appPkg.SetRecipeLabel(compose, stackName, app.Recipe.Name)
|
||||||
appPkg.SetChaosLabel(compose, stackName, internal.Chaos)
|
appPkg.SetChaosLabel(compose, stackName, internal.Chaos)
|
||||||
if internal.Chaos {
|
if internal.Chaos {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -190,7 +190,9 @@ beforehand. See "abra app backup" for more.`),
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
appPkg.ExposeAllEnv(stackName, compose, app.Env)
|
newRecipeWithUpgradeVersion := fmt.Sprintf("%s:%s", app.Recipe.Name, chosenUpgrade)
|
||||||
|
appPkg.ExposeAllEnv(stackName, compose, app.Env, newRecipeWithUpgradeVersion)
|
||||||
|
|
||||||
appPkg.SetRecipeLabel(compose, stackName, app.Recipe.Name)
|
appPkg.SetRecipeLabel(compose, stackName, app.Recipe.Name)
|
||||||
appPkg.SetChaosLabel(compose, stackName, internal.Chaos)
|
appPkg.SetChaosLabel(compose, stackName, internal.Chaos)
|
||||||
if internal.Chaos {
|
if internal.Chaos {
|
||||||
|
|||||||
@ -42,8 +42,7 @@ local file system.`),
|
|||||||
ValidArgsFunction: func(
|
ValidArgsFunction: func(
|
||||||
cmd *cobra.Command,
|
cmd *cobra.Command,
|
||||||
args []string,
|
args []string,
|
||||||
toComplete string,
|
toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
) ([]string, cobra.ShellCompDirective) {
|
|
||||||
switch l := len(args); l {
|
switch l := len(args); l {
|
||||||
case 0:
|
case 0:
|
||||||
return autocomplete.RecipeNameComplete()
|
return autocomplete.RecipeNameComplete()
|
||||||
@ -132,16 +131,10 @@ likely to change.
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
latestRelease := "0.0.0+0.0.0"
|
latestRelease := tags[len(tags)-1]
|
||||||
if len(tags) > 0 {
|
|
||||||
latestRelease = tags[len(tags)-1]
|
|
||||||
}
|
|
||||||
changesTable.Headers(i18n.G("SERVICE"), latestRelease, i18n.G("PROPOSED CHANGES"))
|
changesTable.Headers(i18n.G("SERVICE"), latestRelease, i18n.G("PROPOSED CHANGES"))
|
||||||
|
|
||||||
latestRecipeVersion := latestRelease
|
latestRecipeVersion := versions[len(versions)-1]
|
||||||
if len(versions) > 0 {
|
|
||||||
latestRecipeVersion = versions[len(versions)-1]
|
|
||||||
}
|
|
||||||
allRecipeVersions := catl[recipe.Name].Versions
|
allRecipeVersions := catl[recipe.Name].Versions
|
||||||
for _, recipeVersion := range allRecipeVersions {
|
for _, recipeVersion := range allRecipeVersions {
|
||||||
if serviceVersions, ok := recipeVersion[latestRecipeVersion]; ok {
|
if serviceVersions, ok := recipeVersion[latestRecipeVersion]; ok {
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -502,7 +502,12 @@ func GetAppComposeConfig(recipe string, opts stack.Deploy, appEnv envfile.AppEnv
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ExposeAllEnv exposes all env variables to the app container
|
// ExposeAllEnv exposes all env variables to the app container
|
||||||
func ExposeAllEnv(stackName string, compose *composetypes.Config, appEnv envfile.AppEnv) {
|
func ExposeAllEnv(
|
||||||
|
stackName string,
|
||||||
|
compose *composetypes.Config,
|
||||||
|
appEnv envfile.AppEnv,
|
||||||
|
toDeployVersion string,
|
||||||
|
) {
|
||||||
for _, service := range compose.Services {
|
for _, service := range compose.Services {
|
||||||
if service.Name == "app" {
|
if service.Name == "app" {
|
||||||
log.Debug(i18n.G("adding env vars to %s service config", stackName))
|
log.Debug(i18n.G("adding env vars to %s service config", stackName))
|
||||||
@ -510,6 +515,11 @@ func ExposeAllEnv(stackName string, compose *composetypes.Config, appEnv envfile
|
|||||||
_, exists := service.Environment[k]
|
_, exists := service.Environment[k]
|
||||||
if !exists {
|
if !exists {
|
||||||
value := v
|
value := v
|
||||||
|
if k == "TYPE" || k == "RECIPE" {
|
||||||
|
// NOTE(d1): don't use the wrong version from the app env
|
||||||
|
// since we are deploying a new version
|
||||||
|
value = toDeployVersion
|
||||||
|
}
|
||||||
service.Environment[k] = &value
|
service.Environment[k] = &value
|
||||||
log.Debug(i18n.G("%s: %s: %s", stackName, k, value))
|
log.Debug(i18n.G("%s: %s: %s", stackName, k, value))
|
||||||
}
|
}
|
||||||
@ -624,6 +634,10 @@ func (a App) WipeRecipeVersion() error {
|
|||||||
|
|
||||||
// WriteRecipeVersion writes the recipe version to the app .env file.
|
// WriteRecipeVersion writes the recipe version to the app .env file.
|
||||||
func (a App) WriteRecipeVersion(version string, dryRun bool) error {
|
func (a App) WriteRecipeVersion(version string, dryRun bool) error {
|
||||||
|
if a.Recipe.Local {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
file, err := os.Open(a.Path)
|
file, err := os.Open(a.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@ -44,11 +44,20 @@ func New(serverName string, opts ...Opt) (*client.Client, error) {
|
|||||||
ctx, err := GetContext(serverName)
|
ctx, err := GetContext(serverName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serverDir := path.Join(config.SERVERS_DIR, serverName)
|
serverDir := path.Join(config.SERVERS_DIR, serverName)
|
||||||
if _, err := os.Stat(serverDir); err == nil {
|
if _, err := os.Stat(serverDir); err != nil {
|
||||||
return nil, errors.New(i18n.G("server missing context, run \"abra server add %s\"?", serverName))
|
return nil, errors.New(i18n.G("server missing, run \"abra server add %s\"?", serverName))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(i18n.G("unknown server, run \"abra server add %s\"?", serverName))
|
// NOTE(p4u1): when the docker context does not exist but the server folder
|
||||||
|
// is there, let's create a new docker context.
|
||||||
|
if err = CreateContext(serverName); err != nil {
|
||||||
|
return nil, errors.New(i18n.G("server missing context, context creation failed: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, err = GetContext(serverName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New(i18n.G("server missing context, run \"abra server add %s\"?", serverName))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxEndpoint, err := contextPkg.GetContextEndpoint(ctx)
|
ctxEndpoint, err := contextPkg.GetContextEndpoint(ctx)
|
||||||
|
|||||||
@ -282,11 +282,7 @@ func GatherImagesForDeploy(cl *dockerClient.Client, app appPkg.App, compose *com
|
|||||||
}
|
}
|
||||||
|
|
||||||
imageBaseName := reference.Path(imageParsed)
|
imageBaseName := reference.Path(imageParsed)
|
||||||
namedTag, ok := imageParsed.(reference.NamedTagged)
|
imageTag := imageParsed.(reference.NamedTagged).Tag()
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
imageTag := namedTag.Tag()
|
|
||||||
|
|
||||||
existingImageVersion, ok := newImages[imageBaseName]
|
existingImageVersion, ok := newImages[imageBaseName]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -486,6 +486,10 @@ func LintSecretLengths(recipe recipe.Recipe) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LintValidTags(recipe recipe.Recipe) (bool, error) {
|
func LintValidTags(recipe recipe.Recipe) (bool, error) {
|
||||||
|
if recipe.Local {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
repo, err := git.PlainOpen(recipe.Dir)
|
repo, err := git.PlainOpen(recipe.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.New(i18n.G("unable to open %s: %s", recipe.Dir, err))
|
return false, errors.New(i18n.G("unable to open %s: %s", recipe.Dir, err))
|
||||||
|
|||||||
@ -28,6 +28,10 @@ type EnsureContext struct {
|
|||||||
// Ensure makes sure the recipe exists, is up to date and has the specific
|
// Ensure makes sure the recipe exists, is up to date and has the specific
|
||||||
// version checked out.
|
// version checked out.
|
||||||
func (r Recipe) Ensure(ctx EnsureContext) error {
|
func (r Recipe) Ensure(ctx EnsureContext) error {
|
||||||
|
if r.Local {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := r.EnsureExists(); err != nil {
|
if err := r.EnsureExists(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -68,6 +72,10 @@ func (r Recipe) Ensure(ctx EnsureContext) error {
|
|||||||
|
|
||||||
// EnsureExists ensures that the recipe is locally cloned
|
// EnsureExists ensures that the recipe is locally cloned
|
||||||
func (r Recipe) EnsureExists() error {
|
func (r Recipe) EnsureExists() error {
|
||||||
|
if r.Local {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(r.Dir); os.IsNotExist(err) {
|
if _, err := os.Stat(r.Dir); os.IsNotExist(err) {
|
||||||
if err := gitPkg.Clone(r.Dir, r.GitURL); err != nil {
|
if err := gitPkg.Clone(r.Dir, r.GitURL); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -83,6 +91,10 @@ func (r Recipe) EnsureExists() error {
|
|||||||
|
|
||||||
// IsChaosCommit determines if a version sttring is a chaos commit or not.
|
// IsChaosCommit determines if a version sttring is a chaos commit or not.
|
||||||
func (r Recipe) IsChaosCommit(version string) (bool, error) {
|
func (r Recipe) IsChaosCommit(version string) (bool, error) {
|
||||||
|
if r.Local {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
isChaosCommit := false
|
isChaosCommit := false
|
||||||
|
|
||||||
if err := gitPkg.EnsureGitRepo(r.Dir); err != nil {
|
if err := gitPkg.EnsureGitRepo(r.Dir); err != nil {
|
||||||
@ -118,6 +130,10 @@ func (r Recipe) IsChaosCommit(version string) (bool, error) {
|
|||||||
|
|
||||||
// EnsureVersion checks whether a specific version exists for a recipe.
|
// EnsureVersion checks whether a specific version exists for a recipe.
|
||||||
func (r Recipe) EnsureVersion(version string) (bool, error) {
|
func (r Recipe) EnsureVersion(version string) (bool, error) {
|
||||||
|
if r.Local {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
isChaosCommit := false
|
isChaosCommit := false
|
||||||
|
|
||||||
if err := gitPkg.EnsureGitRepo(r.Dir); err != nil {
|
if err := gitPkg.EnsureGitRepo(r.Dir); err != nil {
|
||||||
@ -182,6 +198,10 @@ func (r Recipe) EnsureVersion(version string) (bool, error) {
|
|||||||
|
|
||||||
// EnsureIsClean makes sure that the recipe repository has no unstaged changes.
|
// EnsureIsClean makes sure that the recipe repository has no unstaged changes.
|
||||||
func (r Recipe) EnsureIsClean() error {
|
func (r Recipe) EnsureIsClean() error {
|
||||||
|
if r.Local {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
isClean, err := gitPkg.IsClean(r.Dir)
|
isClean, err := gitPkg.IsClean(r.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(i18n.G("unable to check git clean status in %s: %s", r.Dir, err))
|
return errors.New(i18n.G("unable to check git clean status in %s: %s", r.Dir, err))
|
||||||
@ -196,6 +216,10 @@ func (r Recipe) EnsureIsClean() error {
|
|||||||
|
|
||||||
// EnsureLatest makes sure the latest commit is checked out for the local recipe repository
|
// EnsureLatest makes sure the latest commit is checked out for the local recipe repository
|
||||||
func (r Recipe) EnsureLatest() error {
|
func (r Recipe) EnsureLatest() error {
|
||||||
|
if r.Local {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if err := gitPkg.EnsureGitRepo(r.Dir); err != nil {
|
if err := gitPkg.EnsureGitRepo(r.Dir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -231,6 +255,10 @@ func (r Recipe) EnsureLatest() error {
|
|||||||
|
|
||||||
// EnsureUpToDate ensures that the local repo is synced to the remote
|
// EnsureUpToDate ensures that the local repo is synced to the remote
|
||||||
func (r Recipe) EnsureUpToDate() error {
|
func (r Recipe) EnsureUpToDate() error {
|
||||||
|
if r.Local {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
repo, err := git.PlainOpen(r.Dir)
|
repo, err := git.PlainOpen(r.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(i18n.G("unable to open %s: %s", r.Dir, err))
|
return errors.New(i18n.G("unable to open %s: %s", r.Dir, err))
|
||||||
@ -282,6 +310,10 @@ func (r Recipe) EnsureUpToDate() error {
|
|||||||
|
|
||||||
// IsDirty checks whether a recipe is dirty or not.
|
// IsDirty checks whether a recipe is dirty or not.
|
||||||
func (r *Recipe) IsDirty() (bool, error) {
|
func (r *Recipe) IsDirty() (bool, error) {
|
||||||
|
if r.Local {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
isClean, err := gitPkg.IsClean(r.Dir)
|
isClean, err := gitPkg.IsClean(r.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -292,6 +324,10 @@ func (r *Recipe) IsDirty() (bool, error) {
|
|||||||
|
|
||||||
// ChaosVersion constructs a chaos mode recipe version.
|
// ChaosVersion constructs a chaos mode recipe version.
|
||||||
func (r *Recipe) ChaosVersion() (string, error) {
|
func (r *Recipe) ChaosVersion() (string, error) {
|
||||||
|
if r.Local {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
var version string
|
var version string
|
||||||
|
|
||||||
head, err := r.Head()
|
head, err := r.Head()
|
||||||
@ -315,6 +351,10 @@ func (r *Recipe) ChaosVersion() (string, error) {
|
|||||||
// Push pushes the latest changes to a SSH URL remote. You need to have your
|
// Push pushes the latest changes to a SSH URL remote. You need to have your
|
||||||
// local SSH configuration for git.coopcloud.tech working for this to work
|
// local SSH configuration for git.coopcloud.tech working for this to work
|
||||||
func (r Recipe) Push(dryRun bool) error {
|
func (r Recipe) Push(dryRun bool) error {
|
||||||
|
if r.Local {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
repo, err := git.PlainOpen(r.Dir)
|
repo, err := git.PlainOpen(r.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -333,6 +373,10 @@ func (r Recipe) Push(dryRun bool) error {
|
|||||||
|
|
||||||
// Tags list the recipe tags
|
// Tags list the recipe tags
|
||||||
func (r Recipe) Tags() ([]string, error) {
|
func (r Recipe) Tags() ([]string, error) {
|
||||||
|
if r.Local {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
var tags []string
|
var tags []string
|
||||||
|
|
||||||
repo, err := git.PlainOpen(r.Dir)
|
repo, err := git.PlainOpen(r.Dir)
|
||||||
@ -371,6 +415,10 @@ func (r Recipe) Tags() ([]string, error) {
|
|||||||
|
|
||||||
// GetRecipeVersions retrieves all recipe versions.
|
// GetRecipeVersions retrieves all recipe versions.
|
||||||
func (r Recipe) GetRecipeVersions() (RecipeVersions, []string, error) {
|
func (r Recipe) GetRecipeVersions() (RecipeVersions, []string, error) {
|
||||||
|
if r.Local {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
var warnMsg []string
|
var warnMsg []string
|
||||||
|
|
||||||
versions := RecipeVersions{}
|
versions := RecipeVersions{}
|
||||||
|
|||||||
@ -124,6 +124,14 @@ type Features struct {
|
|||||||
func Get(name string) Recipe {
|
func Get(name string) Recipe {
|
||||||
version := ""
|
version := ""
|
||||||
versionRaw := ""
|
versionRaw := ""
|
||||||
|
gitURL := ""
|
||||||
|
sshURL := ""
|
||||||
|
dir := ""
|
||||||
|
local := false
|
||||||
|
if strings.HasPrefix(name, "./") {
|
||||||
|
dir = path.Join(config.ABRA_DIR, name)
|
||||||
|
local = true
|
||||||
|
} else {
|
||||||
if strings.Contains(name, ":") {
|
if strings.Contains(name, ":") {
|
||||||
split := strings.Split(name, ":")
|
split := strings.Split(name, ":")
|
||||||
if len(split) > 2 {
|
if len(split) > 2 {
|
||||||
@ -139,8 +147,8 @@ func Get(name string) Recipe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gitURL := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, name)
|
gitURL = fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, name)
|
||||||
sshURL := fmt.Sprintf(config.RECIPES_SSH_URL_TEMPLATE, name)
|
sshURL = fmt.Sprintf(config.RECIPES_SSH_URL_TEMPLATE, name)
|
||||||
if strings.Contains(name, "/") {
|
if strings.Contains(name, "/") {
|
||||||
u, err := url.Parse(name)
|
u, err := url.Parse(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -154,7 +162,8 @@ func Get(name string) Recipe {
|
|||||||
sshURL = u.String() + ".git"
|
sshURL = u.String() + ".git"
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := path.Join(config.RECIPES_DIR, escapeRecipeName(name))
|
dir = path.Join(config.RECIPES_DIR, escapeRecipeName(name))
|
||||||
|
}
|
||||||
|
|
||||||
r := Recipe{
|
r := Recipe{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -163,6 +172,7 @@ func Get(name string) Recipe {
|
|||||||
Dir: dir,
|
Dir: dir,
|
||||||
GitURL: gitURL,
|
GitURL: gitURL,
|
||||||
SSHURL: sshURL,
|
SSHURL: sshURL,
|
||||||
|
Local: local,
|
||||||
|
|
||||||
ComposePath: path.Join(dir, "compose.yml"),
|
ComposePath: path.Join(dir, "compose.yml"),
|
||||||
ReadmePath: path.Join(dir, "README.md"),
|
ReadmePath: path.Join(dir, "README.md"),
|
||||||
@ -187,6 +197,7 @@ type Recipe struct {
|
|||||||
Dir string
|
Dir string
|
||||||
GitURL string
|
GitURL string
|
||||||
SSHURL string
|
SSHURL string
|
||||||
|
Local bool
|
||||||
|
|
||||||
ComposePath string
|
ComposePath string
|
||||||
ReadmePath string
|
ReadmePath string
|
||||||
|
|||||||
@ -127,3 +127,14 @@ teardown(){
|
|||||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||||
assert_success
|
assert_success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# bats test_tags=slow
|
||||||
|
@test "new env version written to container env" {
|
||||||
|
run $ABRA app deploy "$TEST_APP_DOMAIN" "0.1.0+1.20.0" --no-input
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
$(docker ps -f name="$TEST_APP_DOMAIN_$TEST_SERVER" -q)
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "$TEST_RECIIPE:0.1.0+1.20.0"
|
||||||
|
}
|
||||||
|
|||||||
@ -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,44 @@ 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 grep -q "TYPE=$TEST_RECIPE:0.1.0+1.20.0" \
|
||||||
|
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|||||||
@ -33,10 +33,29 @@ teardown(){
|
|||||||
assert_success
|
assert_success
|
||||||
|
|
||||||
run $ABRA app rollback "$TEST_APP_DOMAIN" "0.1.0+1.20.0" \
|
run $ABRA app rollback "$TEST_APP_DOMAIN" "0.1.0+1.20.0" \
|
||||||
--no-input --no-converge-checks --debug
|
--no-input --no-converge-checks
|
||||||
assert_success
|
assert_success
|
||||||
|
|
||||||
run grep -q "TYPE=abra-test-recipe:0.1.0+1.20.0" \
|
run grep -q "TYPE=abra-test-recipe:0.1.0+1.20.0" \
|
||||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||||
assert_success
|
assert_success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# bats test_tags=slow
|
||||||
|
@test "new env version written to container env" {
|
||||||
|
run $ABRA app deploy "$TEST_APP_DOMAIN" "0.2.0+1.21.0" --no-input
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run grep -q "TYPE=abra-test-recipe:0.2.0+1.21.0" \
|
||||||
|
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA app rollback "$TEST_APP_DOMAIN" "0.1.0+1.20.0" \
|
||||||
|
--no-input
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
$(docker ps -f name="$TEST_APP_DOMAIN_$TEST_SERVER" -q)
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "$TEST_RECIIPE:0.1.0+1.20.0"
|
||||||
|
}
|
||||||
|
|||||||
@ -256,7 +256,7 @@ teardown(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
# bats test_tags=slow
|
# bats test_tags=slow
|
||||||
@test "commit deploy upgrade is possible" {
|
@test "specific version upgrade after chaos deploy" {
|
||||||
tagHash=$(_get_tag_hash "0.1.0+1.20.0")
|
tagHash=$(_get_tag_hash "0.1.0+1.20.0")
|
||||||
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" checkout "$tagHash"
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" checkout "$tagHash"
|
||||||
assert_success
|
assert_success
|
||||||
@ -269,17 +269,26 @@ teardown(){
|
|||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "CURRENT DEPLOYMENT.*${tagHash:0:8}"
|
assert_output --regexp "CURRENT DEPLOYMENT.*${tagHash:0:8}"
|
||||||
assert_output --regexp "ENV VERSION.*${tagHash:0:8}"
|
assert_output --regexp "ENV VERSION.*${tagHash:0:8}"
|
||||||
|
assert_output --regexp "NEW DEPLOYMENT.*0\.1\.1\+1\.20\.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "chaos commit upgrade is possible" {
|
# bats test_tags=slow
|
||||||
run $ABRA app deploy "$TEST_APP_DOMAIN" "0.1.0+1.20.0" --no-input --no-converge-checks
|
@test "upgrade to latest after chaos deploy" {
|
||||||
assert_success
|
latestRelease=$(_latest_release)
|
||||||
assert_output --partial '0.1.0+1.20.0'
|
|
||||||
|
|
||||||
tagHash=$(_get_tag_hash "0.2.0+1.21.0")
|
tagHash=$(_get_tag_hash "0.1.0+1.20.0")
|
||||||
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" checkout "$tagHash"
|
||||||
run $ABRA app upgrade "$TEST_APP_DOMAIN" "$tagHash" --no-input --no-converge-checks
|
|
||||||
assert_success
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA app deploy "$TEST_APP_DOMAIN" --no-input --no-converge-checks --chaos
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "${tagHash:0:8}"
|
||||||
|
|
||||||
|
run $ABRA app upgrade "$TEST_APP_DOMAIN" --no-input --no-converge-checks
|
||||||
|
assert_success
|
||||||
|
assert_output --regexp "CURRENT DEPLOYMENT.*${tagHash:0:8}"
|
||||||
|
assert_output --regexp "ENV VERSION.*${tagHash:0:8}"
|
||||||
|
assert_output --partial "${latestRelease}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# bats test_tags=slow
|
# bats test_tags=slow
|
||||||
|
|||||||
@ -40,3 +40,21 @@ teardown(){
|
|||||||
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||||
assert_success
|
assert_success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# bats test_tags=slow
|
||||||
|
@test "new env version written to container env" {
|
||||||
|
run $ABRA app deploy "$TEST_APP_DOMAIN" "0.1.0+1.20.0" --no-input
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run grep -q "TYPE=abra-test-recipe:0.1.0+1.20.0" \
|
||||||
|
"$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA app upgrade "$TEST_APP_DOMAIN" "0.2.0+1.21.0" --no-input
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
$(docker ps -f name="$TEST_APP_DOMAIN_$TEST_SERVER" -q)
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "$TEST_RECIIPE:0.2.0+1.21.0"
|
||||||
|
}
|
||||||
|
|||||||
@ -101,6 +101,9 @@ teardown() {
|
|||||||
assert_success
|
assert_success
|
||||||
assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo"
|
assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo"
|
||||||
|
|
||||||
|
run $ABRA recipe sync "$TEST_RECIPE" --no-input --patch
|
||||||
|
assert_success
|
||||||
|
|
||||||
run $ABRA recipe release "$TEST_RECIPE" --no-input --patch
|
run $ABRA recipe release "$TEST_RECIPE" --no-input --patch
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --partial 'no -p/--publish passed, not publishing'
|
assert_output --partial 'no -p/--publish passed, not publishing'
|
||||||
@ -119,6 +122,9 @@ teardown() {
|
|||||||
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" commit -m "added some release notes"
|
run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" commit -m "added some release notes"
|
||||||
assert_success
|
assert_success
|
||||||
|
|
||||||
|
run $ABRA recipe sync "$TEST_RECIPE" --no-input --patch
|
||||||
|
assert_success
|
||||||
|
|
||||||
run $ABRA recipe release "$TEST_RECIPE" --no-input --minor
|
run $ABRA recipe release "$TEST_RECIPE" --no-input --minor
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --partial 'no -p/--publish passed, not publishing'
|
assert_output --partial 'no -p/--publish passed, not publishing'
|
||||||
|
|||||||
Reference in New Issue
Block a user