Skip to content

Commit 3f7d043

Browse files
authored
Append warning in CLI output when query result is empty (#37379)
1 parent eaf3b90 commit 3f7d043

File tree

7 files changed

+83
-7
lines changed

7 files changed

+83
-7
lines changed

internal/command/query_test.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package command
55

66
import (
77
"path"
8+
"strings"
89
"testing"
910

1011
"github.com/google/go-cmp/cmp"
@@ -83,6 +84,15 @@ Error: Unsupported block type
8384
Blocks of type "resource" are not expected here.
8485
`},
8586
},
87+
{
88+
name: "empty result",
89+
directory: "empty-result",
90+
expectedOut: `list.test_instance.example id=test-instance-1 Test Instance 1
91+
list.test_instance.example id=test-instance-2 Test Instance 2
92+
93+
Warning: list block(s) [list.test_instance.example2] returned 0 results.`,
94+
initCode: 0,
95+
},
8696
}
8797

8898
for _, ts := range tests {
@@ -118,19 +128,22 @@ Blocks of type "resource" are not expected here.
118128
args := []string{"-no-color"}
119129
code = c.Run(args)
120130
output = done(t)
121-
actual := output.All()
122131
if len(ts.expectedErr) == 0 {
123132
if code != 0 {
124133
t.Fatalf("bad: %d\n\n%s", code, output.Stderr())
125134
}
135+
actual := strings.TrimSpace(output.Stdout())
126136

127137
// Check that we have query output
128-
if diff := cmp.Diff(ts.expectedOut, actual); diff != "" {
129-
t.Errorf("expected query output to contain %q, \ngot: %q, \ndiff: %s", ts.expectedOut, actual, diff)
138+
expected := strings.TrimSpace(ts.expectedOut)
139+
if diff := cmp.Diff(expected, actual); diff != "" {
140+
t.Errorf("expected query output to contain \n%q, \ngot: \n%q, \ndiff: %s", expected, actual, diff)
130141
}
131142

132143
} else {
144+
actual := strings.TrimSpace(output.Stderr())
133145
for _, expected := range ts.expectedErr {
146+
expected := strings.TrimSpace(expected)
134147
if diff := cmp.Diff(expected, actual); diff != "" {
135148
t.Errorf("expected error message to contain '%s', \ngot: %s, \ndiff: %s", expected, actual, diff)
136149
}
@@ -228,11 +241,12 @@ func queryFixtureProvider() *testing_provider.MockProvider {
228241

229242
configMap := wholeConfigMap["config"]
230243

231-
// For empty results test case //TODO: Remove?
232-
if ami, ok := wholeConfigMap["ami"]; ok && ami.AsString() == "ami-nonexistent" {
244+
// For empty results test case
245+
ami, ok := configMap.AsValueMap()["ami"]
246+
if ok && ami.AsString() == "ami-nonexistent" {
233247
return providers.ListResourceResponse{
234248
Result: cty.ObjectVal(map[string]cty.Value{
235-
"data": cty.ListVal([]cty.Value{}),
249+
"data": cty.ListValEmpty(cty.DynamicPseudoType),
236250
"config": configMap,
237251
}),
238252
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
terraform {
2+
required_providers {
3+
test = {
4+
source = "hashicorp/test"
5+
}
6+
}
7+
}
8+
9+
provider "test" {}
10+
11+
resource "test_instance" "example" {
12+
ami = "ami-12345"
13+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
list "test_instance" "example" {
2+
provider = test
3+
4+
config {
5+
ami = "ami-12345"
6+
}
7+
}
8+
9+
list "test_instance" "example2" {
10+
provider = test
11+
12+
config {
13+
ami = "ami-nonexistent"
14+
}
15+
}

internal/command/views/hook_json.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,11 @@ func (h *jsonHook) PostListQuery(id terraform.HookResourceIdentity, results plan
263263
json.MessageListResourceFound, result,
264264
)
265265
}
266+
h.view.log.Info(
267+
fmt.Sprintf("%s: List complete", addr.String()),
268+
"type", json.MessageListComplete,
269+
"total", data.LengthInt(),
270+
)
266271
return terraform.HookActionContinue, nil
267272
}
268273

internal/command/views/hook_ui.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,9 @@ func (h *UiHook) PostListQuery(id terraform.HookResourceIdentity, results plans.
534534
result.WriteString(fmt.Sprintf("%s %-*s %s\n", addr.String(), maxIdentityLen, identity, displayNames[i]))
535535
}
536536

537-
h.println(result.String())
537+
if result.Len() > 0 {
538+
h.println(result.String())
539+
}
538540

539541
return terraform.HookActionContinue, nil
540542
}

internal/command/views/json/message_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const (
5050
// List messages
5151
MessageListStart MessageType = "list_start"
5252
MessageListResourceFound MessageType = "list_resource_found"
53+
MessageListComplete MessageType = "list_complete"
5354

5455
// Action messages
5556
MessageActionStart MessageType = "action_start"

internal/command/views/query_operation.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package views
55

66
import (
77
"fmt"
8+
"strings"
89

910
"github.com/hashicorp/terraform/internal/command/arguments"
1011
"github.com/hashicorp/terraform/internal/command/format"
@@ -59,6 +60,31 @@ func (v *QueryOperationHuman) EmergencyDumpState(stateFile *statefile.File) erro
5960
}
6061

6162
func (v *QueryOperationHuman) Plan(plan *plans.Plan, schemas *terraform.Schemas) {
63+
// The hook for individual query blocks do not display any output when the results are empty,
64+
// so we will display a grouped warning message here for the empty queries.
65+
emptyBlocks := []string{}
66+
for _, query := range plan.Changes.Queries {
67+
pSchema := schemas.ProviderSchema(query.ProviderAddr.Provider)
68+
addr := query.Addr
69+
schema := pSchema.ListResourceTypes[addr.Resource.Resource.Type]
70+
71+
results, err := query.Decode(schema)
72+
if err != nil {
73+
v.view.streams.Eprintln(err)
74+
continue
75+
}
76+
77+
data := results.Results.Value.GetAttr("data")
78+
if data.LengthInt() == 0 {
79+
emptyBlocks = append(emptyBlocks, addr.String())
80+
}
81+
82+
}
83+
84+
if len(emptyBlocks) > 0 {
85+
msg := fmt.Sprintf(v.view.colorize.Color("[bold][yellow]Warning:[reset][bold] list block(s) [%s] returned 0 results.\n"), strings.Join(emptyBlocks, ", "))
86+
v.view.streams.Println(format.WordWrap(msg, v.view.outputColumns()))
87+
}
6288
}
6389

6490
func (v *QueryOperationHuman) PlannedChange(change *plans.ResourceInstanceChangeSrc) {

0 commit comments

Comments
 (0)