Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

schema: Implement 1.5 check block #229

Merged
merged 1 commit into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
98 changes: 98 additions & 0 deletions internal/schema/1.5/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package schema

import (
"github.com/hashicorp/hcl-lang/lang"
"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/terraform-schema/internal/schema/refscope"
"github.com/hashicorp/terraform-schema/internal/schema/tokmod"
"github.com/zclconf/go-cty/cty"
)

func checkBlock() *schema.BlockSchema {
return &schema.BlockSchema{
Labels: []*schema.LabelSchema{
{
Name: "name",
Description: lang.PlainText("Local Name"),
SemanticTokenModifiers: lang.SemanticTokenModifiers{tokmod.Name},
},
},
Description: lang.Markdown("Check customized infrastructure requirements to provide ongoing and continuous verification."),
Body: &schema.BodySchema{
HoverURL: "https://developer.hashicorp.com/terraform/language/checks",
Blocks: map[string]*schema.BlockSchema{
"data": scopedDataBlock(),
"assert": {
MinItems: 1,
Description: lang.Markdown(`Assertion, which does not affect Terraform's execution of an operation. ` +
`A failed assertion reports a warning without halting the ongoing operation.`),
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"condition": {
Constraint: schema.AnyExpression{OfType: cty.Bool},
IsRequired: true,
Description: lang.Markdown("Condition to meet for the check to pass (any expression which evaluates to boolean)"),
},
"error_message": {
Constraint: schema.AnyExpression{OfType: cty.String},
IsRequired: true,
Description: lang.Markdown("Text that Terraform will include as part of error messages when it detects an unmet condition"),
},
},
},
},
},
},
}
}

func scopedDataBlock() *schema.BlockSchema {
bs := &schema.BlockSchema{
// TODO: Address: &schema.BlockAddrSchema{},
// See https://github.com/hashicorp/terraform-schema/issues/234
Labels: []*schema.LabelSchema{
{
Name: "type",
Description: lang.PlainText("Data Source Type"),
SemanticTokenModifiers: lang.SemanticTokenModifiers{tokmod.Type, lang.TokenModifierDependent},
IsDepKey: true,
Completable: true,
},
{
Name: "name",
Description: lang.PlainText("Reference Name"),
SemanticTokenModifiers: lang.SemanticTokenModifiers{tokmod.Name},
},
},
Description: lang.PlainText("A data block requests that Terraform read from a given data source and export the result " +
"under the given locally scoped name (i.e. only within the `check` block)."),
MaxItems: 1,
Body: &schema.BodySchema{
Attributes: map[string]*schema.AttributeSchema{
"provider": {
Constraint: schema.Reference{OfScopeId: refscope.ProviderScope},
IsOptional: true,
Description: lang.Markdown("Reference to a `provider` configuration block, e.g. `mycloud.west` or `mycloud`"),
IsDepKey: true,
SemanticTokenModifiers: lang.SemanticTokenModifiers{lang.TokenModifierDependent},
},
"depends_on": {
Constraint: schema.Set{
Elem: schema.OneOf{
schema.Reference{OfScopeId: refscope.DataScope},
schema.Reference{OfScopeId: refscope.ModuleScope},
schema.Reference{OfScopeId: refscope.ResourceScope},
},
},
IsOptional: true,
Description: lang.Markdown("Set of references to hidden dependencies, e.g. resources or data sources"),
},
},
},
}

return bs
}
1 change: 1 addition & 0 deletions internal/schema/1.5/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
func ModuleSchema(v *version.Version) *schema.BodySchema {
bs := v1_4_mod.ModuleSchema(v)
bs.Blocks["import"] = importBlock()
bs.Blocks["check"] = checkBlock()

return bs
}
13 changes: 13 additions & 0 deletions schema/schema_merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ func (m *SchemaMerger) SchemaForModule(meta *tfmod.Meta) (*schema.BodySchema, er
if mergedSchema.Blocks["module"].DependentBody == nil {
mergedSchema.Blocks["module"].DependentBody = make(map[schema.SchemaKey]*schema.BodySchema)
}
if checkBlock, ok := mergedSchema.Blocks["check"]; ok && checkBlock.Body.Blocks["data"].DependentBody == nil {
mergedSchema.Blocks["check"].Body.Blocks["data"].DependentBody = make(map[schema.SchemaKey]*schema.BodySchema)
}

providerRefs := ProviderReferences(meta.ProviderReferences)

Expand Down Expand Up @@ -157,13 +160,20 @@ func (m *SchemaMerger) SchemaForModule(meta *tfmod.Meta) (*schema.BodySchema, er
depBodies := m.dependentBodyForRemoteStateDataSource(providerAddr, localRef)
for key, depBody := range depBodies {
mergedSchema.Blocks["data"].DependentBody[key] = depBody
if _, ok := mergedSchema.Blocks["check"]; ok {
mergedSchema.Blocks["check"].Body.Blocks["data"].DependentBody[key] = depBody
}
}

dsSchema = remoteStateDs
}

mergedSchema.Blocks["data"].DependentBody[schema.NewSchemaKey(depKeys)] = dsSchema

if _, ok := mergedSchema.Blocks["check"]; ok {
mergedSchema.Blocks["check"].Body.Blocks["data"].DependentBody[schema.NewSchemaKey(depKeys)] = dsSchema
}

// No explicit association is required
// if the resource prefix matches provider name
if typeBelongsToProvider(dsName, localRef) {
Expand All @@ -173,6 +183,9 @@ func (m *SchemaMerger) SchemaForModule(meta *tfmod.Meta) (*schema.BodySchema, er
},
}
mergedSchema.Blocks["data"].DependentBody[schema.NewSchemaKey(depKeys)] = dsSchema
if _, ok := mergedSchema.Blocks["check"]; ok {
mergedSchema.Blocks["check"].Body.Blocks["data"].DependentBody[schema.NewSchemaKey(depKeys)] = dsSchema
}
}
}
}
Expand Down