forked from toolshed/abra
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