forked from coop-cloud/abra
186 lines
4.8 KiB
Go
186 lines
4.8 KiB
Go
package recipe
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"strconv"
|
|
|
|
"coopcloud.tech/abra/cli/internal"
|
|
"coopcloud.tech/abra/pkg/autocomplete"
|
|
"coopcloud.tech/abra/pkg/config"
|
|
"coopcloud.tech/tagcmp"
|
|
"github.com/AlecAivazis/survey/v2"
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/go-git/go-git/v5/plumbing"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
var recipeSyncCommand = &cli.Command{
|
|
Name: "sync",
|
|
Usage: "Ensure recipe version labels are up-to-date",
|
|
Aliases: []string{"s"},
|
|
ArgsUsage: "<recipe> [<version>]",
|
|
Flags: []cli.Flag{
|
|
internal.DryFlag,
|
|
internal.MajorFlag,
|
|
internal.MinorFlag,
|
|
internal.PatchFlag,
|
|
},
|
|
Description: `
|
|
This command will generate labels for the main recipe service (i.e. by
|
|
convention, the service named "app") which corresponds to the following format:
|
|
|
|
coop-cloud.${STACK_NAME}.version=<version>
|
|
|
|
The <version> is determined by the recipe maintainer and is specified on the
|
|
command-line. The <recipe> configuration will be updated on the local file
|
|
system.
|
|
|
|
You may invoke this command in "wizard" mode and be prompted for input:
|
|
|
|
abra recipe sync
|
|
|
|
`,
|
|
Action: func(c *cli.Context) error {
|
|
recipe := internal.ValidateRecipeWithPrompt(c)
|
|
|
|
mainApp := internal.GetMainApp(recipe)
|
|
|
|
imagesTmp, err := getImageVersions(recipe)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
mainAppVersion := imagesTmp[mainApp]
|
|
|
|
tags, err := recipe.Tags()
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
|
|
nextTag := c.Args().Get(1)
|
|
if len(tags) == 0 && nextTag == "" {
|
|
logrus.Warnf("no tags found for %s", recipe.Name)
|
|
var chosenVersion string
|
|
edPrompt := &survey.Select{
|
|
Message: "which version do you want to begin with?",
|
|
Options: []string{"0.1.0", "1.0.0"},
|
|
}
|
|
if err := survey.AskOne(edPrompt, &chosenVersion); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
nextTag = fmt.Sprintf("%s+%s", chosenVersion, mainAppVersion)
|
|
}
|
|
|
|
if nextTag == "" && (!internal.Major && !internal.Minor && !internal.Patch) {
|
|
if err := internal.PromptBumpType(""); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
}
|
|
|
|
if nextTag == "" {
|
|
recipeDir := path.Join(config.APPS_DIR, recipe.Name)
|
|
repo, err := git.PlainOpen(recipeDir)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
var lastGitTag tagcmp.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 {
|
|
return err
|
|
}
|
|
tagcmpTag, err := tagcmp.Parse(obj.Name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if (lastGitTag == tagcmp.Tag{}) {
|
|
lastGitTag = tagcmpTag
|
|
} else if tagcmpTag.IsGreaterThan(lastGitTag) {
|
|
lastGitTag = tagcmpTag
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
|
|
// bumpType is used to decide what part of the tag should be incremented
|
|
bumpType := btoi(internal.Major)*4 + btoi(internal.Minor)*2 + btoi(internal.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.")
|
|
}
|
|
}
|
|
|
|
newTag := lastGitTag
|
|
if bumpType > 0 {
|
|
if internal.Patch {
|
|
now, err := strconv.Atoi(newTag.Patch)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
newTag.Patch = strconv.Itoa(now + 1)
|
|
} else if internal.Minor {
|
|
now, err := strconv.Atoi(newTag.Minor)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
newTag.Patch = "0"
|
|
newTag.Minor = strconv.Itoa(now + 1)
|
|
} else if internal.Major {
|
|
now, err := strconv.Atoi(newTag.Major)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
newTag.Patch = "0"
|
|
newTag.Minor = "0"
|
|
newTag.Major = strconv.Itoa(now + 1)
|
|
}
|
|
}
|
|
|
|
newTag.Metadata = mainAppVersion
|
|
logrus.Debugf("choosing %s as new version for %s", newTag.String(), recipe.Name)
|
|
nextTag = newTag.String()
|
|
}
|
|
|
|
if _, err := tagcmp.Parse(nextTag); err != nil {
|
|
logrus.Fatalf("invalid version %s specified", nextTag)
|
|
}
|
|
|
|
mainService := "app"
|
|
var services []string
|
|
hasAppService := false
|
|
for _, service := range recipe.Config.Services {
|
|
services = append(services, service.Name)
|
|
if service.Name == "app" {
|
|
hasAppService = true
|
|
logrus.Debugf("detected app service in %s", recipe.Name)
|
|
}
|
|
}
|
|
|
|
if !hasAppService {
|
|
logrus.Fatalf("%s has no main 'app' service?", recipe.Name)
|
|
}
|
|
|
|
logrus.Debugf("selecting %s as the service to sync version label", mainService)
|
|
|
|
label := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", nextTag)
|
|
if !internal.Dry {
|
|
if err := recipe.UpdateLabel(mainService, label); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
logrus.Infof("synced label '%s' to service '%s'", label, mainService)
|
|
} else {
|
|
logrus.Infof("dry run only: NOT syncing label %s for recipe %s", nextTag, recipe.Name)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
BashComplete: autocomplete.RecipeNameComplete,
|
|
}
|