feat: make sync use wizard mode
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Some bugs squashed while testing this extensively.
This commit is contained in:
parent
a539033b55
commit
2b9395be1a
118
cli/internal/recipe.go
Normal file
118
cli/internal/recipe.go
Normal 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
|
||||||
|
}
|
@ -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",
|
||||||
|
@ -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?")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user