plugin/convert: Show approximate location context for all provider errors

Even if a provider doesn't indicate a specific attribute as the cause of
a resource operation error, we know the error relates to some aspect of
the resource, so we'll include that approximate information in the result
so that we don't produce user-hostile error messages with no context
whatsoever.

Later we can hopefully refine this to place the source range on the header
of the configuration block rather than on an empty part of the body, but
that'll require some more complex rework here and so for now we'll just
accept this as an interim state so that the user can at least figure out
which resource block the error is coming from.
This commit is contained in:
Martin Atkins 2018-10-16 15:01:06 -07:00
parent fd77e56fd6
commit e25f79ed28
2 changed files with 44 additions and 1 deletions

View File

@ -69,7 +69,7 @@ func ProtoToDiagnostics(ds []*proto.Diagnostic) tfdiags.Diagnostics {
path := AttributePathToPath(d.Attribute)
newDiag = tfdiags.AttributeValue(severity, d.Summary, d.Detail, path)
} else {
newDiag = tfdiags.Sourceless(severity, d.Summary, d.Detail)
newDiag = tfdiags.WholeContainingBody(severity, d.Summary, d.Detail)
}
diags = diags.Append(newDiag)

View File

@ -274,3 +274,46 @@ func (d *attributeDiagnostic) Source() Source {
Subject: d.subject,
}
}
// WholeContainingBody returns a diagnostic about the body that is an implied
// current configuration context. This should be returned only from
// functions whose interface specifies a clear configuration context that this
// will be resolved in.
//
// The returned attribute will not have source location information until
// context is applied to the containing diagnostics using diags.InConfigBody.
// After context is applied, the source location is currently the missing item
// range of the body. In future, this may change to some other suitable
// part of the containing body.
func WholeContainingBody(severity Severity, summary, detail string) Diagnostic {
return &wholeBodyDiagnostic{
diagnosticBase: diagnosticBase{
severity: severity,
summary: summary,
detail: detail,
},
}
}
type wholeBodyDiagnostic struct {
diagnosticBase
subject *SourceRange // populated only after ElaborateFromConfigBody
}
func (d *wholeBodyDiagnostic) ElaborateFromConfigBody(body hcl.Body) Diagnostic {
if d.subject != nil {
// Don't modify an already-elaborated diagnostic.
return d
}
ret := *d
rng := SourceRangeFromHCL(body.MissingItemRange())
ret.subject = &rng
return &ret
}
func (d *wholeBodyDiagnostic) Source() Source {
return Source{
Subject: d.subject,
}
}