From 48d28c8dd1f83ac66c2267342706db26ae966322 Mon Sep 17 00:00:00 2001 From: knoflook Date: Wed, 22 Sep 2021 16:03:56 +0200 Subject: [PATCH] feat: tag recipes with abra --- cli/recipe/recipe.go | 1 + cli/recipe/release.go | 123 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 cli/recipe/release.go diff --git a/cli/recipe/recipe.go b/cli/recipe/recipe.go index d349c2d26..0fd3ef4d1 100644 --- a/cli/recipe/recipe.go +++ b/cli/recipe/recipe.go @@ -18,6 +18,7 @@ Cloud community and you can use Abra to read them and create apps for you. Subcommands: []*cli.Command{ recipeListCommand, recipeVersionCommand, + recipeReleaseCommand, recipeNewCommand, recipeUpgradeCommand, recipeSyncCommand, diff --git a/cli/recipe/release.go b/cli/recipe/release.go new file mode 100644 index 000000000..d675ca410 --- /dev/null +++ b/cli/recipe/release.go @@ -0,0 +1,123 @@ +package recipe + +import ( + "fmt" + "os" + "path" + "strconv" + "strings" + + "coopcloud.tech/abra/cli/internal" + "coopcloud.tech/abra/pkg/config" + "coopcloud.tech/abra/pkg/recipe" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/sirupsen/logrus" + "github.com/urfave/cli/v2" +) + +var Dry bool +var DryFlag = &cli.BoolFlag{ + Name: "dry-run", + Value: false, + Destination: &Dry, +} + +var recipeReleaseCommand = &cli.Command{ + Name: "release", + Usage: "tag a recipe", + Aliases: []string{"rl"}, + ArgsUsage: " []", + Flags: []cli.Flag{ + DryFlag, + }, + Action: func(c *cli.Context) error { + recipe := internal.ValidateRecipe(c) + + directory := path.Join(config.APPS_DIR, recipe.Name) + if _, err := os.Stat(directory); os.IsNotExist(err) { + logrus.Fatalf("recipe doesn't exist at path %s.", directory) + return nil + } + + images := getImageVersions(recipe) + tag := c.Args().Get(1) + if tag == "" { + for name, version := range images { + if !isSemver(version) { + logrus.Fatal(fmt.Sprintf("app %s: version number %s is not in the format x.y.z (where x,y,z are integers) - unable to generate tags, please specify a tag yourself.", name, version)) + } + } + } + + repo, err := git.PlainOpen(directory) + if err != nil { + logrus.Fatal(err) + } + head, err := repo.Head() + if err != nil { + logrus.Fatal(err) + } + // get the latest tag with its hash, name etc + if tag == "" { + var lastTag *object.Tag + iter, err := repo.Tags() + if err != nil { + logrus.Fatal(err) + } + // TODO: This is some magic and I have no idea what's going on but it does the job. Re-write if this looks stupid to you. Copied from the docs /knoflook + if err := iter.ForEach(func(ref *plumbing.Reference) error { + obj, err := repo.TagObject(ref.Hash()) + switch err { + case nil: + lastTag = obj + break + case plumbing.ErrObjectNotFound: + logrus.Fatal(err) + default: + return err + } + return nil + }); err != nil { + logrus.Fatal(err) + } + } + + if Dry { + logrus.Info(fmt.Sprintf("Dry run only. NOT creating tag %s at %s", tag, head.Hash())) + return nil + } + + repo.CreateTag(tag, head.Hash(), nil) /* &git.CreateTagOptions{ + Message: tag, + })*/ + logrus.Info(fmt.Sprintf("Created tag %s at %s.", tag, head.Hash())) + + return nil + }, +} + +func getImageVersions(recipe recipe.Recipe) map[string]string { + + var services = make(map[string]string) + for _, service := range recipe.Config.Services { + srv := strings.Split(service.Image, ":") + services[srv[0]] = srv[1] + } + + return services +} + +func isSemver(ver string) bool { + numbers := strings.Split(ver, ".") + if len(numbers) > 3 { + return false + } + for _, part := range numbers { + if _, err := strconv.Atoi(part); err != nil { + return false + } + } + return true +}