Compare commits

..

2 Commits

Author SHA1 Message Date
0d8191bc3e review cleanups
All checks were successful
continuous-integration/drone/pr Build is passing
2023-02-17 03:24:04 -05:00
20cdfe7a72 Adding server prune and undeploy prune
All checks were successful
continuous-integration/drone/pr Build is passing
2023-02-14 21:25:37 -05:00
20 changed files with 88 additions and 187 deletions

View File

@ -5,11 +5,9 @@
- 3wordchant - 3wordchant
- cassowary - cassowary
- codegod100
- decentral1se - decentral1se
- frando - frando
- kawaiipunk - kawaiipunk
- knoflook - knoflook
- moritz - moritz
- roxxers - roxxers
- yksflip

View File

@ -53,7 +53,7 @@ recipes.
conf := runtime.New() conf := runtime.New()
if !internal.Chaos { if !internal.Chaos {
if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil { if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
} }

View File

@ -8,11 +8,8 @@ import (
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter"
stack "coopcloud.tech/abra/pkg/upstream/stack" stack "coopcloud.tech/abra/pkg/upstream/stack"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
dockerClient "github.com/docker/docker/client"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -25,56 +22,47 @@ var pruneFlag = &cli.BoolFlag{
Usage: "Prunes unused containers, networks, and dangling images for an app", Usage: "Prunes unused containers, networks, and dangling images for an app",
} }
// pruneApp runs the equivalent of a "docker system prune" but only filtering func cleanup(c *cli.Context) error {
// against resources connected with the app deployment. It is not a system wide
// prune. Volumes are not pruned to avoid unwated data loss.
func pruneApp(c *cli.Context, cl *dockerClient.Client, app config.App) error {
stackName := app.StackName()
ctx := context.Background()
for { for {
logrus.Debugf("polling for %s stack, waiting to be undeployed...", stackName) if !prune {
return nil
services, err := stack.GetStackServices(ctx, cl, stackName) }
app := internal.ValidateApp(c)
stackName := app.StackName()
cl, err := client.New(app.Server)
if err != nil { if err != nil {
return err logrus.Fatal(err)
}
if len(services) == 0 {
logrus.Debugf("%s undeployed, moving on with pruning logic", stackName)
time.Sleep(time.Second) // give runtime more time to tear down related state
break
}
time.Sleep(time.Second)
} }
ctx := context.Background()
pruneFilters := filters.NewArgs() pruneFilters := filters.NewArgs()
stackSearch := fmt.Sprintf("%s*", stackName) stackSearch := fmt.Sprintf("%s*", stackName)
pruneFilters.Add("label", stackSearch) pruneFilters.Add("label", stackSearch)
cr, err := cl.ContainersPrune(ctx, pruneFilters) cr, err := cl.ContainersPrune(ctx, pruneFilters)
if err != nil { if err != nil {
return err logrus.Errorf(err.Error())
time.Sleep(time.Second)
continue
} }
logrus.Infof("Containers deleted: %s; Space reclaimed: %v", cr.ContainersDeleted, cr.SpaceReclaimed)
cntSpaceReclaimed := formatter.ByteCountSI(cr.SpaceReclaimed)
logrus.Infof("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed)
nr, err := cl.NetworksPrune(ctx, pruneFilters) nr, err := cl.NetworksPrune(ctx, pruneFilters)
if err != nil { if err != nil {
return err logrus.Errorf(err.Error())
time.Sleep(time.Second)
continue
} }
logrus.Infof("Networks deleted %s", nr.NetworksDeleted)
logrus.Infof("networks pruned: %d", len(nr.NetworksDeleted))
ir, err := cl.ImagesPrune(ctx, pruneFilters) ir, err := cl.ImagesPrune(ctx, pruneFilters)
if err != nil { if err != nil {
return err logrus.Errorf(err.Error())
time.Sleep(time.Second)
continue
}
logrus.Infof("Images deleted: %s; Space reclaimed: %v", ir.ImagesDeleted, ir.SpaceReclaimed)
break
} }
imgSpaceReclaimed := formatter.ByteCountSI(ir.SpaceReclaimed)
logrus.Infof("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed)
return nil return nil
} }
@ -89,14 +77,10 @@ var appUndeployCommand = cli.Command{
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Usage: "Undeploy an app", Usage: "Undeploy an app",
BashComplete: autocomplete.AppNameComplete,
Description: ` Description: `
This does not destroy any of the application data. This does not destroy any of the application data. However, you should remain
vigilant, as your swarm installation will consider any previously attached
However, you should remain vigilant, as your swarm installation will consider volumes as eligible for pruning once undeployed.
any previously attached volumes as eligible for pruning once undeployed.
Passing "-p/--prune" does not remove those volumes.
`, `,
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
app := internal.ValidateApp(c) app := internal.ValidateApp(c)
@ -125,13 +109,8 @@ Passing "-p/--prune" does not remove those volumes.
if err := stack.RunRemove(context.Background(), cl, rmOpts); err != nil { if err := stack.RunRemove(context.Background(), cl, rmOpts); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
cleanup(c)
if prune {
if err := pruneApp(c, cl, app); err != nil {
logrus.Fatal(err)
}
}
return nil return nil
}, },
BashComplete: autocomplete.AppNameComplete,
} }

View File

@ -61,7 +61,7 @@ recipes.
} }
if !internal.Chaos { if !internal.Chaos {
if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil { if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
} }

View File

@ -13,7 +13,6 @@ import (
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
gitPkg "coopcloud.tech/abra/pkg/git" gitPkg "coopcloud.tech/abra/pkg/git"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -55,8 +54,6 @@ keys configured on your account.
ArgsUsage: "[<recipe>]", ArgsUsage: "[<recipe>]",
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
recipeName := c.Args().First() recipeName := c.Args().First()
conf := runtime.New()
if recipeName != "" { if recipeName != "" {
internal.ValidateRecipe(c) internal.ValidateRecipe(c)
} }
@ -82,7 +79,7 @@ keys configured on your account.
if !internal.SkipUpdates { if !internal.SkipUpdates {
logrus.Warn(logMsg) logrus.Warn(logMsg)
if err := recipe.UpdateRepositories(repos, recipeName, conf); err != nil { if err := recipe.UpdateRepositories(repos, recipeName); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
} }
@ -100,7 +97,7 @@ keys configured on your account.
continue continue
} }
versions, err := recipe.GetRecipeVersions(recipeMeta.Name, conf) versions, err := recipe.GetRecipeVersions(recipeMeta.Name)
if err != nil { if err != nil {
logrus.Warn(err) logrus.Warn(err)
} }

View File

@ -33,7 +33,7 @@ func DeployAction(c *cli.Context) error {
} }
if !Chaos { if !Chaos {
if err := recipe.EnsureUpToDate(app.Recipe, conf); err != nil { if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
} }

View File

@ -122,8 +122,7 @@ func ensureServerFlag() error {
func NewAction(c *cli.Context) error { func NewAction(c *cli.Context) error {
recipe := ValidateRecipeWithPrompt(c, runtime.WithEnsureRecipeLatest(false)) recipe := ValidateRecipeWithPrompt(c, runtime.WithEnsureRecipeLatest(false))
conf := runtime.New(runtime.WithEnsureRecipeLatest(false)) if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }

View File

@ -42,9 +42,11 @@ func ValidateRecipe(c *cli.Context, opts ...runtime.Option) recipe.Recipe {
} }
} }
if conf.EnsureRecipeLatest {
if err := recipe.EnsureLatest(recipeName, conf); err != nil { if err := recipe.EnsureLatest(recipeName, conf); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
}
logrus.Debugf("validated %s as recipe argument", recipeName) logrus.Debugf("validated %s as recipe argument", recipeName)
@ -108,9 +110,11 @@ func ValidateRecipeWithPrompt(c *cli.Context, opts ...runtime.Option) recipe.Rec
logrus.Fatal(err) logrus.Fatal(err)
} }
if conf.EnsureRecipeLatest {
if err := recipe.EnsureLatest(recipeName, conf); err != nil { if err := recipe.EnsureLatest(recipeName, conf); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
}
logrus.Debugf("validated %s as recipe argument", recipeName) logrus.Debugf("validated %s as recipe argument", recipeName)

View File

@ -4,7 +4,6 @@ import (
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -22,8 +21,6 @@ var recipeFetchCommand = cli.Command{
BashComplete: autocomplete.RecipeNameComplete, BashComplete: autocomplete.RecipeNameComplete,
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
recipeName := c.Args().First() recipeName := c.Args().First()
conf := runtime.New()
if recipeName != "" { if recipeName != "" {
internal.ValidateRecipe(c) internal.ValidateRecipe(c)
return nil // ValidateRecipe ensures latest checkout return nil // ValidateRecipe ensures latest checkout
@ -34,7 +31,7 @@ var recipeFetchCommand = cli.Command{
logrus.Fatal(err) logrus.Fatal(err)
} }
if err := recipe.UpdateRepositories(repos, recipeName, conf); err != nil { if err := recipe.UpdateRepositories(repos, recipeName); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }

View File

@ -8,7 +8,6 @@ import (
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
"coopcloud.tech/abra/pkg/lint" "coopcloud.tech/abra/pkg/lint"
recipePkg "coopcloud.tech/abra/pkg/recipe" recipePkg "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@ -26,9 +25,8 @@ var recipeLintCommand = cli.Command{
BashComplete: autocomplete.RecipeNameComplete, BashComplete: autocomplete.RecipeNameComplete,
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipe(c) recipe := internal.ValidateRecipe(c)
conf := runtime.New()
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil { if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }

View File

@ -14,7 +14,6 @@ import (
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
recipePkg "coopcloud.tech/abra/pkg/recipe" recipePkg "coopcloud.tech/abra/pkg/recipe"
"coopcloud.tech/abra/pkg/runtime"
"coopcloud.tech/tagcmp" "coopcloud.tech/tagcmp"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
@ -61,9 +60,8 @@ You may invoke this command in "wizard" mode and be prompted for input:
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipeWithPrompt(c) recipe := internal.ValidateRecipeWithPrompt(c)
conf := runtime.New()
if err := recipePkg.EnsureUpToDate(recipe.Name, conf); err != nil { if err := recipePkg.EnsureUpToDate(recipe.Name); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }

View File

@ -39,7 +39,11 @@ var serverListCommand = cli.Command{
tableColumns := []string{"name", "host", "user", "port"} tableColumns := []string{"name", "host", "user", "port"}
table := formatter.CreateTable(tableColumns) table := formatter.CreateTable(tableColumns)
if internal.MachineReadable {
defer table.JSONRender()
} else {
defer table.Render()
}
serverNames, err := config.ReadServerNames() serverNames, err := config.ReadServerNames()
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
@ -80,16 +84,6 @@ var serverListCommand = cli.Command{
} }
} }
if internal.MachineReadable {
table.JSONRender()
} else {
if problemsFilter && table.NumLines() == 0 {
logrus.Info("all servers wired up correctly 👏")
} else {
table.Render()
}
}
return nil return nil
}, },
} }

View File

@ -4,9 +4,7 @@ import (
"context" "context"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/formatter"
"github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/filters"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -24,7 +22,7 @@ var volunesFilter bool
var volumesFilterFlag = &cli.BoolFlag{ var volumesFilterFlag = &cli.BoolFlag{
Name: "volumes, v", Name: "volumes, v",
Usage: "Prune volumes. This will remove app data, Be Careful!", Usage: "Prune volumes",
Destination: &volunesFilter, Destination: &volunesFilter,
} }
@ -32,12 +30,7 @@ var serverPruneCommand = cli.Command{
Name: "prune", Name: "prune",
Aliases: []string{"p"}, Aliases: []string{"p"},
Usage: "Prune a managed server; Runs a docker system prune", Usage: "Prune a managed server; Runs a docker system prune",
Description: ` Description: "Prunes unused containers, networks, and dangling images",
Prunes unused containers, networks, and dangling images.
If passing "-v/--volumes" then volumes not connected with a deployed app will
also be removed. This can result in unwanted data loss if not used carefully.
`,
ArgsUsage: "[<server>]", ArgsUsage: "[<server>]",
Flags: []cli.Flag{ Flags: []cli.Flag{
allFilterFlag, allFilterFlag,
@ -45,54 +38,44 @@ also be removed. This can result in unwanted data loss if not used carefully.
internal.DebugFlag, internal.DebugFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.ServerNameComplete,
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
// Leaving filters empty for now
var args filters.Args var args filters.Args
serverName := internal.ValidateServer(c) serverName := internal.ValidateServer(c)
cl, err := client.New(serverName) cl, err := client.New(serverName)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
ctx := context.Background() ctx := context.Background()
cr, err := cl.ContainersPrune(ctx, args) cr, err := cl.ContainersPrune(ctx, args)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
logrus.Infof("Containers deleted: %s; Space reclaimed: %v", cr.ContainersDeleted, cr.SpaceReclaimed)
cntSpaceReclaimed := formatter.ByteCountSI(cr.SpaceReclaimed)
logrus.Infof("containers pruned: %d; space reclaimed: %s", len(cr.ContainersDeleted), cntSpaceReclaimed)
nr, err := cl.NetworksPrune(ctx, args) nr, err := cl.NetworksPrune(ctx, args)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
logrus.Infof("Networks deleted %s", nr.NetworksDeleted)
logrus.Infof("networks pruned: %d", len(nr.NetworksDeleted))
pruneFilters := filters.NewArgs() pruneFilters := filters.NewArgs()
if allFilter { if allFilter {
pruneFilters.Add("dangling", "false") pruneFilters.Add("dangling", "false")
} }
ir, err := cl.ImagesPrune(ctx, pruneFilters) ir, err := cl.ImagesPrune(ctx, pruneFilters)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
logrus.Infof("Images deleted: %s; Space reclaimed: %v", ir.ImagesDeleted, ir.SpaceReclaimed)
imgSpaceReclaimed := formatter.ByteCountSI(ir.SpaceReclaimed)
logrus.Infof("images pruned: %d; space reclaimed: %s", len(ir.ImagesDeleted), imgSpaceReclaimed)
if volunesFilter { if volunesFilter {
vr, err := cl.VolumesPrune(ctx, args) vr, err := cl.VolumesPrune(ctx, args)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
logrus.Infof("Volumes deleted: %s; Space reclaimed: %v", vr.VolumesDeleted, vr.SpaceReclaimed)
volSpaceReclaimed := formatter.ByteCountSI(vr.SpaceReclaimed)
logrus.Infof("volumes pruned: %d; space reclaimed: %s", len(vr.VolumesDeleted), volSpaceReclaimed)
} }
return nil return nil

View File

@ -7,7 +7,6 @@ import (
"path/filepath" "path/filepath"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/formatter"
@ -126,7 +125,6 @@ like tears in rain.
internal.HetznerCloudAPITokenFlag, internal.HetznerCloudAPITokenFlag,
}, },
Before: internal.SubCommandBefore, Before: internal.SubCommandBefore,
BashComplete: autocomplete.ServerNameComplete,
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
serverName := internal.ValidateServer(c) serverName := internal.ValidateServer(c)

View File

@ -321,7 +321,7 @@ func processRecipeRepoVersion(recipeName, version string, conf *runtime.Config)
return err return err
} }
if err := recipe.EnsureUpToDate(recipeName, conf); err != nil { if err := recipe.EnsureUpToDate(recipeName); err != nil {
return err return err
} }

View File

@ -9,7 +9,7 @@ import (
"github.com/urfave/cli" "github.com/urfave/cli"
) )
// AppNameComplete copletes app names. // AppNameComplete copletes app names
func AppNameComplete(c *cli.Context) { func AppNameComplete(c *cli.Context) {
appNames, err := config.GetAppNames() appNames, err := config.GetAppNames()
if err != nil { if err != nil {
@ -25,7 +25,7 @@ func AppNameComplete(c *cli.Context) {
} }
} }
// RecipeNameComplete completes recipe names. // RecipeNameComplete completes recipe names
func RecipeNameComplete(c *cli.Context) { func RecipeNameComplete(c *cli.Context) {
catl, err := recipe.ReadRecipeCatalogue() catl, err := recipe.ReadRecipeCatalogue()
if err != nil { if err != nil {
@ -41,23 +41,7 @@ func RecipeNameComplete(c *cli.Context) {
} }
} }
// ServerNameComplete completes server names. // SubcommandComplete completes subcommands.
func ServerNameComplete(c *cli.Context) {
files, err := config.LoadAppFiles("")
if err != nil {
logrus.Fatal(err)
}
if c.NArg() > 0 {
return
}
for _, appFile := range files {
fmt.Println(appFile.Server)
}
}
// SubcommandComplete completes sub-commands.
func SubcommandComplete(c *cli.Context) { func SubcommandComplete(c *cli.Context) {
if c.NArg() > 0 { if c.NArg() > 0 {
return return

View File

@ -1,7 +1,6 @@
package formatter package formatter
import ( import (
"fmt"
"os" "os"
"strings" "strings"
"time" "time"
@ -71,21 +70,3 @@ func StripTagMeta(image string) string {
return image return image
} }
// ByteCountSI presents a human friendly representation of a byte count. See
// https://yourbasic.org/golang/formatting-byte-size-to-human-readable-format.
func ByteCountSI(b uint64) string {
const unit = 1000
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := uint64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
}

View File

@ -339,10 +339,6 @@ func EnsureVersion(recipeName, version string) error {
// EnsureLatest makes sure the latest commit is checked out for a local recipe repository // EnsureLatest makes sure the latest commit is checked out for a local recipe repository
func EnsureLatest(recipeName string, conf *runtime.Config) error { func EnsureLatest(recipeName string, conf *runtime.Config) error {
if !conf.EnsureRecipeLatest {
return nil
}
recipeDir := path.Join(config.RECIPES_DIR, recipeName) recipeDir := path.Join(config.RECIPES_DIR, recipeName)
isClean, err := gitPkg.IsClean(recipeDir) isClean, err := gitPkg.IsClean(recipeDir)
@ -587,11 +583,7 @@ func GetStringInBetween(recipeName, str, start, end string) (result string, err
} }
// EnsureUpToDate ensures that the local repo is synced to the remote // EnsureUpToDate ensures that the local repo is synced to the remote
func EnsureUpToDate(recipeName string, conf *runtime.Config) error { func EnsureUpToDate(recipeName string) error {
if !conf.EnsureRecipeLatest {
return nil
}
recipeDir := path.Join(config.RECIPES_DIR, recipeName) recipeDir := path.Join(config.RECIPES_DIR, recipeName)
isClean, err := gitPkg.IsClean(recipeDir) isClean, err := gitPkg.IsClean(recipeDir)
@ -936,8 +928,10 @@ func ReadReposMetadata() (RepoCatalogue, error) {
} }
// GetRecipeVersions retrieves all recipe versions. // GetRecipeVersions retrieves all recipe versions.
func GetRecipeVersions(recipeName string, conf *runtime.Config) (RecipeVersions, error) { func GetRecipeVersions(recipeName string, opts ...runtime.Option) (RecipeVersions, error) {
versions := RecipeVersions{} versions := RecipeVersions{}
conf := runtime.New(opts...)
recipeDir := path.Join(config.RECIPES_DIR, recipeName) 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", recipeDir)
@ -1039,7 +1033,7 @@ func GetRecipeCatalogueVersions(recipeName string, catl RecipeCatalogue) ([]stri
} }
// UpdateRepositories clones and updates all recipe repositories locally. // UpdateRepositories clones and updates all recipe repositories locally.
func UpdateRepositories(repos RepoCatalogue, recipeName string, conf *runtime.Config) error { func UpdateRepositories(repos RepoCatalogue, recipeName string) error {
var barLength int var barLength int
if recipeName != "" { if recipeName != "" {
barLength = 1 barLength = 1
@ -1073,7 +1067,7 @@ func UpdateRepositories(repos RepoCatalogue, recipeName string, conf *runtime.Co
logrus.Fatal(err) logrus.Fatal(err)
} }
if err := EnsureUpToDate(rm.Name, conf); err != nil { if err := EnsureUpToDate(rm.Name); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }

View File

@ -11,10 +11,7 @@ type Config struct {
EnsureRecipeLatest bool // ensure the local recipe has latest changes EnsureRecipeLatest bool // ensure the local recipe has latest changes
} }
// Option modified a Config. The convetion for passing Options to functions is // Option modified a Config.
// so far, only used in internal/validate.go. A Config is then constructed and
// passed down further into the code. This may change in the future but this is
// at least the abstraction so far.
type Option func(c *Config) type Option func(c *Config)
// New instantiates a new Config. // New instantiates a new Config.

View File

@ -2,7 +2,7 @@
ABRA_VERSION="0.6.0-beta" ABRA_VERSION="0.6.0-beta"
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION" ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION"
RC_VERSION="0.7.0-rc3-beta" RC_VERSION="0.7.0-rc2-beta"
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION" RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION"
for arg in "$@"; do for arg in "$@"; do