projects/projectconfigs: Decode "context" blocks

f-workspaces2-prototype
Martin Atkins 7 years ago
parent b9b600a236
commit aeccfcd1dc

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/hcl2/ext/typeexpr"
"github.com/hashicorp/hcl2/hcl/hclsyntax"
"github.com/zclconf/go-cty/cty"
@ -34,6 +35,10 @@ type ContextValue struct {
// this is a required context value.
Default hcl.Expression
// Description is a human-oriented description of the purpose of this
// context value, written in full sentences in a natural language.
Description string
// DeclRange is the source range of the block header of this block,
// for use in diagnostic messages. NameRange is the range of the
// Name string specifically.
@ -57,5 +62,50 @@ func decodeContextBlock(block *hcl.Block) (*ContextValue, tfdiags.Diagnostics) {
})
}
content, hclDiags := block.Body.Content(contextSchema)
diags = diags.Append(hclDiags)
if attr, ok := content.Attributes["type"]; ok {
ty, hclDiags := typeexpr.TypeConstraint(attr.Expr)
diags = diags.Append(hclDiags)
cv.Type = ty
} else {
cv.Type = cty.DynamicPseudoType
}
if attr, ok := content.Attributes["default"]; ok {
cv.Default = attr.Expr
}
if attr, ok := content.Attributes["description"]; ok {
// We don't allow variables/functions in the description because
// we want to be able to display it in a UI that might be prompting
// for data that would be needed to evaluate expressions, so we'll
// just evaluate this right now and HCL will generate "variables cannot
// be used here" errors in case a user tries.
val, hclDiags := attr.Expr.Value(nil)
diags = diags.Append(hclDiags)
if !diags.HasErrors() {
if val.Type().Equals(cty.String) && !val.IsNull() {
cv.Description = val.AsString()
} else {
diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Invalid description for context value",
Detail: "The description of a context value must be a string and should contain a natural language description of the meaning of this context value using full sentences.",
Subject: attr.Expr.StartRange().Ptr(),
})
}
}
}
return cv, diags
}
var contextSchema = &hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{Name: "type"},
{Name: "default"},
{Name: "description"},
},
}

@ -5,6 +5,10 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/hcl2/hcl/hclsyntax"
"github.com/hashicorp/terraform/tfdiags"
"github.com/zclconf/go-cty/cty"
)
func TestLoad(t *testing.T) {
@ -26,6 +30,56 @@ func TestLoad(t *testing.T) {
t.Errorf("unexpected result\n%s", diff)
}
})
t.Run("context", func(t *testing.T) {
cfg, diags := Load("testdata/context")
if diags.HasErrors() {
t.Fatalf("Unexpected problems: %s", diags.Err().Error())
}
got := cfg.Context
want := map[string]*ContextValue{
"foo": {
Name: "foo",
Type: cty.String,
Description: "The foo thing.",
Default: &hclsyntax.TemplateExpr{
Parts: []hclsyntax.Expression{
&hclsyntax.LiteralValueExpr{
Val: cty.StringVal("bar"),
SrcRange: hcl.Range{
Filename: "testdata/context/.terraform-project.hcl",
Start: hcl.Pos{Line: 3, Column: 18, Byte: 56},
End: hcl.Pos{Line: 3, Column: 21, Byte: 59},
},
},
},
SrcRange: hcl.Range{
Filename: "testdata/context/.terraform-project.hcl",
Start: hcl.Pos{Line: 3, Column: 17, Byte: 55},
End: hcl.Pos{Line: 3, Column: 22, Byte: 60},
},
},
DeclRange: tfdiags.SourceRange{
Filename: "testdata/context/.terraform-project.hcl",
Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
End: tfdiags.SourcePos{Line: 1, Column: 14, Byte: 13},
},
NameRange: tfdiags.SourceRange{
Filename: "testdata/context/.terraform-project.hcl",
Start: tfdiags.SourcePos{Line: 1, Column: 9, Byte: 8},
End: tfdiags.SourcePos{Line: 1, Column: 14, Byte: 13},
},
},
}
diff := cmp.Diff(
want, got,
cmp.Comparer(cty.Type.Equals),
cmp.Comparer(cty.Value.RawEquals),
)
if diff != "" {
t.Errorf("unexpected result\n%s", diff)
}
})
}
func TestFindProjectRoot(t *testing.T) {

@ -0,0 +1,5 @@
context "foo" {
type = string
default = "bar"
description = "The foo thing."
}
Loading…
Cancel
Save