Skip to content

Commit

Permalink
[auto] Add support for the path option for config operations (#191)
Browse files Browse the repository at this point in the history
Add support for the `--path` flag for config operations in Automation API.
  • Loading branch information
justinvp authored Oct 23, 2023
1 parent 3106dc2 commit 0c572e3
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 15 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
### Improvements

- [sdk/automation-api] Add support for the path option for config operations.
[#191](https://github.com/pulumi/pulumi-dotnet/pull/191)

### Bug Fixes
- [sdk] Register and await tasks created from `Apply` that don't return anything.

- [sdk] Register and await tasks created from `Apply` that don't return anything.
110 changes: 110 additions & 0 deletions sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,116 @@ await Assert.ThrowsAsync<CommandException>(
}
}

[Fact]
public async Task ManipulateConfigPath()
{
var projectName = "manipulate_config_path_test";
var projectSettings = new ProjectSettings(projectName, ProjectRuntimeName.NodeJS);

using var workspace = await LocalWorkspace.CreateAsync(new LocalWorkspaceOptions
{
ProjectSettings = projectSettings,
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
});

var stackName = $"{RandomStackName()}";
var stack = await WorkspaceStack.CreateAsync(stackName, workspace);

try
{
// test backward compatibility
await stack.SetConfigAsync("key1", new ConfigValue("value1"));
// test new flag without subPath
await stack.SetConfigAsync("key2", new ConfigValue("value2"), path: false);
// test new flag with subPath
await stack.SetConfigAsync("key3.subKey1", new ConfigValue("value3"), path: true);
// test secret
await stack.SetConfigAsync("key4", new ConfigValue("value4", isSecret: true));
// test subPath and key as secret
await stack.SetConfigAsync("key5.subKey1", new ConfigValue("value5", isSecret: true), path: true);
// test string with dots
await stack.SetConfigAsync("key6.subKey1", new ConfigValue("value6", isSecret: true));
// test string with dots
await stack.SetConfigAsync("key7.subKey1", new ConfigValue("value7", isSecret: true), path: false);
// test subPath
await stack.SetConfigAsync("key7.subKey2", new ConfigValue("value8"), path: true);
// test subPath
await stack.SetConfigAsync("key7.subKey3", new ConfigValue("value9"), path: true);

// test backward compatibility
var cv1 = await stack.GetConfigAsync("key1");
Assert.NotNull(cv1);
Assert.Equal("value1", cv1.Value);
Assert.False(cv1.IsSecret);

// test new flag without subPath
var cv2 = await stack.GetConfigAsync("key2", path: false);
Assert.NotNull(cv2);
Assert.Equal("value2", cv2.Value);
Assert.False(cv2.IsSecret);

// test new flag with subPath
var cv3 = await stack.GetConfigAsync("key3.subKey1", path: true);
Assert.NotNull(cv3);
Assert.Equal("value3", cv3.Value);
Assert.False(cv3.IsSecret);

// test secret
var cv4 = await stack.GetConfigAsync("key4");
Assert.NotNull(cv4);
Assert.Equal("value4", cv4.Value);
Assert.True(cv4.IsSecret);

// test subPath and key as secret
var cv5 = await stack.GetConfigAsync("key5.subKey1", true);
Assert.NotNull(cv5);
Assert.Equal("value5", cv5.Value);
Assert.True(cv5.IsSecret);

// test string with dots
var cv6 = await stack.GetConfigAsync("key6.subKey1");
Assert.NotNull(cv6);
Assert.Equal("value6", cv6.Value);
Assert.True(cv6.IsSecret);

// test string with dots
var cv7 = await stack.GetConfigAsync("key7.subKey1", false);
Assert.NotNull(cv7);
Assert.Equal("value7", cv7.Value);
Assert.True(cv7.IsSecret);

// test string with dots
var cv8 = await stack.GetConfigAsync("key7.subKey2", true);
Assert.NotNull(cv8);
Assert.Equal("value8", cv8.Value);
Assert.False(cv8.IsSecret);

// test string with dots
var cv9 = await stack.GetConfigAsync("key7.subKey3", true);
Assert.NotNull(cv9);
Assert.Equal("value9", cv9.Value);
Assert.False(cv9.IsSecret);

await stack.RemoveConfigAsync("key1");
await stack.RemoveConfigAsync("key2", path: false);
await stack.RemoveConfigAsync("key3", path: false);
await stack.RemoveConfigAsync("key4", path: false);
await stack.RemoveConfigAsync("key5", path: false);
await stack.RemoveConfigAsync("key6.subKey1", path: false);
await stack.RemoveConfigAsync("key7.subKey1", path: false);

var cfg = await stack.GetAllConfigAsync();
Assert.Equal("{\"subKey2\":\"value8\",\"subKey3\":\"value9\"}", cfg[$"{projectName}:key7"].Value);
}
finally
{
await workspace.RemoveStackAsync(stackName);
}
}

[Fact]
public async Task SupportConfigFlagLike()
{
Expand Down
63 changes: 55 additions & 8 deletions sdk/Pulumi.Automation/LocalWorkspace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -567,9 +567,19 @@ public override async Task<Dictionary<string, string>> ListTagsAsync(string stac
}

/// <inheritdoc/>
public override async Task<ConfigValue> GetConfigAsync(string stackName, string key, CancellationToken cancellationToken = default)
public override Task<ConfigValue> GetConfigAsync(string stackName, string key, CancellationToken cancellationToken = default)
=> GetConfigAsync(stackName, key, false, cancellationToken);

/// <inheritdoc/>
public override async Task<ConfigValue> GetConfigAsync(string stackName, string key, bool path, CancellationToken cancellationToken = default)
{
var result = await this.RunCommandAsync(new[] { "config", "get", key, "--json", "--stack", stackName }, cancellationToken).ConfigureAwait(false);
var args = new List<string> { "config", "get" };
if (path)
{
args.Add("--path");
}
args.AddRange(new[] { key, "--json", "--stack", stackName });
var result = await this.RunCommandAsync(args, cancellationToken).ConfigureAwait(false);
return this._serializer.DeserializeJson<ConfigValue>(result.StandardOutput);
}

Expand All @@ -585,16 +595,34 @@ public override async Task<ImmutableDictionary<string, ConfigValue>> GetAllConfi
}

/// <inheritdoc/>
public override async Task SetConfigAsync(string stackName, string key, ConfigValue value, CancellationToken cancellationToken = default)
public override Task SetConfigAsync(string stackName, string key, ConfigValue value, CancellationToken cancellationToken = default)
=> SetConfigAsync(stackName, key, value, false, cancellationToken);

/// <inheritdoc/>
public override async Task SetConfigAsync(string stackName, string key, ConfigValue value, bool path, CancellationToken cancellationToken = default)
{
var args = new List<string> { "config", "set" };
if (path)
{
args.Add("--path");
}
var secretArg = value.IsSecret ? "--secret" : "--plaintext";
await this.RunCommandAsync(new[] { "config", "set", key, secretArg, "--stack", stackName, "--non-interactive", "--", value.Value }, cancellationToken).ConfigureAwait(false);
args.AddRange(new[] { key, secretArg, "--stack", stackName, "--non-interactive", "--", value.Value });
await this.RunCommandAsync(args, cancellationToken).ConfigureAwait(false);
}

/// <inheritdoc/>
public override async Task SetAllConfigAsync(string stackName, IDictionary<string, ConfigValue> configMap, CancellationToken cancellationToken = default)
public override Task SetAllConfigAsync(string stackName, IDictionary<string, ConfigValue> configMap, CancellationToken cancellationToken = default)
=> SetAllConfigAsync(stackName, configMap, false, cancellationToken);

/// <inheritdoc/>
public override async Task SetAllConfigAsync(string stackName, IDictionary<string, ConfigValue> configMap, bool path, CancellationToken cancellationToken = default)
{
var args = new List<string> { "config", "set-all", "--stack", stackName };
if (path)
{
args.Add("--path");
}
foreach (var (key, value) in configMap)
{
var secretArg = value.IsSecret ? "--secret" : "--plaintext";
Expand All @@ -605,13 +633,32 @@ public override async Task SetAllConfigAsync(string stackName, IDictionary<strin
}

/// <inheritdoc/>
public override async Task RemoveConfigAsync(string stackName, string key, CancellationToken cancellationToken = default)
=> await this.RunCommandAsync(new[] { "config", "rm", key, "--stack", stackName }, cancellationToken).ConfigureAwait(false);
public override Task RemoveConfigAsync(string stackName, string key, CancellationToken cancellationToken = default)
=> RemoveConfigAsync(stackName, key, false, cancellationToken);

/// <inheritdoc/>
public override async Task RemoveConfigAsync(string stackName, string key, bool path, CancellationToken cancellationToken = default)
{
var args = new List<string> { "config", "rm", key, "--stack", stackName };
if (path)
{
args.Add("--path");
}
await this.RunCommandAsync(args, cancellationToken).ConfigureAwait(false);
}

/// <inheritdoc/>
public override Task RemoveAllConfigAsync(string stackName, IEnumerable<string> keys, CancellationToken cancellationToken = default)
=> RemoveAllConfigAsync(stackName, keys, false, cancellationToken);

/// <inheritdoc/>
public override async Task RemoveAllConfigAsync(string stackName, IEnumerable<string> keys, CancellationToken cancellationToken = default)
public override async Task RemoveAllConfigAsync(string stackName, IEnumerable<string> keys, bool path, CancellationToken cancellationToken = default)
{
var args = new List<string> { "config", "rm-all", "--stack", stackName };
if (path)
{
args.Add("--path");
}
args.AddRange(keys);
await this.RunCommandAsync(args, cancellationToken).ConfigureAwait(false);
}
Expand Down
Loading

0 comments on commit 0c572e3

Please sign in to comment.