diff --git a/cli/app/backup.go b/cli/app/backup.go index f6c8d2ae..4f19636a 100644 --- a/cli/app/backup.go +++ b/cli/app/backup.go @@ -47,22 +47,26 @@ var appBackupListCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } @@ -110,22 +114,26 @@ var appBackupDownloadCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } @@ -180,22 +188,27 @@ var appBackupCreateCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } @@ -238,22 +251,27 @@ var appBackupSnapshotsCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } diff --git a/cli/app/check.go b/cli/app/check.go index 6b0e8455..38f9d6f7 100644 --- a/cli/app/check.go +++ b/cli/app/check.go @@ -6,7 +6,6 @@ import ( "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/recipe" - recipePkg "coopcloud.tech/abra/pkg/recipe" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -38,22 +37,26 @@ ${FOO:} syntax). "check" does not confirm or deny this for you.`, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipePkg.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipePkg.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipePkg.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } diff --git a/cli/app/cmd.go b/cli/app/cmd.go index 002eecfa..80aec973 100644 --- a/cli/app/cmd.go +++ b/cli/app/cmd.go @@ -15,7 +15,6 @@ import ( "coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/recipe" - recipePkg "coopcloud.tech/abra/pkg/recipe" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -60,22 +59,27 @@ Example: Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipePkg.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipePkg.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipePkg.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } @@ -228,22 +232,27 @@ var appCmdListCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipePkg.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipePkg.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipePkg.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } diff --git a/cli/app/deploy.go b/cli/app/deploy.go index fb72c0ec..e293baaf 100644 --- a/cli/app/deploy.go +++ b/cli/app/deploy.go @@ -56,28 +56,32 @@ recipes. logrus.Fatal("cannot use and --chaos together") } - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } - r, err := recipe.Get(app.Recipe, internal.Offline) - if err != nil { + if err := r.LoadConfig(); err != nil { logrus.Fatal(err) } @@ -105,7 +109,7 @@ recipes. if specificVersion != "" { version = specificVersion logrus.Debugf("choosing %s as version to deploy", version) - if err := recipe.EnsureVersion(app.Recipe, version); err != nil { + if err := r.EnsureVersion(version); err != nil { logrus.Fatal(err) } } @@ -141,7 +145,7 @@ recipes. if len(versions) == 0 && !internal.Chaos { logrus.Warn("no published versions in catalogue, trying local recipe repository") - recipeVersions, err := recipe.GetRecipeVersions(app.Recipe, internal.Offline) + recipeVersions, err := r.GetVersions(internal.Offline) if err != nil { logrus.Warn(err) } @@ -155,11 +159,11 @@ recipes. if len(versions) > 0 && !internal.Chaos { version = versions[len(versions)-1] logrus.Debugf("choosing %s as version to deploy", version) - if err := recipe.EnsureVersion(app.Recipe, version); err != nil { + if err := r.EnsureVersion(version); err != nil { logrus.Fatal(err) } } else { - head, err := git.GetRecipeHead(app.Recipe) + head, err := git.GetHead(app.Recipe) if err != nil { logrus.Fatal(err) } @@ -171,7 +175,7 @@ recipes. if internal.Chaos { logrus.Warnf("chaos mode engaged") var err error - version, err = recipe.ChaosVersion(app.Recipe) + version, err = r.ChaosVersion() if err != nil { logrus.Fatal(err) } diff --git a/cli/app/errors.go b/cli/app/errors.go index 04e7e68d..704f528b 100644 --- a/cli/app/errors.go +++ b/cli/app/errors.go @@ -88,12 +88,15 @@ the logs. } func checkErrors(c *cli.Context, cl *dockerClient.Client, app config.App) error { - recipe, err := recipe.Get(app.Recipe, internal.Offline) + r, err := recipe.Get(app.Recipe) if err != nil { + logrus.Fatal(err) + } + if err := r.LoadConfig(); err != nil { return err } - for _, service := range recipe.Config.Services { + for _, service := range r.Config.Services { filters := filters.NewArgs() filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), service.Name)) diff --git a/cli/app/logs.go b/cli/app/logs.go index d54dae1e..8f016227 100644 --- a/cli/app/logs.go +++ b/cli/app/logs.go @@ -39,7 +39,12 @@ var appLogsCommand = cli.Command{ app := internal.ValidateApp(c) stackName := app.StackName() - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } diff --git a/cli/app/new.go b/cli/app/new.go index e31e970d..63dff23e 100644 --- a/cli/app/new.go +++ b/cli/app/new.go @@ -10,7 +10,6 @@ import ( "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/jsontable" - recipePkg "coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/secret" "github.com/AlecAivazis/survey/v2" dockerClient "github.com/docker/docker/client" @@ -65,21 +64,21 @@ var appNewCommand = cli.Command{ } }, Action: func(c *cli.Context) error { - recipe := internal.ValidateRecipe(c) + r := internal.ValidateRecipe(c) if !internal.Chaos { - if err := recipePkg.EnsureIsClean(recipe.Name); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } if c.Args().Get(1) == "" { var version string - recipeVersions, err := recipePkg.GetRecipeVersions(recipe.Name, internal.Offline) + recipeVersions, err := r.GetVersions(internal.Offline) if err != nil { logrus.Fatal(err) } @@ -92,16 +91,16 @@ var appNewCommand = cli.Command{ version = tag } - if err := recipePkg.EnsureVersion(recipe.Name, version); err != nil { + if err := r.EnsureVersion(version); err != nil { logrus.Fatal(err) } } else { - if err := recipePkg.EnsureLatest(recipe.Name); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } } else { - if err := recipePkg.EnsureVersion(recipe.Name, c.Args().Get(1)); err != nil { + if err := r.EnsureVersion(c.Args().Get(1)); err != nil { logrus.Fatal(err) } } @@ -111,7 +110,7 @@ var appNewCommand = cli.Command{ logrus.Fatal(err) } - if err := ensureDomainFlag(recipe, internal.NewAppServer); err != nil { + if err := ensureDomainFlag(r.Name, internal.NewAppServer); err != nil { logrus.Fatal(err) } @@ -119,7 +118,7 @@ var appNewCommand = cli.Command{ logrus.Debugf("%s sanitised as %s for new app", internal.Domain, sanitisedAppName) if err := config.TemplateAppEnvSample( - recipe.Name, + r.Name, internal.Domain, internal.NewAppServer, internal.Domain, @@ -130,23 +129,23 @@ var appNewCommand = cli.Command{ var secrets AppSecrets var secretTable *jsontable.JSONTable if internal.Secrets { - sampleEnv, err := recipe.SampleEnv() + sampleEnv, err := r.SampleEnv() if err != nil { logrus.Fatal(err) } - composeFiles, err := config.GetComposeFiles(recipe.Name, sampleEnv) + composeFiles, err := config.GetComposeFiles(r.NameEscaped, sampleEnv) if err != nil { logrus.Fatal(err) } - envSamplePath := path.Join(config.RECIPES_DIR, recipe.Name, ".env.sample") + envSamplePath := path.Join(r.Dir, ".env.sample") secretsConfig, err := secret.ReadSecretsConfig(envSamplePath, composeFiles, config.StackName(internal.Domain)) if err != nil { return err } - if err := promptForSecrets(recipe.Name, secretsConfig); err != nil { + if err := promptForSecrets(r.Name, secretsConfig); err != nil { logrus.Fatal(err) } @@ -173,9 +172,9 @@ var appNewCommand = cli.Command{ tableCol := []string{"server", "recipe", "domain"} table := formatter.CreateTable(tableCol) - table.Append([]string{internal.NewAppServer, recipe.Name, internal.Domain}) + table.Append([]string{internal.NewAppServer, r.Name, internal.Domain}) - fmt.Println(fmt.Sprintf("A new %s app has been created! Here is an overview:", recipe.Name)) + fmt.Println(fmt.Sprintf("A new %s app has been created! Here is an overview:", r.Name)) fmt.Println("") table.Render() fmt.Println("") @@ -231,11 +230,11 @@ func createSecrets(cl *dockerClient.Client, secretsConfig map[string]secret.Secr } // ensureDomainFlag checks if the domain flag was used. if not, asks the user for it/ -func ensureDomainFlag(recipe recipePkg.Recipe, server string) error { +func ensureDomainFlag(recipeName string, server string) error { if internal.Domain == "" && !internal.NoInput { prompt := &survey.Input{ Message: "Specify app domain", - Default: fmt.Sprintf("%s.%s", recipe.Name, server), + Default: fmt.Sprintf("%s.%s", recipeName, server), } if err := survey.AskOne(prompt, &internal.Domain); err != nil { return err diff --git a/cli/app/ps.go b/cli/app/ps.go index 31ab7e61..c16c118a 100644 --- a/cli/app/ps.go +++ b/cli/app/ps.go @@ -39,6 +39,11 @@ var appPsCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) @@ -56,7 +61,7 @@ var appPsCommand = cli.Command{ statuses, err := config.GetAppStatuses([]config.App{app}, true) if statusMeta, ok := statuses[app.StackName()]; ok { if _, exists := statusMeta["chaos"]; !exists { - if err := recipe.EnsureVersion(app.Recipe, deployedVersion); err != nil { + if err := r.EnsureVersion(deployedVersion); err != nil { logrus.Fatal(err) } } diff --git a/cli/app/restore.go b/cli/app/restore.go index c80347f5..55942054 100644 --- a/cli/app/restore.go +++ b/cli/app/restore.go @@ -33,22 +33,27 @@ var appRestoreCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } diff --git a/cli/app/rollback.go b/cli/app/rollback.go index f39d114b..8e39b123 100644 --- a/cli/app/rollback.go +++ b/cli/app/rollback.go @@ -51,33 +51,37 @@ recipes. app := internal.ValidateApp(c) stackName := app.StackName() + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + specificVersion := c.Args().Get(1) if specificVersion != "" && internal.Chaos { logrus.Fatal("cannot use and --chaos together") } - if err := recipe.EnsureExists(app.Recipe); err != nil { + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } - r, err := recipe.Get(app.Recipe, internal.Offline) - if err != nil { + if err := r.LoadConfig(); err != nil { logrus.Fatal(err) } @@ -113,7 +117,7 @@ recipes. if len(versions) == 0 && !internal.Chaos { logrus.Warn("no published versions in catalogue, trying local recipe repository") - recipeVersions, err := recipe.GetRecipeVersions(app.Recipe, internal.Offline) + recipeVersions, err := r.GetVersions(internal.Offline) if err != nil { logrus.Warn(err) } @@ -183,7 +187,7 @@ recipes. } if !internal.Chaos { - if err := recipe.EnsureVersion(app.Recipe, chosenDowngrade); err != nil { + if err := r.EnsureVersion(chosenDowngrade); err != nil { logrus.Fatal(err) } } @@ -191,13 +195,13 @@ recipes. if internal.Chaos { logrus.Warn("chaos mode engaged") var err error - chosenDowngrade, err = recipe.ChaosVersion(app.Recipe) + chosenDowngrade, err = r.ChaosVersion() if err != nil { logrus.Fatal(err) } } - abraShPath := fmt.Sprintf("%s/%s/%s", config.RECIPES_DIR, app.Recipe, "abra.sh") + abraShPath := fmt.Sprintf("%s/%s/%s", r.Dir, "abra.sh") abraShEnv, err := config.ReadAbraShEnvVars(abraShPath) if err != nil { logrus.Fatal(err) diff --git a/cli/app/secret.go b/cli/app/secret.go index c621d51d..9d066d1f 100644 --- a/cli/app/secret.go +++ b/cli/app/secret.go @@ -57,22 +57,27 @@ var appSecretGenerateCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } @@ -264,22 +269,27 @@ Example: Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } @@ -372,22 +382,27 @@ var appSecretLsCommand = cli.Command{ Action: func(c *cli.Context) error { app := internal.ValidateApp(c) - if err := recipe.EnsureExists(app.Recipe); err != nil { + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipe.EnsureLatest(app.Recipe); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } diff --git a/cli/app/upgrade.go b/cli/app/upgrade.go index 366a5932..495ab82c 100644 --- a/cli/app/upgrade.go +++ b/cli/app/upgrade.go @@ -62,28 +62,32 @@ recipes. logrus.Fatal("cannot use and --chaos together") } - if !internal.Chaos { - if err := recipe.EnsureIsClean(app.Recipe); err != nil { - logrus.Fatal(err) - } - - if !internal.Offline { - if err := recipe.EnsureUpToDate(app.Recipe); err != nil { - logrus.Fatal(err) - } - } - - if err := recipe.EnsureLatest(app.Recipe); err != nil { - logrus.Fatal(err) - } - } - - recipe, err := recipePkg.Get(app.Recipe, internal.Offline) + r, err := recipe.Get(app.Recipe) if err != nil { logrus.Fatal(err) } - if err := lint.LintForErrors(recipe); err != nil { + if !internal.Chaos { + if err := r.EnsureIsClean(); err != nil { + logrus.Fatal(err) + } + + if !internal.Offline { + if err := r.EnsureUpToDate(); err != nil { + logrus.Fatal(err) + } + } + + if err := r.EnsureLatest(); err != nil { + logrus.Fatal(err) + } + } + + if err := r.LoadConfig(); err != nil { + logrus.Fatal(err) + } + + if err := lint.LintForErrors(r); err != nil { logrus.Fatal(err) } @@ -115,7 +119,7 @@ recipes. if len(versions) == 0 && !internal.Chaos { logrus.Warn("no published versions in catalogue, trying local recipe repository") - recipeVersions, err := recipePkg.GetRecipeVersions(app.Recipe, internal.Offline) + recipeVersions, err := r.GetVersions(internal.Offline) if err != nil { logrus.Warn(err) } @@ -217,7 +221,7 @@ recipes. } if !internal.Chaos { - if err := recipePkg.EnsureVersion(app.Recipe, chosenUpgrade); err != nil { + if err := r.EnsureVersion(chosenUpgrade); err != nil { logrus.Fatal(err) } } @@ -225,13 +229,13 @@ recipes. if internal.Chaos { logrus.Warn("chaos mode engaged") var err error - chosenUpgrade, err = recipePkg.ChaosVersion(app.Recipe) + chosenUpgrade, err = r.ChaosVersion() if err != nil { logrus.Fatal(err) } } - abraShPath := fmt.Sprintf("%s/%s/%s", config.RECIPES_DIR, app.Recipe, "abra.sh") + abraShPath := fmt.Sprintf("%s/%s/%s", r.Dir, "abra.sh") abraShEnv, err := config.ReadAbraShEnvVars(abraShPath) if err != nil { logrus.Fatal(err) diff --git a/cli/app/version.go b/cli/app/version.go index 437976ab..98006f70 100644 --- a/cli/app/version.go +++ b/cli/app/version.go @@ -58,6 +58,11 @@ var appVersionCommand = cli.Command{ app := internal.ValidateApp(c) stackName := app.StackName() + r, err := recipe.Get(app.Recipe) + if err != nil { + logrus.Fatal(err) + } + cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) @@ -78,7 +83,7 @@ var appVersionCommand = cli.Command{ logrus.Fatalf("failed to determine version of deployed %s", app.Name) } - recipeMeta, err := recipe.GetRecipeMeta(app.Recipe, internal.Offline) + recipeMeta, err := r.GetRecipeMeta(internal.Offline) if err != nil { logrus.Fatal(err) } diff --git a/cli/catalogue/catalogue.go b/cli/catalogue/catalogue.go index b7d09ccc..7d8ec0aa 100644 --- a/cli/catalogue/catalogue.go +++ b/cli/catalogue/catalogue.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "os" "path" "coopcloud.tech/abra/cli/internal" @@ -57,9 +58,10 @@ keys configured on your account. BashComplete: autocomplete.RecipeNameComplete, Action: func(c *cli.Context) error { recipeName := c.Args().First() + r := recipe.Recipe{} if recipeName != "" { - internal.ValidateRecipe(c) + r = internal.ValidateRecipe(c) } if !internal.Chaos { @@ -98,12 +100,12 @@ keys configured on your account. continue } - versions, err := recipe.GetRecipeVersions(recipeMeta.Name, internal.Offline) + versions, err := r.GetVersions(internal.Offline) if err != nil { logrus.Warn(err) } - features, category, err := recipe.GetRecipeFeaturesAndCategory(recipeMeta.Name) + features, category, err := r.GetRecipeFeaturesAndCategory() if err != nil { logrus.Warn(err) } @@ -130,7 +132,7 @@ keys configured on your account. } if recipeName == "" { - if err := ioutil.WriteFile(config.RECIPES_JSON, recipesJSON, 0764); err != nil { + if err := os.WriteFile(config.RECIPES_JSON, recipesJSON, 0764); err != nil { logrus.Fatal(err) } } else { diff --git a/cli/internal/validate.go b/cli/internal/validate.go index 46a442d6..53d2b764 100644 --- a/cli/internal/validate.go +++ b/cli/internal/validate.go @@ -57,7 +57,10 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe { ShowSubcommandHelpAndError(c, errors.New("no recipe name provided")) } - chosenRecipe, err := recipe.Get(recipeName, Offline) + r, err := recipe.Get(recipeName) + if err != nil { + logrus.Fatal(err) + } if err != nil { if c.Command.Name == "generate" { if strings.Contains(err.Error(), "missing a compose") { @@ -74,7 +77,7 @@ func ValidateRecipe(c *cli.Context) recipe.Recipe { logrus.Debugf("validated %s as recipe argument", recipeName) - return chosenRecipe + return r } // ValidateApp ensures the app name arg is valid. diff --git a/cli/recipe/fetch.go b/cli/recipe/fetch.go index de81cfec..b7c696a9 100644 --- a/cli/recipe/fetch.go +++ b/cli/recipe/fetch.go @@ -24,9 +24,14 @@ var recipeFetchCommand = cli.Command{ BashComplete: autocomplete.RecipeNameComplete, Action: func(c *cli.Context) error { recipeName := c.Args().First() + if recipeName != "" { internal.ValidateRecipe(c) - if err := recipe.Ensure(recipeName); err != nil { + r, err := recipe.Get(recipeName) + if err != nil { + logrus.Fatal(err) + } + if err := r.Ensure(); err != nil { logrus.Fatal(err) } return nil @@ -39,7 +44,11 @@ var recipeFetchCommand = cli.Command{ catlBar := formatter.CreateProgressbar(len(catalogue), "fetching latest recipes...") for recipeName := range catalogue { - if err := recipe.Ensure(recipeName); err != nil { + r, err := recipe.Get(recipeName) + if err != nil { + logrus.Fatal(err) + } + if err := r.Ensure(); err != nil { logrus.Error(err) } catlBar.Add(1) diff --git a/cli/recipe/lint.go b/cli/recipe/lint.go index 542164f9..45a7b433 100644 --- a/cli/recipe/lint.go +++ b/cli/recipe/lint.go @@ -7,7 +7,6 @@ import ( "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/lint" - recipePkg "coopcloud.tech/abra/pkg/recipe" "github.com/sirupsen/logrus" "github.com/urfave/cli" ) @@ -27,24 +26,27 @@ var recipeLintCommand = cli.Command{ Before: internal.SubCommandBefore, BashComplete: autocomplete.RecipeNameComplete, Action: func(c *cli.Context) error { - recipe := internal.ValidateRecipe(c) + r := internal.ValidateRecipe(c) + if err := r.LoadConfig(); err != nil { + logrus.Fatal(err) + } - if err := recipePkg.EnsureExists(recipe.Name); err != nil { + if err := r.EnsureExists(); err != nil { logrus.Fatal(err) } if !internal.Chaos { - if err := recipePkg.EnsureIsClean(recipe.Name); err != nil { + if err := r.EnsureIsClean(); err != nil { logrus.Fatal(err) } if !internal.Offline { - if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil { + if err := r.EnsureUpToDate(); err != nil { logrus.Fatal(err) } } - if err := recipePkg.EnsureLatest(recipe.Name); err != nil { + if err := r.EnsureLatest(); err != nil { logrus.Fatal(err) } } @@ -62,7 +64,7 @@ var recipeLintCommand = cli.Command{ } skipped := false - if rule.Skip(recipe) { + if rule.Skip(r) { skipped = true } @@ -73,7 +75,7 @@ var recipeLintCommand = cli.Command{ satisfied := false if !skipped { - ok, err := rule.Function(recipe) + ok, err := rule.Function(r) if err != nil { logrus.Warn(err) } diff --git a/cli/recipe/release.go b/cli/recipe/release.go index 50e0afa7..a9d3533e 100644 --- a/cli/recipe/release.go +++ b/cli/recipe/release.go @@ -108,14 +108,14 @@ your SSH keys configured on your account. } } - isClean, err := gitPkg.IsClean(recipe.Dir()) + isClean, err := gitPkg.IsClean(recipe.Dir) if err != nil { logrus.Fatal(err) } if !isClean { logrus.Infof("%s currently has these unstaged changes 👇", recipe.Name) - if err := gitPkg.DiffUnstaged(recipe.Dir()); err != nil { + if err := gitPkg.DiffUnstaged(recipe.Dir); err != nil { logrus.Fatal(err) } } @@ -184,7 +184,7 @@ func getImageVersions(recipe recipe.Recipe) (map[string]string, error) { func createReleaseFromTag(recipe recipe.Recipe, tagString, mainAppVersion string) error { var err error - directory := path.Join(config.RECIPES_DIR, recipe.Name) + directory := path.Join(recipe.Dir) repo, err := git.PlainOpen(directory) if err != nil { return err @@ -246,8 +246,7 @@ func getTagCreateOptions(tag string) (git.CreateTagOptions, error) { // addReleaseNotes checks if the release/next release note exists and moves the // file to release/. func addReleaseNotes(recipe recipe.Recipe, tag string) error { - repoPath := path.Join(config.RECIPES_DIR, recipe.Name) - tagReleaseNotePath := path.Join(repoPath, "release", tag) + tagReleaseNotePath := path.Join(recipe.Dir, "release", tag) if _, err := os.Stat(tagReleaseNotePath); err == nil { // Release note for current tag already exist exists. return nil @@ -255,7 +254,7 @@ func addReleaseNotes(recipe recipe.Recipe, tag string) error { return err } - nextReleaseNotePath := path.Join(repoPath, "release", "next") + nextReleaseNotePath := path.Join(recipe.Dir, "release", "next") if _, err := os.Stat(nextReleaseNotePath); err == nil { // release/next note exists. Move it to release/ if internal.Dry { @@ -278,11 +277,11 @@ func addReleaseNotes(recipe recipe.Recipe, tag string) error { if err != nil { return err } - err = gitPkg.Add(repoPath, path.Join("release", "next"), internal.Dry) + err = gitPkg.Add(recipe.Dir, path.Join("release", "next"), internal.Dry) if err != nil { return err } - err = gitPkg.Add(repoPath, path.Join("release", tag), internal.Dry) + err = gitPkg.Add(recipe.Dir, path.Join("release", tag), internal.Dry) if err != nil { return err } @@ -311,7 +310,7 @@ func addReleaseNotes(recipe recipe.Recipe, tag string) error { if err != nil { return err } - err = gitPkg.Add(repoPath, path.Join("release", tag), internal.Dry) + err = gitPkg.Add(recipe.Dir, path.Join("release", tag), internal.Dry) if err != nil { return err } @@ -325,14 +324,14 @@ func commitRelease(recipe recipe.Recipe, tag string) error { return nil } - isClean, err := gitPkg.IsClean(recipe.Dir()) + isClean, err := gitPkg.IsClean(recipe.Dir) if err != nil { return err } if isClean { if !internal.Dry { - return fmt.Errorf("no changes discovered in %s, nothing to publish?", recipe.Dir()) + return fmt.Errorf("no changes discovered in %s, nothing to publish?", recipe.Dir) } } @@ -402,8 +401,7 @@ func pushRelease(recipe recipe.Recipe, tagString string) error { } func createReleaseFromPreviousTag(tagString, mainAppVersion string, recipe recipe.Recipe, tags []string) error { - directory := path.Join(config.RECIPES_DIR, recipe.Name) - repo, err := git.PlainOpen(directory) + repo, err := git.PlainOpen(recipe.Dir) if err != nil { return err } diff --git a/cli/recipe/sync.go b/cli/recipe/sync.go index d5b4ad00..78f2008b 100644 --- a/cli/recipe/sync.go +++ b/cli/recipe/sync.go @@ -199,13 +199,13 @@ likely to change. logrus.Infof("dry run: not syncing label %s for recipe %s", nextTag, recipe.Name) } - isClean, err := gitPkg.IsClean(recipe.Dir()) + isClean, err := gitPkg.IsClean(recipe.Dir) if err != nil { logrus.Fatal(err) } if !isClean { logrus.Infof("%s currently has these unstaged changes 👇", recipe.Name) - if err := gitPkg.DiffUnstaged(recipe.Dir()); err != nil { + if err := gitPkg.DiffUnstaged(recipe.Dir); err != nil { logrus.Fatal(err) } } diff --git a/cli/recipe/upgrade.go b/cli/recipe/upgrade.go index 440859cc..9999b31e 100644 --- a/cli/recipe/upgrade.go +++ b/cli/recipe/upgrade.go @@ -73,19 +73,19 @@ You may invoke this command in "wizard" mode and be prompted for input: Action: func(c *cli.Context) error { recipe := internal.ValidateRecipe(c) - if err := recipePkg.EnsureIsClean(recipe.Name); err != nil { + if err := recipe.EnsureIsClean(); err != nil { logrus.Fatal(err) } - if err := recipePkg.EnsureExists(recipe.Name); err != nil { + if err := recipe.EnsureExists(); err != nil { logrus.Fatal(err) } - if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil { + if err := recipe.EnsureUpToDate(); err != nil { logrus.Fatal(err) } - if err := recipePkg.EnsureLatest(recipe.Name); err != nil { + if err := recipe.EnsureLatest(); err != nil { logrus.Fatal(err) } diff --git a/cli/updater/updater.go b/cli/updater/updater.go index 4b036132..15e4dde8 100644 --- a/cli/updater/updater.go +++ b/cli/updater/updater.go @@ -316,22 +316,23 @@ func getAvailableUpgrades(cl *dockerclient.Client, stackName string, recipeName // processRecipeRepoVersion clones, pulls, checks out the version and lints the // recipe repository. -func processRecipeRepoVersion(recipeName, version string) error { - if err := recipe.EnsureExists(recipeName); err != nil { +func processRecipeRepoVersion(recipe recipe.Recipe, version string) error { + if err := recipe.EnsureExists(); err != nil { return err } - if err := recipe.EnsureUpToDate(recipeName); err != nil { + if err := recipe.EnsureUpToDate(); err != nil { return err } - if err := recipe.EnsureVersion(recipeName, version); err != nil { + if err := recipe.EnsureVersion(version); err != nil { return err } - if r, err := recipe.Get(recipeName, internal.Offline); err != nil { + if err := recipe.LoadConfig(); err != nil { return err - } else if err := lint.LintForErrors(r); err != nil { + } + if err := lint.LintForErrors(recipe); err != nil { return err } @@ -442,7 +443,12 @@ func upgrade(cl *dockerclient.Client, stackName, recipeName, Env: env, } - if err = processRecipeRepoVersion(recipeName, upgradeVersion); err != nil { + recipe, err := recipe.Get(recipeName) + if err != nil { + return err + } + + if err = processRecipeRepoVersion(recipe, upgradeVersion); err != nil { return err } diff --git a/pkg/config/app_test.go b/pkg/config/app_test.go index 0823f4e2..0f34b7b6 100644 --- a/pkg/config/app_test.go +++ b/pkg/config/app_test.go @@ -45,7 +45,7 @@ func TestGetApp(t *testing.T) { func TestGetComposeFiles(t *testing.T) { offline := true - r, err := recipe.Get("abra-test-recipe", offline) + r, err := recipe.Get2("abra-test-recipe", offline) if err != nil { t.Fatal(err) } @@ -92,7 +92,7 @@ func TestGetComposeFiles(t *testing.T) { func TestGetComposeFilesError(t *testing.T) { offline := true - r, err := recipe.Get("abra-test-recipe", offline) + r, err := recipe.Get2("abra-test-recipe", offline) if err != nil { t.Fatal(err) } diff --git a/pkg/config/env_test.go b/pkg/config/env_test.go index f0626e6b..b3493e6a 100644 --- a/pkg/config/env_test.go +++ b/pkg/config/env_test.go @@ -94,7 +94,7 @@ func TestReadEnv(t *testing.T) { func TestReadAbraShEnvVars(t *testing.T) { offline := true - r, err := recipe.Get("abra-test-recipe", offline) + r, err := recipe.Get2("abra-test-recipe", offline) if err != nil { t.Fatal(err) } @@ -124,7 +124,7 @@ func TestReadAbraShEnvVars(t *testing.T) { func TestReadAbraShCmdNames(t *testing.T) { offline := true - r, err := recipe.Get("abra-test-recipe", offline) + r, err := recipe.Get2("abra-test-recipe", offline) if err != nil { t.Fatal(err) } @@ -149,7 +149,7 @@ func TestReadAbraShCmdNames(t *testing.T) { func TestCheckEnv(t *testing.T) { offline := true - r, err := recipe.Get("abra-test-recipe", offline) + r, err := recipe.Get2("abra-test-recipe", offline) if err != nil { t.Fatal(err) } @@ -183,7 +183,7 @@ func TestCheckEnv(t *testing.T) { func TestCheckEnvError(t *testing.T) { offline := true - r, err := recipe.Get("abra-test-recipe", offline) + r, err := recipe.Get2("abra-test-recipe", offline) if err != nil { t.Fatal(err) } @@ -219,7 +219,7 @@ func TestCheckEnvError(t *testing.T) { func TestEnvVarCommentsRemoved(t *testing.T) { offline := true - r, err := recipe.Get("abra-test-recipe", offline) + r, err := recipe.Get2("abra-test-recipe", offline) if err != nil { t.Fatal(err) } @@ -251,7 +251,7 @@ func TestEnvVarCommentsRemoved(t *testing.T) { func TestEnvVarModifiersIncluded(t *testing.T) { offline := true - r, err := recipe.Get("abra-test-recipe", offline) + r, err := recipe.Get2("abra-test-recipe", offline) if err != nil { t.Fatal(err) } diff --git a/pkg/git/read.go b/pkg/git/read.go index 47d74d33..5cbd53af 100644 --- a/pkg/git/read.go +++ b/pkg/git/read.go @@ -4,11 +4,9 @@ import ( "io/ioutil" "os" "os/user" - "path" "path/filepath" "strings" - "coopcloud.tech/abra/pkg/config" "github.com/go-git/go-git/v5" gitConfigPkg "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" @@ -16,11 +14,9 @@ import ( "github.com/sirupsen/logrus" ) -// GetRecipeHead retrieves latest HEAD metadata. -func GetRecipeHead(recipeName string) (*plumbing.Reference, error) { - recipeDir := path.Join(config.RECIPES_DIR, recipeName) - - repo, err := git.PlainOpen(recipeDir) +// GetHead retrieves latest HEAD metadata. +func GetHead(dir string) (*plumbing.Reference, error) { + repo, err := git.PlainOpen(dir) if err != nil { return nil, err } diff --git a/pkg/lint/recipe.go b/pkg/lint/recipe.go index 1fc96f82..26c095a0 100644 --- a/pkg/lint/recipe.go +++ b/pkg/lint/recipe.go @@ -210,7 +210,7 @@ func LintComposeVersion(recipe recipe.Recipe) (bool, error) { } func LintEnvConfigPresent(recipe recipe.Recipe) (bool, error) { - envSample := fmt.Sprintf("%s/%s/.env.sample", config.RECIPES_DIR, recipe.Name) + envSample := fmt.Sprintf("%s/%s/.env.sample", recipe.Dir) if _, err := os.Stat(envSample); !os.IsNotExist(err) { return true, nil } @@ -233,7 +233,7 @@ func LintAppService(recipe recipe.Recipe) (bool, error) { // the recipe. This typically means that no domain is required to deploy and // therefore no matching traefik deploy label will be present. func LintTraefikEnabledSkipCondition(recipe recipe.Recipe) (bool, error) { - envSamplePath := path.Join(config.RECIPES_DIR, recipe.Name, ".env.sample") + envSamplePath := path.Join(recipe.Dir, ".env.sample") sampleEnv, err := config.ReadEnv(envSamplePath) if err != nil { return false, fmt.Errorf("Unable to discover .env.sample for %s", recipe.Name) @@ -358,7 +358,7 @@ func LintHasPublishedVersion(recipe recipe.Recipe) (bool, error) { } func LintMetadataFilledIn(r recipe.Recipe) (bool, error) { - features, category, err := recipe.GetRecipeFeaturesAndCategory(r.Name) + features, category, err := r.GetRecipeFeaturesAndCategory() if err != nil { return false, err } diff --git a/pkg/recipe/recipe.go b/pkg/recipe/recipe.go index ac81ce12..ec9c345f 100644 --- a/pkg/recipe/recipe.go +++ b/pkg/recipe/recipe.go @@ -3,7 +3,6 @@ package recipe import ( "encoding/json" "fmt" - "io/ioutil" "net/url" "os" "path" @@ -131,8 +130,8 @@ type Features struct { SSO string `json:"sso"` } -// Recipe represents a recipe. -type Recipe struct { +// Recipe2 represents a recipe. +type Recipe2 struct { Name string Config *composetypes.Config Meta RecipeMeta @@ -141,7 +140,7 @@ type Recipe struct { // 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 func (r Recipe) Push(dryRun bool) error { - repo, err := git.PlainOpen(r.Dir()) + repo, err := git.PlainOpen(r.Dir) if err != nil { return err } @@ -150,21 +149,16 @@ func (r Recipe) Push(dryRun bool) error { return err } - if err := gitPkg.Push(r.Dir(), "origin-ssh", true, dryRun); err != nil { + if err := gitPkg.Push(r.Dir, "origin-ssh", true, dryRun); err != nil { return err } return nil } -// Dir retrieves the recipe repository path -func (r Recipe) Dir() string { - return path.Join(config.RECIPES_DIR, r.Name) -} - // UpdateLabel updates a recipe label func (r Recipe) UpdateLabel(pattern, serviceName, label string) error { - fullPattern := fmt.Sprintf("%s/%s/%s", config.RECIPES_DIR, r.Name, pattern) + fullPattern := fmt.Sprintf("%s/%s", r.Dir, pattern) if err := compose.UpdateLabel(fullPattern, serviceName, label, r.Name); err != nil { return err } @@ -173,7 +167,7 @@ func (r Recipe) UpdateLabel(pattern, serviceName, label string) error { // UpdateTag updates a recipe tag func (r Recipe) UpdateTag(image, tag string) (bool, error) { - pattern := fmt.Sprintf("%s/%s/compose**yml", config.RECIPES_DIR, r.Name) + pattern := fmt.Sprintf("%s/compose**yml", r.Dir) image = formatter.StripTagMeta(image) @@ -189,7 +183,7 @@ func (r Recipe) UpdateTag(image, tag string) (bool, error) { func (r Recipe) Tags() ([]string, error) { var tags []string - repo, err := git.PlainOpen(r.Dir()) + repo, err := git.PlainOpen(r.Dir) if err != nil { return tags, err } @@ -211,49 +205,51 @@ func (r Recipe) Tags() ([]string, error) { return tags, nil } -// Get retrieves a recipe. -func Get(recipeName string, offline bool) (Recipe, error) { - if err := EnsureExists(recipeName); err != nil { - return Recipe{}, err +// // Get2 retrieves a recipe. +// func (r Recipe) Load(offline bool) (Recipe2, error) { +// +// meta, err := r.GetRecipeMeta(offline) +// if err != nil { +// switch err.(type) { +// case RecipeMissingFromCatalogue: +// meta = RecipeMeta{} +// default: +// return Recipe2{}, err +// } +// } +// +// return Recipe2{ +// Name: r.Name, +// Config: config, +// Meta: meta, +// }, nil +// } + +func (r Recipe) LoadConfig() error { + if err := r.EnsureExists(); err != nil { + return err } - pattern := fmt.Sprintf("%s/%s/compose**yml", config.RECIPES_DIR, recipeName) + pattern := fmt.Sprintf("%s/compose**yml", r.Dir) composeFiles, err := filepath.Glob(pattern) if err != nil { - return Recipe{}, err + return err } if len(composeFiles) == 0 { - return Recipe{}, fmt.Errorf("%s is missing a compose.yml or compose.*.yml file?", recipeName) + return fmt.Errorf("%s is missing a compose.yml or compose.*.yml file?", r.Name) } - - envSamplePath := path.Join(config.RECIPES_DIR, recipeName, ".env.sample") - sampleEnv, err := config.ReadEnv(envSamplePath) - if err != nil { - return Recipe{}, err - } - opts := stack.Deploy{Composefiles: composeFiles} + sampleEnv, err := r.SampleEnv() + if err != nil { + return err + } config, err := loader.LoadComposefile(opts, sampleEnv) if err != nil { - return Recipe{}, err + return err } - - meta, err := GetRecipeMeta(recipeName, offline) - if err != nil { - switch err.(type) { - case RecipeMissingFromCatalogue: - meta = RecipeMeta{} - default: - return Recipe{}, err - } - } - - return Recipe{ - Name: recipeName, - Config: config, - Meta: meta, - }, nil + r.Config = config + return nil } func (r Recipe) SampleEnv() (map[string]string, error) { @@ -265,50 +261,19 @@ func (r Recipe) SampleEnv() (map[string]string, error) { return sampleEnv, nil } -// Ensure makes sure the recipe exists, is up to date and has the latest version checked out. -func Ensure(recipeName string) error { - if err := EnsureExists(recipeName); err != nil { - return err - } - if err := EnsureUpToDate(recipeName); err != nil { - return err - } - if err := EnsureLatest(recipeName); err != nil { - return err - } - return nil +type Recipe struct { + Name string + NameEscaped string + Dir string + GitURL string + + Config *composetypes.Config + Meta RecipeMeta } -// EnsureExists ensures that a recipe is locally cloned -func EnsureExists(recipeName string) error { - parsed, err := ParseName(recipeName) - if err != nil { - return err - } - recipeDir := path.Join(config.RECIPES_DIR, parsed.Name) - - if _, err := os.Stat(recipeDir); os.IsNotExist(err) { - logrus.Debugf("%s does not exist, attemmpting to clone", recipeDir) - if err := gitPkg.Clone(recipeDir, parsed.GitURL); err != nil { - return err - } - } - - if err := gitPkg.EnsureGitRepo(recipeDir); err != nil { - return err - } - - return nil -} - -type RecipeName struct { - Name string - GitURL string -} - -func ParseName(recipeName string) (RecipeName, error) { +func Get(recipeName string) (Recipe, error) { if !strings.Contains(recipeName, "/") { - return RecipeName{ + return Recipe{ Name: recipeName, GitURL: fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, recipeName), }, nil @@ -316,28 +281,64 @@ func ParseName(recipeName string) (RecipeName, error) { u, err := url.Parse(recipeName) if err != nil { - return RecipeName{}, err + return Recipe{}, err } u.Scheme = "https" u.RawPath, err = url.JoinPath(u.RawPath, ".git") if err != nil { - return RecipeName{}, err + return Recipe{}, err } - return RecipeName{ - Name: recipeName, - GitURL: u.String(), + return Recipe{ + Name: recipeName, + NameEscaped: escapeRecipeName(recipeName), + Dir: path.Join(config.RECIPES_DIR, escapeRecipeName(recipeName)), + GitURL: u.String(), }, nil } -// EnsureVersion checks whether a specific version exists for a recipe. -func EnsureVersion(recipeName, version string) error { - recipeDir := path.Join(config.RECIPES_DIR, recipeName) +func escapeRecipeName(recipeName string) string { + recipeName = strings.ReplaceAll(recipeName, "/", "_") + recipeName = strings.ReplaceAll(recipeName, ".", "_") + return recipeName +} - if err := gitPkg.EnsureGitRepo(recipeDir); err != nil { +// Ensure makes sure the recipe exists, is up to date and has the latest version checked out. +func (r Recipe) Ensure() error { + if err := r.EnsureExists(); err != nil { + return err + } + if err := r.EnsureUpToDate(); err != nil { + return err + } + if err := r.EnsureLatest(); err != nil { + return err + } + return nil +} + +// EnsureExists ensures that the recipe is locally cloned +func (r Recipe) EnsureExists() error { + if _, err := os.Stat(r.Dir); os.IsNotExist(err) { + logrus.Debugf("%s does not exist, attemmpting to clone", r.Dir) + if err := gitPkg.Clone(r.Dir, r.GitURL); err != nil { + return err + } + } + + if err := gitPkg.EnsureGitRepo(r.Dir); err != nil { return err } - repo, err := git.PlainOpen(recipeDir) + return nil +} + +// EnsureVersion checks whether a specific version exists for a recipe. +func (r Recipe) EnsureVersion(version string) error { + if err := gitPkg.EnsureGitRepo(r.Dir); err != nil { + return err + } + + repo, err := git.PlainOpen(r.Dir) if err != nil { return err } @@ -361,11 +362,11 @@ func EnsureVersion(recipeName, version string) error { joinedTags := strings.Join(parsedTags, ", ") if joinedTags != "" { - logrus.Debugf("read %s as tags for recipe %s", joinedTags, recipeName) + logrus.Debugf("read %s as tags for recipe %s", joinedTags, r.Name) } if tagRef.String() == "" { - return fmt.Errorf("the local copy of %s doesn't seem to have version %s available?", recipeName, version) + return fmt.Errorf("the local copy of %s doesn't seem to have version %s available?", r.Name, version) } worktree, err := repo.Worktree() @@ -382,37 +383,33 @@ func EnsureVersion(recipeName, version string) error { return err } - logrus.Debugf("successfully checked %s out to %s in %s", recipeName, tagRef.Short(), recipeDir) + logrus.Debugf("successfully checked %s out to %s in %s", r.Name, tagRef.Short(), r.Dir) return nil } // EnsureIsClean makes sure that the recipe repository has no unstaged changes. -func EnsureIsClean(recipeName string) error { - recipeDir := path.Join(config.RECIPES_DIR, recipeName) - - isClean, err := gitPkg.IsClean(recipeDir) +func (r Recipe) EnsureIsClean() error { + isClean, err := gitPkg.IsClean(r.Dir) if err != nil { - return fmt.Errorf("unable to check git clean status in %s: %s", recipeDir, err) + return fmt.Errorf("unable to check git clean status in %s: %s", r.Dir, err) } if !isClean { msg := "%s (%s) has locally unstaged changes? please commit/remove your changes before proceeding" - return fmt.Errorf(msg, recipeName, recipeDir) + return fmt.Errorf(msg, r.Name, r.Dir) } return nil } -// EnsureLatest makes sure the latest commit is checked out for a local recipe repository -func EnsureLatest(recipeName string) error { - recipeDir := path.Join(config.RECIPES_DIR, recipeName) - - if err := gitPkg.EnsureGitRepo(recipeDir); err != nil { +// EnsureLatest makes sure the latest commit is checked out for the local recipe repository +func (r Recipe) EnsureLatest() error { + if err := gitPkg.EnsureGitRepo(r.Dir); err != nil { return err } - repo, err := git.PlainOpen(recipeDir) + repo, err := git.PlainOpen(r.Dir) if err != nil { return err } @@ -422,7 +419,7 @@ func EnsureLatest(recipeName string) error { return err } - branch, err := gitPkg.GetDefaultBranch(repo, recipeDir) + branch, err := gitPkg.GetDefaultBranch(repo, r.Dir) if err != nil { return err } @@ -434,7 +431,7 @@ func EnsureLatest(recipeName string) error { } if err := worktree.Checkout(checkOutOpts); err != nil { - logrus.Debugf("failed to check out %s in %s", branch, recipeDir) + logrus.Debugf("failed to check out %s in %s", branch, r.Dir) return err } @@ -442,18 +439,17 @@ func EnsureLatest(recipeName string) error { } // ChaosVersion constructs a chaos mode recipe version. -func ChaosVersion(recipeName string) (string, error) { +func (r Recipe) ChaosVersion() (string, error) { var version string - head, err := gitPkg.GetRecipeHead(recipeName) + head, err := gitPkg.GetHead(r.Dir) if err != nil { return version, err } version = formatter.SmallSHA(head.String()) - recipeDir := path.Join(config.RECIPES_DIR, recipeName) - isClean, err := gitPkg.IsClean(recipeDir) + isClean, err := gitPkg.IsClean(r.Dir) if err != nil { return version, err } @@ -496,22 +492,22 @@ func GetVersionLabelLocal(recipe Recipe) (string, error) { return label, nil } -func GetRecipeFeaturesAndCategory(recipeName string) (Features, string, error) { +func (r Recipe) GetRecipeFeaturesAndCategory() (Features, string, error) { feat := Features{} var category string - readmePath := path.Join(config.RECIPES_DIR, recipeName, "README.md") + readmePath := path.Join(r.Dir, "README.md") logrus.Debugf("attempting to open %s for recipe metadata parsing", readmePath) - readmeFS, err := ioutil.ReadFile(readmePath) + readmeFS, err := os.ReadFile(readmePath) if err != nil { return feat, category, err } readmeMetadata, err := GetStringInBetween( // Find text between delimiters - recipeName, + r.Name, string(readmeFS), "", "", ) @@ -562,7 +558,7 @@ func GetRecipeFeaturesAndCategory(recipeName string) (Features, string, error) { if strings.Contains(val, "**Image**") { imageMetadata, err := GetImageMetadata(strings.TrimSpace( strings.TrimPrefix(val, "* **Image**:"), - ), recipeName) + ), r.Name) if err != nil { continue } @@ -629,38 +625,36 @@ func GetStringInBetween(recipeName, str, start, end string) (result string, err } // EnsureUpToDate ensures that the local repo is synced to the remote -func EnsureUpToDate(recipeName string) error { - recipeDir := path.Join(config.RECIPES_DIR, recipeName) - - repo, err := git.PlainOpen(recipeDir) +func (r Recipe) EnsureUpToDate() error { + repo, err := git.PlainOpen(r.Dir) if err != nil { - return fmt.Errorf("unable to open %s: %s", recipeDir, err) + return fmt.Errorf("unable to open %s: %s", r.Dir, err) } remotes, err := repo.Remotes() if err != nil { - return fmt.Errorf("unable to read remotes in %s: %s", recipeDir, err) + return fmt.Errorf("unable to read remotes in %s: %s", r.Dir, err) } if len(remotes) == 0 { - logrus.Debugf("cannot ensure %s is up-to-date, no git remotes configured", recipeName) + logrus.Debugf("cannot ensure %s is up-to-date, no git remotes configured", r.Name) return nil } worktree, err := repo.Worktree() if err != nil { - return fmt.Errorf("unable to open git work tree in %s: %s", recipeDir, err) + return fmt.Errorf("unable to open git work tree in %s: %s", r.Dir, err) } - branch, err := gitPkg.CheckoutDefaultBranch(repo, recipeDir) + branch, err := gitPkg.CheckoutDefaultBranch(repo, r.Dir) if err != nil { - return fmt.Errorf("unable to check out default branch in %s: %s", recipeDir, err) + return fmt.Errorf("unable to check out default branch in %s: %s", r.Dir, err) } fetchOpts := &git.FetchOptions{Tags: git.AllTags} if err := repo.Fetch(fetchOpts); err != nil { if !strings.Contains(err.Error(), "already up-to-date") { - return fmt.Errorf("unable to fetch tags in %s: %s", recipeDir, err) + return fmt.Errorf("unable to fetch tags in %s: %s", r.Dir, err) } } @@ -672,11 +666,11 @@ func EnsureUpToDate(recipeName string) error { if err := worktree.Pull(opts); err != nil { if !strings.Contains(err.Error(), "already up-to-date") { - return fmt.Errorf("unable to git pull in %s: %s", recipeDir, err) + return fmt.Errorf("unable to git pull in %s: %s", r.Dir, err) } } - logrus.Debugf("fetched latest git changes for %s", recipeName) + logrus.Debugf("fetched latest git changes for %s", r.Name) return nil } @@ -704,7 +698,7 @@ func ReadRecipeCatalogue(offline bool) (RecipeCatalogue, error) { // readRecipeCatalogueFS reads the catalogue from the file system. func readRecipeCatalogueFS(target interface{}) error { - recipesJSONFS, err := ioutil.ReadFile(config.RECIPES_JSON) + recipesJSONFS, err := os.ReadFile(config.RECIPES_JSON) if err != nil { return err } @@ -756,20 +750,20 @@ func (r RecipeMissingFromCatalogue) Error() string { } // GetRecipeMeta retrieves the recipe metadata from the recipe catalogue. -func GetRecipeMeta(recipeName string, offline bool) (RecipeMeta, error) { +func (r Recipe) GetRecipeMeta(offline bool) (RecipeMeta, error) { catl, err := ReadRecipeCatalogue(offline) if err != nil { return RecipeMeta{}, err } - recipeMeta, ok := catl[recipeName] + recipeMeta, ok := catl[r.Name] if !ok { return RecipeMeta{}, RecipeMissingFromCatalogue{ - err: fmt.Sprintf("recipe %s does not exist?", recipeName), + err: fmt.Sprintf("recipe %s does not exist?", r.Name), } } - logrus.Debugf("recipe metadata retrieved for %s", recipeName) + logrus.Debugf("recipe metadata retrieved for %s", r.Name) return recipeMeta, nil } @@ -896,13 +890,12 @@ func ReadReposMetadata() (RepoCatalogue, error) { } // GetRecipeVersions retrieves all recipe versions. -func GetRecipeVersions(recipeName string, offline bool) (RecipeVersions, error) { +func (r Recipe) GetVersions(offline bool) (RecipeVersions, error) { versions := RecipeVersions{} - recipeDir := path.Join(config.RECIPES_DIR, recipeName) - logrus.Debugf("attempting to open git repository in %s", recipeDir) + logrus.Debugf("attempting to open git repository in %s", r.Dir) - repo, err := git.PlainOpen(recipeDir) + repo, err := git.PlainOpen(r.Dir) if err != nil { return versions, err } @@ -920,7 +913,7 @@ func GetRecipeVersions(recipeName string, offline bool) (RecipeVersions, error) if err := gitTags.ForEach(func(ref *plumbing.Reference) (err error) { tag := strings.TrimPrefix(string(ref.Name()), "refs/tags/") - logrus.Debugf("processing %s for %s", tag, recipeName) + logrus.Debugf("processing %s for %s", tag, r.Name) checkOutOpts := &git.CheckoutOptions{ Create: false, @@ -928,19 +921,18 @@ func GetRecipeVersions(recipeName string, offline bool) (RecipeVersions, error) Branch: plumbing.ReferenceName(ref.Name()), } if err := worktree.Checkout(checkOutOpts); err != nil { - logrus.Debugf("failed to check out %s in %s", tag, recipeDir) + logrus.Debugf("failed to check out %s in %s", tag, r.Dir) return err } - logrus.Debugf("successfully checked out %s in %s", ref.Name(), recipeDir) + logrus.Debugf("successfully checked out %s in %s", ref.Name(), r.Dir) - recipe, err := Get(recipeName, offline) - if err != nil { + if err := r.LoadConfig(); err != nil { return err } versionMeta := make(map[string]ServiceMeta) - for _, service := range recipe.Config.Services { + for _, service := range r.Config.Services { img, err := reference.ParseNormalizedNamed(service.Image) if err != nil { @@ -973,14 +965,14 @@ func GetRecipeVersions(recipeName string, offline bool) (RecipeVersions, error) return versions, err } - _, err = gitPkg.CheckoutDefaultBranch(repo, recipeDir) + _, err = gitPkg.CheckoutDefaultBranch(repo, r.Dir) if err != nil { return versions, err } sortRecipeVersions(versions) - logrus.Debugf("collected %s for %s", versions, recipeName) + logrus.Debugf("collected %s for %s", versions, r.Name) return versions, nil } diff --git a/pkg/recipe/recipe_test.go b/pkg/recipe/recipe_test.go index 59a57ebc..56a39031 100644 --- a/pkg/recipe/recipe_test.go +++ b/pkg/recipe/recipe_test.go @@ -8,7 +8,7 @@ import ( func TestGetVersionLabelLocalDoesNotUseTimeoutLabel(t *testing.T) { offline := true - recipe, err := Get("traefik", offline) + recipe, err := Get2("traefik", offline) if err != nil { t.Fatal(err) }