Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .changelog/390.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
```release-note:feature
path: Introduced framework abstraction for attribute path handling
```

```release-note:breaking-change
attr: The `TypeWithValidate` interface has been moved under the `attr/xattr` package and the `*tftypes.AttributePath` parameter is replaced with `path.Path`
```

```release-note:breaking-change
diag: The `NewAttributeErrorDiagnostic` and `NewAttributeWarningDiagnostic` function `*tftypes.AttributePath` parameters are replaced with `path.Path`
```

```release-note:breaking-change
diag: The `DiagnosticWithPath` interface `Path` method `*tftypes.AttributePath` return is replaced with `path.Path`
```

```release-note:breaking-change
diag: The `Diagnostics` type `AddAttributeError` and `AddAttributeWarning` method `*tftypes.AttributePath` parameters are replaced with `path.Path`
```

```release-note:breaking-change
tfsdk: The `Config`, `Plan`, and `State` types `GetAttribute` and `SetAttribute` methods `*tftypes.AttributePath` parameters are replaced with `path.Path`
```

```release-note:breaking-change
tfsdk: The `ModifyAttributePlanRequest`, `ModifyResourcePlanResponse`, and `ValidateAttributeRequest` type `AttributePath *tftypes.AttributePath` fields are replaced with `AttributePath path.Path`
```

```release-note:breaking-change
tfsdk: The `RequiresReplaceIf` and `ResourceImportStatePassthroughID` function `*tftypes.AttributePath` parameters are replaced with `path.Path`
```
4 changes: 4 additions & 0 deletions attr/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package attr contains type and value interfaces for core framework and
// provider-defined data types. The underlying xattr package contains
// additional interfaces for advanced type functionality.
package attr
16 changes: 3 additions & 13 deletions attr/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package attr
import (
"context"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

// Type defines an interface for describing a kind of attribute. Types are
// collections of constraints and behaviors such that they can be reused on
// multiple attributes easily.
//
// Refer also to the xattr package, which contains additional extensions for
// Type, such as validation.
type Type interface {
// TerraformType returns the tftypes.Type that should be used to
// represent this type. This constrains what user input will be
Expand Down Expand Up @@ -74,18 +76,6 @@ type TypeWithElementTypes interface {
ElementTypes() []Type
}

// TypeWithValidate extends the Type interface to include a Validate method,
// used to bundle consistent validation logic with the Type.
type TypeWithValidate interface {
Type

// Validate returns any warnings or errors about the value that is
// being used to populate the Type. It is generally used to check the
// data format and ensure that it complies with the requirements of the
// Type.
Validate(context.Context, tftypes.Value, *tftypes.AttributePath) diag.Diagnostics
}

// TypeWithPlaintextDescription extends the Type interface to include a
// Description method, used to bundle extra information to include in attribute
// descriptions with the Type. It expects the description to be written as
Expand Down
3 changes: 3 additions & 0 deletions attr/xattr/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package xattr contains additional interfaces for attr types. This package
// is separate from the core attr package to prevent import cycles.
package xattr
22 changes: 22 additions & 0 deletions attr/xattr/type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package xattr

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

// TypeWithValidate extends the attr.Type interface to include a Validate
// method, used to bundle consistent validation logic with the Type.
type TypeWithValidate interface {
attr.Type

// Validate returns any warnings or errors about the value that is
// being used to populate the Type. It is generally used to check the
// data format and ensure that it complies with the requirements of the
// Type.
Validate(context.Context, tftypes.Value, path.Path) diag.Diagnostics
}
4 changes: 2 additions & 2 deletions diag/attribute_error_diagnostic.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package diag

import (
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-framework/path"
)

// NewAttributeErrorDiagnostic returns a new error severity diagnostic with the given summary, detail, and path.
func NewAttributeErrorDiagnostic(path *tftypes.AttributePath, summary string, detail string) DiagnosticWithPath {
func NewAttributeErrorDiagnostic(path path.Path, summary string, detail string) DiagnosticWithPath {
return withPath{
Diagnostic: NewErrorDiagnostic(summary, detail),
path: path,
Expand Down
4 changes: 2 additions & 2 deletions diag/attribute_warning_diagnostic.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package diag

import (
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-framework/path"
)

// NewAttributeWarningDiagnostic returns a new warning severity diagnostic with the given summary, detail, and path.
func NewAttributeWarningDiagnostic(path *tftypes.AttributePath, summary string, detail string) DiagnosticWithPath {
func NewAttributeWarningDiagnostic(path path.Path, summary string, detail string) DiagnosticWithPath {
return withPath{
Diagnostic: NewWarningDiagnostic(summary, detail),
path: path,
Expand Down
6 changes: 2 additions & 4 deletions diag/diagnostic.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package diag

import (
"github.com/hashicorp/terraform-plugin-go/tftypes"
)
import "github.com/hashicorp/terraform-plugin-framework/path"

// Diagnostic is an interface for providing enhanced feedback.
//
Expand Down Expand Up @@ -48,5 +46,5 @@ type DiagnosticWithPath interface {
//
// If present, this enables the display of source configuration context for
// supporting implementations such as Terraform CLI commands.
Path() *tftypes.AttributePath
Path() path.Path
}
6 changes: 3 additions & 3 deletions diag/diagnostics.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package diag

import (
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-framework/path"
)

// Diagnostics represents a collection of diagnostics.
Expand All @@ -11,12 +11,12 @@ import (
type Diagnostics []Diagnostic

// AddAttributeError adds a generic attribute error diagnostic to the collection.
func (diags *Diagnostics) AddAttributeError(path *tftypes.AttributePath, summary string, detail string) {
func (diags *Diagnostics) AddAttributeError(path path.Path, 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) {
func (diags *Diagnostics) AddAttributeWarning(path path.Path, summary string, detail string) {
diags.Append(NewAttributeWarningDiagnostic(path, summary, detail))
}

Expand Down
96 changes: 48 additions & 48 deletions diag/diagnostics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,53 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-framework/path"
)

func TestDiagnosticsAddAttributeError(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
diags diag.Diagnostics
path *tftypes.AttributePath
path path.Path
summary string
detail string
expected diag.Diagnostics
}{
"nil-add": {
diags: nil,
path: tftypes.NewAttributePath().WithAttributeName("test"),
path: path.RootPath("test"),
summary: "one summary",
detail: "one detail",
expected: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
},
},
"add": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "two summary", "two detail"),
},
path: tftypes.NewAttributePath().WithAttributeName("test"),
path: path.RootPath("test"),
summary: "three summary",
detail: "three detail",
expected: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "three summary", "three detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "three summary", "three detail"),
},
},
"duplicate": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "two summary", "two detail"),
},
path: tftypes.NewAttributePath().WithAttributeName("test"),
path: path.RootPath("test"),
summary: "one summary",
detail: "one detail",
expected: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "two summary", "two detail"),
},
},
}
Expand All @@ -75,45 +75,45 @@ func TestDiagnosticsAddAttributeWarning(t *testing.T) {

testCases := map[string]struct {
diags diag.Diagnostics
path *tftypes.AttributePath
path path.Path
summary string
detail string
expected diag.Diagnostics
}{
"nil-add": {
diags: nil,
path: tftypes.NewAttributePath().WithAttributeName("test"),
path: path.RootPath("test"),
summary: "one summary",
detail: "one detail",
expected: diag.Diagnostics{
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "one summary", "one detail"),
},
},
"add": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "two summary", "two detail"),
},
path: tftypes.NewAttributePath().WithAttributeName("test"),
path: path.RootPath("test"),
summary: "three summary",
detail: "three detail",
expected: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "two summary", "two detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "three summary", "three detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "two summary", "two detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "three summary", "three detail"),
},
},
"duplicate": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "two summary", "two detail"),
},
path: tftypes.NewAttributePath().WithAttributeName("test"),
path: path.RootPath("test"),
summary: "two summary",
detail: "two detail",
expected: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("test"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("test"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("test"), "two summary", "two detail"),
},
},
}
Expand Down Expand Up @@ -285,16 +285,16 @@ func TestDiagnosticsAppend(t *testing.T) {
},
"append-less-specific": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
},
in: diag.Diagnostics{
diag.NewErrorDiagnostic("one summary", "one detail"),
diag.NewWarningDiagnostic("two summary", "two detail"),
},
expected: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
diag.NewErrorDiagnostic("one summary", "one detail"),
diag.NewWarningDiagnostic("two summary", "two detail"),
},
Expand All @@ -305,14 +305,14 @@ func TestDiagnosticsAppend(t *testing.T) {
diag.NewWarningDiagnostic("two summary", "two detail"),
},
in: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
},
expected: diag.Diagnostics{
diag.NewErrorDiagnostic("one summary", "one detail"),
diag.NewWarningDiagnostic("two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
},
},
"empty-diagnostics": {
Expand Down Expand Up @@ -388,10 +388,10 @@ func TestDiagnosticsContains(t *testing.T) {
},
"matching-attribute-path": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
},
in: diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
in: diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
expected: true,
},
"nil-diagnostics": {
Expand All @@ -409,10 +409,10 @@ func TestDiagnosticsContains(t *testing.T) {
},
"different-attribute-path": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
},
in: diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("different"), "two summary", "two detail"),
in: diag.NewAttributeWarningDiagnostic(path.RootPath("different"), "two summary", "two detail"),
expected: false,
},
"different-detail": {
Expand Down Expand Up @@ -441,8 +441,8 @@ func TestDiagnosticsContains(t *testing.T) {
},
"different-type-less-specific": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
},
in: diag.NewWarningDiagnostic("two summary", "two detail"),
expected: false,
Expand All @@ -452,7 +452,7 @@ func TestDiagnosticsContains(t *testing.T) {
diag.NewErrorDiagnostic("one summary", "one detail"),
diag.NewWarningDiagnostic("two summary", "two detail"),
},
in: diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
in: diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
expected: false,
},
}
Expand Down Expand Up @@ -487,8 +487,8 @@ func TestDiagnosticsHasError(t *testing.T) {
},
"matching-attribute-path": {
diags: diag.Diagnostics{
diag.NewAttributeErrorDiagnostic(tftypes.NewAttributePath().WithAttributeName("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(tftypes.NewAttributePath().WithAttributeName("warning"), "two summary", "two detail"),
diag.NewAttributeErrorDiagnostic(path.RootPath("error"), "one summary", "one detail"),
diag.NewAttributeWarningDiagnostic(path.RootPath("warning"), "two summary", "two detail"),
},
expected: true,
},
Expand Down
Loading