forked from toolshed/abra
		
	Compare commits
	
		
			20 Commits
		
	
	
		
			improve-li
			...
			private-re
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7a24bf9cd5 | |||
| 7c3b740e14 | |||
| 
						
						
							
						
						2fbef41a3a
	
				 | 
					
					
						|||
| 6fb41e5300 | |||
| 1432f480c7 | |||
| 
						
						
							
						
						83af39771b
	
				 | 
					
					
						|||
| 
						
						
							
						
						4d1333202e
	
				 | 
					
					
						|||
| 
						
						
							
						
						55c24f070c
	
				 | 
					
					
						|||
| 229e8eb9da | |||
| 
						
						
							
						
						b3ab95750e
	
				 | 
					
					
						|||
| de009921a2 | |||
| 
						
						
							
						
						d081bbaefa
	
				 | 
					
					
						|||
| 
						
						
							
						
						515b5466ca
	
				 | 
					
					
						|||
| 
						
						
							
						
						6965799bdc
	
				 | 
					
					
						|||
| 
						
						
							
						
						f75c9a6259
	
				 | 
					
					
						|||
| a43a092ba7 | |||
| fa084a61d2 | |||
| 
						
						
							
						
						895a7fe7d6
	
				 | 
					
					
						|||
| 
						
						
							
						
						742a726778
	
				 | 
					
					
						|||
| 
						
						
							
						
						2b9a185aff
	
				 | 
					
					
						
@ -183,7 +183,7 @@ does not).`,
 | 
				
			|||||||
		if err := internal.RunCmdRemote(
 | 
							if err := internal.RunCmdRemote(
 | 
				
			||||||
			cl,
 | 
								cl,
 | 
				
			||||||
			app,
 | 
								app,
 | 
				
			||||||
			requestTTY,
 | 
								disableTTY,
 | 
				
			||||||
			app.Recipe.AbraShPath,
 | 
								app.Recipe.AbraShPath,
 | 
				
			||||||
			targetServiceName, cmdName, parsedCmdArgs, remoteUser); err != nil {
 | 
								targetServiceName, cmdName, parsedCmdArgs, remoteUser); err != nil {
 | 
				
			||||||
			log.Fatal(err)
 | 
								log.Fatal(err)
 | 
				
			||||||
@ -238,7 +238,7 @@ func parseCmdArgs(args []string, isLocal bool) (bool, string) {
 | 
				
			|||||||
var (
 | 
					var (
 | 
				
			||||||
	local      bool
 | 
						local      bool
 | 
				
			||||||
	remoteUser string
 | 
						remoteUser string
 | 
				
			||||||
	requestTTY bool
 | 
						disableTTY bool
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
@ -259,11 +259,11 @@ func init() {
 | 
				
			|||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AppCmdCommand.Flags().BoolVarP(
 | 
						AppCmdCommand.Flags().BoolVarP(
 | 
				
			||||||
		&requestTTY,
 | 
							&disableTTY,
 | 
				
			||||||
		"tty",
 | 
							"tty",
 | 
				
			||||||
		"T",
 | 
							"T",
 | 
				
			||||||
		false,
 | 
							false,
 | 
				
			||||||
		"request remote TTY",
 | 
							"disable remote TTY",
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AppCmdCommand.Flags().BoolVarP(
 | 
						AppCmdCommand.Flags().BoolVarP(
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ var AppCpCommand = &cobra.Command{
 | 
				
			|||||||
  abra app cp 1312.net myfile.txt app:/
 | 
					  abra app cp 1312.net myfile.txt app:/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # copy that file back to your current working directory locally
 | 
					  # copy that file back to your current working directory locally
 | 
				
			||||||
  abra app cp 1312.net app:/myfile.txt`,
 | 
					  abra app cp 1312.net app:/myfile.txt ./`,
 | 
				
			||||||
	Args: cobra.ExactArgs(3),
 | 
						Args: cobra.ExactArgs(3),
 | 
				
			||||||
	ValidArgsFunction: func(
 | 
						ValidArgsFunction: func(
 | 
				
			||||||
		cmd *cobra.Command,
 | 
							cmd *cobra.Command,
 | 
				
			||||||
 | 
				
			|||||||
@ -142,10 +142,14 @@ Use "--status/-S" flag to query all servers for the live deployment status.`,
 | 
				
			|||||||
					appStats.AutoUpdate = autoUpdate
 | 
										appStats.AutoUpdate = autoUpdate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					var newUpdates []string
 | 
										var newUpdates []string
 | 
				
			||||||
					if version != "unknown" {
 | 
										if version != "unknown" && chaosVersion == "unknown" {
 | 
				
			||||||
 | 
											if err := app.Recipe.EnsureExists(); err != nil {
 | 
				
			||||||
 | 
												log.Fatalf("unable to clone %s: %s", app.Name, err)
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						updates, err := app.Recipe.Tags()
 | 
											updates, err := app.Recipe.Tags()
 | 
				
			||||||
						if err != nil {
 | 
											if err != nil {
 | 
				
			||||||
							log.Fatal(err)
 | 
												log.Fatalf("unable to retrieve tags for %s: %s", app.Name, err)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						parsedVersion, err := tagcmp.Parse(version)
 | 
											parsedVersion, err := tagcmp.Parse(version)
 | 
				
			||||||
 | 
				
			|||||||
@ -109,6 +109,15 @@ var AppNewCommand = &cobra.Command{
 | 
				
			|||||||
				if err := recipe.EnsureLatest(); err != nil {
 | 
									if err := recipe.EnsureLatest(); err != nil {
 | 
				
			||||||
					log.Fatal(err)
 | 
										log.Fatal(err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if recipeVersion == "" {
 | 
				
			||||||
 | 
										head, err := recipe.Head()
 | 
				
			||||||
 | 
										if err != nil {
 | 
				
			||||||
 | 
											log.Fatalf("failed to retrieve latest commit for %s: %s", recipe.Name, err)
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										recipeVersion = formatter.SmallSHA(head.String())
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -293,6 +302,12 @@ func ensureServerFlag() error {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(servers) == 1 {
 | 
				
			||||||
 | 
							newAppServer = servers[0]
 | 
				
			||||||
 | 
							log.Infof("single server detected, choosing %s automatically", newAppServer)
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if newAppServer == "" && !internal.NoInput {
 | 
						if newAppServer == "" && !internal.NoInput {
 | 
				
			||||||
		prompt := &survey.Select{
 | 
							prompt := &survey.Select{
 | 
				
			||||||
			Message: "Select app server:",
 | 
								Message: "Select app server:",
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ package app
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"coopcloud.tech/abra/cli/internal"
 | 
						"coopcloud.tech/abra/cli/internal"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/app"
 | 
						"coopcloud.tech/abra/pkg/app"
 | 
				
			||||||
@ -213,9 +214,7 @@ beforehand. See "abra app backup" for more.`,
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if upgradeReleaseNotes != "" && chosenUpgrade != "" {
 | 
							if upgradeReleaseNotes == "" {
 | 
				
			||||||
			fmt.Print(upgradeReleaseNotes)
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			upgradeWarnMessages = append(
 | 
								upgradeWarnMessages = append(
 | 
				
			||||||
				upgradeWarnMessages,
 | 
									upgradeWarnMessages,
 | 
				
			||||||
				fmt.Sprintf("no release notes available for %s", chosenUpgrade),
 | 
									fmt.Sprintf("no release notes available for %s", chosenUpgrade),
 | 
				
			||||||
@ -337,6 +336,11 @@ func getReleaseNotes(
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if note != "" {
 | 
								if note != "" {
 | 
				
			||||||
 | 
									// NOTE(d1): trim any final newline on the end of the note itself before
 | 
				
			||||||
 | 
									//           we manually handle newlines (for multiple release notes and
 | 
				
			||||||
 | 
									//           ensuring space between the warning messages)
 | 
				
			||||||
 | 
									note = strings.TrimSuffix(note, "\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				*upgradeReleaseNotes += fmt.Sprintf("%s\n", note)
 | 
									*upgradeReleaseNotes += fmt.Sprintf("%s\n", note)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@ import (
 | 
				
			|||||||
func RunCmdRemote(
 | 
					func RunCmdRemote(
 | 
				
			||||||
	cl *dockerClient.Client,
 | 
						cl *dockerClient.Client,
 | 
				
			||||||
	app appPkg.App,
 | 
						app appPkg.App,
 | 
				
			||||||
	requestTTY bool,
 | 
						disableTTY bool,
 | 
				
			||||||
	abraSh, serviceName, cmdName, cmdArgs, remoteUser string) error {
 | 
						abraSh, serviceName, cmdName, cmdArgs, remoteUser string) error {
 | 
				
			||||||
	filters := filters.NewArgs()
 | 
						filters := filters.NewArgs()
 | 
				
			||||||
	filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), serviceName))
 | 
						filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), serviceName))
 | 
				
			||||||
@ -84,8 +84,10 @@ func RunCmdRemote(
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	execCreateOpts.Cmd = cmd
 | 
						execCreateOpts.Cmd = cmd
 | 
				
			||||||
	execCreateOpts.Tty = requestTTY
 | 
					
 | 
				
			||||||
	if !requestTTY {
 | 
						execCreateOpts.Tty = true
 | 
				
			||||||
 | 
						if disableTTY {
 | 
				
			||||||
 | 
							execCreateOpts.Tty = false
 | 
				
			||||||
		log.Debugf("not requesting a remote TTY")
 | 
							log.Debugf("not requesting a remote TTY")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -46,7 +46,7 @@ func DeployOverview(
 | 
				
			|||||||
	app appPkg.App,
 | 
						app appPkg.App,
 | 
				
			||||||
	deployedVersion string,
 | 
						deployedVersion string,
 | 
				
			||||||
	toDeployVersion string,
 | 
						toDeployVersion string,
 | 
				
			||||||
	info string,
 | 
						releaseNotes string,
 | 
				
			||||||
	warnMessages []string,
 | 
						warnMessages []string,
 | 
				
			||||||
) error {
 | 
					) error {
 | 
				
			||||||
	deployConfig := "compose.yml"
 | 
						deployConfig := "compose.yml"
 | 
				
			||||||
@ -85,8 +85,8 @@ func DeployOverview(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fmt.Println(overview)
 | 
						fmt.Println(overview)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if info != "" {
 | 
						if releaseNotes != "" {
 | 
				
			||||||
		fmt.Println(info)
 | 
							fmt.Print(releaseNotes)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, msg := range warnMessages {
 | 
						for _, msg := range warnMessages {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,15 @@
 | 
				
			|||||||
package recipe
 | 
					package recipe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"coopcloud.tech/abra/cli/internal"
 | 
						"coopcloud.tech/abra/cli/internal"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
						"coopcloud.tech/abra/pkg/autocomplete"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
						"coopcloud.tech/abra/pkg/formatter"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/log"
 | 
						"coopcloud.tech/abra/pkg/log"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/recipe"
 | 
						"coopcloud.tech/abra/pkg/recipe"
 | 
				
			||||||
 | 
						"github.com/go-git/go-git/v5"
 | 
				
			||||||
 | 
						gitCfg "github.com/go-git/go-git/v5/config"
 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -13,7 +17,16 @@ var RecipeFetchCommand = &cobra.Command{
 | 
				
			|||||||
	Use:     "fetch [recipe | --all] [flags]",
 | 
						Use:     "fetch [recipe | --all] [flags]",
 | 
				
			||||||
	Aliases: []string{"f"},
 | 
						Aliases: []string{"f"},
 | 
				
			||||||
	Short:   "Clone recipe(s) locally",
 | 
						Short:   "Clone recipe(s) locally",
 | 
				
			||||||
 | 
						Long:    `Using "--force/-f" Git syncs an existing recipe. It does not erase unstaged changes.`,
 | 
				
			||||||
	Args:    cobra.RangeArgs(0, 1),
 | 
						Args:    cobra.RangeArgs(0, 1),
 | 
				
			||||||
 | 
						Example: `  # fetch from recipe catalogue
 | 
				
			||||||
 | 
					  abra recipe fetch gitea
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # fetch from remote recipe
 | 
				
			||||||
 | 
					  abra recipe fetch git.foo.org/recipes/myrecipe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # fetch with ssh remote for hacking
 | 
				
			||||||
 | 
					  abra recipe fetch gitea --ssh`,
 | 
				
			||||||
	ValidArgsFunction: func(
 | 
						ValidArgsFunction: func(
 | 
				
			||||||
		cmd *cobra.Command,
 | 
							cmd *cobra.Command,
 | 
				
			||||||
		args []string,
 | 
							args []string,
 | 
				
			||||||
@ -36,10 +49,39 @@ var RecipeFetchCommand = &cobra.Command{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		ensureCtx := internal.GetEnsureContext()
 | 
							ensureCtx := internal.GetEnsureContext()
 | 
				
			||||||
		if recipeName != "" {
 | 
							if recipeName != "" {
 | 
				
			||||||
			r := internal.ValidateRecipe(args, cmd.Name())
 | 
								r := recipe.Get(recipeName)
 | 
				
			||||||
			if err := r.Ensure(ensureCtx); err != nil {
 | 
								if _, err := os.Stat(r.Dir); !os.IsNotExist(err) {
 | 
				
			||||||
				log.Fatal(err)
 | 
									if !force {
 | 
				
			||||||
 | 
										log.Warnf("%s is already fetched", r.Name)
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								r = internal.ValidateRecipe(args, cmd.Name())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if sshRemote {
 | 
				
			||||||
 | 
									if r.SSHURL == "" {
 | 
				
			||||||
 | 
										log.Warnf("unable to discover SSH remote for %s", r.Name)
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									repo, err := git.PlainOpen(r.Dir)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										log.Fatalf("unable to open %s: %s", r.Dir, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if err = repo.DeleteRemote("origin"); err != nil {
 | 
				
			||||||
 | 
										log.Fatalf("unable to remove default remote in %s: %s", r.Dir, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if _, err := repo.CreateRemote(&gitCfg.RemoteConfig{
 | 
				
			||||||
 | 
										Name: "origin",
 | 
				
			||||||
 | 
										URLs: []string{r.SSHURL},
 | 
				
			||||||
 | 
									}); err != nil {
 | 
				
			||||||
 | 
										log.Fatalf("unable to set SSH remote in %s: %s", r.Dir, err)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -61,6 +103,8 @@ var RecipeFetchCommand = &cobra.Command{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
	fetchAllRecipes bool
 | 
						fetchAllRecipes bool
 | 
				
			||||||
 | 
						sshRemote       bool
 | 
				
			||||||
 | 
						force           bool
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
@ -71,4 +115,20 @@ func init() {
 | 
				
			|||||||
		false,
 | 
							false,
 | 
				
			||||||
		"fetch all recipes",
 | 
							"fetch all recipes",
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RecipeFetchCommand.Flags().BoolVarP(
 | 
				
			||||||
 | 
							&sshRemote,
 | 
				
			||||||
 | 
							"ssh",
 | 
				
			||||||
 | 
							"s",
 | 
				
			||||||
 | 
							false,
 | 
				
			||||||
 | 
							"automatically set ssh remote",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RecipeFetchCommand.Flags().BoolVarP(
 | 
				
			||||||
 | 
							&force,
 | 
				
			||||||
 | 
							"force",
 | 
				
			||||||
 | 
							"f",
 | 
				
			||||||
 | 
							false,
 | 
				
			||||||
 | 
							"force re-fetch",
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							@ -19,7 +19,6 @@ require (
 | 
				
			|||||||
	github.com/google/go-cmp v0.7.0
 | 
						github.com/google/go-cmp v0.7.0
 | 
				
			||||||
	github.com/moby/sys/signal v0.7.1
 | 
						github.com/moby/sys/signal v0.7.1
 | 
				
			||||||
	github.com/moby/term v0.5.2
 | 
						github.com/moby/term v0.5.2
 | 
				
			||||||
	github.com/muesli/reflow v0.3.0
 | 
					 | 
				
			||||||
	github.com/pkg/errors v0.9.1
 | 
						github.com/pkg/errors v0.9.1
 | 
				
			||||||
	github.com/schollz/progressbar/v3 v3.18.0
 | 
						github.com/schollz/progressbar/v3 v3.18.0
 | 
				
			||||||
	golang.org/x/term v0.30.0
 | 
						golang.org/x/term v0.30.0
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@ -634,7 +634,6 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
 | 
				
			|||||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
 | 
					github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
 | 
				
			||||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
 | 
					github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
 | 
				
			||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 | 
					github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 | 
				
			||||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
 | 
					 | 
				
			||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
 | 
					github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
 | 
				
			||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 | 
					github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 | 
				
			||||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
 | 
					github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
 | 
				
			||||||
@ -694,8 +693,6 @@ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D
 | 
				
			|||||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
 | 
					github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
 | 
				
			||||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
 | 
					github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
 | 
				
			||||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
 | 
					github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
 | 
				
			||||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
 | 
					 | 
				
			||||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
 | 
					 | 
				
			||||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
 | 
					github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
 | 
				
			||||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
 | 
					github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
 | 
				
			||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 | 
					github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 | 
				
			||||||
@ -813,7 +810,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
 | 
				
			|||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
 | 
					github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
 | 
				
			||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
 | 
					github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
 | 
				
			||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 | 
					github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 | 
				
			||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 | 
					 | 
				
			||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 | 
					github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 | 
				
			||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
 | 
					github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
 | 
				
			||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 | 
					github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,10 @@
 | 
				
			|||||||
package git
 | 
					package git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"os/signal"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/log"
 | 
						"coopcloud.tech/abra/pkg/log"
 | 
				
			||||||
@ -22,46 +25,81 @@ func gitCloneIgnoreErr(err error) bool {
 | 
				
			|||||||
	return false
 | 
						return false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Clone runs a git clone which accounts for different default branches.
 | 
					// Clone runs a git clone which accounts for different default branches. This
 | 
				
			||||||
 | 
					// function respects Ctrl+C (SIGINT) calls from the user, cancelling the
 | 
				
			||||||
 | 
					// context and deleting the (typically) half-baked clone of the repository.
 | 
				
			||||||
 | 
					// This avoids broken state for future clone / recipe ops.
 | 
				
			||||||
func Clone(dir, url string) error {
 | 
					func Clone(dir, url string) error {
 | 
				
			||||||
	if _, err := os.Stat(dir); os.IsNotExist(err) {
 | 
						ctx := context.Background()
 | 
				
			||||||
		log.Debugf("git clone: %s", dir, url)
 | 
						ctx, cancelCtx := context.WithCancel(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_, err := git.PlainClone(dir, false, &git.CloneOptions{
 | 
						sigIntCh := make(chan os.Signal, 1)
 | 
				
			||||||
			URL:           url,
 | 
						signal.Notify(sigIntCh, os.Interrupt)
 | 
				
			||||||
			Tags:          git.AllTags,
 | 
						defer func() {
 | 
				
			||||||
			ReferenceName: plumbing.ReferenceName("refs/heads/main"),
 | 
							signal.Stop(sigIntCh)
 | 
				
			||||||
			SingleBranch:  true,
 | 
							cancelCtx()
 | 
				
			||||||
		})
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err != nil && gitCloneIgnoreErr(err) {
 | 
						errCh := make(chan error)
 | 
				
			||||||
			log.Debugf("git clone: %s cloned successfully", dir)
 | 
					 | 
				
			||||||
			return nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err != nil {
 | 
						go func() {
 | 
				
			||||||
			log.Debug("git clone: main branch failed, attempting master branch")
 | 
							if _, err := os.Stat(dir); os.IsNotExist(err) {
 | 
				
			||||||
 | 
								log.Debugf("git clone: %s", url)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			_, err := git.PlainClone(dir, false, &git.CloneOptions{
 | 
								_, err := git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{
 | 
				
			||||||
				URL:           url,
 | 
									URL:           url,
 | 
				
			||||||
				Tags:          git.AllTags,
 | 
									Tags:          git.AllTags,
 | 
				
			||||||
				ReferenceName: plumbing.ReferenceName("refs/heads/master"),
 | 
									ReferenceName: plumbing.ReferenceName("refs/heads/main"),
 | 
				
			||||||
				SingleBranch:  true,
 | 
									SingleBranch:  true,
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err != nil && gitCloneIgnoreErr(err) {
 | 
								if err != nil && gitCloneIgnoreErr(err) {
 | 
				
			||||||
				log.Debugf("git clone: %s cloned successfully", dir)
 | 
									log.Debugf("git clone: %s cloned successfully", dir)
 | 
				
			||||||
				return nil
 | 
									errCh <- nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if err := ctx.Err(); err != nil {
 | 
				
			||||||
 | 
									errCh <- fmt.Errorf("git clone %s: cancelled due to interrupt", dir)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									log.Debug("git clone: main branch failed, attempting master branch")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									_, err := git.PlainCloneContext(ctx, dir, false, &git.CloneOptions{
 | 
				
			||||||
 | 
										URL:           url,
 | 
				
			||||||
 | 
										Tags:          git.AllTags,
 | 
				
			||||||
 | 
										ReferenceName: plumbing.ReferenceName("refs/heads/master"),
 | 
				
			||||||
 | 
										SingleBranch:  true,
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if err != nil && gitCloneIgnoreErr(err) {
 | 
				
			||||||
 | 
										log.Debugf("git clone: %s cloned successfully", dir)
 | 
				
			||||||
 | 
										errCh <- nil
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										errCh <- err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								log.Debugf("git clone: %s cloned successfully", dir)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								log.Debugf("git clone: %s already exists", dir)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		log.Debugf("git clone: %s cloned successfully", dir)
 | 
							errCh <- nil
 | 
				
			||||||
	} else {
 | 
						}()
 | 
				
			||||||
		log.Debugf("git clone: %s already exists", dir)
 | 
					
 | 
				
			||||||
 | 
						select {
 | 
				
			||||||
 | 
						case <-sigIntCh:
 | 
				
			||||||
 | 
							cancelCtx()
 | 
				
			||||||
 | 
							fmt.Println() // NOTE(d1): newline after ^C
 | 
				
			||||||
 | 
							if err := os.RemoveAll(dir); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("unable to clean up git clone of %s: %s", dir, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return fmt.Errorf("git clone %s: cancelled due to interrupt", dir)
 | 
				
			||||||
 | 
						case err := <-errCh:
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										48
									
								
								pkg/git/clone_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								pkg/git/clone_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					package git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"syscall"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"coopcloud.tech/abra/pkg/config"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestClone(t *testing.T) {
 | 
				
			||||||
 | 
						dir := path.Join(config.RECIPES_DIR, "gitea")
 | 
				
			||||||
 | 
						os.RemoveAll(dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gitURL := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, "gitea")
 | 
				
			||||||
 | 
						if err := Clone(dir, gitURL); err != nil {
 | 
				
			||||||
 | 
							t.Fatalf("unable to git clone gitea: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
 | 
				
			||||||
 | 
							t.Fatal("gitea repo was not cloned successfully")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCancelGitClone(t *testing.T) {
 | 
				
			||||||
 | 
						dir := path.Join(config.RECIPES_DIR, "gitea")
 | 
				
			||||||
 | 
						os.RemoveAll(dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							p, err := os.FindProcess(os.Getpid())
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								t.Fatalf("unable to find current process: %s", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							p.Signal(syscall.SIGINT)
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gitURL := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, "gitea")
 | 
				
			||||||
 | 
						if err := Clone(dir, gitURL); err == nil {
 | 
				
			||||||
 | 
							t.Fatal("cloning should have been interrupted")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := os.Stat(dir); err != nil && !os.IsNotExist(err) {
 | 
				
			||||||
 | 
							t.Fatal("recipe repo was not deleted")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -17,6 +17,7 @@ import (
 | 
				
			|||||||
	"coopcloud.tech/abra/pkg/log"
 | 
						"coopcloud.tech/abra/pkg/log"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/ui"
 | 
						"coopcloud.tech/abra/pkg/ui"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/upstream/convert"
 | 
						"coopcloud.tech/abra/pkg/upstream/convert"
 | 
				
			||||||
 | 
						"github.com/docker/cli/cli/command"
 | 
				
			||||||
	"github.com/docker/cli/cli/command/stack/formatter"
 | 
						"github.com/docker/cli/cli/command/stack/formatter"
 | 
				
			||||||
	composetypes "github.com/docker/cli/cli/compose/types"
 | 
						composetypes "github.com/docker/cli/cli/compose/types"
 | 
				
			||||||
	"github.com/docker/docker/api/types"
 | 
						"github.com/docker/docker/api/types"
 | 
				
			||||||
@ -426,7 +427,8 @@ func deployServices(
 | 
				
			|||||||
	services map[string]swarm.ServiceSpec,
 | 
						services map[string]swarm.ServiceSpec,
 | 
				
			||||||
	namespace convert.Namespace,
 | 
						namespace convert.Namespace,
 | 
				
			||||||
	sendAuth bool,
 | 
						sendAuth bool,
 | 
				
			||||||
	resolveImage string) ([]ui.ServiceMeta, error) {
 | 
						resolveImage string,
 | 
				
			||||||
 | 
					) ([]ui.ServiceMeta, error) {
 | 
				
			||||||
	var servicesMeta []ui.ServiceMeta
 | 
						var servicesMeta []ui.ServiceMeta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	existingServices, err := GetStackServices(ctx, cl, namespace.Name())
 | 
						existingServices, err := GetStackServices(ctx, cl, namespace.Name())
 | 
				
			||||||
@ -446,6 +448,21 @@ func deployServices(
 | 
				
			|||||||
			encodedAuth string
 | 
								encodedAuth string
 | 
				
			||||||
		)
 | 
							)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// When sendAuth is set, use the docker cli to retrieve the auth token
 | 
				
			||||||
 | 
							// for the image we are deploying.
 | 
				
			||||||
 | 
							// This enables using a private registry by running docker login on the
 | 
				
			||||||
 | 
							// machine, that abra is executed.
 | 
				
			||||||
 | 
							if sendAuth {
 | 
				
			||||||
 | 
								dockerCLI, err := command.NewDockerCli()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									log.Errorf("retrieving docker auth token: failed create docker cli: %s", err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								encodedAuth, err = command.RetrieveAuthTokenFromImage(dockerCLI.ConfigFile(), image)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									log.Errorf("failed to retrieve registry auth for image %s: %s", image, err)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if service, exists := existingServiceMap[name]; exists {
 | 
							if service, exists := existingServiceMap[name]; exists {
 | 
				
			||||||
			log.Debugf("updating %s", name)
 | 
								log.Debugf("updating %s", name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -587,7 +604,7 @@ func WaitOnServices(ctx context.Context, cl *dockerClient.Client, opts WaitOpts)
 | 
				
			|||||||
				fmt.Sprintf("%s_%s", opts.AppName, timestamp()),
 | 
									fmt.Sprintf("%s_%s", opts.AppName, timestamp()),
 | 
				
			||||||
			)
 | 
								)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := os.MkdirAll(filepath.Join(config.LOGS_DIR, opts.ServerName), 0764); err != nil {
 | 
								if err := os.MkdirAll(filepath.Join(config.LOGS_DIR, opts.ServerName), 0o764); err != nil {
 | 
				
			||||||
				return fmt.Errorf("waitOnServices: error creating log dir: %s", err)
 | 
									return fmt.Errorf("waitOnServices: error creating log dir: %s", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
#!/usr/bin/env bash
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ABRA_VERSION="0.9.0-beta"
 | 
					ABRA_VERSION="0.10.0-beta"
 | 
				
			||||||
ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/toolshed/abra/releases/tags/$ABRA_VERSION"
 | 
					ABRA_RELEASE_URL="https://git.coopcloud.tech/api/v1/repos/toolshed/abra/releases/tags/$ABRA_VERSION"
 | 
				
			||||||
RC_VERSION="0.10.0-rc2-beta"
 | 
					RC_VERSION="0.10.0-beta"
 | 
				
			||||||
RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/toolshed/abra/releases/tags/$RC_VERSION"
 | 
					RC_VERSION_URL="https://git.coopcloud.tech/api/v1/repos/toolshed/abra/releases/tags/$RC_VERSION"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for arg in "$@"; do
 | 
					for arg in "$@"; do
 | 
				
			||||||
 | 
				
			|||||||
@ -3,5 +3,5 @@ STACK := abra_installer_script
 | 
				
			|||||||
default: deploy
 | 
					default: deploy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
deploy:
 | 
					deploy:
 | 
				
			||||||
	@DOCKER_CONTEXT=swarm.autonomic.zone docker stack rm $(STACK) && \
 | 
						@DOCKER_CONTEXT=swarm-0.coopcloud.tech docker stack rm $(STACK) && \
 | 
				
			||||||
		DOCKER_CONTEXT=swarm.autonomic.zone docker stack deploy -c compose.yml $(STACK)
 | 
							DOCKER_CONTEXT=swarm-0.coopcloud.tech docker stack deploy -c compose.yml $(STACK)
 | 
				
			||||||
 | 
				
			|||||||
@ -401,8 +401,6 @@ teardown(){
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# bats test_tags=slow
 | 
					# bats test_tags=slow
 | 
				
			||||||
@test "ignore env version on new deploy" {
 | 
					@test "ignore env version on new deploy" {
 | 
				
			||||||
  tagHash=$(_get_tag_hash "0.1.0+1.20.0")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  run $ABRA app deploy "$TEST_APP_DOMAIN" "0.1.0+1.20.0" \
 | 
					  run $ABRA app deploy "$TEST_APP_DOMAIN" "0.1.0+1.20.0" \
 | 
				
			||||||
    --no-input --no-converge-checks
 | 
					    --no-input --no-converge-checks
 | 
				
			||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@ setup_file(){
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
teardown_file(){
 | 
					teardown_file(){
 | 
				
			||||||
 | 
					  _undeploy_app
 | 
				
			||||||
  _rm_app
 | 
					  _rm_app
 | 
				
			||||||
  _rm_server
 | 
					  _rm_server
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -18,6 +19,7 @@ setup(){
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
teardown(){
 | 
					teardown(){
 | 
				
			||||||
 | 
					  _reset_recipe
 | 
				
			||||||
  _undeploy_app
 | 
					  _undeploy_app
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -87,6 +89,10 @@ teardown(){
 | 
				
			|||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
  refute_output --partial "$TEST_RECIPE"
 | 
					  refute_output --partial "$TEST_RECIPE"
 | 
				
			||||||
  assert_output --partial "foo-recipe"
 | 
					  assert_output --partial "foo-recipe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run rm -rf "$ABRA_DIR/servers/foo.com"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_not_exists "$ABRA_DIR/servers/foo.com"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@test "output is machine readable" {
 | 
					@test "output is machine readable" {
 | 
				
			||||||
@ -98,3 +104,36 @@ teardown(){
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  assert_output --partial "$expectedOutput"
 | 
					  assert_output --partial "$expectedOutput"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "list with status fetches recipe" {
 | 
				
			||||||
 | 
					  _deploy_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app ls --status
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run rm -rf "$ABRA_DIR/recipes/$TEST_RECIPE"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app ls --status
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "list with chaos version" {
 | 
				
			||||||
 | 
					  run bash -c "echo foo >> $ABRA_DIR/recipes/$TEST_RECIPE/foo"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/$TEST_RECIPE/foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app deploy "$TEST_APP_DOMAIN" \
 | 
				
			||||||
 | 
					    --no-input --no-converge-checks --chaos
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app ls --status
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "+U"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run rm -rf "$ABRA_DIR/servers/foo.com"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_not_exists "$ABRA_DIR/servers/foo.com"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -250,3 +250,10 @@ teardown(){
 | 
				
			|||||||
    "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
 | 
					    "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
 | 
				
			||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@test "automatically select single server" {
 | 
				
			||||||
 | 
					  # NOTE(d1): no --no-input required, single server available
 | 
				
			||||||
 | 
					  run $ABRA app new "$TEST_RECIPE" --domain "$TEST_APP_DOMAIN"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/servers/$TEST_SERVER/$TEST_APP_DOMAIN.env"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -25,13 +25,3 @@ teardown(){
 | 
				
			|||||||
  run "$HOME/.local/bin/abra" -v
 | 
					  run "$HOME/.local/bin/abra" -v
 | 
				
			||||||
  assert_output --partial 'beta'
 | 
					  assert_output --partial 'beta'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
# bats test_tags=slow
 | 
					 | 
				
			||||||
@test "install release candidate from script" {
 | 
					 | 
				
			||||||
  run bash -c 'curl https://install.abra.coopcloud.tech | bash -s -- --rc'
 | 
					 | 
				
			||||||
  assert_success
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert_exists "$HOME/.local/bin/abra"
 | 
					 | 
				
			||||||
  run "$HOME/.local/bin/abra" -v
 | 
					 | 
				
			||||||
  assert_output --partial '-rc'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,16 @@ setup() {
 | 
				
			|||||||
  _common_setup
 | 
					  _common_setup
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					teardown(){
 | 
				
			||||||
 | 
					  run rm -rf "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_not_exists "$ABRA_DIR/recipes/$TEST_RECIPE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run rm -rf "$ABRA_DIR/recipes/git_coopcloud_tech_coop-cloud_matrix-synapse"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_not_exists "$ABRA_DIR/recipes/git_coopcloud_tech_coop-cloud_matrix-synapse"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# bats test_tags=slow
 | 
					# bats test_tags=slow
 | 
				
			||||||
@test "recipe fetch all" {
 | 
					@test "recipe fetch all" {
 | 
				
			||||||
  run rm -rf "$ABRA_DIR/recipes/matrix-synapse"
 | 
					  run rm -rf "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
@ -35,3 +45,81 @@ setup() {
 | 
				
			|||||||
  run $ABRA recipe fetch matrix-synapse --all
 | 
					  run $ABRA recipe fetch matrix-synapse --all
 | 
				
			||||||
  assert_failure
 | 
					  assert_failure
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@test "do not refetch without --force" {
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse
 | 
				
			||||||
 | 
					  assert_output --partial "already fetched"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@test "refetch with --force" {
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse --force
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  refute_output --partial "already fetched"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@test "refetch with --force does not erase unstaged changes" {
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run bash -c "echo foo >> $ABRA_DIR/recipes/matrix-synapse/foo"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse/foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse --force
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse/foo"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@test "fetch with --ssh" {
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse --ssh
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run git -C "$ABRA_DIR/recipes/matrix-synapse" remote -v
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "ssh://"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@test "re-fetch with --ssh/--force" {
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run git -C "$ABRA_DIR/recipes/matrix-synapse" remote -v
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "https://"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch matrix-synapse --ssh --force
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/matrix-synapse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run git -C "$ABRA_DIR/recipes/matrix-synapse" remote -v
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "ssh://"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@test "fetch remote recipe" {
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch git.coopcloud.tech/coop-cloud/matrix-synapse
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/git_coopcloud_tech_coop-cloud_matrix-synapse"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@test "remote recipe do not refetch without --force" {
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch git.coopcloud.tech/coop-cloud/matrix-synapse
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/git_coopcloud_tech_coop-cloud_matrix-synapse"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA recipe fetch git.coopcloud.tech/coop-cloud/matrix-synapse
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "already fetched"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -68,3 +68,27 @@ teardown(){
 | 
				
			|||||||
  assert_output --partial 'fooUser'
 | 
					  assert_output --partial 'fooUser'
 | 
				
			||||||
  assert_output --partial 'foo@example.com'
 | 
					  assert_output --partial 'foo@example.com'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "recipe new, app new, no releases, latest commit" {
 | 
				
			||||||
 | 
					  recipeName="foobar"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA recipe new "$recipeName"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/recipes/$recipeName"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  currentHash=$(git -C "$ABRA_DIR/recipes/$recipeName" show -s --format="%H")
 | 
				
			||||||
 | 
					  domain="$recipeName.$TEST_APP_SERVER" 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app new "$recipeName" \
 | 
				
			||||||
 | 
					    --no-input \
 | 
				
			||||||
 | 
					    --server "$TEST_SERVER" \
 | 
				
			||||||
 | 
					    --domain "$domain"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "version: ${currentHash:0:8}"
 | 
				
			||||||
 | 
					  assert_exists "$ABRA_DIR/servers/$TEST_SERVER/$domain.env"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run grep -q "TYPE=$recipeName:${currentHash:0:8}" \
 | 
				
			||||||
 | 
					    "$ABRA_DIR/servers/$TEST_SERVER/$domain.env"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -26,14 +26,3 @@ teardown(){
 | 
				
			|||||||
  run "$HOME/.local/bin/abra" -v
 | 
					  run "$HOME/.local/bin/abra" -v
 | 
				
			||||||
  assert_output --partial 'beta'
 | 
					  assert_output --partial 'beta'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
# bats test_tags=slow
 | 
					 | 
				
			||||||
@test "abra upgrade release candidate" {
 | 
					 | 
				
			||||||
  run $ABRA upgrade --rc
 | 
					 | 
				
			||||||
  assert_success
 | 
					 | 
				
			||||||
  assert_output --partial 'Public interest infrastructure'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  assert_exists "$HOME/.local/bin/abra"
 | 
					 | 
				
			||||||
  run "$HOME/.local/bin/abra" -v
 | 
					 | 
				
			||||||
  assert_output --partial '-rc'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user