201 lines
5.3 KiB
Go
201 lines
5.3 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/abra/pkg/runtime"
|
|
"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"
|
|
)
|
|
|
|
var recipeSyncCommand = cli.Command{
|
|
Name: "sync",
|
|
Aliases: []string{"s"},
|
|
Usage: "Sync recipe version label",
|
|
ArgsUsage: "<recipe> [<version>]",
|
|
Flags: []cli.Flag{
|
|
internal.DebugFlag,
|
|
internal.NoInputFlag,
|
|
internal.DryFlag,
|
|
internal.MajorFlag,
|
|
internal.MinorFlag,
|
|
internal.PatchFlag,
|
|
},
|
|
Before: internal.SubCommandBefore,
|
|
Description: `
|
|
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>
|
|
|
|
Where <version> can be specifed on the command-line or Abra can attempt to
|
|
auto-generate it for you. The <recipe> configuration will be updated on the
|
|
local file system.
|
|
`,
|
|
Action: func(c *cli.Context) error {
|
|
recipe := internal.ValidateRecipeWithPrompt(c, runtime.WithEnsureRecipeLatest(false))
|
|
|
|
mainApp, err := internal.GetMainAppImage(recipe)
|
|
if err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
|
|
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 git tags found for %s", recipe.Name)
|
|
fmt.Println(fmt.Sprintf(`
|
|
The following options are two types of initial semantic version that you can
|
|
pick for %s that will be published in the recipe catalogue. This follows the
|
|
semver convention (more on https://semver.org), here is a short cheatsheet
|
|
|
|
0.1.0: development release, still hacking. when you make a major upgrade
|
|
you increment the "y" part (i.e. 0.1.0 -> 0.2.0) and only move to
|
|
using the "x" part when things are stable.
|
|
|
|
1.0.0: public release, assumed to be working. you already have a stable
|
|
and reliable deployment of this app and feel relatively confident
|
|
about it.
|
|
|
|
If you want people to be able alpha test your current config for %s but don't
|
|
think it is quite reliable, go with 0.1.0 and people will know that things are
|
|
likely to change.
|
|
|
|
`, recipe.Name, 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) {
|
|
latestRelease := tags[len(tags)-1]
|
|
if err := internal.PromptBumpType("", latestRelease); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
}
|
|
|
|
if nextTag == "" {
|
|
recipeDir := path.Join(config.RECIPES_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 version flag: --major, --minor or --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"
|
|
label := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", nextTag)
|
|
if !internal.Dry {
|
|
if err := recipe.UpdateLabel("compose.y*ml", mainService, label); err != nil {
|
|
logrus.Fatal(err)
|
|
}
|
|
} else {
|
|
logrus.Infof("dry run: not syncing label %s for recipe %s", nextTag, recipe.Name)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
BashComplete: autocomplete.RecipeNameComplete,
|
|
}
|