Compare commits
	
		
			15 Commits
		
	
	
		
			0.8.1-beta
			...
			cr_fix_ls-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d041deec68 | |||
| 3939971d82 | |||
| 1d098eed0e | |||
| 74200318ab | |||
| 609656b4e1 | |||
| 
						
						
							
						
						856c9f2f7d
	
				 | 
					
					
						|||
| bd5cdd3443 | |||
| 79d274e074 | |||
| 51e3df17f1 | |||
| ccf0215495 | |||
| 
						
						
							
						
						254df7f2be
	
				 | 
					
					
						|||
| 
						
						
							
						
						6a673ef101
	
				 | 
					
					
						|||
| 
						
						
							
						
						7f7f7224c6
	
				 | 
					
					
						|||
| 
						
						
							
						
						f96bf9a8ac
	
				 | 
					
					
						|||
| 
						
						
							
						
						dcecf32999
	
				 | 
					
					
						
							
								
								
									
										5
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								Makefile
									
									
									
									
									
								
							@ -30,6 +30,11 @@ build-kadabra:
 | 
			
		||||
 | 
			
		||||
build: build-abra build-kadabra
 | 
			
		||||
 | 
			
		||||
build-docker-abra:
 | 
			
		||||
	docker run -it -v $(PWD):/abra golang:1.21 bash -c 'cd /abra; ./build-docker-inside.sh'
 | 
			
		||||
 | 
			
		||||
build-docker: build-docker-abra
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	@rm '$(GOPATH)/bin/abra'
 | 
			
		||||
	@rm '$(GOPATH)/bin/kadabra'
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								build-docker-inside.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										19
									
								
								build-docker-inside.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
if [ ! -f .envrc ]; then
 | 
			
		||||
    . .envrc.sample
 | 
			
		||||
else
 | 
			
		||||
    . .envrc
 | 
			
		||||
fi
 | 
			
		||||
git config --global --add safe.directory /abra  # work around funky file permissions
 | 
			
		||||
 | 
			
		||||
# fixme for some reason we need to do this
 | 
			
		||||
go get coopcloud.tech/abra/pkg/upstream/commandconn
 | 
			
		||||
go get github.com/sirupsen/logrus@v1.9.3
 | 
			
		||||
go get github.com/cloudflare/circl/dh/x25519@v1.3.3
 | 
			
		||||
go get github.com/mattn/go-runewidth@v0.0.14
 | 
			
		||||
go get go get coopcloud.tech/abra/pkg/config
 | 
			
		||||
go get github.com/mattn/go-colorable@v0.1.12
 | 
			
		||||
go get coopcloud.tech/abra/pkg/config
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
make build
 | 
			
		||||
@ -6,6 +6,7 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"path"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
@ -22,8 +23,7 @@ var appCmdCommand = cli.Command{
 | 
			
		||||
	Name:    "command",
 | 
			
		||||
	Aliases: []string{"cmd"},
 | 
			
		||||
	Usage:   "Run app commands",
 | 
			
		||||
	Description: `
 | 
			
		||||
Run an app specific command.
 | 
			
		||||
	Description: `Run an app specific command.
 | 
			
		||||
 | 
			
		||||
These commands are bash functions, defined in the abra.sh of the recipe itself.
 | 
			
		||||
They can be run within the context of a service (e.g. app) or locally on your
 | 
			
		||||
@ -43,8 +43,8 @@ Example:
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Before:      internal.SubCommandBefore,
 | 
			
		||||
	Subcommands: []cli.Command{appCmdListCommand},
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
 | 
			
		||||
@ -186,3 +186,53 @@ func parseCmdArgs(args []string, isLocal bool) (bool, string) {
 | 
			
		||||
 | 
			
		||||
	return hasCmdArgs, parsedCmdArgs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var appCmdListCommand = cli.Command{
 | 
			
		||||
	Name:      "list",
 | 
			
		||||
	Aliases:   []string{"ls"},
 | 
			
		||||
	Usage:     "List all available commands",
 | 
			
		||||
	ArgsUsage: "<domain>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.OfflineFlag,
 | 
			
		||||
		internal.ChaosFlag,
 | 
			
		||||
	},
 | 
			
		||||
	BashComplete: autocomplete.AppNameComplete,
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		app := internal.ValidateApp(c)
 | 
			
		||||
 | 
			
		||||
		if err := recipe.EnsureExists(app.Recipe); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !internal.Chaos {
 | 
			
		||||
			if err := recipePkg.EnsureIsClean(app.Recipe); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if !internal.Offline {
 | 
			
		||||
				if err := recipePkg.EnsureUpToDate(app.Recipe); err != nil {
 | 
			
		||||
					logrus.Fatal(err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if err := recipePkg.EnsureLatest(app.Recipe); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		abraShPath := fmt.Sprintf("%s/%s/%s", config.RECIPES_DIR, app.Recipe, "abra.sh")
 | 
			
		||||
		cmdNames, err := config.ReadAbraShCmdNames(abraShPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sort.Strings(cmdNames)
 | 
			
		||||
		for _, cmdName := range cmdNames {
 | 
			
		||||
			fmt.Println(cmdName)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -176,25 +176,28 @@ can take some time.
 | 
			
		||||
					appStats.AutoUpdate = autoUpdate
 | 
			
		||||
 | 
			
		||||
					var newUpdates []string
 | 
			
		||||
					if version != "unknown" {
 | 
			
		||||
						updates, err := recipe.GetRecipeCatalogueVersions(app.Recipe, catl)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							logrus.Fatal(err)
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
					if (version != "unknown") {
 | 
			
		||||
						parsedVersion, err := tagcmp.Parse(version)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							logrus.Fatal(err)
 | 
			
		||||
						}
 | 
			
		||||
						if (err != nil) {
 | 
			
		||||
							logrus.Warning("Can't parse ", app.Recipe, " version ", version, " ", err)
 | 
			
		||||
						} else {
 | 
			
		||||
							updates, err := recipe.GetRecipeCatalogueVersions(app.Recipe, catl)
 | 
			
		||||
 | 
			
		||||
						for _, update := range updates {
 | 
			
		||||
							parsedUpdate, err := tagcmp.Parse(update)
 | 
			
		||||
							if err != nil {
 | 
			
		||||
								logrus.Fatal(err)
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							if update != version && parsedUpdate.IsGreaterThan(parsedVersion) {
 | 
			
		||||
								newUpdates = append(newUpdates, update)
 | 
			
		||||
							for _, update := range updates {
 | 
			
		||||
								parsedUpdate, err := tagcmp.Parse(update)
 | 
			
		||||
								if err != nil {
 | 
			
		||||
									logrus.Warning("can't parse ", app.Recipe," update version ", update, " ", err)
 | 
			
		||||
									continue
 | 
			
		||||
								}
 | 
			
		||||
 | 
			
		||||
								if update != version && parsedUpdate.IsGreaterThan(parsedVersion) {
 | 
			
		||||
									newUpdates = append(newUpdates, update)
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
@ -98,11 +98,6 @@ keys configured on your account.
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if _, exists := catalogue.CatalogueSkipList[recipeMeta.Name]; exists {
 | 
			
		||||
				catlBar.Add(1)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			versions, err := recipe.GetRecipeVersions(recipeMeta.Name, internal.Offline)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Warn(err)
 | 
			
		||||
@ -173,7 +168,7 @@ keys configured on your account.
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			msg := "chore: publish new catalogue release changes"
 | 
			
		||||
			if err := gitPkg.Commit(cataloguePath, "**.json", msg, internal.Dry); err != nil {
 | 
			
		||||
			if err := gitPkg.Commit(cataloguePath, msg, internal.Dry); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								cli/recipe/diff.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								cli/recipe/diff.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/config"
 | 
			
		||||
	gitPkg "coopcloud.tech/abra/pkg/git"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
	"github.com/urfave/cli"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var recipeDiffCommand = cli.Command{
 | 
			
		||||
	Name:        "diff",
 | 
			
		||||
	Usage:       "Show unstaged changes in recipe config",
 | 
			
		||||
	Description: "Due to limitations in our underlying Git dependency, this command requires /usr/bin/git.",
 | 
			
		||||
	Aliases:     []string{"d"},
 | 
			
		||||
	ArgsUsage:   "<recipe>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipeName := c.Args().First()
 | 
			
		||||
 | 
			
		||||
		if recipeName != "" {
 | 
			
		||||
			internal.ValidateRecipe(c)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		recipeDir := path.Join(config.RECIPES_DIR, recipeName)
 | 
			
		||||
		if err := gitPkg.DiffUnstaged(recipeDir); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
@ -30,5 +30,7 @@ manner. Abra supports convenient automation for recipe maintainenace, see the
 | 
			
		||||
		recipeSyncCommand,
 | 
			
		||||
		recipeUpgradeCommand,
 | 
			
		||||
		recipeVersionCommand,
 | 
			
		||||
		recipeResetCommand,
 | 
			
		||||
		recipeDiffCommand,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -106,6 +106,18 @@ your SSH keys configured on your account.
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(tags) > 0 {
 | 
			
		||||
			logrus.Warnf("previous git tags detected, assuming this is a new semver release")
 | 
			
		||||
			if err := createReleaseFromPreviousTag(tagString, mainAppVersion, recipe, tags); err != nil {
 | 
			
		||||
@ -244,7 +256,7 @@ func commitRelease(recipe recipe.Recipe, tag string) error {
 | 
			
		||||
 | 
			
		||||
	msg := fmt.Sprintf("chore: publish %s release", tag)
 | 
			
		||||
	repoPath := path.Join(config.RECIPES_DIR, recipe.Name)
 | 
			
		||||
	if err := gitPkg.Commit(repoPath, ".", msg, internal.Dry); err != nil {
 | 
			
		||||
	if err := gitPkg.Commit(repoPath, msg, internal.Dry); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								cli/recipe/reset.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								cli/recipe/reset.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
package recipe
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path"
 | 
			
		||||
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/config"
 | 
			
		||||
	"github.com/go-git/go-git/v5"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
	"github.com/urfave/cli"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var recipeResetCommand = cli.Command{
 | 
			
		||||
	Name:        "reset",
 | 
			
		||||
	Usage:       "Remove all unstaged changes from recipe config",
 | 
			
		||||
	Description: "WARNING, this will delete your changes. Be Careful.",
 | 
			
		||||
	Aliases:     []string{"rs"},
 | 
			
		||||
	ArgsUsage:   "<recipe>",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.DebugFlag,
 | 
			
		||||
		internal.NoInputFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Before:       internal.SubCommandBefore,
 | 
			
		||||
	BashComplete: autocomplete.RecipeNameComplete,
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		recipeName := c.Args().First()
 | 
			
		||||
 | 
			
		||||
		if recipeName != "" {
 | 
			
		||||
			internal.ValidateRecipe(c)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		repoPath := path.Join(config.RECIPES_DIR, recipeName)
 | 
			
		||||
		repo, err := git.PlainOpen(repoPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ref, err := repo.Head()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		worktree, err := repo.Worktree()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		opts := &git.ResetOptions{Commit: ref.Hash(), Mode: git.HardReset}
 | 
			
		||||
		if err := worktree.Reset(opts); err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/cli/internal"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/config"
 | 
			
		||||
	gitPkg "coopcloud.tech/abra/pkg/git"
 | 
			
		||||
	"coopcloud.tech/tagcmp"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
	"github.com/go-git/go-git/v5"
 | 
			
		||||
@ -198,6 +199,17 @@ likely to change.
 | 
			
		||||
			logrus.Infof("dry run: not syncing label %s for recipe %s", nextTag, recipe.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ import (
 | 
			
		||||
	"coopcloud.tech/abra/pkg/client"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/config"
 | 
			
		||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
			
		||||
	gitPkg "coopcloud.tech/abra/pkg/git"
 | 
			
		||||
	recipePkg "coopcloud.tech/abra/pkg/recipe"
 | 
			
		||||
	"coopcloud.tech/tagcmp"
 | 
			
		||||
	"github.com/AlecAivazis/survey/v2"
 | 
			
		||||
@ -326,6 +327,7 @@ You may invoke this command in "wizard" mode and be prompted for input:
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				fmt.Println(string(jsonstring))
 | 
			
		||||
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -336,6 +338,18 @@ You may invoke this command in "wizard" mode and be prompted for input:
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		isClean, err := gitPkg.IsClean(recipeDir)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		if !isClean {
 | 
			
		||||
			logrus.Infof("%s currently has these unstaged changes 👇", recipe.Name)
 | 
			
		||||
			if err := gitPkg.DiffUnstaged(recipeDir); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								go.mod
									
									
									
									
									
								
							@ -7,16 +7,16 @@ require (
 | 
			
		||||
	github.com/AlecAivazis/survey/v2 v2.3.7
 | 
			
		||||
	github.com/Autonomic-Cooperative/godotenv v1.3.1-0.20210731094149-b031ea1211e7
 | 
			
		||||
	github.com/Gurpartap/logrus-stack v0.0.0-20170710170904-89c00d8a28f4
 | 
			
		||||
	github.com/docker/cli v24.0.6+incompatible
 | 
			
		||||
	github.com/docker/cli v24.0.7+incompatible
 | 
			
		||||
	github.com/docker/distribution v2.8.3+incompatible
 | 
			
		||||
	github.com/docker/docker v24.0.6+incompatible
 | 
			
		||||
	github.com/docker/docker v24.0.7+incompatible
 | 
			
		||||
	github.com/docker/go-units v0.5.0
 | 
			
		||||
	github.com/go-git/go-git/v5 v5.9.0
 | 
			
		||||
	github.com/go-git/go-git/v5 v5.10.0
 | 
			
		||||
	github.com/moby/sys/signal v0.7.0
 | 
			
		||||
	github.com/moby/term v0.5.0
 | 
			
		||||
	github.com/olekukonko/tablewriter v0.0.5
 | 
			
		||||
	github.com/pkg/errors v0.9.1
 | 
			
		||||
	github.com/schollz/progressbar/v3 v3.13.1
 | 
			
		||||
	github.com/schollz/progressbar/v3 v3.14.0
 | 
			
		||||
	github.com/sirupsen/logrus v1.9.3
 | 
			
		||||
	gotest.tools/v3 v3.5.1
 | 
			
		||||
)
 | 
			
		||||
@ -78,11 +78,11 @@ require (
 | 
			
		||||
	github.com/xanzy/ssh-agent v0.3.3 // indirect
 | 
			
		||||
	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
 | 
			
		||||
	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.13.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.14.0 // indirect
 | 
			
		||||
	golang.org/x/mod v0.12.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.15.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.17.0 // indirect
 | 
			
		||||
	golang.org/x/sync v0.3.0 // indirect
 | 
			
		||||
	golang.org/x/term v0.12.0 // indirect
 | 
			
		||||
	golang.org/x/term v0.13.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.13.0 // indirect
 | 
			
		||||
	golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
 | 
			
		||||
	golang.org/x/tools v0.13.0 // indirect
 | 
			
		||||
@ -116,5 +116,5 @@ require (
 | 
			
		||||
	github.com/theupdateframework/notary v0.7.0 // indirect
 | 
			
		||||
	github.com/urfave/cli v1.22.9
 | 
			
		||||
	github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b // indirect
 | 
			
		||||
	golang.org/x/sys v0.13.0
 | 
			
		||||
	golang.org/x/sys v0.14.0
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								go.sum
									
									
									
									
									
								
							@ -339,16 +339,16 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK
 | 
			
		||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 | 
			
		||||
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
 | 
			
		||||
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 | 
			
		||||
github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY=
 | 
			
		||||
github.com/docker/cli v24.0.6+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 | 
			
		||||
github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg=
 | 
			
		||||
github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 | 
			
		||||
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
 | 
			
		||||
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
			
		||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
			
		||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
 | 
			
		||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 | 
			
		||||
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
			
		||||
github.com/docker/docker v24.0.6+incompatible h1:hceabKCtUgDqPu+qm0NgsaXf28Ljf4/pWFL7xjWWDgE=
 | 
			
		||||
github.com/docker/docker v24.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
			
		||||
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
 | 
			
		||||
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 | 
			
		||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
 | 
			
		||||
github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o=
 | 
			
		||||
github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c=
 | 
			
		||||
@ -417,10 +417,10 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D
 | 
			
		||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
 | 
			
		||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
 | 
			
		||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.10.0 h1:F0x3xXrAWmhwtzoCokU4IMPcBdncG+HAAqi9FcOOjbQ=
 | 
			
		||||
github.com/go-git/go-git/v5 v5.10.0/go.mod h1:1FOZ/pQnqw24ghP2n7cunVl0ON55BsjPYvhWHvZGhoo=
 | 
			
		||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 | 
			
		||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
			
		||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 | 
			
		||||
@ -1069,8 +1069,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
 | 
			
		||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
			
		||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
 | 
			
		||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
 | 
			
		||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
 | 
			
		||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 | 
			
		||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
 | 
			
		||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 | 
			
		||||
@ -1168,8 +1168,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
 | 
			
		||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
 | 
			
		||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 | 
			
		||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
 | 
			
		||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
 | 
			
		||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 | 
			
		||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
 | 
			
		||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
			
		||||
@ -1323,8 +1323,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
 | 
			
		||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
 | 
			
		||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 | 
			
		||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
 | 
			
		||||
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
 | 
			
		||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 | 
			
		||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
 | 
			
		||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
 | 
			
		||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 | 
			
		||||
 | 
			
		||||
@ -12,46 +12,6 @@ import (
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CatalogueSkipList is all the repos that are not recipes.
 | 
			
		||||
var CatalogueSkipList = map[string]bool{
 | 
			
		||||
	"abra":                        true,
 | 
			
		||||
	"abra-apps":                   true,
 | 
			
		||||
	"abra-aur":                    true,
 | 
			
		||||
	"abra-bash":                   true,
 | 
			
		||||
	"abra-capsul":                 true,
 | 
			
		||||
	"abra-gandi":                  true,
 | 
			
		||||
	"abra-hetzner":                true,
 | 
			
		||||
	"abra-test-recipe":            true,
 | 
			
		||||
	"apps":                        true,
 | 
			
		||||
	"aur-abra-git":                true,
 | 
			
		||||
	"auto-mirror":                 true,
 | 
			
		||||
	"auto-recipes-catalogue-json": true,
 | 
			
		||||
	"backup-bot":                  true,
 | 
			
		||||
	"backup-bot-two":              true,
 | 
			
		||||
	"beta.coopcloud.tech":         true,
 | 
			
		||||
	"comrade-renovate-bot":        true,
 | 
			
		||||
	"coopcloud.tech":              true,
 | 
			
		||||
	"coturn":                      true,
 | 
			
		||||
	"docker-cp-deploy":            true,
 | 
			
		||||
	"docker-dind-bats-kcov":       true,
 | 
			
		||||
	"docs.coopcloud.tech":         true,
 | 
			
		||||
	"drone-abra":                  true,
 | 
			
		||||
	"example":                     true,
 | 
			
		||||
	"gardening":                   true,
 | 
			
		||||
	"go-abra":                     true,
 | 
			
		||||
	"organising":                  true,
 | 
			
		||||
	"pyabra":                      true,
 | 
			
		||||
	"radicle-seed-node":           true,
 | 
			
		||||
	"recipes-catalogue-json":      true,
 | 
			
		||||
	"recipes-wishlist":            true,
 | 
			
		||||
	"recipes.coopcloud.tech":      true,
 | 
			
		||||
	"stack-ssh-deploy":            true,
 | 
			
		||||
	"swarm-cronjob":               true,
 | 
			
		||||
	"tagcmp":                      true,
 | 
			
		||||
	"traefik-cert-dumper":         true,
 | 
			
		||||
	"tyop":                        true,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnsureCatalogue ensures that the catalogue is cloned locally & present.
 | 
			
		||||
func EnsureCatalogue() error {
 | 
			
		||||
	catalogueDir := path.Join(config.ABRA_DIR, "catalogue")
 | 
			
		||||
 | 
			
		||||
@ -79,15 +79,15 @@ func ReadEnv(filePath string, opts ReadEnvOptions) (AppEnv, error) {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for idx, envVar := range envVars {
 | 
			
		||||
		if strings.Contains(envVar, "#") {
 | 
			
		||||
			if opts.IncludeModifiers && ContainsEnvVarModifier(envVar) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			vals := strings.Split(envVar, "#")
 | 
			
		||||
			envVars[idx] = strings.TrimSpace(vals[0])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	//	for idx, envVar := range envVars {
 | 
			
		||||
	//		if strings.Contains(envVar, "#") {
 | 
			
		||||
	//			if opts.IncludeModifiers && ContainsEnvVarModifier(envVar) {
 | 
			
		||||
	//				continue
 | 
			
		||||
	//			}
 | 
			
		||||
	//			vals := strings.Split(envVar, "#")
 | 
			
		||||
	//			envVars[idx] = strings.TrimSpace(vals[0])
 | 
			
		||||
	//		}
 | 
			
		||||
	//	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("read %s from %s", envVars, filePath)
 | 
			
		||||
 | 
			
		||||
@ -249,3 +249,39 @@ func CheckEnv(app App) ([]EnvVar, error) {
 | 
			
		||||
 | 
			
		||||
	return envVars, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReadAbraShCmdNames reads the names of commands.
 | 
			
		||||
func ReadAbraShCmdNames(abraSh string) ([]string, error) {
 | 
			
		||||
	var cmdNames []string
 | 
			
		||||
 | 
			
		||||
	file, err := os.Open(abraSh)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			return cmdNames, nil
 | 
			
		||||
		}
 | 
			
		||||
		return cmdNames, err
 | 
			
		||||
	}
 | 
			
		||||
	defer file.Close()
 | 
			
		||||
 | 
			
		||||
	cmdNameRegex, err := regexp.Compile(`(\w+)(\(\).*\{)`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return cmdNames, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	scanner := bufio.NewScanner(file)
 | 
			
		||||
	for scanner.Scan() {
 | 
			
		||||
		line := scanner.Text()
 | 
			
		||||
		matches := cmdNameRegex.FindStringSubmatch(line)
 | 
			
		||||
		if len(matches) > 0 {
 | 
			
		||||
			cmdNames = append(cmdNames, matches[1])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(cmdNames) > 0 {
 | 
			
		||||
		logrus.Debugf("read %s from %s", strings.Join(cmdNames, " "), abraSh)
 | 
			
		||||
	} else {
 | 
			
		||||
		logrus.Debugf("read 0 command names from %s", abraSh)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cmdNames, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"slices"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
@ -115,6 +116,31 @@ func TestReadAbraShEnvVars(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestReadAbraShCmdNames(t *testing.T) {
 | 
			
		||||
	offline := true
 | 
			
		||||
	r, err := recipe.Get("abra-test-recipe", offline)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	abraShPath := fmt.Sprintf("%s/%s/%s", config.RECIPES_DIR, r.Name, "abra.sh")
 | 
			
		||||
	cmdNames, err := config.ReadAbraShCmdNames(abraShPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(cmdNames) == 0 {
 | 
			
		||||
		t.Error("at least one command name should be found")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expectedCmdNames := []string{"test_cmd", "test_cmd_args"}
 | 
			
		||||
	for _, cmdName := range expectedCmdNames {
 | 
			
		||||
		if !slices.Contains(cmdNames, cmdName) {
 | 
			
		||||
			t.Fatalf("%s should have been found in %s", cmdName, abraShPath)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCheckEnv(t *testing.T) {
 | 
			
		||||
	offline := true
 | 
			
		||||
	r, err := recipe.Get("abra-test-recipe", offline)
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Commit runs a git commit
 | 
			
		||||
func Commit(repoPath, glob, commitMessage string, dryRun bool) error {
 | 
			
		||||
func Commit(repoPath, commitMessage string, dryRun bool) error {
 | 
			
		||||
	if commitMessage == "" {
 | 
			
		||||
		return fmt.Errorf("no commit message specified?")
 | 
			
		||||
	}
 | 
			
		||||
@ -33,17 +33,8 @@ func Commit(repoPath, glob, commitMessage string, dryRun bool) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !dryRun {
 | 
			
		||||
		err = commitWorktree.AddGlob(glob)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		logrus.Debugf("staged %s for commit", glob)
 | 
			
		||||
	} else {
 | 
			
		||||
		logrus.Debugf("dry run: did not stage %s for commit", glob)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !dryRun {
 | 
			
		||||
		_, err = commitWorktree.Commit(commitMessage, &git.CommitOptions{})
 | 
			
		||||
		// NOTE(d1): `All: true` does not include untracked files
 | 
			
		||||
		_, err = commitWorktree.Commit(commitMessage, &git.CommitOptions{All: true})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										42
									
								
								pkg/git/diff.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								pkg/git/diff.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
package git
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// getGitDiffArgs builds the `git diff` invocation args. It removes the usage
 | 
			
		||||
// of a pager and ensures that colours are specified even when Git might detect
 | 
			
		||||
// otherwise.
 | 
			
		||||
func getGitDiffArgs(repoPath string) []string {
 | 
			
		||||
	return []string{
 | 
			
		||||
		"-C",
 | 
			
		||||
		repoPath,
 | 
			
		||||
		"--no-pager",
 | 
			
		||||
		"-c",
 | 
			
		||||
		"color.diff=always",
 | 
			
		||||
		"diff",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiffUnstaged shows a `git diff`. Due to limitations in the underlying go-git
 | 
			
		||||
// library, this implementation requires the /usr/bin/git binary. It gracefully
 | 
			
		||||
// skips if it cannot find the command on the system.
 | 
			
		||||
func DiffUnstaged(path string) error {
 | 
			
		||||
	if _, err := exec.LookPath("git"); err != nil {
 | 
			
		||||
		logrus.Warnf("unable to locate git command, cannot output diff")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gitDiffArgs := getGitDiffArgs(path)
 | 
			
		||||
	diff, err := exec.Command("git", gitDiffArgs...).Output()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Print(string(diff))
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@ -7,6 +7,7 @@ import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"slices"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
@ -31,7 +32,7 @@ import (
 | 
			
		||||
// RecipeCatalogueURL is the only current recipe catalogue available.
 | 
			
		||||
const RecipeCatalogueURL = "https://recipes.coopcloud.tech/recipes.json"
 | 
			
		||||
 | 
			
		||||
// ReposMetadataURL is the recipe repository metadata
 | 
			
		||||
// ReposMetadataURL is the recipe repository metadata.
 | 
			
		||||
const ReposMetadataURL = "https://git.coopcloud.tech/api/v1/orgs/coop-cloud/repos"
 | 
			
		||||
 | 
			
		||||
// tag represents a git tag.
 | 
			
		||||
@ -63,6 +64,11 @@ type RecipeMeta struct {
 | 
			
		||||
	Website       string         `json:"website"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TopicMeta represents a list of topics for a repository.
 | 
			
		||||
type TopicMeta struct {
 | 
			
		||||
	Topics []string `json:"topics"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LatestVersion returns the latest version of a recipe.
 | 
			
		||||
func (r RecipeMeta) LatestVersion() string {
 | 
			
		||||
	var version string
 | 
			
		||||
@ -822,7 +828,16 @@ func ReadReposMetadata() (RepoCatalogue, error) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for idx, repo := range reposList {
 | 
			
		||||
			reposMeta[repo.Name] = reposList[idx]
 | 
			
		||||
			var topicMeta TopicMeta
 | 
			
		||||
 | 
			
		||||
			topicsURL := getReposTopicUrl(repo.Name)
 | 
			
		||||
			if err := web.ReadJSON(topicsURL, &topicMeta); err != nil {
 | 
			
		||||
				return reposMeta, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if slices.Contains(topicMeta.Topics, "recipe") && repo.Name != "example" {
 | 
			
		||||
				reposMeta[repo.Name] = reposList[idx]
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pageIdx++
 | 
			
		||||
@ -1002,14 +1017,8 @@ func UpdateRepositories(repos RepoCatalogue, recipeName string) error {
 | 
			
		||||
				retrieveBar.Add(1)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if _, exists := catalogue.CatalogueSkipList[rm.Name]; exists {
 | 
			
		||||
				ch <- rm.Name
 | 
			
		||||
				retrieveBar.Add(1)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			recipeDir := path.Join(config.RECIPES_DIR, rm.Name)
 | 
			
		||||
 | 
			
		||||
			if err := gitPkg.Clone(recipeDir, rm.CloneURL); err != nil {
 | 
			
		||||
				logrus.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
@ -1025,3 +1034,8 @@ func UpdateRepositories(repos RepoCatalogue, recipeName string) error {
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getReposTopicUrl retrieves the repository specific topic listing.
 | 
			
		||||
func getReposTopicUrl(repoName string) string {
 | 
			
		||||
	return fmt.Sprintf("https://git.coopcloud.tech/api/v1/repos/coop-cloud/%s/topics", repoName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
ABRA_VERSION="0.8.0-beta"
 | 
			
		||||
ABRA_VERSION="0.8.1-beta"
 | 
			
		||||
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$ABRA_VERSION"
 | 
			
		||||
RC_VERSION="0.8.0-beta"
 | 
			
		||||
RC_VERSION="0.8.1-beta"
 | 
			
		||||
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/coop-cloud/abra/releases/tags/$RC_VERSION"
 | 
			
		||||
 | 
			
		||||
for arg in "$@"; do
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								tests/integration/recipe_diff.bats
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/integration/recipe_diff.bats
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
setup() {
 | 
			
		||||
  load "$PWD/tests/integration/helpers/common"
 | 
			
		||||
  _common_setup
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@test "show unstaged changes" {
 | 
			
		||||
  run $ABRA recipe diff "$TEST_RECIPE"
 | 
			
		||||
  assert_success
 | 
			
		||||
  refute_output --partial 'traefik.enable'
 | 
			
		||||
 | 
			
		||||
  run sed -i '/traefik.enable=.*/d' "$ABRA_DIR/recipes/$TEST_RECIPE/compose.yml"
 | 
			
		||||
  assert_success
 | 
			
		||||
 | 
			
		||||
  run $ABRA recipe diff "$TEST_RECIPE"
 | 
			
		||||
  assert_success
 | 
			
		||||
  assert_output --partial 'traefik.enable'
 | 
			
		||||
 | 
			
		||||
  _reset_recipe
 | 
			
		||||
}
 | 
			
		||||
@ -84,3 +84,22 @@ setup(){
 | 
			
		||||
 | 
			
		||||
  _reset_recipe "$TEST_RECIPE"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@test "unknown files not committed" {
 | 
			
		||||
  run $ABRA recipe upgrade "$TEST_RECIPE" --no-input --patch
 | 
			
		||||
  assert_success
 | 
			
		||||
 | 
			
		||||
  run bash -c 'echo "unstaged changes" >> "$ABRA_DIR/recipes/$TEST_RECIPE/foo"'
 | 
			
		||||
  assert_success
 | 
			
		||||
  assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo"
 | 
			
		||||
 | 
			
		||||
  run $ABRA recipe release "$TEST_RECIPE" --no-input --patch
 | 
			
		||||
  assert_success
 | 
			
		||||
  assert_output --partial 'no -p/--publish passed, not publishing'
 | 
			
		||||
 | 
			
		||||
  run git -C "$ABRA_DIR/recipes/$TEST_RECIPE" rm foo
 | 
			
		||||
  assert_failure
 | 
			
		||||
  assert_output --partial "fatal: pathspec 'foo' did not match any files"
 | 
			
		||||
 | 
			
		||||
  _reset_recipe
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										25
									
								
								tests/integration/recipe_reset.bats
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/integration/recipe_reset.bats
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
setup() {
 | 
			
		||||
  load "$PWD/tests/integration/helpers/common"
 | 
			
		||||
  _common_setup
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@test "reset unstaged changes" {
 | 
			
		||||
  run $ABRA recipe fetch "$TEST_RECIPE"
 | 
			
		||||
  assert_success
 | 
			
		||||
 | 
			
		||||
  run sed -i '/traefik.enable=.*/d' "$ABRA_DIR/recipes/$TEST_RECIPE/compose.yml"
 | 
			
		||||
  assert_success
 | 
			
		||||
 | 
			
		||||
  run $ABRA recipe diff "$TEST_RECIPE"
 | 
			
		||||
  assert_success
 | 
			
		||||
  assert_output --partial 'traefik.enable'
 | 
			
		||||
 | 
			
		||||
  run $ABRA recipe reset "$TEST_RECIPE"
 | 
			
		||||
  assert_success
 | 
			
		||||
 | 
			
		||||
  run $ABRA recipe diff "$TEST_RECIPE"
 | 
			
		||||
  assert_success
 | 
			
		||||
  refute_output --partial 'traefik.enable'
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user