diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 959bbe4..7eb8075 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,8 +1,7 @@ name: Lint on: - pull_request_target: - types: [opened, reopened, synchronize] + pull_request: jobs: lint: diff --git a/cmd/hcledit/internal/command/read.go b/cmd/hcledit/internal/command/read.go index 9d78000..f87d629 100644 --- a/cmd/hcledit/internal/command/read.go +++ b/cmd/hcledit/internal/command/read.go @@ -50,12 +50,12 @@ func runRead(opts *ReadOptions, args []string) (string, error) { return "", fmt.Errorf("failed to read file: %s", err) } - readOpts:= []hcledit.Option{} + readOpts := []hcledit.Option{} if opts.Fallback { readOpts = append(readOpts, hcledit.WithReadFallbackToRawString()) } results, err := editor.Read(query, readOpts...) - if err != nil { + if err != nil && !opts.Fallback { return "", fmt.Errorf("failed to read file: %s", err) } diff --git a/hcledit.go b/hcledit.go index bdeb3c1..b048a20 100644 --- a/hcledit.go +++ b/hcledit.go @@ -88,8 +88,9 @@ func (h *HCLEditor) Read(queryStr string, opts ...Option) (map[string]interface{ return nil, err } + fallback := opt.readFallbackToRawString results := make(map[string]cty.Value) - hdlr, err := handler.NewReadHandler(results, opt.readFallbackToRawString) + hdlr, err := handler.NewReadHandler(results, fallback) if err != nil { return nil, err } @@ -99,11 +100,17 @@ func (h *HCLEditor) Read(queryStr string, opts ...Option) (map[string]interface{ Mode: walker.Read, } - if err := w.Walk(h.writeFile.Body(), queries, 0, []string{}); err != nil { - return nil, err + walkErr := w.Walk(h.writeFile.Body(), queries, 0, []string{}) + if walkErr != nil && !fallback { + return nil, walkErr + } + + ret, convertErr := convert(results) + if convertErr != nil { + return ret, convertErr } - return convert(results) + return ret, walkErr } // Update replaces attributes and blocks which matched with its key diff --git a/hcledit_test.go b/hcledit_test.go index 3ff6cb3..5ea9631 100644 --- a/hcledit_test.go +++ b/hcledit_test.go @@ -205,17 +205,19 @@ object1 = { func TestRead(t *testing.T) { cases := map[string]struct { - input string - query string - options []hcledit.Option - want map[string]interface{} + input string + query string + options []hcledit.Option + expectErr bool + want map[string]interface{} }{ "Attribute": { input: ` attribute = "R" `, - query: "attribute", - options: make([]hcledit.Option, 0), + query: "attribute", + options: make([]hcledit.Option, 0), + expectErr: false, want: map[string]interface{}{ "attribute": "R", }, @@ -228,9 +230,10 @@ block "label1" "label2" { attribute = "str" } `, - options: make([]hcledit.Option, 0), - query: "block", - want: map[string]interface{}{}, + options: make([]hcledit.Option, 0), + expectErr: false, + query: "block", + want: map[string]interface{}{}, }, "AttributeInBlock1": { @@ -239,8 +242,9 @@ block "label1" "label2" { attribute = "R" } `, - options: make([]hcledit.Option, 0), - query: "block.label1.label2.attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "block.label1.label2.attribute", want: map[string]interface{}{ "block.label1.label2.attribute": "R", }, @@ -254,8 +258,9 @@ block1 "label1" "label2" { } } `, - options: make([]hcledit.Option, 0), - query: "block1.label1.label2.block2.label3.label4.attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "block1.label1.label2.block2.label3.label4.attribute", want: map[string]interface{}{ "block1.label1.label2.block2.label3.label4.attribute": "R", }, @@ -272,8 +277,9 @@ block "label" "label2" { } `, - options: make([]hcledit.Option, 0), - query: "block.label.*.attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "block.label.*.attribute", want: map[string]interface{}{ "block.label.label1.attribute": "R", "block.label.label2.attribute": "R", @@ -286,8 +292,9 @@ object = { attribute = "R" } `, - options: make([]hcledit.Option, 0), - query: "object.attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "object.attribute", want: map[string]interface{}{ "object.attribute": "R", }, @@ -300,8 +307,9 @@ object1 = { } } `, - options: make([]hcledit.Option, 0), - query: "object1.object2.attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "object1.object2.attribute", want: map[string]interface{}{ "object1.object2.attribute": "R", }, @@ -311,8 +319,9 @@ object1 = { input: ` attribute = 1 `, - options: make([]hcledit.Option, 0), - query: "attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "attribute", want: map[string]interface{}{ "attribute": 1, }, @@ -322,8 +331,9 @@ attribute = 1 input: ` attribute = "str" `, - options: make([]hcledit.Option, 0), - query: "attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "attribute", want: map[string]interface{}{ "attribute": "str", }, @@ -333,8 +343,9 @@ attribute = "str" input: ` attribute = true `, - options: make([]hcledit.Option, 0), - query: "attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "attribute", want: map[string]interface{}{ "attribute": true, }, @@ -344,8 +355,9 @@ attribute = true input: ` attribute = false `, - options: make([]hcledit.Option, 0), - query: "attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "attribute", want: map[string]interface{}{ "attribute": false, }, @@ -355,8 +367,9 @@ attribute = false input: ` attribute = ["str1", "str2", "str3"] `, - options: make([]hcledit.Option, 0), - query: "attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "attribute", want: map[string]interface{}{ "attribute": []string{"str1", "str2", "str3"}, }, @@ -366,8 +379,9 @@ attribute = ["str1", "str2", "str3"] input: ` attribute = [1, 2, 3] `, - options: make([]hcledit.Option, 0), - query: "attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "attribute", want: map[string]interface{}{ "attribute": []int{1, 2, 3}, }, @@ -377,8 +391,9 @@ attribute = [1, 2, 3] input: ` attribute = [true, false, true] `, - options: make([]hcledit.Option, 0), - query: "attribute", + options: make([]hcledit.Option, 0), + expectErr: false, + query: "attribute", want: map[string]interface{}{ "attribute": []bool{true, false, true}, }, @@ -388,8 +403,9 @@ attribute = [true, false, true] input: ` attribute = local.var `, - options: []hcledit.Option{hcledit.WithReadFallbackToRawString()}, - query: "attribute", + options: []hcledit.Option{hcledit.WithReadFallbackToRawString()}, + expectErr: true, + query: "attribute", want: map[string]interface{}{ "attribute": "local.var", }, @@ -399,8 +415,9 @@ attribute = local.var input: ` attribute = "some-${local.var}" `, - options: []hcledit.Option{hcledit.WithReadFallbackToRawString()}, - query: "attribute", + options: []hcledit.Option{hcledit.WithReadFallbackToRawString()}, + expectErr: true, + query: "attribute", want: map[string]interface{}{ "attribute": `"some-${local.var}"`, }, @@ -416,7 +433,7 @@ attribute = "some-${local.var}" } got, err := editor.Read(tc.query, tc.options...) - if err != nil { + if !tc.expectErr && err != nil { t.Fatal(err) } diff --git a/internal/handler/block.go b/internal/handler/block.go index e8c2a7c..4dd93b1 100644 --- a/internal/handler/block.go +++ b/internal/handler/block.go @@ -30,7 +30,7 @@ func (h *blockHandler) HandleBody(body *hclwrite.Body, name string, _ []string) body.AppendUnstructuredTokens( beforeTokens( fmt.Sprintf("// %s", strings.TrimSpace(strings.TrimPrefix(h.comment, "//"))), - true, + true, ), ) } diff --git a/internal/handler/read.go b/internal/handler/read.go index df3bfc6..f9761b9 100644 --- a/internal/handler/read.go +++ b/internal/handler/read.go @@ -25,12 +25,13 @@ func NewReadHandler(results map[string]cty.Value, fallbackToRawString bool) (Han func (h *readHandler) HandleBody(body *hclwrite.Body, name string, keyTrail []string) error { buf := body.GetAttribute(name).BuildTokens(nil).Bytes() - value, err := parse(buf, name, h.fallbackToRawString) - if err != nil { + fallback := h.fallbackToRawString + value, err := parse(buf, name, fallback) + if err != nil && !fallback { return err } h.results[strings.Join(keyTrail, ".")] = value - return nil + return err } func (h *readHandler) HandleObject(object *ast.Object, name string, keyTrail []string) error { @@ -59,7 +60,7 @@ func parse(buf []byte, name string, fallback bool) (cty.Value, error) { // Could not parse the value with a nil EvalContext, so this is likely an // interpolated string. Instead, attempt to parse the raw string value. - return cty.StringVal(string(expr.Range().SliceBytes(buf))), nil + return cty.StringVal(string(expr.Range().SliceBytes(buf))), diags } return v, nil } diff --git a/option.go b/option.go index dba6b2d..878df6e 100644 --- a/option.go +++ b/option.go @@ -32,6 +32,9 @@ func WithNewLine() Option { } } +// This provides a fallback to return the raw string of the value if we could +// not parse it. If this option is provided to HCLEditor.Read(), the error +// return value will signal fallback occurred. func WithReadFallbackToRawString() Option { return func(opt *option) { opt.readFallbackToRawString = true