feat: make sync use wizard mode
All checks were successful
continuous-integration/drone/push Build is passing

Some bugs squashed while testing this extensively.
This commit is contained in:
decentral1se 2021-11-06 23:40:22 +01:00
parent a539033b55
commit 2b9395be1a
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
6 changed files with 312 additions and 170 deletions

118
cli/internal/recipe.go Normal file
View File

@ -0,0 +1,118 @@
package internal
import (
"fmt"
"strings"
"coopcloud.tech/abra/pkg/recipe"
"github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)
var Major bool
var MajorFlag = &cli.BoolFlag{
Name: "major",
Usage: "Increase the major part of the version",
Value: false,
Aliases: []string{"ma", "x"},
Destination: &Major,
}
var Minor bool
var MinorFlag = &cli.BoolFlag{
Name: "minor",
Usage: "Increase the minor part of the version",
Value: false,
Aliases: []string{"mi", "y"},
Destination: &Minor,
}
var Patch bool
var PatchFlag = &cli.BoolFlag{
Name: "patch",
Usage: "Increase the patch part of the version",
Value: false,
Aliases: []string{"p", "z"},
Destination: &Patch,
}
var Dry bool
var DryFlag = &cli.BoolFlag{
Name: "dry-run",
Usage: "No changes are made, only reports changes that would be made",
Value: false,
Aliases: []string{"d"},
Destination: &Dry,
}
// PromptBumpType prompts for version bump type
func PromptBumpType(tagString string) error {
if (!Major && !Minor && !Patch) && tagString == "" {
fmt.Printf(`
semver cheat sheet (more via semver.org):
major: new features/bug fixes, backwards incompatible
minor: new features/bug fixes, backwards compatible
patch: bug fixes, backwards compatible
`)
var chosenBumpType string
prompt := &survey.Select{
Message: fmt.Sprintf("select recipe version increment type"),
Options: []string{"major", "minor", "patch"},
}
if err := survey.AskOne(prompt, &chosenBumpType); err != nil {
return err
}
SetBumpType(chosenBumpType)
}
return nil
}
// GetBumpType figures out which bump type is specified
func GetBumpType() string {
var bumpType string
if Major {
bumpType = "major"
} else if Minor {
bumpType = "minor"
} else if Patch {
bumpType = "patch"
} else {
logrus.Fatal("no version bump type specififed?")
}
return bumpType
}
// SetBumpType figures out which bump type is specified
func SetBumpType(bumpType string) {
if bumpType == "major" {
Major = true
} else if bumpType == "minor" {
Minor = true
} else if bumpType == "patch" {
Patch = true
} else {
logrus.Fatal("no version bump type specififed?")
}
}
// GetMainApp retrieves the main 'app' image name
func GetMainApp(recipe recipe.Recipe) string {
var app string
for _, service := range recipe.Config.Services {
name := service.Name
if name == "app" {
app = strings.Split(service.Image, ":")[0]
}
}
if app == "" {
logrus.Fatalf("%s has no main 'app' service?", recipe.Name)
}
return app
}

View File

@ -4,33 +4,6 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
var Major bool
var MajorFlag = &cli.BoolFlag{
Name: "major",
Usage: "Increase the major part of the version (new functionality, backwards incompatible, x of x.y.z)",
Value: false,
Aliases: []string{"ma", "x"},
Destination: &Major,
}
var Minor bool
var MinorFlag = &cli.BoolFlag{
Name: "minor",
Usage: "Increase the minor part of the version (new functionality, backwards compatible, y of x.y.z)",
Value: false,
Aliases: []string{"mi", "y"},
Destination: &Minor,
}
var Patch bool
var PatchFlag = &cli.BoolFlag{
Name: "patch",
Usage: "Increase the patch part of the version (bug fixes, backwards compatible, z of x.y.z)",
Value: false,
Aliases: []string{"p", "z"},
Destination: &Patch,
}
// RecipeCommand defines all recipe related sub-commands. // RecipeCommand defines all recipe related sub-commands.
var RecipeCommand = &cli.Command{ var RecipeCommand = &cli.Command{
Name: "recipe", Name: "recipe",

View File

@ -29,15 +29,6 @@ var PushFlag = &cli.BoolFlag{
Destination: &Push, Destination: &Push,
} }
var Dry bool
var DryFlag = &cli.BoolFlag{
Name: "dry-run",
Usage: "No changes are made, only reports changes that would be made",
Value: false,
Aliases: []string{"d"},
Destination: &Dry,
}
var CommitMessage string var CommitMessage string
var CommitMessageFlag = &cli.StringFlag{ var CommitMessageFlag = &cli.StringFlag{
Name: "commit-message", Name: "commit-message",
@ -95,10 +86,10 @@ You may invoke this command in "wizard" mode and be prompted for input:
`, `,
Flags: []cli.Flag{ Flags: []cli.Flag{
DryFlag, internal.DryFlag,
MajorFlag, internal.MajorFlag,
MinorFlag, internal.MinorFlag,
PatchFlag, internal.PatchFlag,
PushFlag, PushFlag,
CommitFlag, CommitFlag,
CommitMessageFlag, CommitMessageFlag,
@ -108,7 +99,7 @@ You may invoke this command in "wizard" mode and be prompted for input:
recipe := internal.ValidateRecipeWithPrompt(c) recipe := internal.ValidateRecipeWithPrompt(c)
directory := path.Join(config.APPS_DIR, recipe.Name) directory := path.Join(config.APPS_DIR, recipe.Name)
tagString := c.Args().Get(1) tagString := c.Args().Get(1)
mainApp := getMainApp(recipe) mainApp := internal.GetMainApp(recipe)
imagesTmp, err := getImageVersions(recipe) imagesTmp, err := getImageVersions(recipe)
if err != nil { if err != nil {
@ -130,16 +121,16 @@ You may invoke this command in "wizard" mode and be prompted for input:
} }
} }
if (!Major && !Minor && !Patch) && tagString != "" { if (!internal.Major && !internal.Minor && !internal.Patch) && tagString != "" {
logrus.Fatal("please specify <version> or bump type (--major/--minor/--patch)") logrus.Fatal("please specify <version> or bump type (--major/--minor/--patch)")
} }
if (Major || Minor || Patch) && tagString != "" { if (internal.Major || internal.Minor || internal.Patch) && tagString != "" {
logrus.Fatal("cannot specify tag and bump type at the same time") logrus.Fatal("cannot specify tag and bump type at the same time")
} }
// bumpType is used to decide what part of the tag should be incremented // bumpType is used to decide what part of the tag should be incremented
bumpType := btoi(Major)*4 + btoi(Minor)*2 + btoi(Patch) bumpType := btoi(internal.Major)*4 + btoi(internal.Minor)*2 + btoi(internal.Patch)
if bumpType != 0 { if bumpType != 0 {
// a bitwise check if the number is a power of 2 // a bitwise check if the number is a power of 2
if (bumpType & (bumpType - 1)) != 0 { if (bumpType & (bumpType - 1)) != 0 {
@ -147,29 +138,14 @@ You may invoke this command in "wizard" mode and be prompted for input:
} }
} }
if (!Major && !Minor && !Patch) && tagString == "" { if err := internal.PromptBumpType(tagString); err != nil {
fmt.Printf(` logrus.Fatal(err)
semver cheat sheet (more via semver.org):
major: new features/bug fixes, backwards incompatible
minor: new features/bug fixes, backwards compatible
patch: bug fixes, backwards compatible
`)
var chosenBumpType string
prompt := &survey.Select{
Message: fmt.Sprintf("select recipe version increment type"),
Options: []string{"major", "minor", "patch"},
}
if err := survey.AskOne(prompt, &chosenBumpType); err != nil {
logrus.Fatal(err)
}
setBumpType(chosenBumpType)
} }
if TagMessage == "" { if TagMessage == "" {
prompt := &survey.Input{ prompt := &survey.Input{
Message: "tag message", Message: "tag message",
Default: fmt.Sprintf("chore: publish new %s version", getBumpType()), Default: fmt.Sprintf("chore: publish new %s version", internal.GetBumpType()),
} }
if err := survey.AskOne(prompt, &TagMessage); err != nil { if err := survey.AskOne(prompt, &TagMessage); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
@ -210,7 +186,7 @@ semver cheat sheet (more via semver.org):
if CommitMessage == "" { if CommitMessage == "" {
prompt := &survey.Input{ prompt := &survey.Input{
Message: "commit message", Message: "commit message",
Default: fmt.Sprintf("chore: publish new %s version", getBumpType()), Default: fmt.Sprintf("chore: publish new %s version", internal.GetBumpType()),
} }
if err := survey.AskOne(prompt, &CommitMessage); err != nil { if err := survey.AskOne(prompt, &CommitMessage); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
@ -223,7 +199,7 @@ semver cheat sheet (more via semver.org):
} }
logrus.Debug("staged compose.**yml for commit") logrus.Debug("staged compose.**yml for commit")
if !Dry { if !internal.Dry {
_, err = commitWorktree.Commit(CommitMessage, &git.CommitOptions{}) _, err = commitWorktree.Commit(CommitMessage, &git.CommitOptions{})
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
@ -257,7 +233,7 @@ semver cheat sheet (more via semver.org):
tag.MissingPatch = false tag.MissingPatch = false
} }
tagString = fmt.Sprintf("%s+%s", tag.String(), mainAppVersion) tagString = fmt.Sprintf("%s+%s", tag.String(), mainAppVersion)
if Dry { if internal.Dry {
hash := abraFormatter.SmallSHA(head.Hash().String()) hash := abraFormatter.SmallSHA(head.Hash().String())
logrus.Info(fmt.Sprintf("dry run only: NOT creating tag %s at %s", tagString, hash)) logrus.Info(fmt.Sprintf("dry run only: NOT creating tag %s at %s", tagString, hash))
return nil return nil
@ -266,7 +242,7 @@ semver cheat sheet (more via semver.org):
repo.CreateTag(tagString, head.Hash(), &createTagOptions) repo.CreateTag(tagString, head.Hash(), &createTagOptions)
hash := abraFormatter.SmallSHA(head.Hash().String()) hash := abraFormatter.SmallSHA(head.Hash().String())
logrus.Info(fmt.Sprintf("created tag %s at %s", tagString, hash)) logrus.Info(fmt.Sprintf("created tag %s at %s", tagString, hash))
if Push && !Dry { if Push && !internal.Dry {
if err := repo.Push(&git.PushOptions{}); err != nil { if err := repo.Push(&git.PushOptions{}); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
@ -306,20 +282,20 @@ semver cheat sheet (more via semver.org):
newTag := lastGitTag newTag := lastGitTag
var newtagString string var newtagString string
if bumpType > 0 { if bumpType > 0 {
if Patch { if internal.Patch {
now, err := strconv.Atoi(newTag.Patch) now, err := strconv.Atoi(newTag.Patch)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
newTag.Patch = strconv.Itoa(now + 1) newTag.Patch = strconv.Itoa(now + 1)
} else if Minor { } else if internal.Minor {
now, err := strconv.Atoi(newTag.Minor) now, err := strconv.Atoi(newTag.Minor)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
newTag.Patch = "0" newTag.Patch = "0"
newTag.Minor = strconv.Itoa(now + 1) newTag.Minor = strconv.Itoa(now + 1)
} else if Major { } else if internal.Major {
now, err := strconv.Atoi(newTag.Major) now, err := strconv.Atoi(newTag.Major)
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
@ -332,7 +308,7 @@ semver cheat sheet (more via semver.org):
newTag.Metadata = mainAppVersion newTag.Metadata = mainAppVersion
newtagString = newTag.String() newtagString = newTag.String()
if Dry { if internal.Dry {
hash := abraFormatter.SmallSHA(head.Hash().String()) hash := abraFormatter.SmallSHA(head.Hash().String())
logrus.Info(fmt.Sprintf("dry run only: NOT creating tag %s at %s", newtagString, hash)) logrus.Info(fmt.Sprintf("dry run only: NOT creating tag %s at %s", newtagString, hash))
return nil return nil
@ -341,13 +317,13 @@ semver cheat sheet (more via semver.org):
repo.CreateTag(newtagString, head.Hash(), &createTagOptions) repo.CreateTag(newtagString, head.Hash(), &createTagOptions)
hash := abraFormatter.SmallSHA(head.Hash().String()) hash := abraFormatter.SmallSHA(head.Hash().String())
logrus.Info(fmt.Sprintf("created tag %s at %s", newtagString, hash)) logrus.Info(fmt.Sprintf("created tag %s at %s", newtagString, hash))
if Push && !Dry { if Push && !internal.Dry {
if err := repo.Push(&git.PushOptions{}); err != nil { if err := repo.Push(&git.PushOptions{}); err != nil {
logrus.Fatal(err) logrus.Fatal(err)
} }
logrus.Info(fmt.Sprintf("pushed tag %s to remote", newtagString)) logrus.Info(fmt.Sprintf("pushed tag %s to remote", newtagString))
} else { } else {
logrus.Info("dry run only: NOT pushing changes") logrus.Info("gry run only: NOT pushing changes")
} }
return nil return nil
@ -387,18 +363,6 @@ func getImageVersions(recipe recipe.Recipe) (map[string]string, error) {
return services, nil return services, nil
} }
// getMainApp retrieves the main 'app' image name
func getMainApp(recipe recipe.Recipe) string {
for _, service := range recipe.Config.Services {
name := service.Name
if name == "app" {
return strings.Split(service.Image, ":")[0]
}
}
return ""
}
// btoi converts a boolean value into an integer // btoi converts a boolean value into an integer
func btoi(b bool) int { func btoi(b bool) int {
if b { if b {
@ -407,33 +371,3 @@ func btoi(b bool) int {
return 0 return 0
} }
// getBumpType figures out which bump type is specified
func getBumpType() string {
var bumpType string
if Major {
bumpType = "major"
} else if Minor {
bumpType = "minor"
} else if Patch {
bumpType = "patch"
} else {
logrus.Fatal("no version bump type specififed?")
}
return bumpType
}
// setBumpType figures out which bump type is specified
func setBumpType(bumpType string) {
if bumpType == "major" {
Major = true
} else if bumpType == "minor" {
Minor = true
} else if bumpType == "patch" {
Patch = true
} else {
logrus.Fatal("no version bump type specififed?")
}
}

View File

@ -1,12 +1,17 @@
package recipe package recipe
import ( import (
"errors"
"fmt" "fmt"
"path"
"strconv"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/catalogue" "coopcloud.tech/abra/pkg/catalogue"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/tagcmp"
"github.com/AlecAivazis/survey/v2" "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/sirupsen/logrus"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -16,17 +21,166 @@ var recipeSyncCommand = &cli.Command{
Usage: "Ensure recipe version labels are up-to-date", Usage: "Ensure recipe version labels are up-to-date",
Aliases: []string{"s"}, Aliases: []string{"s"},
ArgsUsage: "<recipe> [<version>]", ArgsUsage: "<recipe> [<version>]",
Flags: []cli.Flag{
internal.DryFlag,
internal.MajorFlag,
internal.MinorFlag,
internal.PatchFlag,
},
Description: ` Description: `
This command will generate labels for the main recipe service (i.e. by This command will generate labels for the main recipe service (i.e. by
convention, typically the service named "app") which corresponds to the convention, the service named "app") which corresponds to the following format:
following format:
coop-cloud.${STACK_NAME}.version=<version> coop-cloud.${STACK_NAME}.version=<version>
The <version> is determined by the recipe maintainer and is specified on the 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 command-line. The <recipe> configuration will be updated on the local file
system. system.
You may invoke this command in "wizard" mode and be prompted for input:
abra recipe sync gitea
`, `,
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: func(c *cli.Context) { BashComplete: func(c *cli.Context) {
catl, err := catalogue.ReadRecipeCatalogue() catl, err := catalogue.ReadRecipeCatalogue()
if err != nil { if err != nil {
@ -39,50 +193,4 @@ system.
fmt.Println(name) fmt.Println(name)
} }
}, },
Action: func(c *cli.Context) error {
if c.Args().Len() != 2 {
internal.ShowSubcommandHelpAndError(c, errors.New("missing <recipe>/<version> arguments?"))
}
recipe := internal.ValidateRecipe(c)
// TODO: validate with tagcmp when new commits come in
// See https://git.coopcloud.tech/coop-cloud/abra/pulls/109
nextTag := c.Args().Get(1)
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.Warnf("no 'app' service defined in '%s'", recipe.Name)
var chosenService string
prompt := &survey.Select{
Message: fmt.Sprintf("what is the main service name for '%s'?", recipe.Name),
Options: services,
}
if err := survey.AskOne(prompt, &chosenService); err != nil {
logrus.Fatal(err)
}
mainService = chosenService
}
logrus.Debugf("selecting '%s' as the service to sync version labels", mainService)
label := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", nextTag)
if err := recipe.UpdateLabel(mainService, label); err != nil {
logrus.Fatal(err)
}
logrus.Infof("synced label '%s' to service '%s'", label, mainService)
return nil
},
} }

View File

@ -39,14 +39,14 @@ is up to the end-user to decide.
`, `,
ArgsUsage: "<recipe>", ArgsUsage: "<recipe>",
Flags: []cli.Flag{ Flags: []cli.Flag{
PatchFlag, internal.PatchFlag,
MinorFlag, internal.MinorFlag,
MajorFlag, internal.MajorFlag,
}, },
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipe(c) recipe := internal.ValidateRecipe(c)
bumpType := btoi(Major)*4 + btoi(Minor)*2 + btoi(Patch) bumpType := btoi(internal.Major)*4 + btoi(internal.Minor)*2 + btoi(internal.Patch)
if bumpType != 0 { if bumpType != 0 {
// a bitwise check if the number is a power of 2 // a bitwise check if the number is a power of 2
if (bumpType & (bumpType - 1)) != 0 { if (bumpType & (bumpType - 1)) != 0 {
@ -179,11 +179,11 @@ is up to the end-user to decide.
if contains { if contains {
logrus.Infof("Upgrading service %s from %s to %s (pinned tag: %s)", service.Name, tag.String(), upgradeTag, pinnedTagString) logrus.Infof("Upgrading service %s from %s to %s (pinned tag: %s)", service.Name, tag.String(), upgradeTag, pinnedTagString)
} else { } else {
logrus.Infof("service %s, image %s pinned to %s. No compatible upgrade found", service.Name, servicePins[service.Name].image, pinnedTagString) logrus.Infof("service %s, image %s pinned to %s, no compatible upgrade found", service.Name, servicePins[service.Name].image, pinnedTagString)
continue continue
} }
} else { } else {
logrus.Fatalf("Service %s is at version %s, but pinned to %s. Please correct your compose.yml file manually!", service.Name, tag.String(), pinnedTag.String()) logrus.Fatalf("Service %s is at version %s, but pinned to %s, please correct your compose.yml file manually!", service.Name, tag.String(), pinnedTag.String())
continue continue
} }
} else { } else {

View File

@ -117,8 +117,11 @@ func UpdateLabel(pattern, serviceName, label, recipeName string) error {
continue continue
} }
discovered := false
for oldLabel, value := range service.Deploy.Labels { for oldLabel, value := range service.Deploy.Labels {
if strings.HasPrefix(oldLabel, "coop-cloud") { if strings.HasPrefix(oldLabel, "coop-cloud") {
discovered = true
bytes, err := ioutil.ReadFile(composeFile) bytes, err := ioutil.ReadFile(composeFile)
if err != nil { if err != nil {
return err return err
@ -127,13 +130,19 @@ func UpdateLabel(pattern, serviceName, label, recipeName string) error {
old := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", value) old := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", value)
replacedBytes := strings.Replace(string(bytes), old, label, -1) replacedBytes := strings.Replace(string(bytes), old, label, -1)
logrus.Debugf("updating '%s' to '%s' in '%s'", old, label, compose.Filename) logrus.Debugf("updating %s to %s in %s", old, label, compose.Filename)
if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0644); err != nil { if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0644); err != nil {
return err return err
} }
} }
} }
if !discovered {
logrus.Warn("no existing label found, cannot continue...")
logrus.Fatalf("add '%s' manually, automagic insertion not supported yet", label)
}
} }
return nil return nil