forked from toolshed/abra
		
	refactor(recipe): load load compoes config where its used
This commit is contained in:
		| @ -58,13 +58,8 @@ recipes. | ||||
| 			log.Fatal("cannot use <version> and --chaos together") | ||||
| 		} | ||||
|  | ||||
| 		r2 := recipe.Get2(app.Recipe) | ||||
| 		if err := r2.Ensure(internal.Chaos, internal.Offline); err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		r, err := recipe.Get(app.Recipe, internal.Offline) | ||||
| 		if err != nil { | ||||
| 		r := recipe.Get2(app.Recipe) | ||||
| 		if err := r.Ensure(internal.Chaos, internal.Offline); err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| @ -92,7 +87,7 @@ recipes. | ||||
| 		if specificVersion != "" { | ||||
| 			version = specificVersion | ||||
| 			log.Debugf("choosing %s as version to deploy", version) | ||||
| 			if err := r2.EnsureVersion(version); err != nil { | ||||
| 			if err := r.EnsureVersion(version); err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
| 		} | ||||
| @ -128,7 +123,7 @@ recipes. | ||||
|  | ||||
| 			if len(versions) == 0 && !internal.Chaos { | ||||
| 				log.Warn("no published versions in catalogue, trying local recipe repository") | ||||
| 				recipeVersions, err := recipe.GetRecipeVersions(app.Recipe, internal.Offline) | ||||
| 				recipeVersions, err := r.GetRecipeVersions(internal.Offline) | ||||
| 				if err != nil { | ||||
| 					log.Warn(err) | ||||
| 				} | ||||
| @ -142,7 +137,7 @@ recipes. | ||||
| 			if len(versions) > 0 && !internal.Chaos { | ||||
| 				version = versions[len(versions)-1] | ||||
| 				log.Debugf("choosing %s as version to deploy", version) | ||||
| 				if err := r2.EnsureVersion(version); err != nil { | ||||
| 				if err := r.EnsureVersion(version); err != nil { | ||||
| 					log.Fatal(err) | ||||
| 				} | ||||
| 			} else { | ||||
| @ -158,7 +153,7 @@ recipes. | ||||
| 		if internal.Chaos { | ||||
| 			log.Warnf("chaos mode engaged") | ||||
| 			var err error | ||||
| 			version, err = r2.ChaosVersion() | ||||
| 			version, err = r.ChaosVersion() | ||||
| 			if err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
| @ -173,7 +168,7 @@ recipes. | ||||
| 			app.Env[k] = v | ||||
| 		} | ||||
|  | ||||
| 		composeFiles, err := r2.GetComposeFiles(app.Env) | ||||
| 		composeFiles, err := r.GetComposeFiles(app.Env) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| @ -80,7 +80,7 @@ var appNewCommand = cli.Command{ | ||||
| 			if c.Args().Get(1) == "" { | ||||
| 				var version string | ||||
|  | ||||
| 				recipeVersions, err := recipePkg.GetRecipeVersions(recipe.Name, internal.Offline) | ||||
| 				recipeVersions, err := r.GetRecipeVersions(internal.Offline) | ||||
| 				if err != nil { | ||||
| 					log.Fatal(err) | ||||
| 				} | ||||
|  | ||||
| @ -58,13 +58,8 @@ recipes. | ||||
| 			log.Fatal("cannot use <version> and --chaos together") | ||||
| 		} | ||||
|  | ||||
| 		r2 := recipe.Get2(app.Recipe) | ||||
| 		if err := r2.Ensure(internal.Chaos, internal.Offline); err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		r, err := recipe.Get(app.Recipe, internal.Offline) | ||||
| 		if err != nil { | ||||
| 		r := recipe.Get2(app.Recipe) | ||||
| 		if err := r.Ensure(internal.Chaos, internal.Offline); err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| @ -100,7 +95,7 @@ recipes. | ||||
|  | ||||
| 		if len(versions) == 0 && !internal.Chaos { | ||||
| 			log.Warn("no published versions in catalogue, trying local recipe repository") | ||||
| 			recipeVersions, err := recipe.GetRecipeVersions(app.Recipe, internal.Offline) | ||||
| 			recipeVersions, err := r.GetRecipeVersions(internal.Offline) | ||||
| 			if err != nil { | ||||
| 				log.Warn(err) | ||||
| 			} | ||||
| @ -170,7 +165,7 @@ recipes. | ||||
| 		} | ||||
|  | ||||
| 		if !internal.Chaos { | ||||
| 			if err := r2.EnsureVersion(chosenDowngrade); err != nil { | ||||
| 			if err := r.EnsureVersion(chosenDowngrade); err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
| 		} | ||||
| @ -178,7 +173,7 @@ recipes. | ||||
| 		if internal.Chaos { | ||||
| 			log.Warn("chaos mode engaged") | ||||
| 			var err error | ||||
| 			chosenDowngrade, err = r2.ChaosVersion() | ||||
| 			chosenDowngrade, err = r.ChaosVersion() | ||||
| 			if err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
| @ -193,7 +188,7 @@ recipes. | ||||
| 			app.Env[k] = v | ||||
| 		} | ||||
|  | ||||
| 		composeFiles, err := r2.GetComposeFiles(app.Env) | ||||
| 		composeFiles, err := r.GetComposeFiles(app.Env) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| @ -69,12 +69,8 @@ recipes. | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		recipe, err := recipePkg.Get(app.Recipe, internal.Offline) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		if err := lint.LintForErrors(recipe); err != nil { | ||||
| 		r2 := recipePkg.Get2(app.Recipe) | ||||
| 		if err := lint.LintForErrors(r2); err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| @ -106,7 +102,7 @@ recipes. | ||||
|  | ||||
| 		if len(versions) == 0 && !internal.Chaos { | ||||
| 			log.Warn("no published versions in catalogue, trying local recipe repository") | ||||
| 			recipeVersions, err := recipePkg.GetRecipeVersions(app.Recipe, internal.Offline) | ||||
| 			recipeVersions, err := r2.GetRecipeVersions(internal.Offline) | ||||
| 			if err != nil { | ||||
| 				log.Warn(err) | ||||
| 			} | ||||
|  | ||||
| @ -99,7 +99,7 @@ keys configured on your account. | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			versions, err := recipe.GetRecipeVersions(recipeMeta.Name, internal.Offline) | ||||
| 			versions, err := r.GetRecipeVersions(internal.Offline) | ||||
| 			if err != nil { | ||||
| 				log.Warn(err) | ||||
| 			} | ||||
|  | ||||
| @ -85,10 +85,14 @@ func SetBumpType(bumpType string) { | ||||
| } | ||||
|  | ||||
| // GetMainAppImage retrieves the main 'app' image name | ||||
| func GetMainAppImage(recipe recipe.Recipe) (string, error) { | ||||
| func GetMainAppImage(recipe recipe.Recipe2) (string, error) { | ||||
| 	var path string | ||||
|  | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		if service.Name == "app" { | ||||
| 			img, err := reference.ParseNormalizedNamed(service.Image) | ||||
| 			if err != nil { | ||||
|  | ||||
| @ -47,7 +47,7 @@ var recipeLintCommand = cli.Command{ | ||||
| 				} | ||||
|  | ||||
| 				skipped := false | ||||
| 				if rule.Skip(recipe) { | ||||
| 				if rule.Skip(r) { | ||||
| 					skipped = true | ||||
| 				} | ||||
|  | ||||
| @ -58,7 +58,7 @@ var recipeLintCommand = cli.Command{ | ||||
|  | ||||
| 				satisfied := false | ||||
| 				if !skipped { | ||||
| 					ok, err := rule.Function(recipe) | ||||
| 					ok, err := rule.Function(r) | ||||
| 					if err != nil { | ||||
| 						log.Warn(err) | ||||
| 					} | ||||
|  | ||||
| @ -65,12 +65,12 @@ your SSH keys configured on your account. | ||||
| 		recipe := internal.ValidateRecipe(c) | ||||
| 		r := recipePkg.Get2(recipe.Name) | ||||
|  | ||||
| 		imagesTmp, err := getImageVersions(recipe) | ||||
| 		imagesTmp, err := getImageVersions(r) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		mainApp, err := internal.GetMainAppImage(recipe) | ||||
| 		mainApp, err := internal.GetMainAppImage(r) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
| @ -104,7 +104,7 @@ your SSH keys configured on your account. | ||||
|  | ||||
| 		if tagString == "" && (!internal.Major && !internal.Minor && !internal.Patch) { | ||||
| 			var err error | ||||
| 			tagString, err = getLabelVersion(recipe, false) | ||||
| 			tagString, err = getLabelVersion(r, false) | ||||
| 			if err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
| @ -143,11 +143,15 @@ your SSH keys configured on your account. | ||||
| } | ||||
|  | ||||
| // getImageVersions retrieves image versions for a recipe | ||||
| func getImageVersions(recipe recipe.Recipe) (map[string]string, error) { | ||||
| func getImageVersions(recipe recipe.Recipe2) (map[string]string, error) { | ||||
| 	services := make(map[string]string) | ||||
|  | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	missingTag := false | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| 	for _, service := range config.Services { | ||||
| 		if service.Image == "" { | ||||
| 			continue | ||||
| 		} | ||||
| @ -526,8 +530,8 @@ func cleanUpTag(tag, recipeName string) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getLabelVersion(recipe recipe.Recipe, prompt bool) (string, error) { | ||||
| 	initTag, err := recipePkg.GetVersionLabelLocal(recipe) | ||||
| func getLabelVersion(recipe recipe.Recipe2, prompt bool) (string, error) { | ||||
| 	initTag, err := recipe.GetVersionLabelLocal() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| @ -47,12 +47,12 @@ local file system. | ||||
| 		recipe := internal.ValidateRecipe(c) | ||||
| 		r := recipePkg.Get2(recipe.Name) | ||||
|  | ||||
| 		mainApp, err := internal.GetMainAppImage(recipe) | ||||
| 		mainApp, err := internal.GetMainAppImage(r) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		imagesTmp, err := getImageVersions(recipe) | ||||
| 		imagesTmp, err := getImageVersions(r) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| @ -130,7 +130,12 @@ You may invoke this command in "wizard" mode and be prompted for input: | ||||
| 			log.Debugf("did not find versions file for %s", recipe.Name) | ||||
| 		} | ||||
|  | ||||
| 		for _, service := range recipe.Config.Services { | ||||
| 		config, err := r.GetComposeConfig(nil) | ||||
| 		if err != nil { | ||||
| 			log.Fatal(err) | ||||
| 		} | ||||
|  | ||||
| 		for _, service := range config.Services { | ||||
| 			img, err := reference.ParseNormalizedNamed(service.Image) | ||||
| 			if err != nil { | ||||
| 				log.Fatal(err) | ||||
|  | ||||
| @ -331,9 +331,7 @@ func processRecipeRepoVersion(r recipe.Recipe2, version string) error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if r, err := recipe.Get(r.Name, internal.Offline); err != nil { | ||||
| 		return err | ||||
| 	} else if err := lint.LintForErrors(r); err != nil { | ||||
| 	if err := lint.LintForErrors(r); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
|  | ||||
| @ -19,13 +19,13 @@ import ( | ||||
| var Warn = "warn" | ||||
| var Critical = "critical" | ||||
|  | ||||
| type LintFunction func(recipe.Recipe) (bool, error) | ||||
| type LintFunction func(recipe.Recipe2) (bool, error) | ||||
|  | ||||
| // SkipFunction determines whether the LintFunction is run or not. It should | ||||
| // not take the lint rule level into account because some rules are always an | ||||
| // error but may depend on some additional context of the recipe configuration. | ||||
| // This function aims to cover those additional cases. | ||||
| type SkipFunction func(recipe.Recipe) (bool, error) | ||||
| type SkipFunction func(recipe.Recipe2) (bool, error) | ||||
|  | ||||
| // LintRule is a linting rule which helps a recipe maintainer avoid common | ||||
| // problems in their recipe configurations. We aim to highlight things that | ||||
| @ -42,7 +42,7 @@ type LintRule struct { | ||||
| } | ||||
|  | ||||
| // Skip implements the SkipFunction for the lint rule. | ||||
| func (l LintRule) Skip(recipe recipe.Recipe) bool { | ||||
| func (l LintRule) Skip(recipe recipe.Recipe2) bool { | ||||
| 	if l.SkipCondition != nil { | ||||
| 		ok, err := l.SkipCondition(recipe) | ||||
| 		if err != nil { | ||||
| @ -173,7 +173,7 @@ var LintRules = map[string][]LintRule{ | ||||
| // LintForErrors lints specifically for errors and not other levels. This is | ||||
| // used in code paths such as "app deploy" to avoid nasty surprises but not for | ||||
| // the typical linting commands, which do handle other levels. | ||||
| func LintForErrors(recipe recipe.Recipe) error { | ||||
| func LintForErrors(recipe recipe.Recipe2) error { | ||||
| 	log.Debugf("linting for critical errors in %s configs", recipe.Name) | ||||
|  | ||||
| 	for level := range LintRules { | ||||
| @ -201,15 +201,19 @@ func LintForErrors(recipe recipe.Recipe) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func LintComposeVersion(recipe recipe.Recipe) (bool, error) { | ||||
| 	if recipe.Config.Version == "3.8" { | ||||
| func LintComposeVersion(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	if config.Version == "3.8" { | ||||
| 		return true, nil | ||||
| 	} | ||||
|  | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintEnvConfigPresent(r recipe.Recipe) (bool, error) { | ||||
| func LintEnvConfigPresent(r recipe.Recipe2) (bool, error) { | ||||
| 	r2 := recipe.Get2(r.Name) | ||||
| 	if _, err := os.Stat(r2.SampleEnvPath); !os.IsNotExist(err) { | ||||
| 		return true, nil | ||||
| @ -218,8 +222,12 @@ func LintEnvConfigPresent(r recipe.Recipe) (bool, error) { | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| func LintAppService(recipe recipe.Recipe) (bool, error) { | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| func LintAppService(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		if service.Name == "app" { | ||||
| 			return true, nil | ||||
| 		} | ||||
| @ -232,7 +240,7 @@ func LintAppService(recipe recipe.Recipe) (bool, error) { | ||||
| // confirms that there is no "DOMAIN=..." in the .env.sample configuration of | ||||
| // the recipe. This typically means that no domain is required to deploy and | ||||
| // therefore no matching traefik deploy label will be present. | ||||
| func LintTraefikEnabledSkipCondition(r recipe.Recipe) (bool, error) { | ||||
| func LintTraefikEnabledSkipCondition(r recipe.Recipe2) (bool, error) { | ||||
| 	r2 := recipe.Get2(r.Name) | ||||
| 	sampleEnv, err := r2.SampleEnv() | ||||
| 	if err != nil { | ||||
| @ -246,8 +254,12 @@ func LintTraefikEnabledSkipCondition(r recipe.Recipe) (bool, error) { | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| func LintTraefikEnabled(recipe recipe.Recipe) (bool, error) { | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| func LintTraefikEnabled(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		for label := range service.Deploy.Labels { | ||||
| 			if label == "traefik.enable" { | ||||
| 				if service.Deploy.Labels[label] == "true" { | ||||
| @ -260,8 +272,12 @@ func LintTraefikEnabled(recipe recipe.Recipe) (bool, error) { | ||||
| 	return false, nil | ||||
| } | ||||
|  | ||||
| func LintHealthchecks(recipe recipe.Recipe) (bool, error) { | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| func LintHealthchecks(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		if service.HealthCheck == nil { | ||||
| 			return false, nil | ||||
| 		} | ||||
| @ -270,8 +286,12 @@ func LintHealthchecks(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintAllImagesTagged(recipe recipe.Recipe) (bool, error) { | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| func LintAllImagesTagged(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		img, err := reference.ParseNormalizedNamed(service.Image) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| @ -284,8 +304,12 @@ func LintAllImagesTagged(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintNoUnstableTags(recipe recipe.Recipe) (bool, error) { | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| func LintNoUnstableTags(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		img, err := reference.ParseNormalizedNamed(service.Image) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| @ -307,8 +331,12 @@ func LintNoUnstableTags(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintSemverLikeTags(recipe recipe.Recipe) (bool, error) { | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| func LintSemverLikeTags(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		img, err := reference.ParseNormalizedNamed(service.Image) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| @ -330,8 +358,12 @@ func LintSemverLikeTags(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintImagePresent(recipe recipe.Recipe) (bool, error) { | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| func LintImagePresent(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		if service.Image == "" { | ||||
| 			return false, nil | ||||
| 		} | ||||
| @ -339,7 +371,7 @@ func LintImagePresent(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintHasPublishedVersion(recipe recipe.Recipe) (bool, error) { | ||||
| func LintHasPublishedVersion(recipe recipe.Recipe2) (bool, error) { | ||||
| 	catl, err := recipePkg.ReadRecipeCatalogue(false) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| @ -357,7 +389,7 @@ func LintHasPublishedVersion(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintMetadataFilledIn(r recipe.Recipe) (bool, error) { | ||||
| func LintMetadataFilledIn(r recipe.Recipe2) (bool, error) { | ||||
| 	r2 := recipe.Get2(r.Name) | ||||
| 	features, category, err := recipe.GetRecipeFeaturesAndCategory(r2) | ||||
| 	if err != nil { | ||||
| @ -379,10 +411,14 @@ func LintMetadataFilledIn(r recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintAbraShVendors(recipe recipe.Recipe) (bool, error) { | ||||
| 	for _, service := range recipe.Config.Services { | ||||
| func LintAbraShVendors(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for _, service := range config.Services { | ||||
| 		if len(service.Configs) > 0 { | ||||
| 			abraSh := path.Join(config.RECIPES_DIR, recipe.Name, "abra.sh") | ||||
| 			abraSh := path.Join(recipe.Dir, "abra.sh") | ||||
| 			if _, err := os.Stat(abraSh); err != nil { | ||||
| 				if os.IsNotExist(err) { | ||||
| 					return false, err | ||||
| @ -394,7 +430,7 @@ func LintAbraShVendors(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintHasRecipeRepo(recipe recipe.Recipe) (bool, error) { | ||||
| func LintHasRecipeRepo(recipe recipe.Recipe2) (bool, error) { | ||||
| 	url := fmt.Sprintf("%s/%s.git", config.REPOS_BASE_URL, recipe.Name) | ||||
|  | ||||
| 	res, err := http.Get(url) | ||||
| @ -409,8 +445,12 @@ func LintHasRecipeRepo(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintSecretLengths(recipe recipe.Recipe) (bool, error) { | ||||
| 	for name := range recipe.Config.Secrets { | ||||
| func LintSecretLengths(recipe recipe.Recipe2) (bool, error) { | ||||
| 	config, err := recipe.GetComposeConfig(nil) | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	for name := range config.Secrets { | ||||
| 		if len(name) > 12 { | ||||
| 			return false, fmt.Errorf("secret %s is longer than 12 characters", name) | ||||
| 		} | ||||
| @ -419,7 +459,7 @@ func LintSecretLengths(recipe recipe.Recipe) (bool, error) { | ||||
| 	return true, nil | ||||
| } | ||||
|  | ||||
| func LintValidTags(recipe recipe.Recipe) (bool, error) { | ||||
| func LintValidTags(recipe recipe.Recipe2) (bool, error) { | ||||
| 	recipeDir := path.Join(config.RECIPES_DIR, recipe.Name) | ||||
|  | ||||
| 	repo, err := git.PlainOpen(recipeDir) | ||||
|  | ||||
| @ -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