Skip to content

Commit

Permalink
fix: show a 100% cost increase with prior empty projects
Browse files Browse the repository at this point in the history
Resolves issue where projects that were previously "empty" (i.e. with no
infrastructure configuration files) were showing an error and zero costs
with `diff`. We now instead show a 100% cost increase in the project.
  • Loading branch information
hugorut committed Feb 23, 2024
1 parent cfd0727 commit 0e2c8c9
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 5 deletions.
14 changes: 14 additions & 0 deletions cmd/infracost/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,3 +320,17 @@ func TestDiffWithPolicyDataUpload(t *testing.T) {
},
)
}

func TestDiffPriorEmptyProject(t *testing.T) {
testName := testutil.CalcGoldenFileTestdataDirName()
dir := path.Join("./testdata", testName)
GoldenFileCommandTest(
t,
testutil.CalcGoldenFileTestdataDirName(), []string{
"diff",
"--compare-to",
path.Join(dir, "base.json"),
"--path",
dir,
}, nil)
}
5 changes: 2 additions & 3 deletions cmd/infracost/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,9 @@ func (r *parallelRunner) run() ([]projectResult, error) {

if err != nil {
m := fmt.Sprintf("%s\n\n", err)
m += fmt.Sprintf("Try adding a config-file to configure how Infracost should run. See %s for details and examples.", ui.LinkString("https://infracost.io/config-file"))
m += fmt.Sprintf(" Try adding a config-file to configure how Infracost should run. See %s for details and examples.", ui.LinkString("https://infracost.io/config-file"))

err = clierror.NewCLIError(errors.New(m), "Could not detect path type")
queue = append(queue, projectJob{index: i, err: err, ctx: ctx})
queue = append(queue, projectJob{index: i, err: schema.NewEmptyPathTypeError(errors.New(m)), ctx: ctx})
continue
}

Expand Down
72 changes: 72 additions & 0 deletions cmd/infracost/testdata/diff_prior_empty_project/base.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"version": "0.2",
"metadata": {
"infracostCommand": "breakdown",
"vcsBranch": "master",
"vcsCommitSha": "71785af96bce822bd54f359d0883cfa4ca805432",
"vcsCommitAuthorName": "Hugo",
"vcsCommitAuthorEmail": "",
"vcsCommitTimestamp": "2024-02-23T11:04:26Z",
"vcsCommitMessage": "wip",
"vcsRepositoryUrl": "https://github.com/infracost/infracost.git"
},
"currency": "USD",
"projects": [
{
"name": "infracost/infracost/cmd/infracost/testdata/diff_prior_empty_project",
"metadata": {
"path": ".",
"type": "error",
"vcsSubPath": "cmd/infracost/testdata/diff_prior_empty_project",
"errors": [
{
"code": 106,
"message": "could not detect path type for '.'\n\nTry adding a config-file to configure how Infracost should run. See \u001b[4;1mhttps://infracost.io/config-file\u001b[0m for details and examples.",
"data": null,
"isError": true
}
]
},
"pastBreakdown": {
"resources": [],
"totalHourlyCost": "0",
"totalMonthlyCost": "0"
},
"breakdown": {
"resources": [],
"totalHourlyCost": "0",
"totalMonthlyCost": "0"
},
"diff": {
"resources": [],
"totalHourlyCost": "0",
"totalMonthlyCost": "0"
},
"summary": {
"totalDetectedResources": 0,
"totalSupportedResources": 0,
"totalUnsupportedResources": 0,
"totalUsageBasedResources": 0,
"totalNoPriceResources": 0,
"unsupportedResourceCounts": {},
"noPriceResourceCounts": {}
}
}
],
"totalHourlyCost": "0",
"totalMonthlyCost": "0",
"pastTotalHourlyCost": "0",
"pastTotalMonthlyCost": "0",
"diffTotalHourlyCost": "0",
"diffTotalMonthlyCost": "0",
"timeGenerated": "2024-02-23T12:58:15.71255Z",
"summary": {
"totalDetectedResources": 0,
"totalSupportedResources": 0,
"totalUnsupportedResources": 0,
"totalUsageBasedResources": 0,
"totalNoPriceResources": 0,
"unsupportedResourceCounts": {},
"noPriceResourceCounts": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
──────────────────────────────────
Project: infracost/infracost/cmd/infracost/testdata/diff_prior_empty_project

+ aws_instance.web_app
+$743

+ Instance usage (Linux/UNIX, on-demand, m5.4xlarge)
+$561

+ root_block_device

+ Storage (general purpose SSD, gp2)
+$5

+ ebs_block_device[0]

+ Storage (provisioned IOPS SSD, io1)
+$125

+ Provisioned IOPS
+$52

Monthly cost change for infracost/infracost/cmd/infracost/testdata/diff_prior_empty_project
Amount: +$743 ($0.00 → $743)

──────────────────────────────────
Key: ~ changed, + added, - removed

1 cloud resource was detected:
∙ 1 was estimated, it includes usage-based costs, see https://infracost.io/usage-file

Infracost estimate: Monthly cost will increase by $743 ↑
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓
┃ Project ┃ Cost change ┃ New monthly cost ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━┫
┃ infracost/infracost/cmd/infraco...tdata/diff_prior_empty_project ┃ +$743 ┃ $743 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━┛

Err:

23 changes: 23 additions & 0 deletions cmd/infracost/testdata/diff_prior_empty_project/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
provider "aws" {
region = "us-east-1" # <<<<< Try changing this to eu-west-1 to compare the costs
skip_credentials_validation = true
skip_requesting_account_id = true
access_key = "mock_access_key"
secret_key = "mock_secret_key"
}

resource "aws_instance" "web_app" {
ami = "ami-674cbc1e"
instance_type = "m5.4xlarge"

root_block_device {
volume_size = 50
}

ebs_block_device {
device_name = "my_data"
volume_type = "io1"
volume_size = 1000
iops = 800
}
}
2 changes: 1 addition & 1 deletion internal/output/combined.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func CompareTo(c *config.Config, current, prior Root) (Root, error) {
scp.Diff = schema.CalculateDiff(scp.PastResources, scp.Resources)
}

if !p.Metadata.HasErrors() && v.Metadata.HasErrors() {
if !p.Metadata.HasErrors() && !v.Metadata.IsEmptyProjectError() && v.Metadata.HasErrors() {
// the prior project has errors, but the current one does not
// The prior errors will be copied over to the current, but we
// also need to remove the current project costs
Expand Down
2 changes: 1 addition & 1 deletion internal/output/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func ToDiff(out Root, opts Options) ([]byte, error) {

s += "──────────────────────────────────\n"
for _, project := range out.Projects {
if project.Metadata.HasErrors() {
if project.Metadata.HasErrors() && !project.Metadata.IsEmptyProjectError() {
erroredProjects = append(erroredProjects, project)
continue
}
Expand Down
15 changes: 15 additions & 0 deletions internal/schema/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
diagTerragruntEvaluationFailure = 103
diagTerragruntModuleEvaluationFailure = 104
diagMissingVars = 105
diagEmptyPathType = 106

// Diags for git module issues
diagPrivateModuleDownloadFailure = 201
Expand All @@ -44,6 +45,12 @@ type ProjectDiag struct {
FriendlyMessage string `json:"-"`
}

// NewEmptyPathTypeError returns a project diag to indicate that a path type
// cannot be detected.
func NewEmptyPathTypeError(err error) *ProjectDiag {
return newDiag(diagEmptyPathType, err.Error(), true, nil, err)
}

// NewDiagRunQuotaExceeded returns a project diag for a run quota exceeded error.
func NewDiagRunQuotaExceeded(err error) *ProjectDiag {
return &ProjectDiag{
Expand Down Expand Up @@ -208,6 +215,14 @@ func (m *ProjectMetadata) HasErrors() bool {
return len(m.Errors) > 0
}

func (m *ProjectMetadata) IsEmptyProjectError() bool {
if len(m.Errors) == 0 || len(m.Errors) > 1 {
return false
}

return m.Errors[0].Code == diagEmptyPathType
}

// IsRunQuotaExceeded checks if any of the project diags are of type "run quota
// exceeded". If found it returns the associated message with this diag. This
// should be used when in any output that notifies the user.
Expand Down

0 comments on commit 0e2c8c9

Please sign in to comment.