feat: teach recipe sync to understand new versions
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is passing Details

Closes coop-cloud/organising#177.
This commit is contained in:
decentral1se 2021-10-05 10:28:09 +02:00
parent a58cea3e0a
commit c616907b71
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
2 changed files with 81 additions and 28 deletions

View File

@ -4,62 +4,88 @@ import (
"fmt" "fmt"
"coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/cli/internal"
"coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/catalogue"
"github.com/docker/distribution/reference" "github.com/AlecAivazis/survey/v2"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
var recipeSyncCommand = &cli.Command{ var recipeSyncCommand = &cli.Command{
Name: "sync", Name: "sync",
Usage: "Generate new recipe labels", Usage: "Ensure recipe version labels are up-to-date",
Aliases: []string{"s"}, Aliases: []string{"s"},
Description: ` Description: `
This command will generate labels for each service which correspond to the This command will generate labels for the main recipe service (i.e. the service
following format: named "app", by convention) which corresponds to the following format:
coop-cloud.${STACK_NAME}.${SERVICE_NAME}.version=${IMAGE_TAG}-${IMAGE_DIGEST} coop-cloud.${STACK_NAME}.version=${RECIPE_TAG}
The <recipe> configuration will be updated on the local file system. These The ${RECIPE_TAG} is determined by the recipe maintainer and is retrieved by
labels are consumed by abra in other command invocations and used to determine this command by asking for the list of git tags on the local git repository.
the versioning metadata of up-and-running containers are. The <recipe> configuration will be updated on the local file system.
`, `,
ArgsUsage: "<recipe>", ArgsUsage: "<recipe>",
BashComplete: func(c *cli.Context) {
catl, err := catalogue.ReadRecipeCatalogue()
if err != nil {
logrus.Warn(err)
}
if c.NArg() > 0 {
return
}
for name := range catl {
fmt.Println(name)
}
},
Action: func(c *cli.Context) error { Action: func(c *cli.Context) error {
recipe := internal.ValidateRecipe(c) recipe := internal.ValidateRecipe(c)
mainService := "app"
var services []string
hasAppService := false hasAppService := false
for _, service := range recipe.Config.Services { for _, service := range recipe.Config.Services {
services = append(services, service.Name)
if service.Name == "app" { if service.Name == "app" {
hasAppService = true hasAppService = true
logrus.Debugf("detected app service in '%s'", recipe.Name)
} }
} }
if !hasAppService { if !hasAppService {
logrus.Fatal(fmt.Sprintf("no 'app' service defined in '%s'", recipe.Name)) 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
} }
for _, service := range recipe.Config.Services { logrus.Debugf("selecting '%s' as the service to sync version labels", mainService)
img, err := reference.ParseNormalizedNamed(service.Image)
if err != nil {
logrus.Fatal(err)
}
logrus.Debugf("detected image '%s' for service '%s'", img, service.Name)
digest, err := client.GetTagDigest(img) tags, err := recipe.Tags()
if err != nil { if err != nil {
logrus.Fatal(err) logrus.Fatal(err)
}
logrus.Debugf("retrieved digest '%s' for '%s'", digest, img)
tag := img.(reference.NamedTagged).Tag()
label := fmt.Sprintf("coop-cloud.${STACK_NAME}.%s.version=%s-%s", service.Name, tag, digest)
if err := recipe.UpdateLabel(service.Name, label); err != nil {
logrus.Fatal(err)
}
logrus.Debugf("added label '%s' to service '%s'", label, service.Name)
} }
if len(tags) == 0 {
logrus.Fatalf("no tags detected for '%s'", recipe.Name)
}
latestTag := tags[len(tags)-1]
logrus.Infof("choosing '%s' as latest tag for recipe '%s'", latestTag, recipe.Name)
label := fmt.Sprintf("coop-cloud.${STACK_NAME}.version=%s", latestTag)
if err := recipe.UpdateLabel(mainService, label); err != nil {
logrus.Fatal(err)
}
logrus.Infof("added label '%s' to service '%s'", label, mainService)
return nil return nil
}, },
} }

View File

@ -41,6 +41,33 @@ func (r Recipe) UpdateTag(image, tag string) error {
return nil return nil
} }
// Tags list the recipe tags
func (r Recipe) Tags() ([]string, error) {
var tags []string
recipeDir := path.Join(config.ABRA_DIR, "apps", r.Name)
repo, err := git.PlainOpen(recipeDir)
if err != nil {
return tags, err
}
gitTags, err := repo.Tags()
if err != nil {
return tags, err
}
if err := gitTags.ForEach(func(ref *plumbing.Reference) (err error) {
tags = append(tags, strings.TrimPrefix(string(ref.Name()), "refs/tags/"))
return nil
}); err != nil {
return tags, err
}
logrus.Debugf("detected '%s' as tags for recipe '%s'", strings.Join(tags, ", "), r.Name)
return tags, nil
}
// Get retrieves a recipe. // Get retrieves a recipe.
func Get(recipeName string) (Recipe, error) { func Get(recipeName string) (Recipe, error) {
if err := EnsureExists(recipeName); err != nil { if err := EnsureExists(recipeName); err != nil {