forked from toolshed/abra
refactor(recipe): load load compoes config where its used
This commit is contained in:
@ -59,6 +59,55 @@ func (r Recipe2) GetComposeFiles(appEnv map[string]string) ([]string, error) {
|
||||
return composeFiles, nil
|
||||
}
|
||||
|
||||
func (r Recipe2) GetComposeConfig(env map[string]string) (*composetypes.Config, error) {
|
||||
pattern := fmt.Sprintf("%s/compose**yml", r.Dir)
|
||||
composeFiles, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(composeFiles) == 0 {
|
||||
return nil, fmt.Errorf("%s is missing a compose.yml or compose.*.yml file?", r.Name)
|
||||
}
|
||||
|
||||
if env == nil {
|
||||
env, err = r.SampleEnv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
opts := stack.Deploy{Composefiles: composeFiles}
|
||||
config, err := loader.LoadComposefile(opts, env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetVersionLabelLocal retrieves the version label on the local recipe config
|
||||
func (r Recipe2) GetVersionLabelLocal() (string, error) {
|
||||
var label string
|
||||
config, err := r.GetComposeConfig(nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, service := range config.Services {
|
||||
for label, value := range service.Deploy.Labels {
|
||||
if strings.HasPrefix(label, "coop-cloud") && strings.Contains(label, "version") {
|
||||
return value, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if label == "" {
|
||||
return label, fmt.Errorf("%s has no version label? try running \"abra recipe sync %s\" first?", r.Name, r.Name)
|
||||
}
|
||||
|
||||
return label, nil
|
||||
}
|
||||
|
||||
// UpdateTag updates an image tag in-place on file system local compose files.
|
||||
func (r Recipe2) UpdateTag(image, tag string) (bool, error) {
|
||||
fullPattern := fmt.Sprintf("%s/compose**yml", r.Dir)
|
||||
@ -119,7 +168,7 @@ func (r Recipe2) UpdateTag(image, tag string) (bool, error) {
|
||||
|
||||
log.Debugf("updating %s to %s in %s", old, new, compose.Filename)
|
||||
|
||||
if err := os.WriteFile(compose.Filename, []byte(replacedBytes), 0764); err != nil {
|
||||
if err := os.WriteFile(compose.Filename, []byte(replacedBytes), 0o764); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
@ -185,7 +234,7 @@ func (r Recipe2) UpdateLabel(pattern, serviceName, label string) error {
|
||||
|
||||
log.Debugf("updating %s to %s in %s", old, label, compose.Filename)
|
||||
|
||||
if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0764); err != nil {
|
||||
if err := ioutil.WriteFile(compose.Filename, []byte(replacedBytes), 0o764); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"coopcloud.tech/abra/pkg/formatter"
|
||||
gitPkg "coopcloud.tech/abra/pkg/git"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
@ -288,3 +289,91 @@ func (r Recipe2) Tags() ([]string, error) {
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
// GetRecipeVersions retrieves all recipe versions.
|
||||
func (r Recipe2) GetRecipeVersions(offline bool) (RecipeVersions, error) {
|
||||
versions := RecipeVersions{}
|
||||
log.Debugf("attempting to open git repository in %s", r.Dir)
|
||||
|
||||
repo, err := git.PlainOpen(r.Dir)
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
worktree, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
gitTags, err := repo.Tags()
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
if err := gitTags.ForEach(func(ref *plumbing.Reference) (err error) {
|
||||
tag := strings.TrimPrefix(string(ref.Name()), "refs/tags/")
|
||||
|
||||
log.Debugf("processing %s for %s", tag, r.Name)
|
||||
|
||||
checkOutOpts := &git.CheckoutOptions{
|
||||
Create: false,
|
||||
Force: true,
|
||||
Branch: plumbing.ReferenceName(ref.Name()),
|
||||
}
|
||||
if err := worktree.Checkout(checkOutOpts); err != nil {
|
||||
log.Debugf("failed to check out %s in %s", tag, r.Dir)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("successfully checked out %s in %s", ref.Name(), r.Dir)
|
||||
|
||||
config, err := r.GetComposeConfig(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
versionMeta := make(map[string]ServiceMeta)
|
||||
for _, service := range config.Services {
|
||||
|
||||
img, err := reference.ParseNormalizedNamed(service.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := reference.Path(img)
|
||||
|
||||
path = formatter.StripTagMeta(path)
|
||||
|
||||
var tag string
|
||||
switch img.(type) {
|
||||
case reference.NamedTagged:
|
||||
tag = img.(reference.NamedTagged).Tag()
|
||||
case reference.Named:
|
||||
log.Warnf("%s service is missing image tag?", path)
|
||||
continue
|
||||
}
|
||||
|
||||
versionMeta[service.Name] = ServiceMeta{
|
||||
Image: path,
|
||||
Tag: tag,
|
||||
}
|
||||
}
|
||||
|
||||
versions = append(versions, map[string]map[string]ServiceMeta{tag: versionMeta})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
_, err = gitPkg.CheckoutDefaultBranch(repo, r.Dir)
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
sortRecipeVersions(versions)
|
||||
|
||||
log.Debugf("collected %s for %s", versions, r.Dir)
|
||||
|
||||
return versions, nil
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
@ -18,14 +17,8 @@ import (
|
||||
gitPkg "coopcloud.tech/abra/pkg/git"
|
||||
"coopcloud.tech/abra/pkg/limit"
|
||||
"coopcloud.tech/abra/pkg/log"
|
||||
"coopcloud.tech/abra/pkg/upstream/stack"
|
||||
loader "coopcloud.tech/abra/pkg/upstream/stack"
|
||||
"coopcloud.tech/abra/pkg/web"
|
||||
"coopcloud.tech/tagcmp"
|
||||
"github.com/distribution/reference"
|
||||
composetypes "github.com/docker/cli/cli/compose/types"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
// RecipeCatalogueURL is the only current recipe catalogue available.
|
||||
@ -131,9 +124,8 @@ type Features struct {
|
||||
|
||||
// Recipe represents a recipe.
|
||||
type Recipe struct {
|
||||
Name string
|
||||
Config *composetypes.Config
|
||||
Meta RecipeMeta
|
||||
Name string
|
||||
Meta RecipeMeta
|
||||
}
|
||||
|
||||
// Get retrieves a recipe.
|
||||
@ -143,27 +135,6 @@ func Get(recipeName string, offline bool) (Recipe, error) {
|
||||
return Recipe{}, err
|
||||
}
|
||||
|
||||
pattern := fmt.Sprintf("%s/%s/compose**yml", config.RECIPES_DIR, r.Name)
|
||||
composeFiles, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
return Recipe{}, err
|
||||
}
|
||||
|
||||
if len(composeFiles) == 0 {
|
||||
return Recipe{}, fmt.Errorf("%s is missing a compose.yml or compose.*.yml file?", r.Name)
|
||||
}
|
||||
|
||||
sampleEnv, err := r.SampleEnv()
|
||||
if err != nil {
|
||||
return Recipe{}, err
|
||||
}
|
||||
|
||||
opts := stack.Deploy{Composefiles: composeFiles}
|
||||
config, err := loader.LoadComposefile(opts, sampleEnv)
|
||||
if err != nil {
|
||||
return Recipe{}, err
|
||||
}
|
||||
|
||||
meta, err := GetRecipeMeta(r.Name, offline)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
@ -175,9 +146,8 @@ func Get(recipeName string, offline bool) (Recipe, error) {
|
||||
}
|
||||
|
||||
return Recipe{
|
||||
Name: recipeName,
|
||||
Config: config,
|
||||
Meta: meta,
|
||||
Name: recipeName,
|
||||
Meta: meta,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -216,25 +186,6 @@ func GetRecipesLocal() ([]string, error) {
|
||||
return recipes, nil
|
||||
}
|
||||
|
||||
// GetVersionLabelLocal retrieves the version label on the local recipe config
|
||||
func GetVersionLabelLocal(recipe Recipe) (string, error) {
|
||||
var label string
|
||||
|
||||
for _, service := range recipe.Config.Services {
|
||||
for label, value := range service.Deploy.Labels {
|
||||
if strings.HasPrefix(label, "coop-cloud") && strings.Contains(label, "version") {
|
||||
return value, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if label == "" {
|
||||
return label, fmt.Errorf("%s has no version label? try running \"abra recipe sync %s\" first?", recipe.Name, recipe.Name)
|
||||
}
|
||||
|
||||
return label, nil
|
||||
}
|
||||
|
||||
func GetRecipeFeaturesAndCategory(r Recipe2) (Features, string, error) {
|
||||
feat := Features{}
|
||||
|
||||
@ -579,96 +530,6 @@ func ReadReposMetadata() (RepoCatalogue, error) {
|
||||
return reposMeta, nil
|
||||
}
|
||||
|
||||
// GetRecipeVersions retrieves all recipe versions.
|
||||
func GetRecipeVersions(recipeName string, offline bool) (RecipeVersions, error) {
|
||||
versions := RecipeVersions{}
|
||||
recipeDir := path.Join(config.RECIPES_DIR, recipeName)
|
||||
|
||||
log.Debugf("attempting to open git repository in %s", recipeDir)
|
||||
|
||||
repo, err := git.PlainOpen(recipeDir)
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
worktree, err := repo.Worktree()
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
gitTags, err := repo.Tags()
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
if err := gitTags.ForEach(func(ref *plumbing.Reference) (err error) {
|
||||
tag := strings.TrimPrefix(string(ref.Name()), "refs/tags/")
|
||||
|
||||
log.Debugf("processing %s for %s", tag, recipeName)
|
||||
|
||||
checkOutOpts := &git.CheckoutOptions{
|
||||
Create: false,
|
||||
Force: true,
|
||||
Branch: plumbing.ReferenceName(ref.Name()),
|
||||
}
|
||||
if err := worktree.Checkout(checkOutOpts); err != nil {
|
||||
log.Debugf("failed to check out %s in %s", tag, recipeDir)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("successfully checked out %s in %s", ref.Name(), recipeDir)
|
||||
|
||||
recipe, err := Get(recipeName, offline)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
versionMeta := make(map[string]ServiceMeta)
|
||||
for _, service := range recipe.Config.Services {
|
||||
|
||||
img, err := reference.ParseNormalizedNamed(service.Image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := reference.Path(img)
|
||||
|
||||
path = formatter.StripTagMeta(path)
|
||||
|
||||
var tag string
|
||||
switch img.(type) {
|
||||
case reference.NamedTagged:
|
||||
tag = img.(reference.NamedTagged).Tag()
|
||||
case reference.Named:
|
||||
log.Warnf("%s service is missing image tag?", path)
|
||||
continue
|
||||
}
|
||||
|
||||
versionMeta[service.Name] = ServiceMeta{
|
||||
Image: path,
|
||||
Tag: tag,
|
||||
}
|
||||
}
|
||||
|
||||
versions = append(versions, map[string]map[string]ServiceMeta{tag: versionMeta})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
_, err = gitPkg.CheckoutDefaultBranch(repo, recipeDir)
|
||||
if err != nil {
|
||||
return versions, err
|
||||
}
|
||||
|
||||
sortRecipeVersions(versions)
|
||||
|
||||
log.Debugf("collected %s for %s", versions, recipeName)
|
||||
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
// sortRecipeVersions sorts the recipe semver versions
|
||||
func sortRecipeVersions(versions RecipeVersions) {
|
||||
sort.Slice(versions, func(i, j int) bool {
|
||||
|
@ -14,13 +14,10 @@ func TestGetVersionLabelLocalDoesNotUseTimeoutLabel(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r, err := Get("traefik", offline)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r := Get2("traefik")
|
||||
|
||||
for i := 1; i < 1000; i++ {
|
||||
label, err := GetVersionLabelLocal(r)
|
||||
label, err := r.GetVersionLabelLocal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user