WIP: feat: translation support
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
See #483
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package lint
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -13,11 +14,12 @@ import (
|
||||
"github.com/distribution/reference"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
)
|
||||
|
||||
var (
|
||||
Warn = "warn"
|
||||
Critical = "critical"
|
||||
Warn = gotext.Get("warn")
|
||||
Critical = gotext.Get("critical")
|
||||
)
|
||||
|
||||
type LintFunction func(recipe.Recipe) (bool, error)
|
||||
@ -47,10 +49,10 @@ func (l LintRule) Skip(recipe recipe.Recipe) bool {
|
||||
if l.SkipCondition != nil {
|
||||
ok, err := l.SkipCondition(recipe)
|
||||
if err != nil {
|
||||
log.Debugf("%s: skip condition: %s", l.Ref, err)
|
||||
log.Debug(gotext.Get("%s: skip condition: %s", l.Ref, err))
|
||||
}
|
||||
if ok {
|
||||
log.Debugf("skipping %s based on skip condition", l.Ref)
|
||||
log.Debug(gotext.Get("skipping %s based on skip condition", l.Ref))
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -62,117 +64,117 @@ var LintRules = map[string][]LintRule{
|
||||
"warn": {
|
||||
{
|
||||
Ref: "R001",
|
||||
Level: "warn",
|
||||
Description: "compose config has expected version",
|
||||
HowToResolve: "ensure 'version: \"3.8\"' in compose configs",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("compose config has expected version"),
|
||||
HowToResolve: gotext.Get("ensure 'version: \"3.8\"' in compose configs"),
|
||||
Function: LintComposeVersion,
|
||||
},
|
||||
{
|
||||
Ref: "R002",
|
||||
Level: "warn",
|
||||
Description: "healthcheck enabled for all services",
|
||||
HowToResolve: "wire up healthchecks",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("healthcheck enabled for all services"),
|
||||
HowToResolve: gotext.Get("wire up healthchecks"),
|
||||
Function: LintHealthchecks,
|
||||
},
|
||||
{
|
||||
Ref: "R003",
|
||||
Level: "warn",
|
||||
Description: "all images use a tag",
|
||||
HowToResolve: "use a tag for all images",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("all images use a tag"),
|
||||
HowToResolve: gotext.Get("use a tag for all images"),
|
||||
Function: LintAllImagesTagged,
|
||||
},
|
||||
{
|
||||
Ref: "R004",
|
||||
Level: "warn",
|
||||
Description: "no unstable tags",
|
||||
HowToResolve: "tag all images with stable tags",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("no unstable tags"),
|
||||
HowToResolve: gotext.Get("tag all images with stable tags"),
|
||||
Function: LintNoUnstableTags,
|
||||
},
|
||||
{
|
||||
Ref: "R005",
|
||||
Level: "warn",
|
||||
Description: "tags use semver-like format",
|
||||
HowToResolve: "use semver-like tags",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("tags use semver-like format"),
|
||||
HowToResolve: gotext.Get("use semver-like tags"),
|
||||
Function: LintSemverLikeTags,
|
||||
},
|
||||
{
|
||||
Ref: "R006",
|
||||
Level: "warn",
|
||||
Description: "has published catalogue version",
|
||||
HowToResolve: "publish a recipe version to the catalogue",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("has published catalogue version"),
|
||||
HowToResolve: gotext.Get("publish a recipe version to the catalogue"),
|
||||
Function: LintHasPublishedVersion,
|
||||
},
|
||||
{
|
||||
Ref: "R007",
|
||||
Level: "warn",
|
||||
Description: "README.md metadata filled in",
|
||||
HowToResolve: "fill out all the metadata",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("README.md metadata filled in"),
|
||||
HowToResolve: gotext.Get("fill out all the metadata"),
|
||||
Function: LintMetadataFilledIn,
|
||||
},
|
||||
{
|
||||
Ref: "R013",
|
||||
Level: "warn",
|
||||
Description: "git.coopcloud.tech repo exists",
|
||||
HowToResolve: "upload your recipe to git.coopcloud.tech/coop-cloud/...",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("git.coopcloud.tech repo exists"),
|
||||
HowToResolve: gotext.Get("upload your recipe to git.coopcloud.tech/coop-cloud/..."),
|
||||
Function: LintHasRecipeRepo,
|
||||
},
|
||||
{
|
||||
Ref: "R015",
|
||||
Level: "warn",
|
||||
Description: "long secret names",
|
||||
HowToResolve: "reduce length of secret names to 12 chars",
|
||||
Level: gotext.Get("warn"),
|
||||
Description: gotext.Get("long secret names"),
|
||||
HowToResolve: gotext.Get("reduce length of secret names to 12 chars"),
|
||||
Function: LintSecretLengths,
|
||||
},
|
||||
},
|
||||
"error": {
|
||||
{
|
||||
Ref: "R008",
|
||||
Level: "error",
|
||||
Description: ".env.sample provided",
|
||||
HowToResolve: "create an example .env.sample",
|
||||
Level: gotext.Get("error"),
|
||||
Description: gotext.Get(".env.sample provided"),
|
||||
HowToResolve: gotext.Get("create an example .env.sample"),
|
||||
Function: LintEnvConfigPresent,
|
||||
},
|
||||
{
|
||||
Ref: "R009",
|
||||
Level: "error",
|
||||
Description: "one service named 'app'",
|
||||
HowToResolve: "name a servce 'app'",
|
||||
Level: gotext.Get("error"),
|
||||
Description: gotext.Get("one service named 'app'"),
|
||||
HowToResolve: gotext.Get("name a servce 'app'"),
|
||||
Function: LintAppService,
|
||||
},
|
||||
{
|
||||
Ref: "R015",
|
||||
Level: "error",
|
||||
Description: "deploy labels stanza present",
|
||||
HowToResolve: "include \"deploy: labels: ...\" stanza",
|
||||
Level: gotext.Get("error"),
|
||||
Description: gotext.Get("deploy labels stanza present"),
|
||||
HowToResolve: gotext.Get("include \"deploy: labels: ...\" stanza"),
|
||||
Function: LintDeployLabelsPresent,
|
||||
},
|
||||
{
|
||||
Ref: "R010",
|
||||
Level: "error",
|
||||
Description: "traefik routing enabled",
|
||||
HowToResolve: "include \"traefik.enable=true\" deploy label",
|
||||
Level: gotext.Get("error"),
|
||||
Description: gotext.Get("traefik routing enabled"),
|
||||
HowToResolve: gotext.Get("include \"traefik.enable=true\" deploy label"),
|
||||
Function: LintTraefikEnabled,
|
||||
SkipCondition: LintTraefikEnabledSkipCondition,
|
||||
},
|
||||
{
|
||||
Ref: "R011",
|
||||
Level: "error",
|
||||
Description: "all services have images",
|
||||
HowToResolve: "ensure \"image: ...\" set on all services",
|
||||
Level: gotext.Get("error"),
|
||||
Description: gotext.Get("all services have images"),
|
||||
HowToResolve: gotext.Get("ensure \"image: ...\" set on all services"),
|
||||
Function: LintImagePresent,
|
||||
},
|
||||
{
|
||||
Ref: "R012",
|
||||
Level: "error",
|
||||
Description: "config version are vendored",
|
||||
HowToResolve: "vendor config versions in an abra.sh",
|
||||
Level: gotext.Get("error"),
|
||||
Description: gotext.Get("config version are vendored"),
|
||||
HowToResolve: gotext.Get("vendor config versions in an abra.sh"),
|
||||
Function: LintAbraShVendors,
|
||||
},
|
||||
{
|
||||
Ref: "R014",
|
||||
Level: "error",
|
||||
Description: "only annotated tags used for recipe version",
|
||||
HowToResolve: "replace lightweight tag with annotated tag",
|
||||
Level: gotext.Get("error"),
|
||||
Description: gotext.Get("only annotated tags used for recipe version"),
|
||||
HowToResolve: gotext.Get("replace lightweight tag with annotated tag"),
|
||||
Function: LintValidTags,
|
||||
},
|
||||
},
|
||||
@ -182,9 +184,9 @@ var LintRules = map[string][]LintRule{
|
||||
// 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 {
|
||||
log.Debugf("linting for critical errors in %s configs", recipe.Name)
|
||||
log.Debug(gotext.Get("linting for critical errors in %s configs", recipe.Name))
|
||||
|
||||
var errors string
|
||||
var errs string
|
||||
|
||||
for level := range LintRules {
|
||||
if level != "error" {
|
||||
@ -198,19 +200,19 @@ func LintForErrors(recipe recipe.Recipe) error {
|
||||
|
||||
ok, err := rule.Function(recipe)
|
||||
if err != nil {
|
||||
errors += fmt.Sprintf("\nlint %s: %s", rule.Ref, err)
|
||||
errs += gotext.Get("\nlint %s: %s", rule.Ref, err)
|
||||
}
|
||||
if !ok {
|
||||
errors += fmt.Sprintf("\n * %s (%s)", rule.Description, rule.Ref)
|
||||
errs += fmt.Sprintf("\n * %s (%s)", rule.Description, rule.Ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return fmt.Errorf("recipe '%s' failed lint checks:\n"+errors[1:], recipe.Name)
|
||||
if len(errs) > 0 {
|
||||
return errors.New(gotext.Get("recipe '%s' failed lint checks:\n"+errs[1:], recipe.Name))
|
||||
}
|
||||
|
||||
log.Debugf("linting successful, %s is well configured", recipe.Name)
|
||||
log.Debug(gotext.Get("linting successful, %s is well configured", recipe.Name))
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -256,7 +258,7 @@ func LintAppService(recipe recipe.Recipe) (bool, error) {
|
||||
func LintTraefikEnabledSkipCondition(r recipe.Recipe) (bool, error) {
|
||||
sampleEnv, err := r.SampleEnv()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Unable to discover .env.sample for %s", r.Name)
|
||||
return false, errors.New(gotext.Get("unable to discover .env.sample for %s", r.Name))
|
||||
}
|
||||
|
||||
if _, ok := sampleEnv["DOMAIN"]; !ok {
|
||||
@ -476,7 +478,7 @@ func LintSecretLengths(recipe recipe.Recipe) (bool, error) {
|
||||
}
|
||||
for name := range config.Secrets {
|
||||
if len(name) > 12 {
|
||||
return false, fmt.Errorf("secret %s is longer than 12 characters", name)
|
||||
return false, errors.New(gotext.Get("secret %s is longer than 12 characters", name))
|
||||
}
|
||||
}
|
||||
|
||||
@ -486,12 +488,12 @@ func LintSecretLengths(recipe recipe.Recipe) (bool, error) {
|
||||
func LintValidTags(recipe recipe.Recipe) (bool, error) {
|
||||
repo, err := git.PlainOpen(recipe.Dir)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("unable to open %s: %s", recipe.Dir, err)
|
||||
return false, errors.New(gotext.Get("unable to open %s: %s", recipe.Dir, err))
|
||||
}
|
||||
|
||||
iter, err := repo.Tags()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to list local tags for %s", recipe.Name)
|
||||
log.Fatal(gotext.Get("unable to list local tags for %s", recipe.Name))
|
||||
}
|
||||
|
||||
if err := iter.ForEach(func(ref *plumbing.Reference) error {
|
||||
@ -499,7 +501,7 @@ func LintValidTags(recipe recipe.Recipe) (bool, error) {
|
||||
if err != nil {
|
||||
switch err {
|
||||
case plumbing.ErrObjectNotFound:
|
||||
return fmt.Errorf("invalid lightweight tag detected")
|
||||
return errors.New(gotext.Get("invalid lightweight tag detected"))
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
Reference in New Issue
Block a user