mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
helper/schema: allow Schema attrs to be Deprecated
Deprecated fields show a customizable warning message to the user when they are used in a Terraform config. This is a tool that provider authors can use for user feedback as they evolve their Schemas. fixes #957
This commit is contained in:
parent
9270af6dfa
commit
888f16d2d3
@ -113,6 +113,13 @@ type Schema struct {
|
|||||||
//
|
//
|
||||||
// NOTE: This currently does not work.
|
// NOTE: This currently does not work.
|
||||||
ComputedWhen []string
|
ComputedWhen []string
|
||||||
|
|
||||||
|
// When Deprecated is set, this field is deprecated.
|
||||||
|
//
|
||||||
|
// A deprecated field still works, but will probably stop working in near
|
||||||
|
// future. This string is the message shown to the user with instructions on
|
||||||
|
// how to address the deprecation.
|
||||||
|
Deprecated string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SchemaDefaultFunc is a function called to return a default value for
|
// SchemaDefaultFunc is a function called to return a default value for
|
||||||
@ -877,7 +884,7 @@ func (m schemaMap) validate(
|
|||||||
raw, err = schema.DefaultFunc()
|
raw, err = schema.DefaultFunc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, []error{fmt.Errorf(
|
return nil, []error{fmt.Errorf(
|
||||||
"%s, error loading default: %s", k, err)}
|
"%q, error loading default: %s", k, err)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're okay as long as we had a value set
|
// We're okay as long as we had a value set
|
||||||
@ -886,7 +893,7 @@ func (m schemaMap) validate(
|
|||||||
if !ok {
|
if !ok {
|
||||||
if schema.Required {
|
if schema.Required {
|
||||||
return nil, []error{fmt.Errorf(
|
return nil, []error{fmt.Errorf(
|
||||||
"%s: required field is not set", k)}
|
"%q: required field is not set", k)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -895,7 +902,7 @@ func (m schemaMap) validate(
|
|||||||
if !schema.Required && !schema.Optional {
|
if !schema.Required && !schema.Optional {
|
||||||
// This is a computed-only field
|
// This is a computed-only field
|
||||||
return nil, []error{fmt.Errorf(
|
return nil, []error{fmt.Errorf(
|
||||||
"%s: this field cannot be set", k)}
|
"%q: this field cannot be set", k)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.validateType(k, raw, schema, c)
|
return m.validateType(k, raw, schema, c)
|
||||||
@ -1066,16 +1073,25 @@ func (m schemaMap) validateType(
|
|||||||
raw interface{},
|
raw interface{},
|
||||||
schema *Schema,
|
schema *Schema,
|
||||||
c *terraform.ResourceConfig) ([]string, []error) {
|
c *terraform.ResourceConfig) ([]string, []error) {
|
||||||
|
var ws []string
|
||||||
|
var es []error
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeSet:
|
case TypeSet:
|
||||||
fallthrough
|
fallthrough
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return m.validateList(k, raw, schema, c)
|
ws, es = m.validateList(k, raw, schema, c)
|
||||||
case TypeMap:
|
case TypeMap:
|
||||||
return m.validateMap(k, raw, schema, c)
|
ws, es = m.validateMap(k, raw, schema, c)
|
||||||
default:
|
default:
|
||||||
return m.validatePrimitive(k, raw, schema, c)
|
ws, es = m.validatePrimitive(k, raw, schema, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if schema.Deprecated != "" {
|
||||||
|
ws = append(ws, fmt.Sprintf(
|
||||||
|
"%q: [DEPRECATED] %s", k, schema.Deprecated))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ws, es
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero returns the zero value for a type.
|
// Zero returns the zero value for a type.
|
||||||
|
@ -2587,8 +2587,8 @@ func TestSchemaMap_Validate(t *testing.T) {
|
|||||||
Schema map[string]*Schema
|
Schema map[string]*Schema
|
||||||
Config map[string]interface{}
|
Config map[string]interface{}
|
||||||
Vars map[string]string
|
Vars map[string]string
|
||||||
Warn bool
|
|
||||||
Err bool
|
Err bool
|
||||||
|
Warnings []string
|
||||||
}{
|
}{
|
||||||
"Good": {
|
"Good": {
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
@ -3019,6 +3019,83 @@ func TestSchemaMap_Validate(t *testing.T) {
|
|||||||
|
|
||||||
Err: true,
|
Err: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"Deprecated attribute usage generates warning, but not error": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"old_news": &Schema{
|
||||||
|
Type: TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Deprecated: "please use 'new_news' instead",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"old_news": "extra extra!",
|
||||||
|
},
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
|
||||||
|
Warnings: []string{
|
||||||
|
"\"old_news\": [DEPRECATED] please use 'new_news' instead",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"Deprecated generates no warnings if attr not used": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"old_news": &Schema{
|
||||||
|
Type: TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Deprecated: "please use 'new_news' instead",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
|
||||||
|
Warnings: nil,
|
||||||
|
},
|
||||||
|
|
||||||
|
"Deprecated works with set/list type": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"old_news": &Schema{
|
||||||
|
Type: TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &Schema{Type: TypeString},
|
||||||
|
Deprecated: "please use 'new_news' instead",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"old_news": []interface{}{"extra extra!"},
|
||||||
|
},
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
|
||||||
|
Warnings: []string{
|
||||||
|
"\"old_news\": [DEPRECATED] please use 'new_news' instead",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"Deprecated works with map type": {
|
||||||
|
Schema: map[string]*Schema{
|
||||||
|
"old_news": &Schema{
|
||||||
|
Type: TypeMap,
|
||||||
|
Optional: true,
|
||||||
|
Deprecated: "please use 'new_news' instead",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Config: map[string]interface{}{
|
||||||
|
"old_news": map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Err: false,
|
||||||
|
|
||||||
|
Warnings: []string{
|
||||||
|
"\"old_news\": [DEPRECATED] please use 'new_news' instead",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for tn, tc := range cases {
|
for tn, tc := range cases {
|
||||||
@ -3050,8 +3127,8 @@ func TestSchemaMap_Validate(t *testing.T) {
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len(ws) > 0) != tc.Warn {
|
if !reflect.DeepEqual(ws, tc.Warnings) {
|
||||||
t.Fatalf("%q: ws: %#v", tn, ws)
|
t.Fatalf("%q: warnings:\n\nexpected: %#v\ngot:%#v", tn, tc.Warnings, ws)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user