dockerfile: add hint suggestions to UndeclaredArgInFrom

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi committed 2024-05-13 23:40:01 -07:00
1 parent 05782a788c
commit 555ea7d152
4 files changed
+34 -25

No files matched your search

@@ -261,7 +261,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
// set base state for every image
for i, st := range stages {
nameMatch, err := shlex.ProcessWordWithMatches(st.BaseName, metaArgsToMap(optMetaArgs))
reportUnusedFromArgs(nameMatch.Unmatched, st.Location, opt.Warn)
reportUnusedFromArgs(metaArgsKeys(optMetaArgs), nameMatch.Unmatched, st.Location, opt.Warn)
used := nameMatch.Matched
if err != nil {
@@ -285,7 +285,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
if v := st.Platform; v != "" {
platMatch, err := shlex.ProcessWordWithMatches(v, metaArgsToMap(optMetaArgs))
reportUnusedFromArgs(platMatch.Unmatched, st.Location, opt.Warn)
reportUnusedFromArgs(metaArgsKeys(optMetaArgs), platMatch.Unmatched, st.Location, opt.Warn)
if err != nil {
return nil, parser.WithLocation(errors.Wrapf(err, "failed to process arguments for platform %s", platMatch.Result), st.Location)
@@ -2169,9 +2169,10 @@ func toPBLocation(sourceIndex int, location []parser.Range) pb.Location {
}
}
func reportUnusedFromArgs(unmatched map[string]struct{}, location []parser.Range, warn linter.LintWarnFunc) {
func reportUnusedFromArgs(values []string, unmatched map[string]struct{}, location []parser.Range, warn linter.LintWarnFunc) {
for arg := range unmatched {
msg := linter.RuleUndeclaredArgInFrom.Format(arg)
suggest, _ := suggest.Search(arg, values, true)
msg := linter.RuleUndeclaredArgInFrom.Format(arg, suggest)
linter.RuleUndeclaredArgInFrom.Run(warn, location, msg)
}
}
@@ -2199,7 +2200,7 @@ func validateUsedOnce(c instructions.Command, loc *instructionTracker, warn lint
func wrapSuggestAny(err error, keys map[string]struct{}, options []string) error {
for k := range keys {
var ok bool
err, ok = suggest.WrapErrorMaybe(err, k, options, true)
ok, err = suggest.WrapErrorMaybe(err, k, options, true)
if ok {
break
}
+2 -2
View File
@@ -462,7 +462,7 @@ COPY Dockerfile .
{
RuleName: "UndeclaredArgInFrom",
Description: "FROM command must use declared ARGs",
Detail: "FROM argument 'BULIDPLATFORM' is not declared",
Detail: "FROM argument 'BULIDPLATFORM' is not declared (did you mean BUILDPLATFORM?)",
Level: 1,
Line: 2,
},
@@ -484,7 +484,7 @@ COPY Dockerfile .
{
RuleName: "UndeclaredArgInFrom",
Description: "FROM command must use declared ARGs",
Detail: "FROM argument 'MYARCH' is not declared",
Detail: "FROM argument 'MYARCH' is not declared (did you mean MY_ARCH?)",
Level: 1,
Line: 4,
},
+7 -3
View File
@@ -70,11 +70,15 @@ var (
return "Maintainer instruction is deprecated in favor of using label"
},
}
RuleUndeclaredArgInFrom = LinterRule[func(string) string]{
RuleUndeclaredArgInFrom = LinterRule[func(string, string) string]{
Name: "UndeclaredArgInFrom",
Description: "FROM command must use declared ARGs",
Format: func(baseArg string) string {
return fmt.Sprintf("FROM argument '%s' is not declared", baseArg)
Format: func(baseArg, suggest string) string {
out := fmt.Sprintf("FROM argument '%s' is not declared", baseArg)
if suggest != "" {
out += fmt.Sprintf(" (did you mean %s?)", suggest)
}
return out
},
}
RuleWorkdirRelativePath = LinterRule[func(workdir string) string]{
+19 -15
View File
@@ -6,16 +6,7 @@ import (
"github.com/agext/levenshtein"
)
// WrapError wraps error with a suggestion for fixing it
func WrapError(err error, val string, options []string, caseSensitive bool) error {
err, _ = WrapErrorMaybe(err, val, options, caseSensitive)
return err
}
func WrapErrorMaybe(err error, val string, options []string, caseSensitive bool) (error, bool) {
if err == nil {
return nil, false
}
func Search(val string, options []string, caseSensitive bool) (string, bool) {
orig := val
if !caseSensitive {
val = strings.ToLower(val)
@@ -28,7 +19,7 @@ func WrapErrorMaybe(err error, val string, options []string, caseSensitive bool)
}
if val == opt {
// exact match means error was unrelated to the value
return err, false
return "", false
}
dist := levenshtein.Distance(val, opt, nil)
if dist < mindist {
@@ -40,15 +31,28 @@ func WrapErrorMaybe(err error, val string, options []string, caseSensitive bool)
mindist = dist
}
}
return match, match != ""
}
if match == "" {
return err, false
// WrapError wraps error with a suggestion for fixing it
func WrapError(err error, val string, options []string, caseSensitive bool) error {
_, err = WrapErrorMaybe(err, val, options, caseSensitive)
return err
}
func WrapErrorMaybe(err error, val string, options []string, caseSensitive bool) (bool, error) {
if err == nil {
return false, nil
}
match, ok := Search(val, options, caseSensitive)
if match == "" || !ok {
return false, err
}
return &suggestError{
return true, &suggestError{
err: err,
match: match,
}, true
}
}
type suggestError struct {