From ea60aa7d52fb3c3d7bbce5c709dd35c2c7e6f3b9 Mon Sep 17 00:00:00 2001 From: Cleve Littlefield Date: Mon, 22 Jan 2024 17:11:24 -0800 Subject: [PATCH 1/5] add support for pulumi config env ls --- .../LocalWorkspaceTests.cs | 14 +++++++++++--- sdk/Pulumi.Automation/LocalWorkspace.cs | 19 +++++++++++++++++++ sdk/Pulumi.Automation/Pulumi.Automation.xml | 10 ++++++++++ sdk/Pulumi.Automation/Workspace.cs | 6 ++++++ sdk/Pulumi.Automation/WorkspaceStack.cs | 3 +++ 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs b/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs index bb38589e..e52bc255 100644 --- a/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs +++ b/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs @@ -23,6 +23,7 @@ using static Pulumi.Automation.Tests.Utility; using Xunit.Sdk; +using Castle.DynamicProxy.Generators; namespace Pulumi.Automation.Tests { @@ -159,16 +160,23 @@ public async Task AddAndRemoveEnvironment() var program = PulumiFn.Create(); var stackName = FullyQualifiedStackName(_pulumiOrg, projectName, $"int_test{GetTestSuffix()}"); await workspace.CreateStackAsync(stackName); + var stack = await WorkspaceStack.SelectAsync(stackName, workspace); - await Assert.ThrowsAsync(() => workspace.AddEnvironmentsAsync(stackName, new[] { "non-existent-env" })); + await Assert.ThrowsAsync(() => stack.AddEnvironmentsAsync(new[] { "non-existent-env" })); - await workspace.AddEnvironmentsAsync(stackName, new[] { "automation-api-test-env", "automation-api-test-env-2" }); + await stack.AddEnvironmentsAsync(new[] { "automation-api-test-env", "automation-api-test-env-2" }); + + var environments = await stack.ListEnvironmentsAsync(); + Assert.Equal(new string[]{"automation-api-test-env", "automation-api-test-env-2"}, environments); var config = await workspace.GetAllConfigAsync(stackName); Assert.Equal("test_value", config["node_env_test:new_key"].Value); Assert.Equal("business", config["node_env_test:also"].Value); - await workspace.RemoveEnvironmentAsync(stackName, "automation-api-test-env"); + await stack.RemoveEnvironmentAsync("automation-api-test-env"); + environments = await stack.ListEnvironmentsAsync(); + Assert.Equal(new string[]{"automation-api-test-env-2"}, environments); + config = await workspace.GetAllConfigAsync(stackName); Assert.Equal("business", config["node_env_test:also"].Value); Assert.False(config.ContainsKey("node_env_test:new_key")); diff --git a/sdk/Pulumi.Automation/LocalWorkspace.cs b/sdk/Pulumi.Automation/LocalWorkspace.cs index c5204217..66ef54c9 100644 --- a/sdk/Pulumi.Automation/LocalWorkspace.cs +++ b/sdk/Pulumi.Automation/LocalWorkspace.cs @@ -550,6 +550,14 @@ public override async Task AddEnvironmentsAsync(string stackName, IEnumerable + public override async Task ListEnvironmentsAsync(string stackName, CancellationToken cancellationToken = default) + { + CheckSupportsEnvironmentsListCommand(); + var result = await this.RunCommandAsync(new[] { "config", "env", "ls", "--stack", stackName, "--json" }, cancellationToken).ConfigureAwait(false); + return this._serializer.DeserializeJson(result.StandardOutput); + } + /// public override async Task RemoveEnvironmentAsync(string stackName, string environment, CancellationToken cancellationToken = default) { @@ -991,5 +999,16 @@ private void CheckSupportsEnvironmentsCommands() throw new InvalidOperationException("The Pulumi CLI version does not support env operations on a stack. Please update the Pulumi CLI."); } } + + private void CheckSupportsEnvironmentsListCommand() + { + var version = this._pulumiVersion ?? new SemVersion(3, 0); + + // 3.99 added this command (https://github.com/pulumi/pulumi/releases/tag/v3.99.0) + if (version < new SemVersion(3, 99)) + { + throw new InvalidOperationException("The Pulumi CLI version does not support env ls operations on a stack. Please update the Pulumi CLI."); + } + } } } diff --git a/sdk/Pulumi.Automation/Pulumi.Automation.xml b/sdk/Pulumi.Automation/Pulumi.Automation.xml index 9bdee7c5..261c2655 100644 --- a/sdk/Pulumi.Automation/Pulumi.Automation.xml +++ b/sdk/Pulumi.Automation/Pulumi.Automation.xml @@ -569,6 +569,9 @@ + + + @@ -1458,6 +1461,13 @@ List of environments to add to the end of the stack's import list. A cancellation token. + + + Returns the list of environments associated with the specified stack name + + The name of the stack. + A cancellation token. + Removes environments from a stack's import list. diff --git a/sdk/Pulumi.Automation/Workspace.cs b/sdk/Pulumi.Automation/Workspace.cs index 561a17a1..6e5409b8 100644 --- a/sdk/Pulumi.Automation/Workspace.cs +++ b/sdk/Pulumi.Automation/Workspace.cs @@ -133,6 +133,12 @@ internal Workspace(IPulumiCmd cmd) /// A cancellation token. public abstract Task AddEnvironmentsAsync(string stackName, IEnumerable environments, CancellationToken cancellationToken = default); + /// + /// Returns the list of environments associated with the specified stack name + /// + /// The name of the stack. + /// A cancellation token. + public abstract Task ListEnvironmentsAsync(string stackName, CancellationToken cancellationToken = default); /// /// Removes environments from a stack's import list. diff --git a/sdk/Pulumi.Automation/WorkspaceStack.cs b/sdk/Pulumi.Automation/WorkspaceStack.cs index 764d37e5..718d3ebc 100644 --- a/sdk/Pulumi.Automation/WorkspaceStack.cs +++ b/sdk/Pulumi.Automation/WorkspaceStack.cs @@ -285,6 +285,9 @@ public Task> RefreshConfigAsync(Cancell public Task AddEnvironmentsAsync(IEnumerable environments, CancellationToken cancellationToken = default) => this.Workspace.AddEnvironmentsAsync(this.Name, environments, cancellationToken); + public Task ListEnvironmentsAsync(CancellationToken cancellationToken = default) + => this.Workspace.ListEnvironmentsAsync(this.Name, cancellationToken); + /// /// Removes environments from a stack's import list. /// From 6ecf0ead18bc5aaa667f70f9a658fe75d4ec92d4 Mon Sep 17 00:00:00 2001 From: Cleve Littlefield Date: Tue, 23 Jan 2024 15:05:34 -0800 Subject: [PATCH 2/5] pr feedback --- .../LocalWorkspaceTests.cs | 6 ++---- sdk/Pulumi/Pulumi.xml | 18 +++++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs b/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs index e52bc255..13adada4 100644 --- a/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs +++ b/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs @@ -22,8 +22,6 @@ using ILogger = Microsoft.Extensions.Logging.ILogger; using static Pulumi.Automation.Tests.Utility; -using Xunit.Sdk; -using Castle.DynamicProxy.Generators; namespace Pulumi.Automation.Tests { @@ -167,7 +165,7 @@ public async Task AddAndRemoveEnvironment() await stack.AddEnvironmentsAsync(new[] { "automation-api-test-env", "automation-api-test-env-2" }); var environments = await stack.ListEnvironmentsAsync(); - Assert.Equal(new string[]{"automation-api-test-env", "automation-api-test-env-2"}, environments); + Assert.Equal(new string[]{ "automation-api-test-env", "automation-api-test-env-2" }, environments); var config = await workspace.GetAllConfigAsync(stackName); Assert.Equal("test_value", config["node_env_test:new_key"].Value); @@ -175,7 +173,7 @@ public async Task AddAndRemoveEnvironment() await stack.RemoveEnvironmentAsync("automation-api-test-env"); environments = await stack.ListEnvironmentsAsync(); - Assert.Equal(new string[]{"automation-api-test-env-2"}, environments); + Assert.Equal(new string[]{ "automation-api-test-env-2" }, environments); config = await workspace.GetAllConfigAsync(stackName); Assert.Equal("business", config["node_env_test:also"].Value); diff --git a/sdk/Pulumi/Pulumi.xml b/sdk/Pulumi/Pulumi.xml index 657e9bde..955f1ba7 100644 --- a/sdk/Pulumi/Pulumi.xml +++ b/sdk/Pulumi/Pulumi.xml @@ -3650,7 +3650,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. @@ -4039,7 +4039,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. @@ -4323,7 +4323,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. @@ -5319,7 +5319,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. @@ -7548,7 +7548,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. @@ -8207,7 +8207,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. @@ -8467,7 +8467,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. @@ -8594,7 +8594,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. @@ -8723,7 +8723,7 @@ An object implementing the server-side handling logic. - Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. + Register service method with a service binder with or without implementation. Useful when customizing the service binding logic. Note: this method is part of an experimental API that can change or be removed without any prior notice. Service methods will be bound by calling AddMethod on this object. An object implementing the server-side handling logic. From 8cde922dc0618a760f42175e412dfd28033c74ec Mon Sep 17 00:00:00 2001 From: Cleve Littlefield Date: Tue, 23 Jan 2024 15:09:07 -0800 Subject: [PATCH 3/5] Add changelog --- .changes/unreleased/Improvements-225.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/unreleased/Improvements-225.yaml diff --git a/.changes/unreleased/Improvements-225.yaml b/.changes/unreleased/Improvements-225.yaml new file mode 100644 index 00000000..7bdfbbf9 --- /dev/null +++ b/.changes/unreleased/Improvements-225.yaml @@ -0,0 +1,6 @@ +component: sdk +kind: Improvements +body: Add support for pulumi config env ls +time: 2024-01-23T15:08:21.991404636-08:00 +custom: + PR: "225" From 14a22725d1e1c098c337f32a10d9f1bf8cacfadf Mon Sep 17 00:00:00 2001 From: Cleve Littlefield Date: Tue, 23 Jan 2024 16:11:39 -0800 Subject: [PATCH 4/5] lint issues --- sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs b/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs index 13adada4..5c160bcb 100644 --- a/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs +++ b/sdk/Pulumi.Automation.Tests/LocalWorkspaceTests.cs @@ -165,7 +165,7 @@ public async Task AddAndRemoveEnvironment() await stack.AddEnvironmentsAsync(new[] { "automation-api-test-env", "automation-api-test-env-2" }); var environments = await stack.ListEnvironmentsAsync(); - Assert.Equal(new string[]{ "automation-api-test-env", "automation-api-test-env-2" }, environments); + Assert.Equal(new string[] { "automation-api-test-env", "automation-api-test-env-2" }, environments); var config = await workspace.GetAllConfigAsync(stackName); Assert.Equal("test_value", config["node_env_test:new_key"].Value); @@ -173,7 +173,7 @@ public async Task AddAndRemoveEnvironment() await stack.RemoveEnvironmentAsync("automation-api-test-env"); environments = await stack.ListEnvironmentsAsync(); - Assert.Equal(new string[]{ "automation-api-test-env-2" }, environments); + Assert.Equal(new string[] { "automation-api-test-env-2" }, environments); config = await workspace.GetAllConfigAsync(stackName); Assert.Equal("business", config["node_env_test:also"].Value); From e39a102e0ec6146212ed1104389b97a544462266 Mon Sep 17 00:00:00 2001 From: Cleve Littlefield Date: Wed, 24 Jan 2024 11:19:52 -0800 Subject: [PATCH 5/5] Change to ImmutableList --- sdk/Pulumi.Automation/LocalWorkspace.cs | 4 ++-- sdk/Pulumi.Automation/Workspace.cs | 2 +- sdk/Pulumi.Automation/WorkspaceStack.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/Pulumi.Automation/LocalWorkspace.cs b/sdk/Pulumi.Automation/LocalWorkspace.cs index 66ef54c9..fcbfc004 100644 --- a/sdk/Pulumi.Automation/LocalWorkspace.cs +++ b/sdk/Pulumi.Automation/LocalWorkspace.cs @@ -551,11 +551,11 @@ public override async Task AddEnvironmentsAsync(string stackName, IEnumerable - public override async Task ListEnvironmentsAsync(string stackName, CancellationToken cancellationToken = default) + public override async Task> ListEnvironmentsAsync(string stackName, CancellationToken cancellationToken = default) { CheckSupportsEnvironmentsListCommand(); var result = await this.RunCommandAsync(new[] { "config", "env", "ls", "--stack", stackName, "--json" }, cancellationToken).ConfigureAwait(false); - return this._serializer.DeserializeJson(result.StandardOutput); + return this._serializer.DeserializeJson(result.StandardOutput).ToImmutableList(); } /// diff --git a/sdk/Pulumi.Automation/Workspace.cs b/sdk/Pulumi.Automation/Workspace.cs index 6e5409b8..f8308050 100644 --- a/sdk/Pulumi.Automation/Workspace.cs +++ b/sdk/Pulumi.Automation/Workspace.cs @@ -138,7 +138,7 @@ internal Workspace(IPulumiCmd cmd) /// /// The name of the stack. /// A cancellation token. - public abstract Task ListEnvironmentsAsync(string stackName, CancellationToken cancellationToken = default); + public abstract Task> ListEnvironmentsAsync(string stackName, CancellationToken cancellationToken = default); /// /// Removes environments from a stack's import list. diff --git a/sdk/Pulumi.Automation/WorkspaceStack.cs b/sdk/Pulumi.Automation/WorkspaceStack.cs index 718d3ebc..cb8f32ec 100644 --- a/sdk/Pulumi.Automation/WorkspaceStack.cs +++ b/sdk/Pulumi.Automation/WorkspaceStack.cs @@ -285,7 +285,7 @@ public Task> RefreshConfigAsync(Cancell public Task AddEnvironmentsAsync(IEnumerable environments, CancellationToken cancellationToken = default) => this.Workspace.AddEnvironmentsAsync(this.Name, environments, cancellationToken); - public Task ListEnvironmentsAsync(CancellationToken cancellationToken = default) + public Task> ListEnvironmentsAsync(CancellationToken cancellationToken = default) => this.Workspace.ListEnvironmentsAsync(this.Name, cancellationToken); ///