Skip to content

Add Environment Variable directive parsing #965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions src/System.CommandLine.Tests/EnvironmentVariableDirectiveTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
using FluentAssertions;

using System.CommandLine.Builder;
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using System.Linq;
using System.Threading.Tasks;

using Xunit;

namespace System.CommandLine.Tests
{
public class EnvironmentVariableDirectiveTests
{
private static readonly Random randomizer = new Random(Seed: 456476756);
private readonly string test_variable = $"TEST_ENVIRONMENT_VARIABLE{randomizer.Next()}";

[Fact]
public async Task Sets_environment_variable_to_value()
{
bool asserted = false;
string variable = test_variable;
const string value = "This is a test";
var rootCommand = new RootCommand
{
Handler = CommandHandler.Create(() =>
{
asserted = true;
Environment.GetEnvironmentVariable(variable).Should().Be(value);
})
};

var parser = new CommandLineBuilder(rootCommand)
.UseEnvironmentVariableDirective()
.Build();

await parser.InvokeAsync(new[] { $"[env:{variable}={value}]" });

asserted.Should().BeTrue();
}

[Fact]
public async Task Trims_environment_variable_name()
{
bool asserted = false;
string variable = test_variable;
const string value = "This is a test";
var rootCommand = new RootCommand
{
Handler = CommandHandler.Create(() =>
{
asserted = true;
Environment.GetEnvironmentVariable(variable).Should().Be(value);
})
};

var parser = new CommandLineBuilder(rootCommand)
.UseEnvironmentVariableDirective()
.Build();

await parser.InvokeAsync(new[] { $"[env: {variable} ={value}]" });

asserted.Should().BeTrue();
}

[Fact]
public async Task Trims_environment_variable_value()
{
bool asserted = false;
string variable = test_variable;
const string value = "This is a test";
var rootCommand = new RootCommand
{
Handler = CommandHandler.Create(() =>
{
asserted = true;
Environment.GetEnvironmentVariable(variable).Should().Be(value);
})
};

var parser = new CommandLineBuilder(rootCommand)
.UseEnvironmentVariableDirective()
.Build();

await parser.InvokeAsync(new[] { $"[env:{variable}= {value} ]" });

asserted.Should().BeTrue();
}

[Fact]
public async Task Sets_environment_variable_value_containing_equals_sign()
{
bool asserted = false;
string variable = test_variable;
const string value = "This is = a test containing equals";
var rootCommand = new RootCommand
{
Handler = CommandHandler.Create(() =>
{
asserted = true;
Environment.GetEnvironmentVariable(variable).Should().Be(value);
})
};

var parser = new CommandLineBuilder(rootCommand)
.UseEnvironmentVariableDirective()
.Build();

await parser.InvokeAsync(new[] { $"[env:{variable}={value}]" });

asserted.Should().BeTrue();
}

[Fact]
public async Task Ignores_environment_directive_without_equals_sign()
{
bool asserted = false;
string variable = test_variable;
var rootCommand = new RootCommand
{
Handler = CommandHandler.Create(() =>
{
asserted = true;
Environment.GetEnvironmentVariable(variable).Should().BeNull();
})
};

var parser = new CommandLineBuilder(rootCommand)
.UseEnvironmentVariableDirective()
.Build();

await parser.InvokeAsync(new[] { $"[env:{variable}]" });

asserted.Should().BeTrue();
}

[Fact]
public static async Task Ignores_environment_directive_with_empty_variable_name()
{
bool asserted = false;
string value = $"This is a test, random: {randomizer.Next()}";
var rootCommand = new RootCommand
{
Handler = CommandHandler.Create(() =>
{
asserted = true;
var env = Environment.GetEnvironmentVariables();
env.Values.Cast<string>().Should().NotContain(value);
})
};

var parser = new CommandLineBuilder(rootCommand)
.UseEnvironmentVariableDirective()
.Build();

await parser.InvokeAsync(new[] { $"[env:={value}]" });

asserted.Should().BeTrue();
}

[Fact]
public static async Task Ignores_environment_directive_with_whitespace_variable_name()
{
bool asserted = false;
string value = $"This is a test, random: {randomizer.Next()}";
var rootCommand = new RootCommand
{
Handler = CommandHandler.Create(() =>
{
asserted = true;
var env = Environment.GetEnvironmentVariables();
env.Values.Cast<string>().Should().NotContain(value);
})
};

var parser = new CommandLineBuilder(rootCommand)
.UseEnvironmentVariableDirective()
.Build();

await parser.InvokeAsync(new[] { $"[env: ={value}]" });

asserted.Should().BeTrue();
}
}
}
27 changes: 27 additions & 0 deletions src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,38 @@ public static CommandLineBuilder UseDebugDirective(
return builder;
}

public static CommandLineBuilder UseEnvironmentVariableDirective(
this CommandLineBuilder builder)
{
builder.AddMiddleware((context, next) =>
{
if (context.ParseResult.Directives.TryGetValues("env", out var directives))
{
foreach (var envDirective in directives)
{
var components = envDirective.Split(new[] { '=' }, count: 2);
var variable = components.Length > 0 ? components[0].Trim() : string.Empty;
if (string.IsNullOrEmpty(variable) || components.Length < 2)
{
continue;
}
var value = components[1].Trim();
SetEnvironmentVariable(variable, value);
}
}

return next(context);
}, MiddlewareOrderInternal.EnvironmentVariableDirective);

return builder;
}

public static CommandLineBuilder UseDefaults(this CommandLineBuilder builder)
{
return builder
.UseVersionOption()
.UseHelp()
.UseEnvironmentVariableDirective()
.UseParseDirective()
.UseDebugDirective()
.UseSuggestDirective()
Expand Down
1 change: 1 addition & 0 deletions src/System.CommandLine/Invocation/MiddlewareOrder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal enum MiddlewareOrderInternal
{
Startup = -4000,
ExceptionHandler = -3000,
EnvironmentVariableDirective = -2600,
ConfigureConsole = -2500,
RegisterWithDotnetSuggest = -2400,
DebugDirective = -2300,
Expand Down