Skip to content

Commit 75c94f6

Browse files
committed
fix: Deduplicate attribute diagnostics
1 parent cd4dec7 commit 75c94f6

File tree

5 files changed

+67
-13
lines changed

5 files changed

+67
-13
lines changed

internal/backend/local/backend_plan.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ func (b *Local) opPlan(
7676
b.ContextOpts = new(terraform.ContextOpts)
7777
}
7878

79-
// Get our context
80-
// first diagnostic
79+
// Set up backend and get our context
8180
lr, configSnap, opState, ctxDiags := b.localRun(op)
8281
diags = diags.Append(ctxDiags)
8382
if ctxDiags.HasErrors() {
@@ -106,7 +105,6 @@ func (b *Local) opPlan(
106105
defer logging.PanicHandler()
107106
defer close(doneCh)
108107
log.Printf("[INFO] backend/local: plan calling Plan")
109-
// second diagnostic
110108
plan, planDiags = lr.Core.Plan(lr.Config, lr.InputState, lr.PlanOpts)
111109
}()
112110

@@ -122,7 +120,7 @@ func (b *Local) opPlan(
122120
// NOTE: We intentionally don't stop here on errors because we always want
123121
// to try to present a partial plan report and, if the user chose to,
124122
// generate a partial saved plan file for external analysis.
125-
diags = planDiags
123+
diags = diags.AppendWithoutDuplicates(planDiags...)
126124

127125
// Even if there are errors we need to handle anything that may be
128126
// contained within the plan, so only exit if there is no data at all.

internal/tfdiags/compare.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,15 @@ var DiagnosticComparer cmp.Option = cmp.Comparer(diagnosticComparerSimple)
2020
// diagnosticComparerSimple returns false when a difference is identified between
2121
// the two Diagnostic arguments.
2222
func diagnosticComparerSimple(l, r Diagnostic) bool {
23-
if l.Severity() != r.Severity() {
24-
return false
25-
}
26-
if l.Description() != r.Description() {
23+
ld, ok := l.(ComparableDiagnostic)
24+
if !ok {
2725
return false
2826
}
2927

30-
// Do the diagnostics originate from the same attribute name, if any?
31-
lp := GetAttribute(l)
32-
rp := GetAttribute(r)
33-
if len(lp) != len(rp) {
28+
rd, ok := r.(ComparableDiagnostic)
29+
if !ok {
3430
return false
3531
}
36-
return lp.Equals(rp)
32+
33+
return ld.Equals(rd)
3734
}

internal/tfdiags/contextual.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,26 @@ func (d *attributeDiagnostic) ElaborateFromConfigBody(body hcl.Body, addr string
205205
return &ret
206206
}
207207

208+
func (d *attributeDiagnostic) Equals(otherDiag ComparableDiagnostic) bool {
209+
od, ok := otherDiag.(*attributeDiagnostic)
210+
if !ok {
211+
return false
212+
}
213+
if d.severity != od.severity {
214+
return false
215+
}
216+
if d.summary != od.summary {
217+
return false
218+
}
219+
if d.detail != od.detail {
220+
return false
221+
}
222+
if d.address != od.address {
223+
return false
224+
}
225+
return d.attrPath.Equals(od.attrPath)
226+
}
227+
208228
func traversePathSteps(traverse []cty.PathStep, body hcl.Body) hcl.Body {
209229
for i := 0; i < len(traverse); i++ {
210230
step := traverse[i]

internal/tfdiags/diagnostic.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ type Diagnostic interface {
2727
ExtraInfo() interface{}
2828
}
2929

30+
type ComparableDiagnostic interface {
31+
Equals(otherDiag ComparableDiagnostic) bool
32+
}
33+
3034
type Severity rune
3135

3236
//go:generate go tool golang.org/x/tools/cmd/stringer -type=Severity

internal/tfdiags/diagnostics.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,41 @@ func (diags Diagnostics) Append(new ...interface{}) Diagnostics {
8383
return diags
8484
}
8585

86+
func (diags Diagnostics) ContainsDiagnostic(diag ComparableDiagnostic) bool {
87+
for _, d := range diags {
88+
if cd, ok := d.(ComparableDiagnostic); ok && diag.Equals(cd) {
89+
return true
90+
}
91+
}
92+
return false
93+
}
94+
95+
func (diags Diagnostics) AppendWithoutDuplicates(newDiags ...Diagnostic) Diagnostics {
96+
for _, newItem := range newDiags {
97+
if newItem == nil {
98+
continue
99+
}
100+
101+
cd, ok := newItem.(ComparableDiagnostic)
102+
if !ok {
103+
// append what we cannot compare
104+
diags = diags.Append(newItem)
105+
}
106+
107+
if diags.ContainsDiagnostic(cd) {
108+
continue
109+
}
110+
111+
diags = diags.Append(newItem)
112+
}
113+
114+
if len(diags) == 0 {
115+
return nil
116+
}
117+
118+
return diags
119+
}
120+
86121
func diagnosticsForError(err error) []Diagnostic {
87122
if err == nil {
88123
return nil

0 commit comments

Comments
 (0)