Skip to content

Commit

Permalink
Add support for the output command (cake-contrib#54)
Browse files Browse the repository at this point in the history
added Output wrapper

---------

Co-authored-by: David Obee <[email protected]>
  • Loading branch information
david-obee and David Obee authored May 23, 2024
1 parent 7f0cfdf commit 073fbd3
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 29 deletions.
1 change: 0 additions & 1 deletion src/Cake.Terraform.Tests/TerraformEnvListTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Cake.Core;
using Cake.Terraform.EnvList;
using Cake.Testing;
using Cake.Testing.Fixtures;
using Xunit;

namespace Cake.Terraform.Tests
Expand Down
205 changes: 205 additions & 0 deletions src/Cake.Terraform.Tests/TerraformOutputTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using Cake.Core;
using Cake.Terraform.Output;
using Cake.Testing;
using Xunit;

namespace Cake.Terraform.Tests
{
public class TerraformOutputTests
{
class Fixture : TerraformFixture<TerraformOutputSettings>
{
public Fixture(PlatformFamily platformFamily = PlatformFamily.Windows) : base(platformFamily) { }

public List<string> ToolOutput { get; set; } = new List<string> { "foo = 123", "bar = abc" };
public string Outputs { get; private set; } = null;

protected override void RunTool()
{
ProcessRunner.Process.SetStandardOutput(ToolOutput);

var tool = new TerraformOutputRunner(FileSystem, Environment, ProcessRunner, Tools);

Outputs = tool.Run(Settings);
}
}

public class TheExecutable
{
[Fact]
public void Should_throw_if_terraform_runner_was_not_found()
{
var fixture = new Fixture();
fixture.GivenDefaultToolDoNotExist();

var result = Record.Exception(() => fixture.Run());

Assert.IsType<CakeException>(result);
Assert.Equal("Terraform: Could not locate executable.", result.Message);
}

[Theory]
[InlineData("/bin/tools/terraform/terraform.exe", "/bin/tools/terraform/terraform.exe")]
[InlineData("/bin/tools/terraform/terraform", "/bin/tools/terraform/terraform")]
public void Should_use_terraform_from_tool_path_if_provided(string toolPath, string expected)
{
var fixture = new Fixture() {Settings = {ToolPath = toolPath}};
fixture.GivenSettingsToolPathExist();

var result = fixture.Run();

Assert.Equal(expected, result.Path.FullPath);
}

[Fact]
public void Should_find_terraform_if_tool_path_not_provided()
{
var fixture = new Fixture();

var result = fixture.Run();

Assert.Equal("/Working/tools/terraform.exe", result.Path.FullPath);
}

[Fact]
public void Should_throw_if_process_has_a_non_zero_exit_code()
{
var fixture = new Fixture();
fixture.GivenProcessExitsWithCode(1);

var result = Record.Exception(() => fixture.Run());

Assert.IsType<CakeException>(result);
Assert.Equal("Terraform: Process returned an error (exit code 1).", result.Message);
}

[Fact]
public void Should_find_linux_executable()
{
var fixture = new Fixture(PlatformFamily.Linux);
fixture.Environment.Platform.Family = PlatformFamily.Linux;

var result = fixture.Run();

Assert.Equal("/Working/tools/terraform", result.Path.FullPath);
}

[Fact]
public void Should_call_only_command_if_no_settings_specified()
{
var fixture = new Fixture();

var result = fixture.Run();

Assert.Equal("output -no-color", result.Args);
}

[Fact]
public void Should_request_json_if_specified()
{
var fixture = new Fixture { Settings = new TerraformOutputSettings { Json = true } };

var result = fixture.Run();

Assert.Equal("output -no-color -json", result.Args);
}

[Fact]
public void Should_request_raw_if_specified()
{
var fixture = new Fixture { Settings = new TerraformOutputSettings { Raw = true } };

var result = fixture.Run();

Assert.Equal("output -no-color -raw", result.Args);
}

[Fact]
public void Should_request_raw_over_json_if_both_are_specified()
{
var fixture = new Fixture { Settings = new TerraformOutputSettings { Raw = true, Json = true} };

var result = fixture.Run();

Assert.Equal("output -no-color -raw", result.Args);
}

[Fact]
public void Should_request_specific_state_path_if_specified()
{
var fixture = new Fixture { Settings = new TerraformOutputSettings { StatePath = "some_path"} };

var result = fixture.Run();

Assert.Equal("output -no-color -state=some_path", result.Args);
}

[Fact]
public void Should_request_particular_output_if_specified()
{
var fixture = new Fixture { Settings = new TerraformOutputSettings { OutputName = "some_output"} };

var result = fixture.Run();

Assert.Equal("output -no-color some_output", result.Args);
}

[Fact]
public void Should_combine_output_lines_into_string()
{
var fixture = new Fixture();

fixture.Run();

Assert.Equal("foo = 123\nbar = abc", fixture.Outputs);
}

[Fact]
public void Should_raise_exception_if_output_not_found()
{
var fixture = new Fixture
{
ToolOutput = new List<string>
{
"The output variable requested could not be found in the state",
"file. If you recently added this to your configuration, be",
"sure to run `terraform apply`, since the state won't be updated",
"with new output variables until that command is run."
}
};

var exception = Assert.Throws<ArgumentException>(() => fixture.Run());
Assert.Equal(
"The output variable requested could not be found in the state\nfile. If you recently added this to your configuration, be\nsure to run `terraform apply`, since the state won't be updated\nwith new output variables until that command is run.",
exception.Message);
}

[Fact]
public void Should_not_raise_exception_if_output_not_found_and_validation_disabled()
{
var fixture = new Fixture
{
ToolOutput = new List<string>
{
"The output variable requested could not be found in the state",
"file. If you recently added this to your configuration, be",
"sure to run `terraform apply`, since the state won't be updated",
"with new output variables until that command is run."
},
Settings = new TerraformOutputSettings
{
ValidateToolOutput = false
}
};

fixture.Run();

Assert.Equal(
"The output variable requested could not be found in the state\nfile. If you recently added this to your configuration, be\nsure to run `terraform apply`, since the state won't be updated\nwith new output variables until that command is run.",
fixture.Outputs);
}
}
}
}
56 changes: 28 additions & 28 deletions src/Cake.Terraform.sln
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.Terraform", "Cake.Terraform\Cake.Terraform.csproj", "{C6E9A60F-9055-4E54-9E29-7F277875ABC1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.Terraform.Tests", "Cake.Terraform.Tests\Cake.Terraform.Tests.csproj", "{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C6E9A60F-9055-4E54-9E29-7F277875ABC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C6E9A60F-9055-4E54-9E29-7F277875ABC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C6E9A60F-9055-4E54-9E29-7F277875ABC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C6E9A60F-9055-4E54-9E29-7F277875ABC1}.Release|Any CPU.Build.0 = Release|Any CPU
{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.Terraform", "Cake.Terraform\Cake.Terraform.csproj", "{C6E9A60F-9055-4E54-9E29-7F277875ABC1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.Terraform.Tests", "Cake.Terraform.Tests\Cake.Terraform.Tests.csproj", "{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C6E9A60F-9055-4E54-9E29-7F277875ABC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C6E9A60F-9055-4E54-9E29-7F277875ABC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C6E9A60F-9055-4E54-9E29-7F277875ABC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C6E9A60F-9055-4E54-9E29-7F277875ABC1}.Release|Any CPU.Build.0 = Release|Any CPU
{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB9EDCDE-48B6-4B6E-B0B6-28CF549A6591}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
93 changes: 93 additions & 0 deletions src/Cake.Terraform/Output/TerraformOutputRunner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Linq;
using System.Text;
using Cake.Core;
using Cake.Core.IO;
using Cake.Core.Tooling;

namespace Cake.Terraform.Output
{
public class TerraformOutputRunner : TerraformRunner<TerraformOutputSettings>
{
public TerraformOutputRunner(IFileSystem fileSystem, ICakeEnvironment environment, IProcessRunner processRunner, IToolLocator tools)
: base(fileSystem, environment, processRunner, tools)
{
}

private static string RemoveWhitespace(string x)
{
return x
.Replace("\n", "")
.Replace("\r", "")
.Replace(" ", "");
}

private void ConfirmSuccess(string output)
{
string outputNotFoundErrorString = RemoveWhitespace("The output variable requested could not be found in the state file. If you recently added this to your configuration, be sure to run `terraform apply`, since the state won't be updated with new output variables until that command is run.");

if (RemoveWhitespace(output) == outputNotFoundErrorString)
{
throw new ArgumentException(output);
}
}

public string Run(TerraformOutputSettings settings)
{
var arguments = new ProcessArgumentBuilder()
.Append("output")
.Append("-no-color");

if (settings.StatePath != null)
{
arguments.Append($"-state={settings.StatePath}");
}

if (settings.Raw)
{
arguments.Append("-raw");
}
else if (settings.Json)
{
arguments.Append("-json");
}

if (settings.OutputName != null)
{
arguments.Append(settings.OutputName);
}

var processSettings = new ProcessSettings
{
RedirectStandardOutput = true
};

string output = null;
Run(settings, arguments, processSettings, x =>
{
var outputLines = x.GetStandardOutput().ToList();
int lineCount = outputLines.Count();
var builder = new StringBuilder();
for (int i = 0; i < lineCount; i++)
{
builder.Append(outputLines[i]);
if (i < lineCount - 1)
{
builder.Append("\n"); // OS consistent
}
}
output = builder.ToString();
});

if (settings.ValidateToolOutput)
{
ConfirmSuccess(output);
}

return output;
}
}
}
11 changes: 11 additions & 0 deletions src/Cake.Terraform/Output/TerraformOutputSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Cake.Terraform.Output
{
public class TerraformOutputSettings : TerraformSettings
{
public string OutputName { get; set; }
public bool Json { get; set; }
public bool Raw { get; set; }
public string StatePath { get; set; }
public bool ValidateToolOutput { get; set; } = true;
}
}
Loading

0 comments on commit 073fbd3

Please sign in to comment.