Skip to content

Commit ae8ad06

Browse files
committed
fix: match dashboard's hasDiff and exclude deleted resources from fixes
Switches the cost section visibility (hasDiff) and per-project diff check to key off DiffBreakdown.Resources rather than per-resource Action, matching the dashboard's projectHasDiff. ProjectResult.Resources is no longer read anywhere in the comment package and has been removed. Also filters fixed-issue counts to exclude resources that no longer appear in any current policy result (passing or failing) — claiming a "fix" for a resource that has disappeared, or whose policy is no longer applicable, is misleading.
1 parent 2a44c61 commit ae8ad06

7 files changed

Lines changed: 138 additions & 97 deletions

File tree

pkg/vcs/comment/costs.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"sort"
66

77
"github.com/infracost/go-proto/pkg/rat"
8-
"github.com/infracost/proto/gen/go/infracost/provider"
98
)
109

1110
// processProjectCosts builds the project costs table entries, determines which
@@ -120,17 +119,11 @@ func (data *Data) usageCostsMessage() string {
120119
return fmt.Sprintf("*Usage costs can be estimated by updating %s, see %s for other options.", cloudSettingsStr, usageDocsStr)
121120
}
122121

123-
// projectHasDiff returns true if any resource in the project has a non-NOOP action.
122+
// projectHasDiff returns true if the project's pre-computed diff breakdown
123+
// contains any resource entries. Matches the dashboard's projectHasDiff in
124+
// dashboard/api/src/services/templates/helpers.ts.
124125
func projectHasDiff(project ProjectResult) bool {
125-
for _, r := range project.Resources {
126-
switch r.Action {
127-
case provider.ResourceAction_CREATE,
128-
provider.ResourceAction_MODIFY,
129-
provider.ResourceAction_DELETE:
130-
return true
131-
}
132-
}
133-
return false
126+
return project.DiffBreakdown != nil && len(project.DiffBreakdown.Resources) > 0
134127
}
135128

136129
// costChangeOpts controls formatting of cost change strings.
@@ -242,4 +235,4 @@ func truncateMiddle(s string, maxLen int) string {
242235
}
243236
half := (maxLen - 3) / 2
244237
return s[:half] + "..." + s[len(s)-half:]
245-
}
238+
}

pkg/vcs/comment/data.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,6 @@ type ProjectResult struct {
183183
// Available from runner's Project.Diff.
184184
DiffBreakdown *CostBreakdown
185185

186-
// Resources contains the current resources with their costs from the
187-
// provider output. Each resource has an Action field (CREATE, MODIFY,
188-
// DELETE, NOOP) indicating whether it changed between runs.
189-
Resources []*provider.Resource
190-
191186
// Diagnostics contains any parsing errors or warnings for this project.
192187
Diagnostics []*diagnostic.Diagnostic
193188

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package comment
2+
3+
import "github.com/infracost/proto/gen/go/infracost/provider"
4+
5+
// buildDeletedResources returns the set of resource IDs/addresses that were
6+
// failing in the previous run but no longer appear in any current policy
7+
// result (passing or failing) across finops, security, and tagging policies.
8+
//
9+
// Such a resource was either deleted, or stopped being applicable to every
10+
// policy that previously covered it. In either case it shouldn't be counted
11+
// as a "fix" in the comment — claiming we fixed an issue on a resource that
12+
// has disappeared (or whose policy has retired) is misleading.
13+
//
14+
// FinOps results key resources by parser-supplied ID; tagging results key by
15+
// address. They share the same map: keys are strings and any collision (when
16+
// a parser uses the address as the ID) is harmless.
17+
func (data *Data) buildDeletedResources() map[string]bool {
18+
current := make(map[string]bool)
19+
addFinopsCurrent(current, data.FinOpsPolicyResults)
20+
addFinopsCurrent(current, data.SecurityPolicyResults)
21+
for _, r := range data.TaggingPolicyResults {
22+
for _, fr := range r.FailingResources {
23+
current[fr.Address] = true
24+
}
25+
for _, pr := range r.PassingResources {
26+
current[pr.Address] = true
27+
}
28+
}
29+
30+
deleted := make(map[string]bool)
31+
addFinopsDeleted(deleted, current, data.PreviousFinOpsPolicyResults)
32+
addFinopsDeleted(deleted, current, data.PreviousSecurityPolicyResults)
33+
for _, r := range data.PreviousTaggingPolicyResults {
34+
for _, fr := range r.FailingResources {
35+
if !current[fr.Address] {
36+
deleted[fr.Address] = true
37+
}
38+
}
39+
}
40+
return deleted
41+
}
42+
43+
func addFinopsCurrent(current map[string]bool, results []*provider.FinopsPolicyResult) {
44+
for _, r := range results {
45+
for _, fr := range r.FailingResources {
46+
current[fr.Id] = true
47+
}
48+
for _, id := range r.PassingResourceIds {
49+
current[id] = true
50+
}
51+
}
52+
}
53+
54+
func addFinopsDeleted(deleted, current map[string]bool, previous []*provider.FinopsPolicyResult) {
55+
for _, r := range previous {
56+
for _, fr := range r.FailingResources {
57+
if !current[fr.Id] {
58+
deleted[fr.Id] = true
59+
}
60+
}
61+
}
62+
}

pkg/vcs/comment/fixed_issues.go

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import (
1414
func (data *Data) processFixedIssues(inputs *Inputs, finopsIndex, securityIndex policyFailureIndex, taggingIndex taggingFailureIndex) {
1515
counts := make([]FixedIssueCount, 0, len(data.PreviousFinOpsPolicyResults)+len(data.PreviousSecurityPolicyResults)+len(data.TaggingPolicyResults))
1616

17-
counts = append(counts, finopsFixedIssueCounts(data.PreviousFinOpsPolicyResults, finopsIndex)...)
18-
counts = append(counts, finopsFixedIssueCounts(data.PreviousSecurityPolicyResults, securityIndex)...)
19-
counts = append(counts, taggingFixedIssueCounts(data.TaggingPolicyResults, taggingIndex)...)
17+
deleted := data.buildDeletedResources()
18+
19+
counts = append(counts, finopsFixedIssueCounts(data.PreviousFinOpsPolicyResults, finopsIndex, deleted)...)
20+
counts = append(counts, finopsFixedIssueCounts(data.PreviousSecurityPolicyResults, securityIndex, deleted)...)
21+
counts = append(counts, taggingFixedIssueCounts(data.TaggingPolicyResults, taggingIndex, deleted)...)
2022

2123
// Sort by count descending, then policy name ascending.
2224
sort.Slice(counts, func(i, j int) bool {
@@ -44,8 +46,11 @@ func (data *Data) processFixedIssues(inputs *Inputs, finopsIndex, securityIndex
4446
}
4547

4648
// finopsFixedIssueCounts computes fixed issue counts for FinOps/security policies.
47-
// A fixed issue is a resource that was failing previously but is no longer failing.
48-
func finopsFixedIssueCounts(previousResults []*provider.FinopsPolicyResult, index policyFailureIndex) []FixedIssueCount {
49+
// A fixed issue is a resource that was failing previously, is no longer failing,
50+
// and still appears in some current policy result. Resources in the deleted set
51+
// (gone from every current policy's scope) are excluded so we don't claim a fix
52+
// for a resource that has disappeared.
53+
func finopsFixedIssueCounts(previousResults []*provider.FinopsPolicyResult, index policyFailureIndex, deleted map[string]bool) []FixedIssueCount {
4954
if len(previousResults) == 0 {
5055
return nil
5156
}
@@ -59,9 +64,13 @@ func finopsFixedIssueCounts(previousResults []*provider.FinopsPolicyResult, inde
5964
currentIDs := index.current[prev.PolicySlug]
6065
fixed := 0
6166
for _, r := range prev.FailingResources {
62-
if currentIDs == nil || !currentIDs[r.Id] {
63-
fixed++
67+
if currentIDs != nil && currentIDs[r.Id] {
68+
continue
69+
}
70+
if deleted[r.Id] {
71+
continue
6472
}
73+
fixed++
6574
}
6675

6776
if fixed > 0 {
@@ -76,8 +85,10 @@ func finopsFixedIssueCounts(previousResults []*provider.FinopsPolicyResult, inde
7685
}
7786

7887
// taggingFixedIssueCounts computes fixed issue counts for tagging policies.
79-
// A fixed issue is an address that was failing previously but is no longer failing.
80-
func taggingFixedIssueCounts(results []event.TaggingPolicyResult, index taggingFailureIndex) []FixedIssueCount {
88+
// A fixed issue is an address that was failing previously, is no longer
89+
// failing, and still appears in some current policy result. Addresses in the
90+
// deleted set are excluded — see finopsFixedIssueCounts for rationale.
91+
func taggingFixedIssueCounts(results []event.TaggingPolicyResult, index taggingFailureIndex, deleted map[string]bool) []FixedIssueCount {
8192
var counts []FixedIssueCount
8293

8394
for _, result := range results {
@@ -93,9 +104,13 @@ func taggingFixedIssueCounts(results []event.TaggingPolicyResult, index taggingF
93104
currentAddrs := index.current[result.TagPolicyID]
94105
fixed := 0
95106
for addr := range prevAddrs {
96-
if currentAddrs == nil || !currentAddrs[addr] {
97-
fixed++
107+
if currentAddrs != nil && currentAddrs[addr] {
108+
continue
109+
}
110+
if deleted[addr] {
111+
continue
98112
}
113+
fixed++
99114
}
100115

101116
if fixed > 0 {

pkg/vcs/comment/template.go

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import (
66
"fmt"
77
"strings"
88
"text/template"
9-
10-
"github.com/infracost/proto/gen/go/infracost/provider"
119
)
1210

1311
const (
@@ -109,25 +107,12 @@ func (data *Data) processDisplayCosts(inputs *Inputs, hasGuardrail bool) {
109107
}
110108

111109
hasError := len(inputs.ProjectErrors) > 0
110+
hasUnsupported := data.Summary.TotalUnsupportedResources > 0
112111
hasDiff := false
113-
hasUnsupported := false
114112

115113
for _, project := range data.Projects {
116-
for _, r := range project.Resources {
117-
switch r.Action {
118-
case provider.ResourceAction_CREATE,
119-
provider.ResourceAction_MODIFY,
120-
provider.ResourceAction_DELETE:
121-
hasDiff = true
122-
}
123-
if !r.IsSupported && !r.IsFree {
124-
hasUnsupported = true
125-
}
126-
if hasDiff && hasUnsupported {
127-
break
128-
}
129-
}
130-
if hasDiff && hasUnsupported {
114+
if projectHasDiff(project) {
115+
hasDiff = true
131116
break
132117
}
133118
}

0 commit comments

Comments
 (0)