package recipe import ( "fmt" "path" "strconv" "strings" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/config" "coopcloud.tech/abra/pkg/recipe" "coopcloud.tech/tagcmp" "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, Aliases: []string{"d"}, Destination: &Dry, } var Major bool var MajorFlag = &cli.BoolFlag{ Name: "major", Value: false, Aliases: []string{"ma", "x"}, Destination: &Major, } var Minor bool var MinorFlag = &cli.BoolFlag{ Name: "minor", Value: false, Aliases: []string{"mi", "y"}, Destination: &Minor, } var Patch bool var PatchFlag = &cli.BoolFlag{ Name: "patch", Value: false, Aliases: []string{"p", "z"}, Destination: &Patch, } var recipeReleaseCommand = &cli.Command{ Name: "release", Usage: "tag a recipe", Aliases: []string{"rl"}, ArgsUsage: " []", Flags: []cli.Flag{ DryFlag, PatchFlag, MinorFlag, MajorFlag, }, Action: func(c *cli.Context) error { recipe := internal.ValidateRecipe(c) directory := path.Join(config.APPS_DIR, recipe.Name) tagstring := c.Args().Get(1) imagesTmp := getImageVersions(recipe) repo, err := git.PlainOpen(directory) if err != nil { logrus.Fatal(err) } head, err := repo.Head() if err != nil { logrus.Fatal(err) } if tagstring != "" { repo, err := git.PlainOpen(directory) if err != nil { logrus.Fatal(err) } head, err := repo.Head() if err != nil { logrus.Fatal(err) } if Dry { logrus.Info(fmt.Sprintf("Dry run only. NOT creating tag %s at %s", tagstring, head.Hash())) return nil } repo.CreateTag(tagstring, head.Hash(), nil) /* &git.CreateTagOptions{ Message: tag, })*/ logrus.Info(fmt.Sprintf("Created tag %s at %s.", tagstring, head.Hash())) return nil } // bumpType is used to decide what part of the tag should be incremented bumpType := btoi(Major)*4 + btoi(Minor)*2 + btoi(Patch) if bumpType != 0 { // a bitwise check if the number is a power of 2 if (bumpType & (bumpType - 1)) != 0 { logrus.Fatal("you can only use one of: --major, --minor, --patch.") } } // get the latest tag with its hash, name etc var lastGitTag *object.Tag iter, err := repo.Tags() if err != nil { logrus.Fatal(err) } if err := iter.ForEach(func(ref *plumbing.Reference) error { obj, err := repo.TagObject(ref.Hash()) if err == nil { lastGitTag = obj return nil } return err }); err != nil { logrus.Fatal(err) } newTag, err := tagcmp.Parse(lastGitTag.Name) if err != nil { logrus.Fatal(err) } var newTagString string if bumpType > 0 { if Patch { now, err := strconv.Atoi(newTag.Patch) if err != nil { logrus.Fatal(err) } newTag.Patch = strconv.Itoa(now + 1) } else if Minor { now, err := strconv.Atoi(newTag.Minor) if err != nil { logrus.Fatal(err) } newTag.Minor = strconv.Itoa(now + 1) } else if Major { now, err := strconv.Atoi(newTag.Major) if err != nil { logrus.Fatal(err) } newTag.Major = strconv.Itoa(now + 1) } newTagString = newTag.String() } else { // calculate the new tag var images = make(map[string]tagcmp.Tag) for name, version := range imagesTmp { t, err := tagcmp.Parse(version) if err != nil { logrus.Fatal(err) } images[name] = t } } if Dry { logrus.Info(fmt.Sprintf("Dry run only. NOT creating tag %s at %s", newTagString, head.Hash())) return nil } repo.CreateTag(newTagString, head.Hash(), nil) /* &git.CreateTagOptions{ Message: tag, })*/ logrus.Info(fmt.Sprintf("Created tag %s at %s.", newTagString, 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 btoi(b bool) int { if b { return 1 } return 0 }