Skip to content

Commit

Permalink
refactor: move graph evaluator flag to run context
Browse files Browse the repository at this point in the history
This allows us to keep running the tests in parallel
  • Loading branch information
aliscott committed Feb 16, 2024
1 parent ec0225b commit d460a1b
Show file tree
Hide file tree
Showing 13 changed files with 96 additions and 46 deletions.
5 changes: 3 additions & 2 deletions cmd/infracost/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ func GoldenFileCommandTest(t *testing.T, testName string, args []string, testOpt
})

t.Run("HCL Graph", func(t *testing.T) {
t.Setenv("INFRACOST_GRAPH_EVALUATOR", "true")

ctxOptions = append(ctxOptions, func(ctx *config.RunContext) {
ctx.Config.GraphEvaluator = true
})
goldenFileCommandTest(t, testName, args, testOptions, true, ctxOptions...)
})

Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ type Config struct {
EnableCloud *bool `yaml:"enable_cloud,omitempty" envconfig:"ENABLE_CLOUD"`
EnableCloudUpload *bool `yaml:"enable_cloud_upload,omitempty" envconfig:"ENABLE_CLOUD_UPLOAD"`
DisableHCLParsing bool `yaml:"disable_hcl_parsing,omitempty" envconfig:"DISABLE_HCL_PARSING"`
GraphEvaluator bool `yaml:"graph_evaluator,omitempty" envconfig:"GRAPH_EVALUATOR"`

TLSInsecureSkipVerify *bool `envconfig:"TLS_INSECURE_SKIP_VERIFY"`
TLSCACertFile string `envconfig:"TLS_CA_CERT_FILE"`
Expand Down
7 changes: 4 additions & 3 deletions internal/hcl/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package hcl

import (
"fmt"
"os"
"runtime/debug"
"strings"

Expand Down Expand Up @@ -45,6 +44,8 @@ type Attribute struct {
// Verbose defines if the attribute should log verbose diagnostics messages to debug.
Verbose bool
Logger zerolog.Logger
// isGraph is a flag that indicates if the attribute should be evaluated with the graph evaluation
isGraph bool
// newMock generates a mock value for the attribute if it's value is missing.
newMock func(attr *Attribute) cty.Value
previousValue cty.Value
Expand Down Expand Up @@ -129,7 +130,7 @@ func (attr *Attribute) Value() cty.Value {

attr.Logger.Debug().Msg("fetching attribute value")
var val cty.Value
if os.Getenv("INFRACOST_GRAPH_EVALUATOR") == "true" {
if attr.isGraph {
val = attr.graphValue()
} else {
val = attr.value(0)
Expand All @@ -155,7 +156,7 @@ func (attr *Attribute) HasChanged() (change bool) {

previous := attr.previousValue
var current cty.Value
if os.Getenv("INFRACOST_GRAPH_EVALUATOR") == "true" {
if attr.isGraph {
current = attr.graphValue()
} else {
current = attr.value(0)
Expand Down
6 changes: 3 additions & 3 deletions internal/hcl/attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ func TestAttribute_AsString(t *testing.T) {
}

func TestAttributeValueWithIncompleteContextAndConditionalShouldNotPanic(t *testing.T) {
t.Setenv("INFRACOST_GRAPH_EVALUATOR", "true")

p := hclparse.NewParser()
f, diags := p.ParseHCL([]byte(`
locals {
Expand Down Expand Up @@ -150,7 +148,8 @@ locals {
Ctx: &Context{ctx: &hcl.EvalContext{
Variables: map[string]cty.Value{},
}},
Logger: discard,
Logger: discard,
isGraph: true,
}

attr := Attribute{
Expand All @@ -171,6 +170,7 @@ locals {
},
Verbose: false,
Logger: logger,
isGraph: true,
}

v := attr.Value()
Expand Down
13 changes: 11 additions & 2 deletions internal/hcl/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,10 @@ type Block struct {
// parent is the parent block if this is a child block.
parent *Block
// verbose determines whether the block uses verbose debug logging.
verbose bool
logger zerolog.Logger
verbose bool
logger zerolog.Logger
// isGraph is a flag that indicates if the attribute should be evaluated with the graph evaluation
isGraph bool
newMock func(attr *Attribute) cty.Value
attributes []*Attribute
reference *Reference
Expand All @@ -298,6 +300,7 @@ type BlockBuilder struct {
SetAttributes []SetAttributesFunc
Logger zerolog.Logger
HCLParser *modules.SharedHCLParser
isGraph bool
}

// NewBlock returns a Block with Context and child Blocks initialised.
Expand All @@ -319,6 +322,7 @@ func (b BlockBuilder) NewBlock(filename string, rootPath string, hclBlock *hcl.B
rootPath: rootPath,
childBlocks: make(Blocks, len(body.Blocks)),
verbose: isLoggingVerbose,
isGraph: b.isGraph,
newMock: b.MockFunc,
parent: parent,
}
Expand Down Expand Up @@ -352,6 +356,7 @@ func (b BlockBuilder) NewBlock(filename string, rootPath string, hclBlock *hcl.B
moduleBlock: moduleBlock,
rootPath: rootPath,
verbose: isLoggingVerbose,
isGraph: b.isGraph,
newMock: b.MockFunc,
}
block.setLogger(b.Logger)
Expand All @@ -370,6 +375,7 @@ func (b BlockBuilder) NewBlock(filename string, rootPath string, hclBlock *hcl.B
rootPath: rootPath,
childBlocks: make(Blocks, len(content.Blocks)),
verbose: isLoggingVerbose,
isGraph: b.isGraph,
newMock: b.MockFunc,
}

Expand Down Expand Up @@ -858,6 +864,7 @@ func (b *Block) GetAttributes() []*Attribute {
Logger: b.logger.With().Str(
"attribute_name", k,
).Logger(),
isGraph: b.isGraph,
})
continue
}
Expand All @@ -870,6 +877,7 @@ func (b *Block) GetAttributes() []*Attribute {
Logger: b.logger.With().Str(
"attribute_name", hclAttributes[k].Name,
).Logger(),
isGraph: b.isGraph,
})
}

Expand Down Expand Up @@ -927,6 +935,7 @@ func (b *Block) syntheticAttribute(name string, val cty.Value) *Attribute {
Logger: b.logger.With().Str(
"attribute_name", name,
).Logger(),
isGraph: b.isGraph,
}
}

Expand Down
13 changes: 7 additions & 6 deletions internal/hcl/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ type Evaluator struct {
blockBuilder BlockBuilder
newSpinner ui.SpinnerFunc
logger zerolog.Logger
isGraph bool
filteredBlocks []*Block
}

Expand All @@ -111,6 +112,7 @@ func NewEvaluator(
blockBuilder BlockBuilder,
spinFunc ui.SpinnerFunc,
logger zerolog.Logger,
isGraph bool,
) *Evaluator {
ctx := NewContext(&hcl.EvalContext{
Functions: ExpFunctions(module.RootPath, logger),
Expand Down Expand Up @@ -165,13 +167,10 @@ func NewEvaluator(
blockBuilder: blockBuilder,
newSpinner: spinFunc,
logger: l,
isGraph: isGraph,
}
}

func (e *Evaluator) isGraphEvaluator() bool {
return os.Getenv("INFRACOST_GRAPH_EVALUATOR") == "true"
}

func (e *Evaluator) AddFilteredBlocks(blocks ...*Block) {
for _, block := range blocks {
if block != nil {
Expand Down Expand Up @@ -349,6 +348,7 @@ func (e *Evaluator) evaluateModules() {
e.blockBuilder,
nil,
e.logger,
e.isGraph,
)

moduleCall.Module, _ = moduleEvaluator.Run()
Expand Down Expand Up @@ -463,6 +463,7 @@ func (e *Evaluator) expandDynamicBlock(b *Block) *Block {
parent: b.parent,
verbose: b.verbose,
logger: b.logger,
isGraph: b.isGraph,
newMock: b.newMock,
attributes: b.attributes,
reference: b.reference,
Expand Down Expand Up @@ -522,7 +523,7 @@ func (e *Evaluator) expandBlockForEaches(blocks Blocks) Blocks {
continue
}

if !e.isGraphEvaluator() && (block.IsCountExpanded() || !block.IsForEachReferencedExpanded(blocks) || !shouldExpandBlock(block)) {
if !e.isGraph && (block.IsCountExpanded() || !block.IsForEachReferencedExpanded(blocks) || !shouldExpandBlock(block)) {
original := block.original.GetAttribute("for_each")
if !original.HasChanged() {
expanded = append(expanded, block)
Expand Down Expand Up @@ -694,7 +695,7 @@ func (e *Evaluator) expandBlockCounts(blocks Blocks) Blocks {
continue
}

if !e.isGraphEvaluator() && (block.IsCountExpanded() || !shouldExpandBlock(block)) {
if !e.isGraph && (block.IsCountExpanded() || !shouldExpandBlock(block)) {
original := block.original.GetAttribute("count")
if !original.HasChanged() {
expanded = append(expanded, block)
Expand Down
1 change: 1 addition & 0 deletions internal/hcl/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ func (g *Graph) loadBlocksForModule(evaluator *Evaluator) ([]*Block, error) {
evaluator.blockBuilder,
nil,
evaluator.logger,
evaluator.isGraph,
)

modBlocks, err := g.loadBlocksForModule(moduleEvaluator)
Expand Down
1 change: 1 addition & 0 deletions internal/hcl/graph_vertex_module_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func (v *VertexModuleCall) expand(e *Evaluator, b *Block, mutex *sync.Mutex) ([]
e.blockBuilder,
nil,
e.logger,
e.isGraph,
)

v.moduleConfigs.Add(unexpandedName, ModuleConfig{
Expand Down
12 changes: 11 additions & 1 deletion internal/hcl/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ func OptionWithSpinner(f ui.SpinnerFunc) Option {
}
}

// OptionGraphEvaluator sets the Parser to use the experimental graph evaluator.
func OptionGraphEvaluator() Option {
return func(p *Parser) {
p.isGraph = true
p.blockBuilder.isGraph = true
}
}

type DetectedProject interface {
ProjectName() string
RelativePath() string
Expand All @@ -277,6 +285,7 @@ type Parser struct {
newSpinner ui.SpinnerFunc
remoteVariablesLoader *RemoteVariablesLoader
logger zerolog.Logger
isGraph bool
hasChanges bool
moduleSuffix string
envMatcher *EnvFileMatcher
Expand Down Expand Up @@ -421,12 +430,13 @@ func (p *Parser) ParseDirectory() (m *Module, err error) {
p.blockBuilder,
p.newSpinner,
p.logger,
p.isGraph,
)

var root *Module

// Graph evaluation
if evaluator.isGraphEvaluator() {
if evaluator.isGraph {
// we use the base zerolog log here so that it's consistent with the spinner logs
log.Info().Msgf("Building project with experimental graph runner")

Expand Down
12 changes: 5 additions & 7 deletions internal/hcl/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1636,8 +1636,6 @@ resource "baz" "bat" {
}

func Test_ObjectLiteralIsMockedCorrectly(t *testing.T) {
t.Setenv("INFRACOST_GRAPH_EVALUATOR", "true")

path := createTestFileWithModule(`
module "mod1" {
source = "../module"
Expand Down Expand Up @@ -1666,11 +1664,13 @@ resource "aws_instance" "example" {

logger := newDiscardLogger()
loader := modules.NewModuleLoader(filepath.Dir(path), modules.NewSharedHCLParser(), nil, config.TerraformSourceMap{}, logger, &sync.KeyMutex{})

parser := NewParser(
RootPath{Path: path},
CreateEnvFileMatcher([]string{}),
loader,
logger,
OptionGraphEvaluator(),
)
module, err := parser.ParseDirectory()
require.NoError(t, err)
Expand All @@ -1696,12 +1696,10 @@ resource "aws_instance" "example" {
}

func Test_ModuleTernaryWithMockedValue(t *testing.T) {
t.Setenv("INFRACOST_GRAPH_EVALUATOR", "true")

path := createTestFileWithModule(`
module "mod1" {
source = "../mod"
count = 1
count = 1
var1 = "don't create"
}
Expand All @@ -1726,6 +1724,7 @@ resource "aws_instance" "example" {
CreateEnvFileMatcher([]string{}),
loader,
logger,
OptionGraphEvaluator(),
)
module, err := parser.ParseDirectory()
require.NoError(t, err)
Expand All @@ -1743,8 +1742,6 @@ resource "aws_instance" "example" {
}

func Test_VariableLengthWhenMocked(t *testing.T) {
t.Setenv("INFRACOST_GRAPH_EVALUATOR", "true")

path := createTestFile("main.tf", `
variable "my_config" {
type = any
Expand All @@ -1765,6 +1762,7 @@ resource "aws_instance" "example" {
CreateEnvFileMatcher([]string{}),
loader,
logger,
OptionGraphEvaluator(),
)
module, err := parser.ParseDirectory()
require.NoError(t, err)
Expand Down
4 changes: 4 additions & 0 deletions internal/providers/terraform/hcl_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ func NewHCLProvider(ctx *config.ProjectContext, rootPath hcl.RootPath, config *H
}
}

if ctx.RunContext.Config.GraphEvaluator {
options = append(options, hcl.OptionGraphEvaluator())
}

rootPath.Path = initialPath
return &HCLProvider{
policyClient: policyClient,
Expand Down

0 comments on commit d460a1b

Please sign in to comment.