-
Notifications
You must be signed in to change notification settings - Fork 96
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create diag package and switch all applicable []tfprotov6.Diagnostic …
…usage (#110) Create a diag package with a native abstraction for diagnostics, represented as an interface so they can be discriminated between programmatically rather than acting only as practitioner-facing values. Switch all existing diagnostic usage to the new interface. Create new diagnostics helpers implementing the new interface.
- Loading branch information
Showing
75 changed files
with
3,820 additions
and
2,592 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
```release-note:breaking-change | ||
Most uses of `[]*tfprotov6.Diagnostic` have been replaced with a new `diag.Diagnostics` type. Please update your type signatures, and use one of the `diags.New*` helper functions instead of constructing `*tfprotov6.Diagnostic`s by hand. | ||
``` | ||
|
||
```release-note:feature | ||
Introduced first-class diagnostics (`diag` package). | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package diag | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-go/tftypes" | ||
) | ||
|
||
var _ DiagnosticWithPath = AttributeErrorDiagnostic{} | ||
|
||
// AttributeErrorDiagnostic is a generic attribute diagnostic with error severity. | ||
type AttributeErrorDiagnostic struct { | ||
ErrorDiagnostic | ||
|
||
path *tftypes.AttributePath | ||
} | ||
|
||
// Equal returns true if the other diagnostic is wholly equivalent. | ||
func (d AttributeErrorDiagnostic) Equal(other Diagnostic) bool { | ||
aed, ok := other.(AttributeErrorDiagnostic) | ||
|
||
if !ok { | ||
return false | ||
} | ||
|
||
if !aed.Path().Equal(d.Path()) { | ||
return false | ||
} | ||
|
||
return aed.ErrorDiagnostic.Equal(d.ErrorDiagnostic) | ||
} | ||
|
||
// Path returns the diagnostic path. | ||
func (d AttributeErrorDiagnostic) Path() *tftypes.AttributePath { | ||
return d.path | ||
} | ||
|
||
// NewAttributeErrorDiagnostic returns a new error severity diagnostic with the given summary, detail, and path. | ||
func NewAttributeErrorDiagnostic(path *tftypes.AttributePath, summary string, detail string) AttributeErrorDiagnostic { | ||
return AttributeErrorDiagnostic{ | ||
ErrorDiagnostic: ErrorDiagnostic{ | ||
detail: detail, | ||
summary: summary, | ||
}, | ||
path: path, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package diag | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-go/tftypes" | ||
) | ||
|
||
var _ DiagnosticWithPath = AttributeWarningDiagnostic{} | ||
|
||
// AttributeErrorDiagnostic is a generic attribute diagnostic with warning severity. | ||
type AttributeWarningDiagnostic struct { | ||
WarningDiagnostic | ||
|
||
path *tftypes.AttributePath | ||
} | ||
|
||
// Equal returns true if the other diagnostic is wholly equivalent. | ||
func (d AttributeWarningDiagnostic) Equal(other Diagnostic) bool { | ||
awd, ok := other.(AttributeWarningDiagnostic) | ||
|
||
if !ok { | ||
return false | ||
} | ||
|
||
if !awd.Path().Equal(d.Path()) { | ||
return false | ||
} | ||
|
||
return awd.WarningDiagnostic.Equal(d.WarningDiagnostic) | ||
} | ||
|
||
// Path returns the diagnostic path. | ||
func (d AttributeWarningDiagnostic) Path() *tftypes.AttributePath { | ||
return d.path | ||
} | ||
|
||
// NewAttributeWarningDiagnostic returns a new warning severity diagnostic with the given summary, detail, and path. | ||
func NewAttributeWarningDiagnostic(path *tftypes.AttributePath, summary string, detail string) AttributeWarningDiagnostic { | ||
return AttributeWarningDiagnostic{ | ||
WarningDiagnostic: WarningDiagnostic{ | ||
detail: detail, | ||
summary: summary, | ||
}, | ||
path: path, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package diag | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-go/tftypes" | ||
) | ||
|
||
// Diagnostic is an interface for providing enhanced feedback. | ||
// | ||
// These are typically practitioner facing, however it is possible for | ||
// functionality, such as validation, to use these to change behaviors or | ||
// otherwise have these be manipulated or removed before being presented. | ||
// | ||
// See the ErrorDiagnostic and WarningDiagnostic concrete types for generic | ||
// implementations. | ||
type Diagnostic interface { | ||
// Severity returns the desired level of feedback for the diagnostic. | ||
Severity() Severity | ||
|
||
// Summary is a short description for the diagnostic. | ||
// | ||
// Typically this is implemented as a title, such as "Invalid Resource Name", | ||
// or single line sentence. | ||
Summary() string | ||
|
||
// Detail is a long description for the diagnostic. | ||
// | ||
// This should contain all relevant information about why the diagnostic | ||
// was generated and if applicable, ways to prevent the diagnostic. It | ||
// should generally be written and formatted for human consumption by | ||
// practitioners or provider developers. | ||
Detail() string | ||
|
||
// Equal returns true if the other diagnostic is wholly equivalent. | ||
Equal(Diagnostic) bool | ||
} | ||
|
||
// DiagnosticWithPath is a diagnostic associated with an attribute path. | ||
// | ||
// This attribute information is used to display contextual source configuration | ||
// to practitioners. | ||
type DiagnosticWithPath interface { | ||
Diagnostic | ||
|
||
// Path points to a specific value within an aggregate value. | ||
// | ||
// If present, this enables the display of source configuration context for | ||
// supporting implementations such as Terraform CLI commands. | ||
Path() *tftypes.AttributePath | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package diag_test | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-framework/diag" | ||
) | ||
|
||
var _ diag.Diagnostic = invalidSeverityDiagnostic{} | ||
|
||
type invalidSeverityDiagnostic struct{} | ||
|
||
func (d invalidSeverityDiagnostic) Detail() string { | ||
return "detail for invalid severity diagnostic" | ||
} | ||
|
||
func (d invalidSeverityDiagnostic) Equal(other diag.Diagnostic) bool { | ||
isd, ok := other.(invalidSeverityDiagnostic) | ||
|
||
if !ok { | ||
return false | ||
} | ||
|
||
return isd.Summary() == d.Summary() && isd.Detail() == d.Detail() && isd.Severity() == d.Severity() | ||
} | ||
|
||
func (d invalidSeverityDiagnostic) Severity() diag.Severity { | ||
return diag.SeverityInvalid | ||
} | ||
|
||
func (d invalidSeverityDiagnostic) Summary() string { | ||
return "summary for invalid severity diagnostic" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package diag | ||
|
||
import ( | ||
"github.com/hashicorp/terraform-plugin-go/tfprotov6" | ||
"github.com/hashicorp/terraform-plugin-go/tftypes" | ||
) | ||
|
||
// Diagnostics represents a collection of diagnostics. | ||
// | ||
// While this collection is ordered, the order is not guaranteed as reliable | ||
// or consistent. | ||
type Diagnostics []Diagnostic | ||
|
||
// AddAttributeError adds a generic attribute error diagnostic to the collection. | ||
func (diags *Diagnostics) AddAttributeError(path *tftypes.AttributePath, summary string, detail string) { | ||
diags.Append(NewAttributeErrorDiagnostic(path, summary, detail)) | ||
} | ||
|
||
// AddAttributeWarning adds a generic attribute warning diagnostic to the collection. | ||
func (diags *Diagnostics) AddAttributeWarning(path *tftypes.AttributePath, summary string, detail string) { | ||
diags.Append(NewAttributeWarningDiagnostic(path, summary, detail)) | ||
} | ||
|
||
// AddError adds a generic error diagnostic to the collection. | ||
func (diags *Diagnostics) AddError(summary string, detail string) { | ||
diags.Append(NewErrorDiagnostic(summary, detail)) | ||
} | ||
|
||
// AddWarning adds a generic warning diagnostic to the collection. | ||
func (diags *Diagnostics) AddWarning(summary string, detail string) { | ||
diags.Append(NewWarningDiagnostic(summary, detail)) | ||
} | ||
|
||
// Append adds non-empty and non-duplicate diagnostics to the collection. | ||
func (diags *Diagnostics) Append(in ...Diagnostic) { | ||
for _, diag := range in { | ||
if diag == nil { | ||
continue | ||
} | ||
|
||
if diags.Contains(diag) { | ||
continue | ||
} | ||
|
||
if diags == nil { | ||
*diags = Diagnostics{diag} | ||
} else { | ||
*diags = append(*diags, diag) | ||
} | ||
} | ||
} | ||
|
||
// Contains returns true if the collection contains an equal Diagnostic. | ||
func (diags Diagnostics) Contains(in Diagnostic) bool { | ||
for _, diag := range diags { | ||
if diag.Equal(in) { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
// HasError returns true if the collection has an error severity Diagnostic. | ||
func (diags Diagnostics) HasError() bool { | ||
for _, diag := range diags { | ||
if diag.Severity() == SeverityError { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
// ToTfprotov6Diagnostics converts the diagnostics into the tfprotov6 collection type. | ||
// | ||
// Usage of this method outside the framework is not supported nor considered | ||
// for backwards compatibility promises. | ||
func (diags Diagnostics) ToTfprotov6Diagnostics() []*tfprotov6.Diagnostic { | ||
var results []*tfprotov6.Diagnostic | ||
|
||
for _, diag := range diags { | ||
tfprotov6Diagnostic := &tfprotov6.Diagnostic{ | ||
Detail: diag.Detail(), | ||
Severity: diag.Severity().ToTfprotov6DiagnosticSeverity(), | ||
Summary: diag.Summary(), | ||
} | ||
|
||
if diagWithPath, ok := diag.(DiagnosticWithPath); ok { | ||
tfprotov6Diagnostic.Attribute = diagWithPath.Path() | ||
} | ||
|
||
results = append(results, tfprotov6Diagnostic) | ||
} | ||
|
||
return results | ||
} |
Oops, something went wrong.