Skip to content

Commit 008e320

Browse files
add deprecation singleton
This struct tracks and validates deprecations in the context of a graph walk. We need a struct to keep track of the module calls that opt-out of deprecation warnings.
1 parent e179454 commit 008e320

File tree

6 files changed

+127
-3
lines changed

6 files changed

+127
-3
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package deprecation
5+
6+
import (
7+
"sync"
8+
9+
"github.com/hashicorp/hcl/v2"
10+
"github.com/hashicorp/terraform/internal/addrs"
11+
"github.com/hashicorp/terraform/internal/lang/marks"
12+
"github.com/hashicorp/terraform/internal/tfdiags"
13+
"github.com/zclconf/go-cty/cty"
14+
)
15+
16+
// Deprecations keeps track of meta-information related to deprecation, e.g. which module calls
17+
// suppress deprecation warnings.
18+
type Deprecations struct {
19+
// Must hold this lock when accessing all fields after this one.
20+
mu sync.Mutex
21+
22+
suppressedModules addrs.Set[addrs.Module]
23+
}
24+
25+
func NewDeprecations() *Deprecations {
26+
return &Deprecations{
27+
suppressedModules: addrs.MakeSet[addrs.Module](),
28+
}
29+
}
30+
31+
func (d *Deprecations) SuppressModuleCallDeprecation(addr addrs.Module) {
32+
d.mu.Lock()
33+
defer d.mu.Unlock()
34+
35+
d.suppressedModules.Add(addr)
36+
}
37+
38+
func (d *Deprecations) Validate(value cty.Value, module addrs.Module, rng *hcl.Range) (cty.Value, tfdiags.Diagnostics) {
39+
var diags tfdiags.Diagnostics
40+
deprecationMarks := marks.GetDeprecationMarks(value)
41+
if len(deprecationMarks) == 0 {
42+
return value, diags
43+
}
44+
45+
notDeprecatedValue := marks.RemoveDeprecationMarks(value)
46+
47+
// Check if we need to suppress deprecation warnings for this module call.
48+
if d.IsModuleCallDeprecationSuppressed(module) {
49+
return notDeprecatedValue, diags
50+
}
51+
52+
for _, depMark := range deprecationMarks {
53+
diags = diags.Append(&hcl.Diagnostic{
54+
Severity: hcl.DiagWarning,
55+
Summary: "Deprecated value used",
56+
Detail: depMark.Message,
57+
Subject: rng,
58+
})
59+
}
60+
61+
return notDeprecatedValue, diags
62+
}
63+
64+
func (d *Deprecations) ValidateAsConfig(value cty.Value, module addrs.Module) tfdiags.Diagnostics {
65+
var diags tfdiags.Diagnostics
66+
_, pvms := value.UnmarkDeepWithPaths()
67+
68+
if len(pvms) == 0 || d.IsModuleCallDeprecationSuppressed(module) {
69+
return diags
70+
}
71+
72+
for _, pvm := range pvms {
73+
for m := range pvm.Marks {
74+
if depMark, ok := m.(marks.DeprecationMark); ok {
75+
diags = diags.Append(
76+
tfdiags.AttributeValue(
77+
tfdiags.Warning,
78+
"Deprecated value used",
79+
depMark.Message,
80+
pvm.Path,
81+
),
82+
)
83+
}
84+
}
85+
}
86+
return diags
87+
}
88+
89+
func (d *Deprecations) IsModuleCallDeprecationSuppressed(addr addrs.Module) bool {
90+
for _, mod := range d.suppressedModules {
91+
if addr.Equal(mod) || mod.TargetContains(addr) {
92+
return true
93+
}
94+
}
95+
return false
96+
}

internal/terraform/context_walk.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/hashicorp/terraform/internal/addrs"
1212
"github.com/hashicorp/terraform/internal/checks"
1313
"github.com/hashicorp/terraform/internal/configs"
14+
"github.com/hashicorp/terraform/internal/deprecation"
1415
"github.com/hashicorp/terraform/internal/instances"
1516
"github.com/hashicorp/terraform/internal/lang"
1617
"github.com/hashicorp/terraform/internal/moduletest/mocking"
@@ -201,5 +202,6 @@ func (c *Context) graphWalker(graph *Graph, operation walkOperation, opts *graph
201202
functionResults: opts.FunctionResults,
202203
Forget: opts.Forget,
203204
Actions: actions.NewActions(),
205+
Deprecations: deprecation.NewDeprecations(),
204206
}
205207
}

internal/terraform/eval_context.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/hashicorp/terraform/internal/checks"
1515
"github.com/hashicorp/terraform/internal/configs"
1616
"github.com/hashicorp/terraform/internal/configs/configschema"
17+
"github.com/hashicorp/terraform/internal/deprecation"
1718
"github.com/hashicorp/terraform/internal/experiments"
1819
"github.com/hashicorp/terraform/internal/instances"
1920
"github.com/hashicorp/terraform/internal/lang"
@@ -222,6 +223,10 @@ type EvalContext interface {
222223
// declarations and their instances that are available in this
223224
// EvalContext.
224225
Actions() *actions.Actions
226+
227+
// Deprecations returns the deprecations object that tracks meta-information
228+
// about deprecation, e.g. which module calls suppress deprecation warnings.
229+
Deprecations() *deprecation.Deprecations
225230
}
226231

227232
func evalContextForModuleInstance(baseCtx EvalContext, addr addrs.ModuleInstance) EvalContext {

internal/terraform/eval_context_builtin.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/hashicorp/terraform/internal/checks"
1919
"github.com/hashicorp/terraform/internal/configs"
2020
"github.com/hashicorp/terraform/internal/configs/configschema"
21+
"github.com/hashicorp/terraform/internal/deprecation"
2122
"github.com/hashicorp/terraform/internal/experiments"
2223
"github.com/hashicorp/terraform/internal/instances"
2324
"github.com/hashicorp/terraform/internal/lang"
@@ -93,6 +94,7 @@ type BuiltinEvalContext struct {
9394
MoveResultsValue refactoring.MoveResults
9495
OverrideValues *mocking.Overrides
9596
ActionsValue *actions.Actions
97+
DeprecationsValue *deprecation.Deprecations
9698
}
9799

98100
// BuiltinEvalContext implements EvalContext
@@ -643,3 +645,7 @@ func (ctx *BuiltinEvalContext) ClientCapabilities() providers.ClientCapabilities
643645
func (ctx *BuiltinEvalContext) Actions() *actions.Actions {
644646
return ctx.ActionsValue
645647
}
648+
649+
func (ctx *BuiltinEvalContext) Deprecations() *deprecation.Deprecations {
650+
return ctx.DeprecationsValue
651+
}

internal/terraform/eval_context_mock.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/hashicorp/terraform/internal/checks"
1717
"github.com/hashicorp/terraform/internal/configs"
1818
"github.com/hashicorp/terraform/internal/configs/configschema"
19+
"github.com/hashicorp/terraform/internal/deprecation"
1920
"github.com/hashicorp/terraform/internal/experiments"
2021
"github.com/hashicorp/terraform/internal/instances"
2122
"github.com/hashicorp/terraform/internal/lang"
@@ -170,6 +171,9 @@ type MockEvalContext struct {
170171

171172
ActionsCalled bool
172173
ActionsState *actions.Actions
174+
175+
DeprecationCalled bool
176+
DeprecationState *deprecation.Deprecations
173177
}
174178

175179
// MockEvalContext implements EvalContext
@@ -451,3 +455,11 @@ func (c *MockEvalContext) Actions() *actions.Actions {
451455
c.ActionsCalled = true
452456
return c.ActionsState
453457
}
458+
459+
func (c *MockEvalContext) Deprecations() *deprecation.Deprecations {
460+
c.DeprecationCalled = true
461+
if c.DeprecationState != nil {
462+
return c.DeprecationState
463+
}
464+
return deprecation.NewDeprecations()
465+
}

internal/terraform/graph_walk_context.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/hashicorp/terraform/internal/collections"
1515
"github.com/hashicorp/terraform/internal/configs"
1616
"github.com/hashicorp/terraform/internal/configs/configschema"
17+
"github.com/hashicorp/terraform/internal/deprecation"
1718
"github.com/hashicorp/terraform/internal/instances"
1819
"github.com/hashicorp/terraform/internal/lang"
1920
"github.com/hashicorp/terraform/internal/moduletest/mocking"
@@ -53,9 +54,10 @@ type ContextGraphWalker struct {
5354
PlanTimestamp time.Time
5455
Overrides *mocking.Overrides
5556
// Forget if set to true will cause the plan to forget all resources. This is
56-
// only allowd in the context of a destroy plan.
57-
Forget bool
58-
Actions *actions.Actions
57+
// only allowed in the context of a destroy plan.
58+
Forget bool
59+
Actions *actions.Actions
60+
Deprecations *deprecation.Deprecations
5961

6062
// This is an output. Do not set this, nor read it while a graph walk
6163
// is in progress.
@@ -144,6 +146,7 @@ func (w *ContextGraphWalker) EvalContext() EvalContext {
144146
OverrideValues: w.Overrides,
145147
forget: w.Forget,
146148
ActionsValue: w.Actions,
149+
DeprecationsValue: w.Deprecations,
147150
}
148151

149152
return ctx

0 commit comments

Comments
 (0)