[dotnet] Fix Resharper code issues (#7178)

* Fix resharper code issues for language usage opportunities

* Fix resharper code issues for common practices and code improvements

* Fix resharper code issues for potential code quality issues

* Fix resharper code issues for redundancies in code

* Fix xunit test output

* Update changelog

* Fix resharper code issues for compiler warnings

* Fix resharper code issues for inconsistent naming

* Add resharper solution settings file

* Fix resharper code issues for potential code quality issues

* Fix resharper code issues for redundancies in code

* Fix resharper code issues for redundancies in symbol declarations
This commit is contained in:
Sean Fausett 2021-06-11 02:32:33 +12:00 committed by GitHub
parent 3e170f6f80
commit 3530ba3205
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
110 changed files with 624 additions and 687 deletions

View file

@ -1,5 +1,7 @@
### Improvements
- [dotnet] Fix Resharper code issues.
[#7178](https://github.com/pulumi/pulumi/pull/7178)
- [codegen] - Include properties with an underlying type of string on Go provider instances.

View file

@ -80,8 +80,9 @@ namespace Pulumi.Automation.Tests
var program = PulumiFn.Create(() =>
{
hitSemaphore = true;
// ReSharper disable once AccessToDisposedClosure
semaphore.Wait();
return new Dictionary<string, object?>()
return new Dictionary<string, object?>
{
["test"] = "doesnt matter",
};

View file

@ -1,9 +1,9 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using System;
using Pulumi.Automation.Events;
using Xunit;
@ -37,12 +37,7 @@ namespace Pulumi.Automation.Tests
[Fact]
public async Task PropagatesUserExceptionsToCaller()
{
using var fx = new Fixture();
fx.Action = ev =>
{
throw new MyException();
};
using var fx = new Fixture { Action = ev => throw new MyException() };
await fx.Write("{}");
@ -62,7 +57,7 @@ namespace Pulumi.Automation.Tests
private class MyException : Exception { }
private class Fixture : IDisposable
private sealed class Fixture : IDisposable
{
public int EventCounter;
public string LogFileName { get; }

View file

@ -2,10 +2,10 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;
using Pulumi.Automation.Commands;
using System.Linq;
using System.Threading.Tasks;
using Pulumi.Automation.Commands;
using Xunit;
namespace Pulumi.Automation.Tests
{
@ -15,8 +15,8 @@ namespace Pulumi.Automation.Tests
public async Task CheckVersionCommand()
{
var localCmd = new LocalPulumiCmd();
IDictionary<string, string?> extraEnv = new Dictionary<string, string?>();
IEnumerable<string> args = new string[]{ "version" };
var extraEnv = new Dictionary<string, string?>();
var args = new[] { "version" };
var stdoutLines = new List<string>();
var stderrLines = new List<string>();

View file

@ -1,19 +1,20 @@
// Copyright 2016-2021, Pulumi Corporation
using Semver;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Pulumi.Automation.Exceptions;
using Microsoft.Extensions.DependencyInjection;
using Pulumi.Automation.Commands.Exceptions;
using Pulumi.Automation.Events;
using Pulumi.Automation.Exceptions;
using Semver;
using Xunit;
using System.Collections.Immutable;
using Microsoft.Extensions.DependencyInjection;
namespace Pulumi.Automation.Tests
{
@ -124,7 +125,7 @@ namespace Pulumi.Automation.Tests
using var workspace = await LocalWorkspace.CreateAsync(new LocalWorkspaceOptions
{
ProjectSettings = projectSettings,
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -144,7 +145,7 @@ namespace Pulumi.Automation.Tests
stacks = await workspace.ListStacksAsync();
var newStack = stacks.FirstOrDefault(s => s.Name == stackName);
Assert.NotNull(newStack);
Assert.True(newStack.IsCurrent);
Assert.True(newStack!.IsCurrent);
await workspace.SelectStackAsync(stackName);
await workspace.RemoveStackAsync(stackName);
@ -166,8 +167,6 @@ namespace Pulumi.Automation.Tests
ProjectSettings = projectSettings
});
StackDeployment deployment;
var stackName = $"{RandomStackName()}";
try
{
@ -178,7 +177,7 @@ namespace Pulumi.Automation.Tests
Assert.Equal(UpdateState.Succeeded, upResult.Summary.Result);
Assert.Equal(3, upResult.Outputs.Count);
deployment = await workspace.ExportStackAsync(stackName);
var deployment = await workspace.ExportStackAsync(stackName);
Assert.True(deployment.Version > 0);
var previewBeforeDestroy = await stack.PreviewAsync();
@ -214,7 +213,7 @@ namespace Pulumi.Automation.Tests
using var workspace = await LocalWorkspace.CreateAsync(new LocalWorkspaceOptions
{
ProjectSettings = projectSettings,
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -223,12 +222,6 @@ namespace Pulumi.Automation.Tests
var stackName = $"{RandomStackName()}";
var stack = await WorkspaceStack.CreateAsync(stackName, workspace);
var config = new Dictionary<string, ConfigValue>()
{
["plain"] = new ConfigValue("abc"),
["secret"] = new ConfigValue("def", isSecret: true),
};
var plainKey = NormalizeConfigKey("plain", projectName);
var secretKey = NormalizeConfigKey("secret", projectName);
@ -240,7 +233,13 @@ namespace Pulumi.Automation.Tests
var values = await stack.GetAllConfigAsync();
Assert.Empty(values);
var config = new Dictionary<string, ConfigValue>
{
["plain"] = new ConfigValue("abc"),
["secret"] = new ConfigValue("def", isSecret: true),
};
await stack.SetAllConfigAsync(config);
values = await stack.GetAllConfigAsync();
Assert.True(values.TryGetValue(plainKey, out var plainValue));
Assert.Equal("abc", plainValue!.Value);
@ -282,7 +281,7 @@ namespace Pulumi.Automation.Tests
using var workspace = await LocalWorkspace.CreateAsync(new LocalWorkspaceOptions
{
ProjectSettings = projectSettings,
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -320,7 +319,7 @@ namespace Pulumi.Automation.Tests
using var workspace = await LocalWorkspace.CreateAsync(new LocalWorkspaceOptions
{
ProjectSettings = projectSettings,
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -348,19 +347,19 @@ namespace Pulumi.Automation.Tests
var workingDir = ResourcePath(Path.Combine("Data", "testproj"));
using var stack = await LocalWorkspace.CreateStackAsync(new LocalProgramArgs(stackName, workingDir)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
});
var config = new Dictionary<string, ConfigValue>()
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
try
{
var config = new Dictionary<string, ConfigValue>
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
await stack.SetAllConfigAsync(config);
// pulumi up
@ -410,7 +409,7 @@ namespace Pulumi.Automation.Tests
{
var program = PulumiFn.Create(() =>
{
var config = new Pulumi.Config();
var config = new Config();
return new Dictionary<string, object?>
{
["exp_static"] = "foo",
@ -424,19 +423,19 @@ namespace Pulumi.Automation.Tests
var projectName = "inline_node";
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
});
var config = new Dictionary<string, ConfigValue>()
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
try
{
var config = new Dictionary<string, ConfigValue>
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
await stack.SetAllConfigAsync(config);
// pulumi up
@ -499,20 +498,19 @@ namespace Pulumi.Automation.Tests
var projectName = "inline_node";
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
});
var config = new Dictionary<string, ConfigValue>()
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
try
{
var config = new Dictionary<string, ConfigValue>
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
await stack.SetAllConfigAsync(config);
var initialOutputs = await stack.GetOutputsAsync();
@ -565,12 +563,10 @@ namespace Pulumi.Automation.Tests
public async Task StackReferenceDestroyDiscardsWithTwoInlinePrograms()
{
var programA = PulumiFn.Create(() =>
{
return new Dictionary<string, object?>
new Dictionary<string, object?>
{
["exp_static"] = "foo",
};
});
});
var programB = PulumiFn.Create(() =>
{
@ -588,7 +584,7 @@ namespace Pulumi.Automation.Tests
var stackA = await SetupStack(projectName, stackNameA, programA, new Dictionary<string, ConfigValue>());
var stackB = await SetupStack(projectName, stackNameB, programB, new Dictionary<string, ConfigValue>()
var stackB = await SetupStack(projectName, stackNameB, programB, new Dictionary<string, ConfigValue>
{
["Ref"] = new ConfigValue(FullyQualifiedStackName(_pulumiOrg, projectName, stackNameA)),
});
@ -645,7 +641,7 @@ namespace Pulumi.Automation.Tests
{
var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(project, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -661,18 +657,16 @@ namespace Pulumi.Automation.Tests
public async Task OutputStreamAndDelegateIsWritten()
{
var program = PulumiFn.Create(() =>
{
return new Dictionary<string, object?>
new Dictionary<string, object?>
{
["test"] = "test",
};
});
});
var stackName = $"{RandomStackName()}";
var projectName = "inline_output";
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -680,29 +674,27 @@ namespace Pulumi.Automation.Tests
try
{
var outputCalled = false;
// pulumi preview
outputCalled = false;
var previewResult = await stack.PreviewAsync(new PreviewOptions { OnStandardOutput = (str) => outputCalled = true });
var outputCalled = false;
var previewResult = await stack.PreviewAsync(new PreviewOptions { OnStandardOutput = str => outputCalled = true });
Assert.False(string.IsNullOrEmpty(previewResult.StandardOutput));
Assert.True(outputCalled);
// pulumi up
outputCalled = false;
var upResult = await stack.UpAsync(new UpOptions { OnStandardOutput = (str) => outputCalled = true });
var upResult = await stack.UpAsync(new UpOptions { OnStandardOutput = str => outputCalled = true });
Assert.False(string.IsNullOrEmpty(upResult.StandardOutput));
Assert.True(outputCalled);
// pulumi refresh
outputCalled = false;
var refreshResult = await stack.RefreshAsync(new RefreshOptions { OnStandardOutput = (str) => outputCalled = true });
var refreshResult = await stack.RefreshAsync(new RefreshOptions { OnStandardOutput = str => outputCalled = true });
Assert.False(string.IsNullOrEmpty(refreshResult.StandardOutput));
Assert.True(outputCalled);
// pulumi destroy
outputCalled = false;
var destroyResult = await stack.DestroyAsync(new DestroyOptions { OnStandardOutput = (str) => outputCalled = true });
var destroyResult = await stack.DestroyAsync(new DestroyOptions { OnStandardOutput = str => outputCalled = true });
Assert.False(string.IsNullOrEmpty(destroyResult.StandardOutput));
Assert.True(outputCalled);
}
@ -716,17 +708,15 @@ namespace Pulumi.Automation.Tests
public async Task HandlesEvents()
{
var program = PulumiFn.Create(() =>
{
return new Dictionary<string, object?>
new Dictionary<string, object?>
{
["exp_static"] = "foo",
};
});
});
var projectName = "event_test";
var stackName = $"inline_events{GetTestSuffix()}";
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -769,7 +759,7 @@ namespace Pulumi.Automation.Tests
{
var events = new List<EngineEvent>();
var result = await func(new TOptions() { OnEvent = events.Add }, CancellationToken.None);
var result = await func(new TOptions { OnEvent = events.Add }, CancellationToken.None);
var seenSummaryEvent = events.Any(@event => @event.SummaryEvent != null);
var seenCancelEvent = events.Any(@event => @event.CancelEvent != null);
@ -806,10 +796,10 @@ namespace Pulumi.Automation.Tests
config.GetSecretInt32("plainint3");
config.RequireSecretInt32("plainint4");
config.GetObject<System.Text.Json.JsonElement>("plainobj1");
config.RequireObject<System.Text.Json.JsonElement>("plainobj2");
config.GetSecretObject<System.Text.Json.JsonElement>("plainobj3");
config.RequireSecretObject<System.Text.Json.JsonElement>("plainobj4");
config.GetObject<JsonElement>("plainobj1");
config.RequireObject<JsonElement>("plainobj2");
config.GetSecretObject<JsonElement>("plainobj3");
config.RequireSecretObject<JsonElement>("plainobj4");
config.Get("str1");
config.Require("str2");
@ -826,59 +816,59 @@ namespace Pulumi.Automation.Tests
config.GetSecretInt32("int3");
config.RequireSecretInt32("int4");
config.GetObject<System.Text.Json.JsonElement>("obj1");
config.RequireObject<System.Text.Json.JsonElement>("obj2");
config.GetSecretObject<System.Text.Json.JsonElement>("obj3");
config.RequireSecretObject<System.Text.Json.JsonElement>("obj4");
config.GetObject<JsonElement>("obj1");
config.RequireObject<JsonElement>("obj2");
config.GetSecretObject<JsonElement>("obj3");
config.RequireSecretObject<JsonElement>("obj4");
});
var projectName = "inline_dotnet";
var stackName = $"inline_dotnet{GetTestSuffix()}";
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
});
var config = new Dictionary<string, ConfigValue>()
{
{ "plainstr1", new ConfigValue("1") },
{ "plainstr2", new ConfigValue("2") },
{ "plainstr3", new ConfigValue("3") },
{ "plainstr4", new ConfigValue("4") },
{ "plainbool1", new ConfigValue("true") },
{ "plainbool2", new ConfigValue("true") },
{ "plainbool3", new ConfigValue("true") },
{ "plainbool4", new ConfigValue("true") },
{ "plainint1", new ConfigValue("1") },
{ "plainint2", new ConfigValue("2") },
{ "plainint3", new ConfigValue("3") },
{ "plainint4", new ConfigValue("4") },
{ "plainobj1", new ConfigValue("{}") },
{ "plainobj2", new ConfigValue("{}") },
{ "plainobj3", new ConfigValue("{}") },
{ "plainobj4", new ConfigValue("{}") },
{ "str1", new ConfigValue("1", isSecret: true) },
{ "str2", new ConfigValue("2", isSecret: true) },
{ "str3", new ConfigValue("3", isSecret: true) },
{ "str4", new ConfigValue("4", isSecret: true) },
{ "bool1", new ConfigValue("true", isSecret: true) },
{ "bool2", new ConfigValue("true", isSecret: true) },
{ "bool3", new ConfigValue("true", isSecret: true) },
{ "bool4", new ConfigValue("true", isSecret: true) },
{ "int1", new ConfigValue("1", isSecret: true) },
{ "int2", new ConfigValue("2", isSecret: true) },
{ "int3", new ConfigValue("3", isSecret: true) },
{ "int4", new ConfigValue("4", isSecret: true) },
{ "obj1", new ConfigValue("{}", isSecret: true) },
{ "obj2", new ConfigValue("{}", isSecret: true) },
{ "obj3", new ConfigValue("{}", isSecret: true) },
{ "obj4", new ConfigValue("{}", isSecret: true) },
};
try
{
var config = new Dictionary<string, ConfigValue>
{
{ "plainstr1", new ConfigValue("1") },
{ "plainstr2", new ConfigValue("2") },
{ "plainstr3", new ConfigValue("3") },
{ "plainstr4", new ConfigValue("4") },
{ "plainbool1", new ConfigValue("true") },
{ "plainbool2", new ConfigValue("true") },
{ "plainbool3", new ConfigValue("true") },
{ "plainbool4", new ConfigValue("true") },
{ "plainint1", new ConfigValue("1") },
{ "plainint2", new ConfigValue("2") },
{ "plainint3", new ConfigValue("3") },
{ "plainint4", new ConfigValue("4") },
{ "plainobj1", new ConfigValue("{}") },
{ "plainobj2", new ConfigValue("{}") },
{ "plainobj3", new ConfigValue("{}") },
{ "plainobj4", new ConfigValue("{}") },
{ "str1", new ConfigValue("1", isSecret: true) },
{ "str2", new ConfigValue("2", isSecret: true) },
{ "str3", new ConfigValue("3", isSecret: true) },
{ "str4", new ConfigValue("4", isSecret: true) },
{ "bool1", new ConfigValue("true", isSecret: true) },
{ "bool2", new ConfigValue("true", isSecret: true) },
{ "bool3", new ConfigValue("true", isSecret: true) },
{ "bool4", new ConfigValue("true", isSecret: true) },
{ "int1", new ConfigValue("1", isSecret: true) },
{ "int2", new ConfigValue("2", isSecret: true) },
{ "int3", new ConfigValue("3", isSecret: true) },
{ "int4", new ConfigValue("4", isSecret: true) },
{ "obj1", new ConfigValue("{}", isSecret: true) },
{ "obj2", new ConfigValue("{}", isSecret: true) },
{ "obj3", new ConfigValue("{}", isSecret: true) },
{ "obj4", new ConfigValue("{}", isSecret: true) },
};
await stack.SetAllConfigAsync(config);
// pulumi preview
@ -895,7 +885,7 @@ namespace Pulumi.Automation.Tests
static async Task<T> RunCommand<T, TOptions>(Func<TOptions, CancellationToken, Task<T>> func, string command)
where TOptions : UpdateOptions, new()
{
var expectedWarnings = new string[]
var expectedWarnings = new[]
{
"Configuration 'inline_dotnet:str1' value is a secret; use `GetSecret` instead of `Get`",
"Configuration 'inline_dotnet:str2' value is a secret; use `RequireSecret` instead of `Require`",
@ -908,7 +898,7 @@ namespace Pulumi.Automation.Tests
};
// These keys should not be in any warning messages.
var unexpectedWarnings = new string[]
var unexpectedWarnings = new[]
{
"plainstr1",
"plainstr2",
@ -938,7 +928,7 @@ namespace Pulumi.Automation.Tests
var events = new List<DiagnosticEvent>();
var result = await func(new TOptions()
var result = await func(new TOptions
{
OnEvent = @event =>
{
@ -976,7 +966,7 @@ namespace Pulumi.Automation.Tests
public ValidStack()
{
var config = new Pulumi.Config();
var config = new Config();
this.ExpStatic = Output.Create("foo");
this.ExpConfig = Output.Create(config.Get("bar")!);
this.ExpSecret = config.GetSecret("buzz")!;
@ -993,19 +983,19 @@ namespace Pulumi.Automation.Tests
var projectName = "inline_tstack_node";
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
});
var config = new Dictionary<string, ConfigValue>()
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
try
{
var config = new Dictionary<string, ConfigValue>
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
await stack.SetAllConfigAsync(config);
// pulumi up
@ -1053,7 +1043,7 @@ namespace Pulumi.Automation.Tests
[Fact]
public async Task StackLifecycleInlineProgramWithServiceProvider()
{
using var provider = new ServiceCollection()
await using var provider = new ServiceCollection()
.AddTransient<ValidStack>() // must be transient so it is instantiated each time
.BuildServiceProvider();
@ -1064,19 +1054,19 @@ namespace Pulumi.Automation.Tests
var projectName = "inline_serviceprovider_node";
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
});
var config = new Dictionary<string, ConfigValue>()
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
try
{
var config = new Dictionary<string, ConfigValue>
{
["bar"] = new ConfigValue("abc"),
["buzz"] = new ConfigValue("secret", isSecret: true),
};
await stack.SetAllConfigAsync(config);
// pulumi up
@ -1131,7 +1121,7 @@ namespace Pulumi.Automation.Tests
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -1146,7 +1136,7 @@ namespace Pulumi.Automation.Tests
() => upTask);
}
private class FileNotFoundStack : Pulumi.Stack
private class FileNotFoundStack : Stack
{
public FileNotFoundStack()
{
@ -1164,7 +1154,7 @@ namespace Pulumi.Automation.Tests
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -1182,7 +1172,7 @@ namespace Pulumi.Automation.Tests
[Fact]
public async Task InlineProgramExceptionPropagatesToCallerWithServiceProvider()
{
using var provider = new ServiceCollection()
await using var provider = new ServiceCollection()
.AddTransient<FileNotFoundStack>() // must be transient so it is instantiated each time
.BuildServiceProvider();
@ -1193,7 +1183,7 @@ namespace Pulumi.Automation.Tests
using var stack = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectName, stackName, program)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -1225,10 +1215,11 @@ namespace Pulumi.Automation.Tests
// the semaphore because we want to alternately stutter
// programOne and programTwo so we can assert they aren't
// touching eachothers instances
var config = new Pulumi.Config();
var config = new Config();
Assert.Equal(projectNameOne, Deployment.Instance.ProjectName);
Assert.Equal(stackNameOne, Deployment.Instance.StackName);
hasReachedSemaphoreOne = true;
// ReSharper disable once AccessToDisposedClosure
semaphoreOne.Wait();
Assert.Equal(projectNameOne, Deployment.Instance.ProjectName);
Assert.Equal(stackNameOne, Deployment.Instance.StackName);
@ -1245,10 +1236,11 @@ namespace Pulumi.Automation.Tests
var programTwo = PulumiFn.Create(() =>
{
var config = new Pulumi.Config();
var config = new Config();
Assert.Equal(projectNameTwo, Deployment.Instance.ProjectName);
Assert.Equal(stackNameTwo, Deployment.Instance.StackName);
hasReachedSemaphoreTwo = true;
// ReSharper disable once AccessToDisposedClosure
semaphoreTwo.Wait();
Assert.Equal(projectNameTwo, Deployment.Instance.ProjectName);
Assert.Equal(stackNameTwo, Deployment.Instance.StackName);
@ -1262,7 +1254,7 @@ namespace Pulumi.Automation.Tests
using var stackOne = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectNameOne, stackNameOne, programOne)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
@ -1270,19 +1262,19 @@ namespace Pulumi.Automation.Tests
using var stackTwo = await LocalWorkspace.CreateStackAsync(new InlineProgramArgs(projectNameTwo, stackNameTwo, programTwo)
{
EnvironmentVariables = new Dictionary<string, string?>()
EnvironmentVariables = new Dictionary<string, string?>
{
["PULUMI_CONFIG_PASSPHRASE"] = "test",
}
});
await stackOne.SetAllConfigAsync(new Dictionary<string, ConfigValue>()
await stackOne.SetAllConfigAsync(new Dictionary<string, ConfigValue>
{
["bar"] = new ConfigValue("1"),
["buzz"] = new ConfigValue("1", isSecret: true),
});
await stackTwo.SetAllConfigAsync(new Dictionary<string, ConfigValue>()
await stackTwo.SetAllConfigAsync(new Dictionary<string, ConfigValue>
{
["bar"] = new ConfigValue("2"),
["buzz"] = new ConfigValue("2", isSecret: true),
@ -1295,7 +1287,7 @@ namespace Pulumi.Automation.Tests
await Task.Delay(TimeSpan.FromSeconds(2));
if (upTaskOne.IsFaulted)
throw upTaskOne.Exception!;
else if (upTaskOne.IsCompleted)
if (upTaskOne.IsCompleted)
throw new Exception("Never hit semaphore in first UP task.");
}
@ -1306,7 +1298,7 @@ namespace Pulumi.Automation.Tests
await Task.Delay(TimeSpan.FromSeconds(2));
if (upTaskTwo.IsFaulted)
throw upTaskTwo.Exception!;
else if (upTaskTwo.IsCompleted)
if (upTaskTwo.IsCompleted)
throw new Exception("Never hit semaphore in second UP task.");
}
@ -1370,7 +1362,7 @@ namespace Pulumi.Automation.Tests
try
{
Task.WaitAll(new Task[] { destroyTask, cancelTask });
Task.WaitAll(destroyTask, cancelTask);
}
catch (AggregateException)
{
@ -1422,8 +1414,8 @@ namespace Pulumi.Automation.Tests
var testMinVersion = SemVersion.Parse("2.21.1");
if (errorExpected)
{
Action act = () => LocalWorkspace.ValidatePulumiVersion(testMinVersion, currentVersion, optOut);
Assert.Throws<InvalidOperationException>(act);
void ValidatePulumiVersion() => LocalWorkspace.ValidatePulumiVersion(testMinVersion, currentVersion, optOut);
Assert.Throws<InvalidOperationException>(ValidatePulumiVersion);
}
else
{

View file

@ -8,7 +8,7 @@ namespace Pulumi.Automation.Tests.Serialization
{
public class DynamicObjectTests
{
private static LocalSerializer _serializer = new LocalSerializer();
private static readonly LocalSerializer _serializer = new LocalSerializer();
[Fact]
public void Dynamic_With_YamlDotNet()

View file

@ -9,7 +9,7 @@ namespace Pulumi.Automation.Tests.Serialization
{
public class GeneralJsonConverterTests
{
private static LocalSerializer _serializer = new LocalSerializer();
private static readonly LocalSerializer _serializer = new LocalSerializer();
[Fact]
public void CanDeserializeConfigValue()

View file

@ -1,15 +1,21 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
using System.Text.Json;
using Pulumi.Automation.Serialization;
using Xunit;
using Xunit.Abstractions;
namespace Pulumi.Automation.Tests.Serialization
{
public class ProjectRuntimeJsonConverterTests
{
private static LocalSerializer _serializer = new LocalSerializer();
private readonly ITestOutputHelper _output;
private static readonly LocalSerializer _serializer = new LocalSerializer();
public ProjectRuntimeJsonConverterTests(ITestOutputHelper output)
{
_output = output;
}
[Theory]
[InlineData(ProjectRuntimeName.NodeJS)]
@ -71,7 +77,7 @@ namespace Pulumi.Automation.Tests.Serialization
var runtime = new ProjectRuntime(ProjectRuntimeName.Dotnet);
var json = _serializer.SerializeJson(runtime);
Console.WriteLine(json);
_output.WriteLine(json);
using var document = JsonDocument.Parse(json);
Assert.NotNull(document);
@ -91,7 +97,7 @@ namespace Pulumi.Automation.Tests.Serialization
};
var json = _serializer.SerializeJson(runtime);
Console.WriteLine(json);
_output.WriteLine(json);
using var document = JsonDocument.Parse(json);
Assert.NotNull(document);

View file

@ -4,12 +4,19 @@ using System;
using System.Text;
using Pulumi.Automation.Serialization;
using Xunit;
using Xunit.Abstractions;
namespace Pulumi.Automation.Tests.Serialization
{
public class ProjectRuntimeYamlConverterTests
{
private static LocalSerializer _serializer = new LocalSerializer();
private readonly ITestOutputHelper _output;
private static readonly LocalSerializer _serializer = new LocalSerializer();
public ProjectRuntimeYamlConverterTests(ITestOutputHelper output)
{
_output = output;
}
[Theory]
[InlineData(ProjectRuntimeName.NodeJS)]
@ -67,7 +74,7 @@ runtime:
var runtime = new ProjectRuntime(ProjectRuntimeName.Dotnet);
var yaml = _serializer.SerializeYaml(runtime);
Console.WriteLine(yaml);
_output.WriteLine(yaml);
Assert.Equal("dotnet" + Environment.NewLine, yaml);
}
@ -84,7 +91,7 @@ runtime:
};
var yaml = _serializer.SerializeYaml(runtime);
Console.WriteLine(yaml);
_output.WriteLine(yaml);
var expected = new StringBuilder();
expected.AppendLine("name: dotnet");

View file

@ -9,7 +9,7 @@ namespace Pulumi.Automation.Tests.Serialization
{
public class StackSettingsConfigValueJsonConverterTests
{
private static LocalSerializer _serializer = new LocalSerializer();
private static readonly LocalSerializer _serializer = new LocalSerializer();
[Fact]
public void CanDeserializePlainString()
@ -23,7 +23,7 @@ namespace Pulumi.Automation.Tests.Serialization
";
var settings = _serializer.DeserializeJson<StackSettings>(json);
Assert.NotNull(settings?.Config);
Assert.NotNull(settings.Config);
Assert.True(settings!.Config!.ContainsKey("test"));
var value = settings.Config["test"];
@ -46,7 +46,7 @@ namespace Pulumi.Automation.Tests.Serialization
";
var settings = _serializer.DeserializeJson<StackSettings>(json);
Assert.NotNull(settings?.Config);
Assert.NotNull(settings.Config);
Assert.True(settings!.Config!.ContainsKey("test"));
var value = settings.Config["test"];

View file

@ -9,7 +9,7 @@ namespace Pulumi.Automation.Tests.Serialization
{
public class StackSettingsConfigValueYamlConverterTests
{
private static LocalSerializer _serializer = new LocalSerializer();
private static readonly LocalSerializer _serializer = new LocalSerializer();
[Fact]
public void CanDeserializePlainString()
@ -20,7 +20,7 @@ config:
";
var settings = _serializer.DeserializeYaml<StackSettings>(yaml);
Assert.NotNull(settings?.Config);
Assert.NotNull(settings.Config);
Assert.True(settings!.Config!.ContainsKey("test"));
var value = settings.Config["test"];
@ -39,7 +39,7 @@ config:
";
var settings = _serializer.DeserializeYaml<StackSettings>(yaml);
Assert.NotNull(settings?.Config);
Assert.NotNull(settings.Config);
Assert.True(settings!.Config!.ContainsKey("test"));
var value = settings.Config["test"];

View file

@ -5,18 +5,18 @@ using System.Collections.Generic;
namespace Pulumi.Automation.Collections
{
/// Compares two dictionaries for equality by content, as F# maps would.
internal sealed class DictionaryContentsComparer<K, V> : IEqualityComparer<IDictionary<K, V>> where K : notnull
internal sealed class DictionaryContentsComparer<TKey, TValue> : IEqualityComparer<IDictionary<TKey, TValue>> where TKey : notnull
{
private readonly IEqualityComparer<K> _keyComparer;
private readonly IEqualityComparer<V> _valueComparer;
private readonly IEqualityComparer<TKey> _keyComparer;
private readonly IEqualityComparer<TValue> _valueComparer;
public DictionaryContentsComparer(IEqualityComparer<K> keyComparer, IEqualityComparer<V> valueComparer)
public DictionaryContentsComparer(IEqualityComparer<TKey> keyComparer, IEqualityComparer<TValue> valueComparer)
{
this._keyComparer = keyComparer;
this._valueComparer = valueComparer;
}
bool IEqualityComparer<IDictionary<K, V>>.Equals(IDictionary<K, V>? x, IDictionary<K, V>? y)
bool IEqualityComparer<IDictionary<TKey, TValue>>.Equals(IDictionary<TKey, TValue>? x, IDictionary<TKey, TValue>? y)
{
if (x == null)
{
@ -24,7 +24,7 @@ namespace Pulumi.Automation.Collections
}
if (y == null)
{
return x == null;
return false;
}
if (ReferenceEquals(x, y))
{
@ -34,7 +34,7 @@ namespace Pulumi.Automation.Collections
{
return false;
}
var y2 = new Dictionary<K, V>(y, this._keyComparer);
var y2 = new Dictionary<TKey, TValue>(y, this._keyComparer);
foreach (var pair in x)
{
if (!y2.ContainsKey(pair.Key))
@ -50,7 +50,7 @@ namespace Pulumi.Automation.Collections
return true;
}
int IEqualityComparer<IDictionary<K, V>>.GetHashCode(IDictionary<K, V> obj)
int IEqualityComparer<IDictionary<TKey, TValue>>.GetHashCode(IDictionary<TKey, TValue> obj)
{
return 0; // inefficient but correct
}

View file

@ -20,14 +20,14 @@ namespace Pulumi.Automation.Commands.Exceptions
this.Name = name;
}
private static readonly Regex NotFoundRegexPattern = new Regex("no stack named.*found");
private static readonly Regex AlreadyExistsRegexPattern = new Regex("stack.*already exists");
private static readonly string ConflictText = "[409] Conflict: Another update is currently in progress.";
private static readonly Regex _notFoundRegexPattern = new Regex("no stack named.*found");
private static readonly Regex _alreadyExistsRegexPattern = new Regex("stack.*already exists");
private static readonly string _conflictText = "[409] Conflict: Another update is currently in progress.";
internal static CommandException CreateFromResult(CommandResult result)
=> NotFoundRegexPattern.IsMatch(result.StandardError) ? new StackNotFoundException(result)
: AlreadyExistsRegexPattern.IsMatch(result.StandardError) ? new StackAlreadyExistsException(result)
: result.StandardError?.IndexOf(ConflictText) >= 0 ? new ConcurrentUpdateException(result)
=> _notFoundRegexPattern.IsMatch(result.StandardError) ? new StackNotFoundException(result)
: _alreadyExistsRegexPattern.IsMatch(result.StandardError) ? new StackAlreadyExistsException(result)
: result.StandardError.IndexOf(_conflictText, StringComparison.Ordinal) >= 0 ? new ConcurrentUpdateException(result)
: new CommandException(result);
}
}

View file

@ -11,7 +11,7 @@ namespace Pulumi.Automation.Commands
internal interface IPulumiCmd
{
Task<CommandResult> RunAsync(
IEnumerable<string> args,
IList<string> args,
string workingDir,
IDictionary<string, string?> additionalEnv,
Action<string>? onStandardOutput = null,

View file

@ -9,7 +9,6 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using CliWrap;
using Pulumi.Automation.Commands.Exceptions;
using Pulumi.Automation.Events;
@ -20,7 +19,7 @@ namespace Pulumi.Automation.Commands
{
public async Task<CommandResult> RunAsync(
IEnumerable<string> args,
IList<string> args,
string workingDir,
IDictionary<string, string?> additionalEnv,
Action<string>? onStandardOutput = null,
@ -40,14 +39,11 @@ namespace Pulumi.Automation.Commands
await eventLogWatcher.Stop();
}
}
else
{
return await RunAsyncInner(args, workingDir, additionalEnv, onStandardOutput, onStandardError, eventLogFile: null, cancellationToken);
}
return await RunAsyncInner(args, workingDir, additionalEnv, onStandardOutput, onStandardError, eventLogFile: null, cancellationToken);
}
private async Task<CommandResult> RunAsyncInner(
IEnumerable<string> args,
IList<string> args,
string workingDir,
IDictionary<string, string?> additionalEnv,
Action<string>? onStandardOutput = null,
@ -88,10 +84,7 @@ namespace Pulumi.Automation.Commands
{
throw CommandException.CreateFromResult(result);
}
else
{
return result;
}
return result;
}
private static IReadOnlyDictionary<string, string?> PulumiEnvironment(IDictionary<string, string?> additionalEnv, bool debugCommands)
@ -108,18 +101,18 @@ namespace Pulumi.Automation.Commands
return env;
}
private static IEnumerable<string> PulumiArgs(IEnumerable<string> args, EventLogFile? eventLogFile)
private static IList<string> PulumiArgs(IList<string> args, EventLogFile? eventLogFile)
{
// all commands should be run in non-interactive mode.
// this causes commands to fail rather than prompting for input (and thus hanging indefinitely)
if (!args.Contains("--non-interactive"))
{
args = args.Concat(new[] { "--non-interactive" });
args = args.Concat(new[] { "--non-interactive" }).ToList();
}
if (eventLogFile != null)
{
args = args.Concat(new[] { "--event-log", eventLogFile.FilePath });
args = args.Concat(new[] { "--event-log", eventLogFile.FilePath }).ToList();
}
return args;
@ -132,15 +125,12 @@ namespace Pulumi.Automation.Commands
{
return "event-log";
}
else
{
return alphaNumWord.IsMatch(firstArgument) ? firstArgument : "event-log";
}
return alphaNumWord.IsMatch(firstArgument) ? firstArgument : "event-log";
}
private class EventLogFile : IDisposable
private sealed class EventLogFile : IDisposable
{
private bool _disposedValue;
public string FilePath { get; }
public EventLogFile(string command)
{
@ -149,37 +139,21 @@ namespace Pulumi.Automation.Commands
this.FilePath = Path.Combine(logDir, "eventlog.txt");
}
public string FilePath { get; }
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
var dir = Path.GetDirectoryName(this.FilePath);
try
{
Directory.Delete(dir, recursive: true);
}
catch (Exception e)
{
// allow graceful exit if for some reason
// we're not able to delete the directory
// will rely on OS to clean temp directory
// in this case.
Trace.TraceWarning("Ignoring exception during cleanup of {0} folder: {1}", dir, e);
}
}
_disposedValue = true;
}
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
var dir = Path.GetDirectoryName(this.FilePath);
try
{
Directory.Delete(dir, recursive: true);
}
catch (Exception e)
{
// allow graceful exit if for some reason
// we're not able to delete the directory
// will rely on OS to clean temp directory
// in this case.
Trace.TraceWarning("Ignoring exception during cleanup of {0} folder: {1}", dir, e);
}
}
}
}

View file

@ -1,7 +1,5 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
namespace Pulumi.Automation
{
/// <summary>

View file

@ -8,14 +8,14 @@ using Pulumi.Automation.Serialization;
namespace Pulumi.Automation.Events
{
internal class EventLogWatcher : IDisposable
internal sealed class EventLogWatcher : IDisposable
{
private readonly LocalSerializer _localSerializer = new LocalSerializer();
private readonly Action<EngineEvent> _onEvent;
private const int _pollingIntervalMilliseconds = 100;
// We keep track of the last position in the file.
private long _position = 0;
private long _position;
public string LogFile { get; }
private readonly Task _pollingTask;
private readonly CancellationTokenSource _internalCancellationTokenSource = new CancellationTokenSource();
@ -82,6 +82,7 @@ namespace Pulumi.Automation.Events
await ReadEventsOnce();
await Task.Delay(_pollingIntervalMilliseconds, linkedSource.Token);
}
// ReSharper disable once FunctionNeverReturns
}
private async Task ReadEventsOnce()
@ -91,15 +92,11 @@ namespace Pulumi.Automation.Events
return;
}
using var fs = new FileStream(LogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
{
Position = this._position
};
await using var fs = new FileStream(LogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) { Position = this._position };
using var reader = new StreamReader(fs);
string? line;
while (reader.Peek() >= 0)
{
line = await reader.ReadLineAsync();
var line = await reader.ReadLineAsync();
this._position = fs.Position;
if (!string.IsNullOrWhiteSpace(line))
{

View file

@ -1,10 +1,12 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Events;
namespace Pulumi.Automation.Exceptions
{
public sealed class NoSummaryEventException : MissingExpectedEventException
{
internal NoSummaryEventException(string? message) : base(nameof(Events.SummaryEvent), message)
internal NoSummaryEventException(string? message) : base(nameof(SummaryEvent), message)
{
}
}

View file

@ -1,16 +1,16 @@
// Copyright 2016-2021, Pulumi Corporation
using Semver;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Pulumi.Automation.Commands;
using Pulumi.Automation.Exceptions;
using Pulumi.Automation.Serialization;
using Semver;
namespace Pulumi.Automation
{
@ -43,9 +43,9 @@ namespace Pulumi.Automation
/// <inheritdoc/>
public override string? PulumiHome { get; }
private SemVersion? pulumiVersion;
private SemVersion? _pulumiVersion;
/// <inheritdoc/>
public override string PulumiVersion => pulumiVersion?.ToString() ?? throw new InvalidOperationException("Failed to get Pulumi version.");
public override string PulumiVersion => _pulumiVersion?.ToString() ?? throw new InvalidOperationException("Failed to get Pulumi version.");
/// <inheritdoc/>
public override string? SecretsProvider { get; }
@ -358,11 +358,11 @@ namespace Pulumi.Automation
!ProjectSettings.Comparer.Equals(projectSettings, existingSettings))
{
var path = this.FindSettingsFile();
throw new Exceptions.ProjectSettingsConflictException(path);
throw new ProjectSettingsConflictException(path);
}
}
private static readonly string[] SettingsExtensions = new string[] { ".yaml", ".yml", ".json" };
private static readonly string[] _settingsExtensions = { ".yaml", ".yml", ".json" };
private async Task PopulatePulumiVersionAsync(CancellationToken cancellationToken)
{
@ -376,8 +376,8 @@ namespace Pulumi.Automation
var skipVersionCheckVar = "PULUMI_AUTOMATION_API_SKIP_VERSION_CHECK";
var hasSkipEnvVar = this.EnvironmentVariables?.ContainsKey(skipVersionCheckVar) ?? false;
var optOut = hasSkipEnvVar || Environment.GetEnvironmentVariable(skipVersionCheckVar) != null;
LocalWorkspace.ValidatePulumiVersion(LocalWorkspace._minimumVersion, version, optOut);
this.pulumiVersion = version;
ValidatePulumiVersion(_minimumVersion, version, optOut);
this._pulumiVersion = version;
}
internal static void ValidatePulumiVersion(SemVersion minVersion, SemVersion currentVersion, bool optOut)
@ -410,12 +410,8 @@ namespace Pulumi.Automation
{
return this._serializer.DeserializeJson<ProjectSettings>(content);
}
else
{
var model = this._serializer.DeserializeYaml<ProjectSettingsModel>(content);
return model.Convert();
}
var model = this._serializer.DeserializeYaml<ProjectSettingsModel>(content);
return model.Convert();
}
/// <inheritdoc/>
@ -429,7 +425,7 @@ namespace Pulumi.Automation
private string FindSettingsFile()
{
foreach (var ext in SettingsExtensions)
foreach (var ext in _settingsExtensions)
{
var testPath = Path.Combine(this.WorkDir, $"Pulumi{ext}");
if (File.Exists(testPath))
@ -455,7 +451,7 @@ namespace Pulumi.Automation
{
var settingsName = GetStackSettingsName(stackName);
foreach (var ext in SettingsExtensions)
foreach (var ext in _settingsExtensions)
{
var isJson = ext == ".json";
var path = Path.Combine(this.WorkDir, $"Pulumi.{settingsName}{ext}");
@ -475,7 +471,7 @@ namespace Pulumi.Automation
var settingsName = GetStackSettingsName(stackName);
var foundExt = ".yaml";
foreach (var ext in SettingsExtensions)
foreach (var ext in _settingsExtensions)
{
var testPath = Path.Combine(this.WorkDir, $"Pulumi.{settingsName}{ext}");
if (File.Exists(testPath))
@ -567,7 +563,7 @@ namespace Pulumi.Automation
/// <inheritdoc/>
public override Task CreateStackAsync(string stackName, CancellationToken cancellationToken)
{
var args = new List<string>()
var args = new List<string>
{
"stack",
"init",
@ -614,7 +610,7 @@ namespace Pulumi.Automation
var tempFileName = Path.GetTempFileName();
try
{
File.WriteAllText(tempFileName, state.Json.GetRawText());
await File.WriteAllTextAsync(tempFileName, state.Json.GetRawText(), cancellationToken);
await this.RunCommandAsync(new[] { "stack", "import", "--file", tempFileName, "--stack", stackName },
cancellationToken).ConfigureAwait(false);
}
@ -631,7 +627,7 @@ namespace Pulumi.Automation
/// <inheritdoc/>
public override Task RemovePluginAsync(string? name = null, string? versionRange = null, PluginKind kind = PluginKind.Resource, CancellationToken cancellationToken = default)
{
var args = new List<string>()
var args = new List<string>
{
"plugin",
"rm",

View file

@ -25,7 +25,7 @@ namespace Pulumi.Automation
if (y == null)
{
return x == null;
return false;
}
if (ReferenceEquals(x, y))

View file

@ -32,7 +32,7 @@ namespace Pulumi.Automation
if (y == null)
{
return x == null;
return false;
}
if (ReferenceEquals(x, y))

View file

@ -7,6 +7,7 @@ namespace Pulumi.Automation
/// </summary>
public enum ProjectRuntimeName
{
// ReSharper disable once InconsistentNaming
NodeJS,
Go,
Python,

View file

@ -46,7 +46,7 @@ namespace Pulumi.Automation
if (y == null)
{
return x == null;
return false;
}
if (ReferenceEquals(x, y))

View file

@ -48,17 +48,14 @@ namespace Pulumi.Automation
{
}
internal static ProjectSettings Default(string name) {
var defaultSettings = new ProjectSettings(name, new ProjectRuntime(ProjectRuntimeName.Dotnet));
defaultSettings.Main = Directory.GetCurrentDirectory();
return defaultSettings;
}
internal static ProjectSettings Default(string name) =>
new ProjectSettings(name, new ProjectRuntime(ProjectRuntimeName.Dotnet)) { Main = Directory.GetCurrentDirectory() };
internal bool IsDefault
{
get
{
return ProjectSettings.Comparer.Equals(this, ProjectSettings.Default(this.Name));
return Comparer.Equals(this, Default(this.Name));
}
}
@ -73,7 +70,7 @@ namespace Pulumi.Automation
if (y == null)
{
return x == null;
return false;
}
if (ReferenceEquals(x, y))

View file

@ -24,7 +24,7 @@ namespace Pulumi.Automation
private sealed class ProjectTemplateComparer : IEqualityComparer<ProjectTemplate>
{
private IEqualityComparer<IDictionary<string, ProjectTemplateConfigValue>> _configComparer =
private readonly IEqualityComparer<IDictionary<string, ProjectTemplateConfigValue>> _configComparer =
new DictionaryContentsComparer<string, ProjectTemplateConfigValue>(
EqualityComparer<string>.Default,
ProjectTemplateConfigValue.Comparer);
@ -38,7 +38,7 @@ namespace Pulumi.Automation
if (y == null)
{
return x == null;
return false;
}
if (ReferenceEquals(x, y))

View file

@ -29,7 +29,7 @@ namespace Pulumi.Automation
if (y == null)
{
return x == null;
return false;
}
if (ReferenceEquals(x, y))

View file

@ -1,6 +1,5 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
using System.Collections.Generic;
using System.Runtime.ExceptionServices;

View file

@ -23,7 +23,7 @@ namespace Pulumi.Automation
if (stackType is null)
throw new ArgumentNullException(nameof(stackType));
var pulumiStackType = typeof(Pulumi.Stack);
var pulumiStackType = typeof(Stack);
if (!pulumiStackType.IsAssignableFrom(stackType) || pulumiStackType == stackType)
throw new ArgumentException($"Provided stack type must derive from {pulumiStackType.FullName}.", nameof(stackType));
@ -42,7 +42,7 @@ namespace Pulumi.Automation
if (this._serviceProvider is null)
throw new ArgumentNullException(nameof(this._serviceProvider), $"The provided service provider was null by the time this {nameof(PulumiFn)} was invoked.");
return this._serviceProvider.GetService(this._stackType) as Pulumi.Stack
return this._serviceProvider.GetService(this._stackType) as Stack
?? throw new ApplicationException(
$"Failed to resolve instance of type {this._stackType.FullName} from service provider. Register the type with the service provider before this {nameof(PulumiFn)} is invoked.");
}

View file

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace Pulumi.Automation
{
internal class PulumiFn<TStack> : PulumiFn where TStack : Pulumi.Stack
internal class PulumiFn<TStack> : PulumiFn where TStack : Stack
{
private readonly Func<TStack> _stackFactory;

View file

@ -40,13 +40,13 @@ namespace Pulumi.Automation
/// <param name="program">An asynchronous pulumi program that takes in a <see cref="CancellationToken"/>.</param>
public static PulumiFn Create(Func<CancellationToken, Task> program)
{
Func<CancellationToken, Task<IDictionary<string, object?>>> wrapper = async cancellationToken =>
async Task<IDictionary<string, object?>> Wrapper(CancellationToken cancellationToken)
{
await program(cancellationToken).ConfigureAwait(false);
return ImmutableDictionary<string, object?>.Empty;
};
}
return new PulumiFnInline(wrapper);
return new PulumiFnInline(Wrapper);
}
/// <summary>
@ -55,13 +55,13 @@ namespace Pulumi.Automation
/// <param name="program">An asynchronous pulumi program.</param>
public static PulumiFn Create(Func<Task> program)
{
Func<CancellationToken, Task<IDictionary<string, object?>>> wrapper = async cancellationToken =>
async Task<IDictionary<string, object?>> Wrapper(CancellationToken cancellationToken)
{
await program().ConfigureAwait(false);
return ImmutableDictionary<string, object?>.Empty;
};
}
return new PulumiFnInline(wrapper);
return new PulumiFnInline(Wrapper);
}
/// <summary>
@ -70,13 +70,13 @@ namespace Pulumi.Automation
/// <param name="program">A pulumi program that returns an output.</param>
public static PulumiFn Create(Func<IDictionary<string, object?>> program)
{
Func<CancellationToken, Task<IDictionary<string, object?>>> wrapper = cancellationToken =>
Task<IDictionary<string, object?>> Wrapper(CancellationToken cancellationToken)
{
var output = program();
return Task.FromResult(output);
};
}
return new PulumiFnInline(wrapper);
return new PulumiFnInline(Wrapper);
}
/// <summary>
@ -91,7 +91,7 @@ namespace Pulumi.Automation
/// </summary>
/// <typeparam name="TStack">The <see cref="Pulumi.Stack"/> type.</typeparam>
public static PulumiFn Create<TStack>()
where TStack : Pulumi.Stack, new()
where TStack : Stack, new()
=> new PulumiFn<TStack>(() => new TStack());
/// <summary>
@ -104,7 +104,7 @@ namespace Pulumi.Automation
/// <typeparam name="TStack">The <see cref="Pulumi.Stack"/> type.</typeparam>
/// <param name="serviceProvider">The service provider that will be used to resolve an instance of <typeparamref name="TStack"/>.</param>
public static PulumiFn Create<TStack>(IServiceProvider serviceProvider)
where TStack : Pulumi.Stack
where TStack : Stack
=> new PulumiFnServiceProvider(serviceProvider, typeof(TStack));
/// <summary>

View file

@ -1,7 +1,5 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
namespace Pulumi.Automation
{
/// <summary>

View file

@ -1,7 +1,5 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;
@ -56,6 +54,7 @@ namespace Pulumi.Automation
this._callerContext.ExceptionDispatchInfo = await Deployment.RunInlineAsync(
settings,
// ReSharper disable once AccessToDisposedClosure
runner => this._callerContext.Program.InvokeAsync(runner, cts.Token))
.ConfigureAwait(false);

View file

@ -1,7 +1,7 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,7 +1,7 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -23,7 +23,7 @@ namespace Pulumi.Automation.Serialization.Json
if (reader.TokenType == JsonTokenType.Number)
{
if (reader.TryGetInt64(out long l))
if (reader.TryGetInt64(out var l))
{
return l;
}
@ -33,7 +33,7 @@ namespace Pulumi.Automation.Serialization.Json
if (reader.TokenType == JsonTokenType.String)
{
if (reader.TryGetDateTime(out DateTime datetime))
if (reader.TryGetDateTime(out var datetime))
{
return datetime;
}

View file

@ -1,7 +1,7 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,8 +1,8 @@
// Copyright 2016-2021, Pulumi Corporation
using System.Collections.Generic;
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,7 +1,7 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,7 +1,7 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,7 +1,7 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,7 +1,7 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,7 +1,7 @@
// Copyright 2016-2021, Pulumi Corporation
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,9 +1,9 @@
// Copyright 2016-2021, Pulumi Corporation
using System.Collections.Generic;
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using System.Linq;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,8 +1,8 @@
// Copyright 2016-2021, Pulumi Corporation
using System.Collections.Generic;
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go

View file

@ -1,8 +1,8 @@
// Copyright 2016-2021, Pulumi Corporation
using System.Collections.Generic;
using Pulumi.Automation.Serialization.Json;
using Pulumi.Automation.Events;
using Pulumi.Automation.Serialization.Json;
// NOTE: The classes in this file are intended to align with the serialized
// JSON types defined and versioned in sdk/go/common/apitype/events.go
@ -22,7 +22,9 @@ namespace Pulumi.Automation.Serialization
new SummaryEvent(
this.MaybeCorrupt,
this.DurationSeconds,
// ReSharper disable once ConstantNullCoalescingCondition
this.ResourceChanges ?? new Dictionary<OperationType, int>(),
// ReSharper disable once ConstantNullCoalescingCondition
this.PolicyPacks ?? new Dictionary<string, string>());
}
}

View file

@ -11,9 +11,9 @@ namespace Pulumi.Automation.Serialization.Yaml
{
internal class ProjectRuntimeOptionsYamlConverter : IYamlTypeConverter
{
private static readonly Type Type = typeof(ProjectRuntimeOptions);
private static readonly List<string> PropertyNames = typeof(ProjectRuntimeOptions).GetProperties().Select(x => x.Name).ToList();
private static readonly Dictionary<string, Func<Scalar, string, Type, object?>> Readers =
private static readonly Type _type = typeof(ProjectRuntimeOptions);
private static readonly List<string> _propertyNames = typeof(ProjectRuntimeOptions).GetProperties().Select(x => x.Name).ToList();
private static readonly Dictionary<string, Func<Scalar, string, Type, object?>> _readers =
new Dictionary<string, Func<Scalar, string, Type, object?>>(StringComparer.OrdinalIgnoreCase)
{
[nameof(ProjectRuntimeOptions.Binary)] = (x, p, t) => x.Value,
@ -21,22 +21,21 @@ namespace Pulumi.Automation.Serialization.Yaml
[nameof(ProjectRuntimeOptions.VirtualEnv)] = (x, p, t) => x.Value,
};
public bool Accepts(Type type)
=> type == Type;
public bool Accepts(Type type) => type == _type;
public object? ReadYaml(IParser parser, Type type)
public object ReadYaml(IParser parser, Type type)
{
if (!parser.TryConsume<MappingStart>(out _))
throw new YamlException($"Unable to deserialize [{type.FullName}]. Expecting object.");
var values = PropertyNames.ToDictionary(x => x, x => (object?)null, StringComparer.OrdinalIgnoreCase);
var values = _propertyNames.ToDictionary(x => x, x => (object?)null, StringComparer.OrdinalIgnoreCase);
do
{
if (!parser.TryConsume<Scalar>(out var propertyNameScalar))
throw new YamlException($"Unable to deserialize [{type.FullName}]. Expecting a property name.");
if (!Readers.TryGetValue(propertyNameScalar.Value, out var readerFunc))
if (!_readers.TryGetValue(propertyNameScalar.Value, out var readerFunc))
throw new YamlException($"Unable to deserialize [{type.FullName}]. Invalid property [{propertyNameScalar.Value}].");
if (!parser.TryConsume<Scalar>(out var propertyValueScalar))

View file

@ -9,15 +9,14 @@ namespace Pulumi.Automation.Serialization.Yaml
{
internal class ProjectRuntimeYamlConverter : IYamlTypeConverter
{
private static readonly Type Type = typeof(ProjectRuntime);
private static readonly Type OptionsType = typeof(ProjectRuntimeOptions);
private static readonly Type _type = typeof(ProjectRuntime);
private static readonly Type _optionsType = typeof(ProjectRuntimeOptions);
private readonly IYamlTypeConverter _optionsConverter = new ProjectRuntimeOptionsYamlConverter();
public bool Accepts(Type type)
=> type == Type;
public bool Accepts(Type type) => type == _type;
public object? ReadYaml(IParser parser, Type type)
public object ReadYaml(IParser parser, Type type)
{
if (parser.TryConsume<Scalar>(out var nameValueScalar))
{
@ -51,7 +50,7 @@ namespace Pulumi.Automation.Serialization.Yaml
if (!parser.Accept<MappingStart>(out _))
throw new YamlException($"Unable to deserialize [{type.FullName}]. Runtime options property should be an object.");
var runtimeOptionsObj = this._optionsConverter.ReadYaml(parser, OptionsType);
var runtimeOptionsObj = this._optionsConverter.ReadYaml(parser, _optionsType);
if (!(runtimeOptionsObj is ProjectRuntimeOptions runtimeOptions))
throw new YamlException("There was an issue deserializing the runtime options object.");
@ -87,7 +86,7 @@ namespace Pulumi.Automation.Serialization.Yaml
emitter.Emit(new Scalar(runtime.Name.ToString().ToLower()));
emitter.Emit(new Scalar("options"));
this._optionsConverter.WriteYaml(emitter, runtime.Options, OptionsType);
this._optionsConverter.WriteYaml(emitter, runtime.Options, _optionsType);
emitter.Emit(new MappingEnd());
}

View file

@ -9,12 +9,11 @@ namespace Pulumi.Automation.Serialization.Yaml
{
internal class StackSettingsConfigValueYamlConverter : IYamlTypeConverter
{
private static readonly Type Type = typeof(StackSettingsConfigValue);
private static readonly Type _type = typeof(StackSettingsConfigValue);
public bool Accepts(Type type)
=> type == Type;
public bool Accepts(Type type) => type == _type;
public object? ReadYaml(IParser parser, Type type)
public object ReadYaml(IParser parser, Type type)
{
// check if plain string
if (parser.Accept<Scalar>(out var stringValue))
@ -43,10 +42,7 @@ namespace Pulumi.Automation.Serialization.Yaml
parser.MoveNext();
return new StackSettingsConfigValue(securePropertyValue.Value, true);
}
else
{
throw new NotSupportedException("Automation API does not currently support deserializing complex objects from stack settings.");
}
throw new NotSupportedException("Automation API does not currently support deserializing complex objects from stack settings.");
}
public void WriteYaml(IEmitter emitter, object? value, Type type)

View file

@ -1,6 +1,8 @@
// Copyright 2016-2021, Pulumi Corporation
using System.Collections.Generic;
using System.Text.Json.Serialization;
using YamlDotNet.Serialization;
namespace Pulumi.Automation
{
@ -9,8 +11,8 @@ namespace Pulumi.Automation
/// <summary>
/// This stack's secrets provider.
/// </summary>
[YamlDotNet.Serialization.YamlMember(Alias="secretsprovider")]
[System.Text.Json.Serialization.JsonPropertyName("secretsprovider")]
[YamlMember(Alias="secretsprovider")]
[JsonPropertyName("secretsprovider")]
public string? SecretsProvider { get; set; }
@ -18,8 +20,8 @@ namespace Pulumi.Automation
/// This is the KMS-encrypted ciphertext for the data key used for secrets
/// encryption. Only used for cloud-based secrets providers.
/// </summary>
[YamlDotNet.Serialization.YamlMember(Alias="encryptedkey")]
[System.Text.Json.Serialization.JsonPropertyName("encryptedkey")]
[YamlMember(Alias="encryptedkey")]
[JsonPropertyName("encryptedkey")]
public string? EncryptedKey { get; set; }
@ -27,8 +29,8 @@ namespace Pulumi.Automation
/// This is this stack's base64 encoded encryption salt. Only used for
/// passphrase-based secrets providers.
/// </summary>
[YamlDotNet.Serialization.YamlMember(Alias="encryptionsalt")]
[System.Text.Json.Serialization.JsonPropertyName("encryptionsalt")]
[YamlMember(Alias="encryptionsalt")]
[JsonPropertyName("encryptionsalt")]
public string? EncryptionSalt { get; set; }

View file

@ -9,6 +9,8 @@ using System.Threading.Tasks;
using Pulumi.Automation.Commands;
using Pulumi.Automation.Commands.Exceptions;
using Pulumi.Automation.Events;
// ReSharper disable UnusedMemberInSuper.Global
// ReSharper disable VirtualMemberNeverOverridden.Global
namespace Pulumi.Automation
{
@ -276,7 +278,7 @@ namespace Pulumi.Automation
internal async Task<CommandResult> RunStackCommandAsync(
string stackName,
IEnumerable<string> args,
IList<string> args,
Action<string>? onStandardOutput,
Action<string>? onStandardError,
Action<EngineEvent>? onEngineEvent,
@ -291,12 +293,12 @@ namespace Pulumi.Automation
}
internal Task<CommandResult> RunCommandAsync(
IEnumerable<string> args,
IList<string> args,
CancellationToken cancellationToken)
=> this.RunCommandAsync(args, onStandardOutput: null, onStandardError: null, onEngineEvent: null, cancellationToken);
internal Task<CommandResult> RunCommandAsync(
IEnumerable<string> args,
IList<string> args,
Action<string>? onStandardOutput,
Action<string>? onStandardError,
Action<EngineEvent>? onEngineEvent,

View file

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.ExceptionServices;
@ -117,30 +116,23 @@ namespace Pulumi.Automation
this.Name = name;
this.Workspace = workspace;
switch (mode)
this._readyTask = mode switch
{
case WorkspaceStackInitMode.Create:
this._readyTask = workspace.CreateStackAsync(name, cancellationToken);
break;
case WorkspaceStackInitMode.Select:
this._readyTask = workspace.SelectStackAsync(name, cancellationToken);
break;
case WorkspaceStackInitMode.CreateOrSelect:
this._readyTask = Task.Run(async () =>
WorkspaceStackInitMode.Create => workspace.CreateStackAsync(name, cancellationToken),
WorkspaceStackInitMode.Select => workspace.SelectStackAsync(name, cancellationToken),
WorkspaceStackInitMode.CreateOrSelect => Task.Run(async () =>
{
try
{
try
{
await workspace.CreateStackAsync(name, cancellationToken).ConfigureAwait(false);
}
catch (StackAlreadyExistsException)
{
await workspace.SelectStackAsync(name, cancellationToken).ConfigureAwait(false);
}
});
break;
default:
throw new InvalidOperationException($"Unexpected Stack creation mode: {mode}");
}
await workspace.CreateStackAsync(name, cancellationToken).ConfigureAwait(false);
}
catch (StackAlreadyExistsException)
{
await workspace.SelectStackAsync(name, cancellationToken).ConfigureAwait(false);
}
}),
_ => throw new InvalidOperationException($"Unexpected Stack creation mode: {mode}")
};
}
/// <summary>
@ -211,7 +203,7 @@ namespace Pulumi.Automation
{
var execKind = ExecKind.Local;
var program = this.Workspace.Program;
var args = new List<string>()
var args = new List<string>
{
"up",
"--yes",
@ -313,7 +305,7 @@ namespace Pulumi.Automation
{
var execKind = ExecKind.Local;
var program = this.Workspace.Program;
var args = new List<string>() { "preview" };
var args = new List<string> { "preview" };
if (options != null)
{
@ -423,7 +415,7 @@ namespace Pulumi.Automation
RefreshOptions? options = null,
CancellationToken cancellationToken = default)
{
var args = new List<string>()
var args = new List<string>
{
"refresh",
"--yes",
@ -478,7 +470,7 @@ namespace Pulumi.Automation
DestroyOptions? options = null,
CancellationToken cancellationToken = default)
{
var args = new List<string>()
var args = new List<string>
{
"destroy",
"--yes",
@ -539,7 +531,7 @@ namespace Pulumi.Automation
HistoryOptions? options = null,
CancellationToken cancellationToken = default)
{
var args = new List<string>()
var args = new List<string>
{
"stack",
"history",
@ -616,14 +608,13 @@ namespace Pulumi.Automation
}
private async Task<CommandResult> RunCommandAsync(
IEnumerable<string> args,
IList<string> args,
Action<string>? onStandardOutput,
Action<string>? onStandardError,
Action<EngineEvent>? onEngineEvent,
CancellationToken cancellationToken)
{
var argsList = args.ToList();
argsList.AddRange(new List<string>() { "--stack", this.Name });
args = args.Concat(new[] { "--stack", this.Name }).ToList();
return await this.Workspace.RunStackCommandAsync(this.Name, args, onStandardOutput, onStandardError, onEngineEvent, cancellationToken);
}

View file

@ -1,11 +1,7 @@
// Copyright 2016-2019, Pulumi Corporation
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Pulumi.Serialization;
using Xunit;
namespace Pulumi.Tests.Core
@ -16,14 +12,18 @@ namespace Pulumi.Tests.Core
public Task MergeInputMaps()
=> RunInPreview(async () =>
{
var map1 = new InputMap<string>();
map1.Add("K1", "V1");
map1.Add("K2", Output.Create("V2"));
map1.Add("K3", Output.Create("V3_wrong"));
var map1 = new InputMap<string>
{
{ "K1", "V1" },
{ "K2", Output.Create("V2") },
{ "K3", Output.Create("V3_wrong") }
};
var map2 = new InputMap<string>();
map2.Add("K3", Output.Create("V3"));
map2.Add("K4", "V4");
var map2 = new InputMap<string>
{
{ "K3", Output.Create("V3") },
{ "K4", "V4" }
};
var result = InputMap<string>.Merge(map1, map2);
@ -31,7 +31,7 @@ namespace Pulumi.Tests.Core
var data = await result.ToOutput().DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.Equal(4, data.Value.Count);
for (int i = 1; i <=4; i++)
for (var i = 1; i <=4; i++)
Assert.True(data.Value.Contains($"K{i}", $"V{i}"));
// Check that the input maps haven't changed

View file

@ -8,7 +8,7 @@ using Xunit;
namespace Pulumi.Tests.Core
{
public partial class OutputTests : PulumiTest
public class OutputTests : PulumiTest
{
private static Output<T> CreateOutput<T>(T value, bool isKnown, bool isSecret = false)
=> new Output<T>(Task.FromResult(OutputData.Create(

View file

@ -2,7 +2,6 @@
using System.Collections.Immutable;
using System.Threading.Tasks;
using Pulumi.Serialization;
using Xunit;
namespace Pulumi.Tests.Core
@ -17,7 +16,8 @@ namespace Pulumi.Tests.Core
[Input("array")] private InputList<bool> _array = null!;
public InputList<bool> Array
{
get => _array ?? (_array = new InputList<bool>());
// ReSharper disable once ConstantNullCoalescingCondition
get => _array ??= new InputList<bool>();
set => _array = value;
}
}
@ -90,14 +90,16 @@ namespace Pulumi.Tests.Core
[Input("array", json: true)] private InputList<bool> _array = null!;
public InputList<bool> Array
{
get => _array ?? (_array = new InputList<bool>());
// ReSharper disable once ConstantNullCoalescingCondition
get => _array ??= new InputList<bool>();
set => _array = value;
}
[Input("map", json: true)] private InputMap<int> _map = null!;
public InputMap<int> Map
{
get => _map ?? (_map = new InputMap<int>());
// ReSharper disable once ConstantNullCoalescingCondition
get => _map ??= new InputMap<int>();
set => _map = value;
}
}

View file

@ -17,23 +17,16 @@ namespace Pulumi.Tests.Mocks
return Task.FromResult<object>(args);
}
public Task<(string? id, object state)> NewResourceAsync(MockResourceArgs args)
{
switch (args.Type)
public Task<(string? id, object state)> NewResourceAsync(MockResourceArgs args) =>
args.Type switch
{
case "aws:ec2/instance:Instance":
return Task.FromResult<(string?, object)>(("i-1234567890abcdef0", new Dictionary<string, object> {
{ "publicIp", "203.0.113.12" },
}));
case "pkg:index:MyCustom":
return Task.FromResult<(string?, object)>((args.Name + "_id", args.Inputs));
default:
throw new Exception($"Unknown resource {args.Type}");
}
}
"aws:ec2/instance:Instance" => Task.FromResult<(string?, object)>(("i-1234567890abcdef0", new Dictionary<string, object> { { "publicIp", "203.0.113.12" }, })),
"pkg:index:MyCustom" => Task.FromResult<(string?, object)>((args.Name + "_id", args.Inputs)),
_ => throw new Exception($"Unknown resource {args.Type}")
};
}
public partial class MocksTests
public class MocksTests
{
[Fact]
public async Task TestCustom()
@ -43,7 +36,7 @@ namespace Pulumi.Tests.Mocks
var instance = resources.OfType<Instance>().FirstOrDefault();
Assert.NotNull(instance);
var ip = await instance.PublicIp.GetValueAsync();
var ip = await instance!.PublicIp.GetValueAsync();
Assert.Equal("203.0.113.12", ip);
}
@ -52,10 +45,10 @@ namespace Pulumi.Tests.Mocks
{
var resources = await Testing.RunAsync<MyStack>();
var mycustom = resources.OfType<MyCustom>().FirstOrDefault();
Assert.NotNull(mycustom);
var myCustom = resources.OfType<MyCustom>().FirstOrDefault();
Assert.NotNull(myCustom);
var instance = await mycustom.Instance.GetValueAsync();
var instance = await myCustom!.Instance.GetValueAsync();
Assert.IsType<Instance>(instance);
var ip = await instance.PublicIp.GetValueAsync();
@ -70,7 +63,7 @@ namespace Pulumi.Tests.Mocks
var stack = resources.OfType<MyStack>().FirstOrDefault();
Assert.NotNull(stack);
var ip = await stack.PublicIp.GetValueAsync();
var ip = await stack!.PublicIp.GetValueAsync();
Assert.Equal("203.0.113.12", ip);
}
}

View file

@ -3,33 +3,33 @@
namespace Pulumi.Tests.Mocks
{
[ResourceType("aws:ec2/instance:Instance", null)]
public partial class Instance : Pulumi.CustomResource
public class Instance : CustomResource
{
[Output("publicIp")]
public Output<string> PublicIp { get; private set; } = null!;
public Instance(string name, InstanceArgs args, CustomResourceOptions? options = null)
: base("aws:ec2/instance:Instance", name, args ?? new InstanceArgs(), options)
: base("aws:ec2/instance:Instance", name, args, options)
{
}
}
public sealed class InstanceArgs : Pulumi.ResourceArgs
public sealed class InstanceArgs : ResourceArgs
{
}
public partial class MyCustom : Pulumi.CustomResource
public class MyCustom : CustomResource
{
[Output("instance")]
public Output<Instance> Instance { get; private set; } = null!;
public MyCustom(string name, MyCustomArgs args, CustomResourceOptions? options = null)
: base("pkg:index:MyCustom", name, args ?? new MyCustomArgs(), options)
: base("pkg:index:MyCustom", name, args, options)
{
}
}
public sealed class MyCustomArgs : Pulumi.ResourceArgs
public sealed class MyCustomArgs : ResourceArgs
{
[Input("instance")]
public Input<Instance>? Instance { get; set; }
@ -38,15 +38,12 @@ namespace Pulumi.Tests.Mocks
public class MyStack : Stack
{
[Output("publicIp")]
public Output<string> PublicIp { get; private set; } = null!;
public Output<string> PublicIp { get; private set; }
public MyStack()
{
var myInstance = new Instance("instance", new InstanceArgs());
var myCustom = new MyCustom("mycustom", new MyCustomArgs
{
Instance = myInstance,
});
new MyCustom("mycustom", new MyCustomArgs { Instance = myInstance });
this.PublicIp = myInstance.PublicIp;
}
}

View file

@ -52,7 +52,7 @@ namespace Pulumi.Tests.Serialization
{
Assert.Throws<InvalidOperationException>(() =>
{
var data = Converter.ConvertValue<bool>("", new Value { StringValue = "" });
Converter.ConvertValue<bool>("", new Value { StringValue = "" });
});
}
@ -94,7 +94,7 @@ namespace Pulumi.Tests.Serialization
{
Assert.Throws<InvalidOperationException>(() =>
{
var data = Converter.ConvertValue<bool>("", new Value { StringValue = "" });
Converter.ConvertValue<bool>("", new Value { StringValue = "" });
});
}

View file

@ -35,7 +35,7 @@ namespace Pulumi.Tests.Serialization
public override bool Equals(object? obj) => obj is ContainerColor other && Equals(other);
public bool Equals(ContainerColor other) => string.Equals(_value, other._value, StringComparison.Ordinal);
public override int GetHashCode() => _value?.GetHashCode() ?? 0;
public override int GetHashCode() => _value.GetHashCode();
public override string ToString() => _value;
}

View file

@ -3,9 +3,12 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Pulumi.Serialization;
using Xunit;
using Type = System.Type;
namespace Pulumi.Tests.Serialization
{
@ -35,7 +38,7 @@ namespace Pulumi.Tests.Serialization
public bool Equals(ContainerColor other) => string.Equals(_value, other._value, StringComparison.Ordinal);
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => _value?.GetHashCode() ?? 0;
public override int GetHashCode() => _value.GetHashCode();
public override string ToString() => _value;
}
@ -60,12 +63,13 @@ namespace Pulumi.Tests.Serialization
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object? obj) => obj is ContainerBrightness other && Equals(other);
// ReSharper disable once CompareOfFloatsByEqualityOperator
public bool Equals(ContainerBrightness other) => _value == other._value;
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => _value.GetHashCode();
public override string ToString() => _value.ToString();
public override string ToString() => _value.ToString(CultureInfo.InvariantCulture);
}
public enum ContainerSize
@ -196,14 +200,14 @@ namespace Pulumi.Tests.Serialization
public static IEnumerable<object[]> EnumsWithUnconvertibleValues()
=> new[]
{
new object[] { typeof(ContainerColor), new Google.Protobuf.WellKnownTypes.Value { NumberValue = 1.0 } },
new object[] { typeof(ContainerBrightness), new Google.Protobuf.WellKnownTypes.Value { StringValue = "hello" } },
new object[] { typeof(ContainerSize), new Google.Protobuf.WellKnownTypes.Value { StringValue = "hello" } },
new object[] { typeof(ContainerColor), new Value { NumberValue = 1.0 } },
new object[] { typeof(ContainerBrightness), new Value { StringValue = "hello" } },
new object[] { typeof(ContainerSize), new Value { StringValue = "hello" } },
};
[Theory]
[MemberData(nameof(EnumsWithUnconvertibleValues))]
public void ConvertingUnconvertibleValuesThrows(Type targetType, Google.Protobuf.WellKnownTypes.Value value)
public void ConvertingUnconvertibleValuesThrows(Type targetType, Value value)
{
Assert.Throws<InvalidOperationException>(() =>
{

View file

@ -1,9 +1,6 @@
// Copyright 2016-2019, Pulumi Corporation
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Pulumi.Serialization;
using Xunit;

View file

@ -14,7 +14,7 @@ namespace Pulumi.Tests.Serialization
{
public class ResourceRefPropertyTests : ConverterTests
{
public sealed class MyArgs : Pulumi.ResourceArgs
public sealed class MyArgs : ResourceArgs
{
}
@ -52,18 +52,18 @@ namespace Pulumi.Tests.Serialization
{
public MyStack()
{
var customResource = new MyCustomResource("test", null, null);
var componentResource = new MyComponentResource("test", null, null);
new MyCustomResource("test", null);
new MyComponentResource("test", null);
}
}
class MyMocks : IMocks
{
bool isPreview;
private readonly bool _isPreview;
public MyMocks(bool isPreview)
{
this.isPreview = isPreview;
this._isPreview = isPreview;
}
public Task<object> CallAsync(MockCallArgs args)
@ -77,10 +77,10 @@ namespace Pulumi.Tests.Serialization
{
case "test:index:resource":
case "test:missing:resource":
return Task.FromResult<(string?, object)>((this.isPreview ? null : "id", new Dictionary<string, object> {}));
return Task.FromResult<(string?, object)>((this._isPreview ? null : "id", new Dictionary<string, object>()));
case "test:index:component":
case "test:missing:component":
return Task.FromResult<(string?, object)>((null, new Dictionary<string, object> {}));
return Task.FromResult<(string?, object)>((null, new Dictionary<string, object>()));
default:
throw new Exception($"Unknown resource {args.Type}");
}
@ -129,7 +129,7 @@ namespace Pulumi.Tests.Serialization
var res = resources.OfType<MyCustomResource>().FirstOrDefault();
Assert.NotNull(res);
var urn = (await res.Urn.DataTask).Value;
var urn = (await res!.Urn.DataTask).Value;
var id = (await res.Id.DataTask).Value;
var v = await SerializeToValueAsync(res);
@ -145,7 +145,7 @@ namespace Pulumi.Tests.Serialization
var res = resources.OfType<MyCustomResource>().FirstOrDefault();
Assert.NotNull(res);
var id = await SerializeToValueAsync(res.Id);
var id = await SerializeToValueAsync(res!.Id);
var v = await SerializeToValueAsync(res, false);
Assert.Equal(id, v);
@ -154,11 +154,11 @@ namespace Pulumi.Tests.Serialization
public class DeserializeCustomResourceStack : Stack
{
[Output("values")]
public Output<ImmutableDictionary<string, string>> Values { get; private set; } = null!;
public Output<ImmutableDictionary<string, string>> Values { get; private set; }
public DeserializeCustomResourceStack()
{
var res = new MyCustomResource("test", null, null);
var res = new MyCustomResource("test", null);
var urn = res.Urn.DataTask.Result.Value;
var id = res.Id.DataTask.Result.Value;
@ -184,7 +184,7 @@ namespace Pulumi.Tests.Serialization
var stack = resources.OfType<DeserializeCustomResourceStack>().FirstOrDefault();
Assert.NotNull(stack);
var values = (await stack.Values.DataTask).Value;
var values = (await stack!.Values.DataTask).Value;
Assert.Equal(values["expectedUrn"], values["actualUrn"]);
Assert.Equal(values["expectedId"], values["actualId"]);
}
@ -192,11 +192,11 @@ namespace Pulumi.Tests.Serialization
public class DeserializeMissingCustomResourceStack : Stack
{
[Output("values")]
public Output<ImmutableDictionary<string, string>> Values { get; private set; } = null!;
public Output<ImmutableDictionary<string, string>> Values { get; private set; }
public DeserializeMissingCustomResourceStack()
{
var res = new MissingCustomResource("test", null, null);
var res = new MissingCustomResource("test", null);
var urn = res.Urn.DataTask.Result.Value;
@ -219,7 +219,7 @@ namespace Pulumi.Tests.Serialization
var stack = resources.OfType<DeserializeMissingCustomResourceStack>().FirstOrDefault();
Assert.NotNull(stack);
var values = (await stack.Values.DataTask).Value;
var values = (await stack!.Values.DataTask).Value;
Assert.Equal(values["expectedUrn"], values["actualUrn"]);
}
@ -232,7 +232,7 @@ namespace Pulumi.Tests.Serialization
var res = resources.OfType<MyComponentResource>().FirstOrDefault();
Assert.NotNull(res);
var urn = (await res.Urn.DataTask).Value;
var urn = (await res!.Urn.DataTask).Value;
var v = await SerializeToValueAsync(res);
Assert.Equal(CreateComponentResourceReference(urn), v);
@ -247,7 +247,7 @@ namespace Pulumi.Tests.Serialization
var res = resources.OfType<MyComponentResource>().FirstOrDefault();
Assert.NotNull(res);
var urn = await SerializeToValueAsync(res.Urn);
var urn = await SerializeToValueAsync(res!.Urn);
var v = await SerializeToValueAsync(res, false);
Assert.Equal(urn, v);
@ -256,11 +256,11 @@ namespace Pulumi.Tests.Serialization
public class DeserializeComponentResourceStack : Stack
{
[Output("values")]
public Output<ImmutableDictionary<string, string>> Values { get; private set; } = null!;
public Output<ImmutableDictionary<string, string>> Values { get; private set; }
public DeserializeComponentResourceStack()
{
var res = new MyComponentResource("test", null, null);
var res = new MyComponentResource("test", null);
var urn = res.Urn.DataTask.Result.Value;
@ -283,18 +283,18 @@ namespace Pulumi.Tests.Serialization
var stack = resources.OfType<DeserializeComponentResourceStack>().FirstOrDefault();
Assert.NotNull(stack);
var values = (await stack.Values.DataTask).Value;
var values = (await stack!.Values.DataTask).Value;
Assert.Equal(values["expectedUrn"], values["actualUrn"]);
}
public class DeserializeMissingComponentResourceStack : Stack
{
[Output("values")]
public Output<ImmutableDictionary<string, string>> Values { get; private set; } = null!;
public Output<ImmutableDictionary<string, string>> Values { get; private set; }
public DeserializeMissingComponentResourceStack()
{
var res = new MissingComponentResource("test", null, null);
var res = new MissingComponentResource("test", null);
var urn = res.Urn.DataTask.Result.Value;
@ -317,7 +317,7 @@ namespace Pulumi.Tests.Serialization
var stack = resources.OfType<DeserializeMissingComponentResourceStack>().FirstOrDefault();
Assert.NotNull(stack);
var values = (await stack.Values.DataTask).Value;
var values = (await stack!.Values.DataTask).Value;
Assert.Equal(values["expectedUrn"], values["actualUrn"]);
}
}

View file

@ -50,7 +50,7 @@ namespace Pulumi.Tests.Serialization
{
Assert.Throws<InvalidOperationException>(() =>
{
var data = Converter.ConvertValue<Union<int, string>>("", new Value { BoolValue = true });
Converter.ConvertValue<Union<int, string>>("", new Value { BoolValue = true });
});
}
}

View file

@ -38,7 +38,7 @@ namespace Pulumi.Tests
private class NullOutputStack : Stack
{
[Output("foo")]
public Output<string>? Foo { get; }
public Output<string>? Foo { get; } = null;
}
[Fact]
@ -46,7 +46,7 @@ namespace Pulumi.Tests
{
try
{
var (stack, outputs) = await Run<NullOutputStack>();
await Run<NullOutputStack>();
}
catch (RunException ex)
{
@ -73,7 +73,7 @@ namespace Pulumi.Tests
{
try
{
var (stack, outputs) = await Run<InvalidOutputTypeStack>();
await Run<InvalidOutputTypeStack>();
}
catch (RunException ex)
{

View file

@ -1,7 +1,6 @@
// Copyright 2016-2019, Pulumi Corporation
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text.Json;
@ -32,14 +31,10 @@ namespace Pulumi
/// </summary>
public Config(string? name = null)
{
if (name == null)
{
name = Deployment.Instance.ProjectName;
}
name ??= Deployment.Instance.ProjectName;
if (name.EndsWith(":config", StringComparison.Ordinal))
{
name = name[0..^":config".Length];
name = name[..^":config".Length];
}
_name = name;
@ -84,9 +79,13 @@ namespace Pulumi
private bool? GetBooleanImpl(string key, string? use = null, [CallerMemberName] string? insteadOf = null)
{
var v = GetImpl(key, use, insteadOf);
return v == null ? default(bool?) :
v == "true" ? true :
v == "false" ? false : throw new ConfigTypeException(FullKey(key), v, nameof(Boolean));
return v switch
{
null => default(bool?),
"true" => true,
"false" => false,
_ => throw new ConfigTypeException(FullKey(key), v, nameof(Boolean))
};
}
/// <summary>
@ -155,8 +154,7 @@ namespace Pulumi
/// <summary>
/// Loads an optional configuration value, as an object, by its key, marking it as a secret
/// or null if it doesn't exist. This works by taking the value associated with <paramref
/// name="key"/> and passing it to <see cref="JsonSerializer.Deserialize{TValue}(string,
/// JsonSerializerOptions)"/>.
/// name="key"/> and passing it to <see cref="JsonSerializer.Deserialize{TValue}(string, JsonSerializerOptions)"/>.
/// </summary>
public Output<T>? GetSecretObject<T>(string key)
{
@ -238,8 +236,8 @@ namespace Pulumi
/// <summary>
/// Loads a configuration value as a JSON string and deserializes the JSON into a JavaScript
/// object, marking it as a secret. If it doesn't exist, or the configuration value cannot
/// be converted using <see cref="JsonSerializer.Deserialize{TValue}(string,
/// JsonSerializerOptions)"/>. an error is thrown.
/// be converted using <see cref="JsonSerializer.Deserialize{TValue}(string, JsonSerializerOptions)"/>,
/// an error is thrown.
/// </summary>
public Output<T> RequireSecretObject<T>(string key)
=> Output.CreateSecret(RequireObjectImpl<T>(key));

View file

@ -11,12 +11,7 @@ namespace Pulumi
/// </summary>
private class ConfigTypeException : RunException
{
public ConfigTypeException(string key, object? v, string expectedType)
: this(key, v, expectedType, innerException: null)
{
}
public ConfigTypeException(string key, object? v, string expectedType, Exception? innerException)
public ConfigTypeException(string key, object? v, string expectedType, Exception? innerException = null)
: base($"Configuration '{key}' value '{v}' is not a valid {expectedType}", innerException)
{
}

View file

@ -1,5 +1,7 @@
// Copyright 2016-2019, Pulumi Corporation
using System;
namespace Pulumi
{
/// <summary>
@ -13,9 +15,9 @@ namespace Pulumi
private protected AssetOrArchive(string sigKey, string propName, object value)
{
SigKey = sigKey ?? throw new System.ArgumentNullException(nameof(sigKey));
PropName = propName ?? throw new System.ArgumentNullException(nameof(propName));
Value = value ?? throw new System.ArgumentNullException(nameof(value));
SigKey = sigKey ?? throw new ArgumentNullException(nameof(sigKey));
PropName = propName ?? throw new ArgumentNullException(nameof(propName));
Value = value ?? throw new ArgumentNullException(nameof(value));
}
}
}

View file

@ -127,13 +127,13 @@ namespace Pulumi
#region construct from Output of some list type.
public static implicit operator InputList<T>(Output<T[]> values)
=> values.Apply(a => ImmutableArray.CreateRange(a));
=> values.Apply(ImmutableArray.CreateRange);
public static implicit operator InputList<T>(Output<List<T>> values)
=> values.Apply(a => ImmutableArray.CreateRange(a));
=> values.Apply(ImmutableArray.CreateRange);
public static implicit operator InputList<T>(Output<IEnumerable<T>> values)
=> values.Apply(a => ImmutableArray.CreateRange(a));
=> values.Apply(ImmutableArray.CreateRange);
public static implicit operator InputList<T>(Output<ImmutableArray<T>> values)
=> new InputList<T>(values);

View file

@ -13,7 +13,7 @@ namespace Pulumi
/// <see cref="Resource"/>. The individual values are themselves <see cref="Input{T}"/>s. i.e.
/// the individual values can be concrete values or <see cref="Output{T}"/>s.
/// <para/>
/// <see cref="InputMap{V}"/> differs from a normal <see cref="IDictionary{K,V}"/> in that it is
/// <see cref="InputMap{V}"/> differs from a normal <see cref="IDictionary{TKey,TValue}"/> in that it is
/// itself an <see cref="Input{T}"/>. For example, a <see cref="Resource"/> that accepts an
/// <see cref="InputMap{V}"/> will accept not just a dictionary but an <see cref="Output{T}"/>
/// of a dictionary as well. This is important for cases where the <see cref="Output{T}"/>
@ -96,10 +96,10 @@ namespace Pulumi
=> Output.Create(values);
public static implicit operator InputMap<V>(Output<Dictionary<string, V>> values)
=> values.Apply(d => ImmutableDictionary.CreateRange(d));
=> values.Apply(ImmutableDictionary.CreateRange);
public static implicit operator InputMap<V>(Output<IDictionary<string, V>> values)
=> values.Apply(d => ImmutableDictionary.CreateRange(d));
=> values.Apply(ImmutableDictionary.CreateRange);
public static implicit operator InputMap<V>(Output<ImmutableDictionary<string, V>> values)
=> new InputMap<V>(values);

View file

@ -1,7 +1,5 @@
// Copyright 2016-2019, Pulumi Corporation
using System;
namespace Pulumi
{
/// <summary>
@ -29,10 +27,10 @@ namespace Pulumi
=> Output.Create(value);
public static implicit operator InputUnion<T0, T1>(Output<T0> value)
=> new InputUnion<T0, T1>(value.Apply(v => Union<T0, T1>.FromT0(v)));
=> new InputUnion<T0, T1>(value.Apply(Union<T0, T1>.FromT0));
public static implicit operator InputUnion<T0, T1>(Output<T1> value)
=> new InputUnion<T0, T1>(value.Apply(v => Union<T0, T1>.FromT1(v)));
=> new InputUnion<T0, T1>(value.Apply(Union<T0, T1>.FromT1));
#endregion
}

View file

@ -1,5 +1,6 @@
// Copyright 2016-2019, Pulumi Corporation
// ReSharper disable NotAccessedField.Global
namespace Pulumi
{
internal class Options

View file

@ -192,19 +192,19 @@ namespace Pulumi
}
/// <summary>
/// <see cref="Apply{U}(Func{T, Output{U}})"/> for more details.
/// <see cref="Output{T}.Apply{U}(Func{T, Output{U}})"/> for more details.
/// </summary>
public Output<U> Apply<U>(Func<T, U> func)
=> Apply(t => Output.Create(func(t)));
/// <summary>
/// <see cref="Apply{U}(Func{T, Output{U}})"/> for more details.
/// <see cref="Output{T}.Apply{U}(Func{T, Output{U}})"/> for more details.
/// </summary>
public Output<U> Apply<U>(Func<T, Task<U>> func)
=> Apply(t => Output.Create(func(t)));
/// <summary>
/// <see cref="Apply{U}(Func{T, Output{U}})"/> for more details.
/// <see cref="Output{T}.Apply{U}(Func{T, Output{U}})"/> for more details.
/// </summary>
public Output<U> Apply<U>(Func<T, Input<U>?> func)
=> Apply(t => func(t).ToOutput());
@ -303,6 +303,7 @@ namespace Pulumi
var isKnown = true;
var isSecret = false;
#pragma warning disable 8601
Update(await GetData(item1).ConfigureAwait(false), ref tuple.Item1);
Update(await GetData(item2).ConfigureAwait(false), ref tuple.Item2);
Update(await GetData(item3).ConfigureAwait(false), ref tuple.Item3);
@ -311,6 +312,7 @@ namespace Pulumi
Update(await GetData(item6).ConfigureAwait(false), ref tuple.Item6);
Update(await GetData(item7).ConfigureAwait(false), ref tuple.Item7);
Update(await GetData(item8).ConfigureAwait(false), ref tuple.Item8);
#pragma warning restore 8601
return OutputData.Create(resources.ToImmutable(), tuple, isKnown, isSecret);

View file

@ -3,6 +3,8 @@
using System;
using OneOf;
// ReSharper disable PossiblyImpureMethodCallOnReadonlyVariable
namespace Pulumi
{
/// <summary>
@ -26,7 +28,7 @@ namespace Pulumi
/// or a <see cref="string"/> can be represented as <c>Output&lt;int, string&gt;</c>. The <see
/// cref="Input{T}"/> version of this is <see cref="InputUnion{T0, T1}"/>.
/// </summary>
public struct Union<T0, T1> : IEquatable<Union<T0, T1>>, IUnion
public readonly struct Union<T0, T1> : IEquatable<Union<T0, T1>>, IUnion
{
private readonly OneOf<T0, T1> _data;

View file

@ -66,10 +66,7 @@ namespace Pulumi
if (childName!.StartsWith(parentName, StringComparison.Ordinal))
{
aliasName = parentAlias.ToOutput().Apply<string>(parentAliasUrn =>
{
return parentAliasUrn.Substring(parentAliasUrn.LastIndexOf("::", StringComparison.Ordinal) + 2)
+ childName.Substring(parentName.Length);
});
parentAliasUrn.Substring(parentAliasUrn.LastIndexOf("::", StringComparison.Ordinal) + 2) + childName.Substring(parentName.Length));
}
var urn = Create(

View file

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
@ -29,7 +30,7 @@ namespace Pulumi
public Runner(IDeploymentInternal deployment)
=> _deployment = deployment;
public Task<int> RunAsync<TStack>(IServiceProvider serviceProvider) where TStack : Stack
Task<int> IRunner.RunAsync<TStack>(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
{
@ -40,8 +41,7 @@ namespace Pulumi
?? throw new ApplicationException($"Failed to resolve instance of type {typeof(TStack)} from service provider. Register the type with the service provider before calling {nameof(RunAsync)}."));
}
public Task<int> RunAsync<TStack>() where TStack : Stack, new()
=> RunAsync(() => new TStack());
Task<int> IRunner.RunAsync<TStack>() => RunAsync(() => new TStack());
public Task<int> RunAsync<TStack>(Func<TStack> stackFactory) where TStack : Stack
{
@ -60,7 +60,7 @@ namespace Pulumi
return WhileRunningAsync();
}
public Task<int> RunAsync(Func<Task<IDictionary<string, object?>>> func, StackOptions? options)
Task<int> IRunner.RunAsync(Func<Task<IDictionary<string, object?>>> func, StackOptions? options)
{
var stack = new Stack(func, options);
RegisterTask("User program code.", stack.Outputs.DataTask);
@ -214,10 +214,9 @@ namespace Pulumi
}
else
{
var location = System.Reflection.Assembly.GetEntryAssembly()?.Location;
await _deployment.Logger.ErrorAsync(
$@"Running program '{location}' failed with an unhandled exception:
{exception.ToString()}").ConfigureAwait(false);
var location = Assembly.GetEntryAssembly()?.Location;
await _deployment.Logger.ErrorAsync($@"Running program '{location}' failed with an unhandled exception:
{exception}").ConfigureAwait(false);
}
_deployment.Serilogger.Debug("Wrote last error. Returning from program.");

View file

@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Pulumi.Testing;
using Pulumirpc;
using Serilog;
using Serilog.Events;
@ -30,7 +31,7 @@ namespace Pulumi
/// </para>
/// Importantly: Cloud resources cannot be created outside of the lambda passed to any of the
/// <see cref="Deployment.RunAsync(Action)"/> overloads. Because cloud Resource construction is
/// inherently asynchronous, the result of this function is a <see cref="Task{T}"/> which should
/// inherently asynchronous, the result of this function is a <see cref="Task{TResult}"/> which should
/// then be returned or awaited. This will ensure that any problems that are encountered during
/// the running of the program are properly reported. Failure to do this may lead to the
/// program ending early before all resources are properly registered.
@ -38,7 +39,7 @@ namespace Pulumi
public sealed partial class Deployment : IDeploymentInternal
{
private static readonly object _instanceLock = new object();
private static AsyncLocal<DeploymentInstance?> _instance = new AsyncLocal<DeploymentInstance?>();
private static readonly AsyncLocal<DeploymentInstance?> _instance = new AsyncLocal<DeploymentInstance?>();
/// <summary>
/// The current running deployment instance. This is only available from inside the function
@ -101,6 +102,7 @@ namespace Pulumi
private Deployment()
{
// ReSharper disable UnusedVariable
var monitor = Environment.GetEnvironmentVariable("PULUMI_MONITOR");
var engine = Environment.GetEnvironmentVariable("PULUMI_ENGINE");
var project = Environment.GetEnvironmentVariable("PULUMI_PROJECT");
@ -121,6 +123,7 @@ namespace Pulumi
{
throw new InvalidOperationException("Program run without the Pulumi engine available; re-run using the `pulumi` CLI");
}
// ReSharper restore UnusedVariable
_isDryRun = dryRunValue;
_stackName = stack;
@ -193,7 +196,7 @@ namespace Pulumi
{
if (!this._featureSupport.ContainsKey(feature))
{
var request = new Pulumirpc.SupportsFeatureRequest {Id = feature };
var request = new SupportsFeatureRequest {Id = feature };
var response = await this.Monitor.SupportsFeatureAsync(request).ConfigureAwait(false);
this._featureSupport[feature] = response.HasSupport;
}

View file

@ -36,6 +36,7 @@ namespace Pulumi
Log.Debug(label);
// Be resilient to misbehaving callers.
// ReSharper disable once ConstantNullCoalescingCondition
args ??= InvokeArgs.Empty;
// Wait for all values to be available, and then perform the RPC.

View file

@ -1,6 +1,5 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@ -40,7 +39,7 @@ namespace Pulumi
// Wait for the parent to complete.
// If no parent was provided, parent to the root resource.
LogExcessive($"Getting parent urn: t={type}, name={name}, custom={custom}, remote={remote}");
var parentURN = options.Parent != null
var parentUrn = options.Parent != null
? await options.Parent.Urn.GetValueAsync().ConfigureAwait(false)
: await GetRootResourceAsync(type).ConfigureAwait(false);
LogExcessive($"Got parent urn: t={type}, name={name}, custom={custom}, remote={remote}");
@ -53,25 +52,21 @@ namespace Pulumi
}
var providerRefs = new Dictionary<string, string>();
if (remote)
if (remote && options is ComponentResourceOptions componentOpts)
{
var componentOpts = options as ComponentResourceOptions;
if (componentOpts != null)
// If only the Provider opt is set, move it to the Providers list for further processing.
if (componentOpts.Provider != null && componentOpts.Providers.Count == 0)
{
// If only the Provider opt is set, move it to the Providers list for further processing.
if (componentOpts.Provider != null && componentOpts.Providers.Count == 0)
{
componentOpts.Providers.Add(componentOpts.Provider);
componentOpts.Provider = null;
}
componentOpts.Providers.Add(componentOpts.Provider);
componentOpts.Provider = null;
}
foreach (var provider in componentOpts.Providers)
foreach (var provider in componentOpts.Providers)
{
var pref = await ProviderResource.RegisterAsync(provider).ConfigureAwait(false);
if (pref != null)
{
var pref = await ProviderResource.RegisterAsync(provider).ConfigureAwait(false);
if (pref != null)
{
providerRefs.Add(provider.Package, pref);
}
providerRefs.Add(provider.Package, pref);
}
}
}
@ -82,16 +77,16 @@ namespace Pulumi
// The list of all dependencies (implicit or explicit).
var allDirectDependencies = new HashSet<Resource>(explicitDirectDependencies);
var allDirectDependencyURNs = await GetAllTransitivelyReferencedCustomResourceURNsAsync(explicitDirectDependencies).ConfigureAwait(false);
var propertyToDirectDependencyURNs = new Dictionary<string, HashSet<string>>();
var allDirectDependencyUrns = await GetAllTransitivelyReferencedCustomResourceUrnsAsync(explicitDirectDependencies).ConfigureAwait(false);
var propertyToDirectDependencyUrns = new Dictionary<string, HashSet<string>>();
foreach (var (propertyName, directDependencies) in propertyToDirectDependencies)
{
allDirectDependencies.AddRange(directDependencies);
var urns = await GetAllTransitivelyReferencedCustomResourceURNsAsync(directDependencies).ConfigureAwait(false);
allDirectDependencyURNs.AddRange(urns);
propertyToDirectDependencyURNs[propertyName] = urns;
var urns = await GetAllTransitivelyReferencedCustomResourceUrnsAsync(directDependencies).ConfigureAwait(false);
allDirectDependencyUrns.AddRange(urns);
propertyToDirectDependencyUrns[propertyName] = urns;
}
// Wait for all aliases. Note that we use 'res._aliases' instead of 'options.aliases' as
@ -111,11 +106,11 @@ namespace Pulumi
return new PrepareResult(
serializedProps,
parentURN ?? "",
parentUrn ?? "",
providerRef ?? "",
providerRefs,
allDirectDependencyURNs,
propertyToDirectDependencyURNs,
allDirectDependencyUrns,
propertyToDirectDependencyUrns,
aliases);
void LogExcessive(string message)
@ -128,7 +123,7 @@ namespace Pulumi
private static Task<ImmutableArray<Resource>> GatherExplicitDependenciesAsync(InputList<Resource> resources)
=> resources.ToOutput().GetValueAsync();
private static async Task<HashSet<string>> GetAllTransitivelyReferencedCustomResourceURNsAsync(
private static async Task<HashSet<string>> GetAllTransitivelyReferencedCustomResourceUrnsAsync(
HashSet<Resource> resources)
{
// Go through 'resources', but transitively walk through **Component** resources,
@ -190,24 +185,24 @@ namespace Pulumi
}
}
private struct PrepareResult
private readonly struct PrepareResult
{
public readonly Struct SerializedProps;
public readonly string ParentUrn;
public readonly string ProviderRef;
public readonly Dictionary<string, string> ProviderRefs;
public readonly HashSet<string> AllDirectDependencyURNs;
public readonly Dictionary<string, HashSet<string>> PropertyToDirectDependencyURNs;
public readonly HashSet<string> AllDirectDependencyUrns;
public readonly Dictionary<string, HashSet<string>> PropertyToDirectDependencyUrns;
public readonly List<string> Aliases;
public PrepareResult(Struct serializedProps, string parentUrn, string providerRef, Dictionary<string, string> providerRefs, HashSet<string> allDirectDependencyURNs, Dictionary<string, HashSet<string>> propertyToDirectDependencyURNs, List<string> aliases)
public PrepareResult(Struct serializedProps, string parentUrn, string providerRef, Dictionary<string, string> providerRefs, HashSet<string> allDirectDependencyUrns, Dictionary<string, HashSet<string>> propertyToDirectDependencyUrns, List<string> aliases)
{
SerializedProps = serializedProps;
ParentUrn = parentUrn;
ProviderRef = providerRef;
ProviderRefs = providerRefs;
AllDirectDependencyURNs = allDirectDependencyURNs;
PropertyToDirectDependencyURNs = propertyToDirectDependencyURNs;
AllDirectDependencyUrns = allDirectDependencyUrns;
PropertyToDirectDependencyUrns = propertyToDirectDependencyUrns;
Aliases = aliases;
}
}

View file

@ -90,8 +90,9 @@ namespace Pulumi
resource, remote, newDependency, args, options).ConfigureAwait(false);
completionSources[Constants.UrnPropertyName].SetStringValue(response.urn, isKnown: true);
if (resource is CustomResource customResource)
if (resource is CustomResource)
{
// ReSharper disable once ConstantNullCoalescingCondition
var id = response.id ?? "";
completionSources[Constants.IdPropertyName].SetStringValue(id, isKnown: id != "");
}

View file

@ -1,10 +1,8 @@
// Copyright 2016-2019, Pulumi Corporation
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Pulumi.Serialization;
using Pulumirpc;
namespace Pulumi
@ -22,7 +20,6 @@ namespace Pulumi
var prepareResult = await this.PrepareResourceAsync(
label, resource, custom: true, remote: false, args, options).ConfigureAwait(false);
var serializer = new Serializer(_excessiveDebugOutput);
Log.Debug($"ReadResource RPC prepared: id={id}, t={type}, name={name}" +
(_excessiveDebugOutput ? $", obj={prepareResult.SerializedProps}" : ""));
@ -35,12 +32,12 @@ namespace Pulumi
Parent = prepareResult.ParentUrn,
Provider = prepareResult.ProviderRef,
Properties = prepareResult.SerializedProps,
Version = options?.Version ?? "",
Version = options.Version ?? "",
AcceptSecrets = true,
AcceptResources = !_disableResourceReferences,
};
request.Dependencies.AddRange(prepareResult.AllDirectDependencyURNs);
request.Dependencies.AddRange(prepareResult.AllDirectDependencyUrns);
// Now run the operation, serializing the invocation if necessary.
var response = await this.Monitor.ReadResourceAsync(resource, request);

View file

@ -54,12 +54,12 @@ namespace Pulumi
request.Provider = prepareResult.ProviderRef;
request.Providers.Add(prepareResult.ProviderRefs);
request.Aliases.AddRange(prepareResult.Aliases);
request.Dependencies.AddRange(prepareResult.AllDirectDependencyURNs);
request.Dependencies.AddRange(prepareResult.AllDirectDependencyUrns);
foreach (var (key, resourceURNs) in prepareResult.PropertyToDirectDependencyURNs)
foreach (var (key, resourceUrns) in prepareResult.PropertyToDirectDependencyUrns)
{
var deps = new RegisterResourceRequest.Types.PropertyDependencies();
deps.Urns.AddRange(resourceURNs);
deps.Urns.AddRange(resourceUrns);
request.PropertyDependencies.Add(key, deps);
}
}
@ -70,7 +70,7 @@ namespace Pulumi
var customOpts = options as CustomResourceOptions;
var deleteBeforeReplace = customOpts?.DeleteBeforeReplace;
var request = new RegisterResourceRequest()
var request = new RegisterResourceRequest
{
Type = type,
Name = name,
@ -113,7 +113,7 @@ namespace Pulumi
// Simply put, we simply convert our ticks to the integral number of nanoseconds
// corresponding to it. Since each tick is 100ns, this can trivialy be done just by
// appending "00" to it.
return timeSpan.Value.Ticks.ToString() + "00ns";
return timeSpan.Value.Ticks + "00ns";
}
}
}

View file

@ -1,7 +1,6 @@
// Copyright 2016-2019, Pulumi Corporation
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Google.Protobuf;
using Pulumirpc;
@ -22,7 +21,7 @@ namespace Pulumi
private async Task RegisterResourceOutputsAsync(
Resource resource, Output<IDictionary<string, object?>> outputs)
{
var opLabel = $"monitor.registerResourceOutputs(...)";
var opLabel = "monitor.registerResourceOutputs(...)";
// The registration could very well still be taking place, so we will need to wait for its URN.
// Additionally, the output properties might have come from other resources, so we must await those too.

View file

@ -9,7 +9,7 @@ namespace Pulumi
public partial class Deployment
{
private Task<string>? _rootResource;
private object _rootResourceLock = new object();
private readonly object _rootResourceLock = new object();
/// <summary>
/// Returns a root resource URN that will automatically become the default parent of all

View file

@ -12,7 +12,7 @@ namespace Pulumi
public partial class Deployment
{
/// <summary>
/// <see cref="RunAsync(Func{Task{IDictionary{string, object}}}, StackOptions)"/> for more details.
/// <see cref="RunAsync(Func{Task{IDictionary{string,object}}}, StackOptions)"/> for more details.
/// </summary>
/// <param name="action">Callback that creates stack resources.</param>
public static Task<int> RunAsync(Action action)
@ -174,7 +174,7 @@ namespace Pulumi
return engine.Errors.Count switch
{
1 => throw new RunException(engine.Errors.Single()),
int v when v > 1 => throw new AggregateException(engine.Errors.Select(e => new RunException(e))),
var v when v > 1 => throw new AggregateException(engine.Errors.Select(e => new RunException(e))),
_ => monitor.Resources.ToImmutableArray()
};
}

View file

@ -1,7 +1,6 @@
// Copyright 2016-2019, Pulumi Corporation
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
@ -65,7 +64,7 @@ namespace Pulumi
propertyToDependentResources.ToImmutable());
}
private struct SerializationResult
private readonly struct SerializationResult
{
public readonly Struct Serialized;
public readonly ImmutableDictionary<string, HashSet<Resource>> PropertyToDependentResources;

View file

@ -1,7 +1,7 @@
// Copyright 2016-2020, Pulumi Corporation
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Threading.Tasks;
using Grpc.Core;
using Pulumirpc;

View file

@ -1,7 +1,7 @@
// Copyright 2016-2020, Pulumi Corporation
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Threading.Tasks;
using Grpc.Core;
using Pulumirpc;

View file

@ -3,8 +3,7 @@
namespace Pulumi
{
/// <summary>
/// Options to help control the behavior of <see cref="IDeployment.InvokeAsync{T}(string,
/// InvokeArgs, InvokeOptions)"/>.
/// Options to help control the behavior of <see cref="IDeployment.InvokeAsync{T}(string, InvokeArgs, InvokeOptions)"/>.
/// </summary>
public class InvokeOptions
{

View file

@ -12,8 +12,8 @@ namespace Pulumi
/// </summary>
public class ResourceException : Exception
{
internal readonly Resource? Resource;
internal readonly bool HideStack;
internal Resource? Resource { get; }
internal bool HideStack { get; }
public ResourceException(string message, Resource? resource, bool hideStack = false) : base(message)
{

View file

@ -21,7 +21,7 @@ namespace Pulumi
return result;
}
public static void Deconstruct<K, V>(this KeyValuePair<K, V> pair, out K key, out V value)
public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> pair, out TKey key, out TValue value)
{
key = pair.Key;
value = pair.Value;
@ -43,6 +43,7 @@ namespace Pulumi
{
_ = response.ContinueWith(t =>
{
// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (t.Status)
{
default: throw new InvalidOperationException("Task was not complete: " + t.Status);

View file

@ -1,6 +1,5 @@
// Copyright 2016-2019, Pulumi Corporation
using System;
using System.Collections.Generic;
namespace Pulumi
@ -20,7 +19,7 @@ namespace Pulumi
/// </summary>
public List<ProviderResource> Providers
{
get => _providers ?? (_providers = new List<ProviderResource>());
get => _providers ??= new List<ProviderResource>();
set => _providers = value;
}

View file

@ -26,7 +26,7 @@ namespace Pulumi
/// </summary>
public List<string> AdditionalSecretOutputs
{
get => _additionalSecretOutputs ?? (_additionalSecretOutputs = new List<string>());
get => _additionalSecretOutputs ??= new List<string>();
set => _additionalSecretOutputs = value;
}

View file

@ -16,13 +16,13 @@ namespace Pulumi
public DependencyProviderResource(string reference)
: base(package: "", name: "", args: ResourceArgs.Empty, dependency: true)
{
int lastSep = reference.LastIndexOf("::", StringComparison.Ordinal);
var lastSep = reference.LastIndexOf("::", StringComparison.Ordinal);
if (lastSep == -1)
{
throw new ArgumentException($"Expected \"::\" in provider reference ${reference}.");
}
string urn = reference.Substring(0, lastSep);
string id = reference.Substring(lastSep + 2);
var urn = reference.Substring(0, lastSep);
var id = reference.Substring(lastSep + 2);
var resources = ImmutableHashSet.Create<Resource>(this);

View file

@ -35,14 +35,15 @@ namespace Pulumi
var all = fieldQuery.Concat(propQuery).ToList();
foreach (var (attr, memberName, memberType, getValue) in all)
foreach (var (_, memberName, memberType, _) in all)
{
var fullName = $"[Input] {this.GetType().FullName}.{memberName}";
// ReSharper disable once VirtualMemberCallInConstructor
ValidateMember(memberType, fullName);
}
_inputInfos = all.Select(t =>
new InputInfo(t.attr, t.memberName, t.memberType, t.getValue)).ToImmutableArray();
new InputInfo(t.attr!, t.memberName, t.memberType, t.getValue)).ToImmutableArray();
}
internal virtual async Task<ImmutableDictionary<string, object?>> ToDictionaryAsync()
@ -80,14 +81,15 @@ namespace Pulumi
return JsonFormatter.Default.Format(value);
}
private struct InputInfo
private readonly struct InputInfo
{
public readonly InputAttribute Attribute;
// ReSharper disable once NotAccessedField.Local
public readonly Type MemberType;
public readonly string MemberName;
public Func<object, object?> GetValue;
public readonly Func<object, object?> GetValue;
public InputInfo(InputAttribute attribute, string memberName, Type memberType, Func<object, object> getValue) : this()
public InputInfo(InputAttribute attribute, string memberName, Type memberType, Func<object, object?> getValue) : this()
{
Attribute = attribute;
MemberName = memberName;

View file

@ -11,10 +11,6 @@ namespace Pulumi
{
public static readonly InvokeArgs Empty = new EmptyInvokeArgs();
protected InvokeArgs()
{
}
private protected override void ValidateMember(Type memberType, string fullName)
{
if (typeof(IInput).IsAssignableFrom(memberType))

View file

@ -12,7 +12,7 @@ namespace Pulumi
/// </summary>
public class ProviderResource : CustomResource
{
internal readonly string Package;
internal string Package { get; }
private string? _registrationId;
@ -53,14 +53,14 @@ namespace Pulumi
if (provider._registrationId == null)
{
var providerURN = await provider.Urn.GetValueAsync().ConfigureAwait(false);
var providerID = await provider.Id.GetValueAsync().ConfigureAwait(false);
if (string.IsNullOrEmpty(providerID))
var providerUrn = await provider.Urn.GetValueAsync().ConfigureAwait(false);
var providerId = await provider.Id.GetValueAsync().ConfigureAwait(false);
if (string.IsNullOrEmpty(providerId))
{
providerID = Constants.UnknownValue;
providerId = Constants.UnknownValue;
}
provider._registrationId = $"{providerURN}::{providerID}";
provider._registrationId = $"{providerUrn}::{providerId}";
}
return provider._registrationId;

View file

@ -16,11 +16,6 @@ namespace Pulumi
private readonly string _type;
private readonly string _name;
/// <summary>
/// The optional parent of this resource.
/// </summary>
private readonly Resource? _parentResource;
/// <summary>
/// The child resources of this resource. We use these (only from a ComponentResource) to
/// allow code to dependOn a ComponentResource and have that effectively mean that it is
@ -56,7 +51,7 @@ namespace Pulumi
/// ever need to reference the urn of a component resource. So it's acceptable if that sort
/// of pattern failed in practice.
/// </summary>
internal readonly HashSet<Resource> ChildResources = new HashSet<Resource>();
internal HashSet<Resource> ChildResources { get; } = new HashSet<Resource>();
/// <summary>
/// Urn is the stable logical URN used to distinctly address a resource, both before and
@ -187,14 +182,13 @@ namespace Pulumi
if (options.Parent != null)
{
this._parentResource = options.Parent;
lock (this._parentResource.ChildResources)
var parentResource = options.Parent;
lock (parentResource.ChildResources)
{
this._parentResource.ChildResources.Add(this);
parentResource.ChildResources.Add(this);
}
if (options.Protect == null)
options.Protect = options.Parent._protect;
options.Protect ??= options.Parent._protect;
// Make a copy of the aliases array, and add to it any implicit aliases inherited from its parent
options.Aliases = options.Aliases.ToList();
@ -331,7 +325,6 @@ $"Only specify one of '{nameof(Alias.Parent)}', '{nameof(Alias.ParentUrn)}' or '
if (value != null)
{
ThrowAliasPropertyConflict(name);
return;
}
}

View file

@ -11,10 +11,6 @@ namespace Pulumi
{
public static readonly ResourceArgs Empty = new EmptyResourceArgs();
protected ResourceArgs()
{
}
private protected override void ValidateMember(Type memberType, string fullName)
{
// No validation. A member may or may not be IInput.

View file

@ -26,7 +26,7 @@ namespace Pulumi
/// </summary>
public InputList<Resource> DependsOn
{
get => _dependsOn ?? (_dependsOn = new InputList<Resource>());
get => _dependsOn ??= new InputList<Resource>();
set => _dependsOn = value;
}
@ -42,7 +42,7 @@ namespace Pulumi
/// </summary>
public List<string> IgnoreChanges
{
get => _ignoreChanges ?? (_ignoreChanges = new List<string>());
get => _ignoreChanges ??= new List<string>();
set => _ignoreChanges = value;
}
@ -78,7 +78,7 @@ namespace Pulumi
/// </summary>
public List<ResourceTransformation> ResourceTransformations
{
get => _resourceTransformations ?? (_resourceTransformations = new List<ResourceTransformation>());
get => _resourceTransformations ??= new List<ResourceTransformation>();
set => _resourceTransformations = value;
}

View file

@ -4,7 +4,6 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Pulumi.Serialization;
namespace Pulumi
{
@ -152,6 +151,6 @@ namespace Pulumi
/// The name of the stack to reference.
/// </summary>
[Input("name", required: true)]
public Input<string>? Name { get; set; } = null!;
public Input<string>? Name { get; set; }
}
}

View file

@ -8,6 +8,10 @@ using System.Linq;
using System.Reflection;
using System.Text.Json;
using Google.Protobuf.WellKnownTypes;
using Enum = System.Enum;
using Type = System.Type;
// ReSharper disable TailRecursiveCall
namespace Pulumi.Serialization
{
@ -19,15 +23,15 @@ namespace Pulumi.Serialization
return new OutputData<T>(ImmutableHashSet<Resource>.Empty, (T)data!, isKnown, isSecret);
}
public static OutputData<object?> ConvertValue(string context, Value value, System.Type targetType)
public static OutputData<object?> ConvertValue(string context, Value value, Type targetType)
{
return ConvertValue(context, value, targetType, ImmutableHashSet<Resource>.Empty);
}
public static OutputData<object?> ConvertValue(
string context, Value value, System.Type targetType, ImmutableHashSet<Resource> resources)
string context, Value value, Type targetType, ImmutableHashSet<Resource> resources)
{
CheckTargetType(context, targetType, new HashSet<System.Type>());
CheckTargetType(context, targetType, new HashSet<Type>());
var (deserialized, isKnown, isSecret) = Deserializer.Deserialize(value);
var converted = ConvertObject(context, deserialized, targetType);
@ -35,7 +39,7 @@ namespace Pulumi.Serialization
return new OutputData<object?>(resources, converted, isKnown, isSecret);
}
private static object? ConvertObject(string context, object? val, System.Type targetType)
private static object? ConvertObject(string context, object? val, Type targetType)
{
var (result, exception) = TryConvertObject(context, val, targetType);
if (exception != null)
@ -44,7 +48,7 @@ namespace Pulumi.Serialization
return result;
}
private static (object?, InvalidOperationException?) TryConvertObject(string context, object? val, System.Type targetType)
private static (object?, InvalidOperationException?) TryConvertObject(string context, object? val, Type targetType)
{
var targetIsNullable = targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>);
@ -116,7 +120,7 @@ namespace Pulumi.Serialization
if (exception != null || value is null)
return (null, exception);
return (System.Enum.ToObject(targetType, value), null);
return (Enum.ToObject(targetType, value), null);
}
if (targetType.IsValueType && targetType.GetCustomAttribute<EnumTypeAttribute>() != null)
@ -136,7 +140,7 @@ namespace Pulumi.Serialization
return (null, new InvalidOperationException(
$"Expected target type {targetType.FullName} to have a constructor with a single {valType.FullName} parameter."));
}
return (enumTypeConstructor.Invoke(new object[] { val }), null);
return (enumTypeConstructor.Invoke(new[] { val }), null);
}
if (targetType.IsConstructedGenericType)
@ -154,14 +158,14 @@ namespace Pulumi.Serialization
$"Unexpected generic target type {targetType.FullName} when deserializing {context}");
}
if (targetType.GetCustomAttribute<Pulumi.OutputTypeAttribute>() == null)
if (targetType.GetCustomAttribute<OutputTypeAttribute>() == null)
return (null, new InvalidOperationException(
$"Unexpected target type {targetType.FullName} when deserializing {context}"));
var constructor = GetPropertyConstructor(targetType);
if (constructor == null)
return (null, new InvalidOperationException(
$"Expected target type {targetType.FullName} to have [{nameof(Pulumi.OutputConstructorAttribute)}] constructor when deserializing {context}"));
$"Expected target type {targetType.FullName} to have [{nameof(OutputConstructorAttribute)}] constructor when deserializing {context}"));
var (dictionary, tempException) = TryEnsureType<ImmutableDictionary<string, object>>(context, val);
if (tempException != null)
@ -191,20 +195,18 @@ namespace Pulumi.Serialization
private static (object?, InvalidOperationException?) TryConvertJsonElement(
string context, object val)
{
using (var stream = new MemoryStream())
using var stream = new MemoryStream();
using (var writer = new Utf8JsonWriter(stream))
{
using (var writer = new Utf8JsonWriter(stream))
{
var exception = TryWriteJson(context, writer, val);
if (exception != null)
return (null, exception);
}
stream.Position = 0;
var document = JsonDocument.Parse(stream);
var element = document.RootElement;
return (element, null);
var exception = TryWriteJson(context, writer, val);
if (exception != null)
return (null, exception);
}
stream.Position = 0;
var document = JsonDocument.Parse(stream);
var element = document.RootElement;
return (element, null);
}
private static InvalidOperationException? TryWriteJson(string context, Utf8JsonWriter writer, object? val)
@ -252,7 +254,7 @@ namespace Pulumi.Serialization
private static (T, InvalidOperationException?) TryEnsureType<T>(string context, object val)
=> val is T t ? (t, null) : (default(T)!, new InvalidOperationException($"Expected {typeof(T).FullName} but got {val.GetType().FullName} deserializing {context}"));
private static (object?, InvalidOperationException?) TryConvertOneOf(string context, object val, System.Type oneOfType)
private static (object?, InvalidOperationException?) TryConvertOneOf(string context, object val, Type oneOfType)
{
var firstType = oneOfType.GenericTypeArguments[0];
var secondType = oneOfType.GenericTypeArguments[1];
@ -275,14 +277,14 @@ namespace Pulumi.Serialization
}
private static (object?, InvalidOperationException?) TryConvertArray(
string fieldName, object val, System.Type targetType)
string fieldName, object val, Type targetType)
{
if (!(val is ImmutableArray<object> array))
return (null, new InvalidOperationException(
$"Expected {typeof(ImmutableArray<object>).FullName} but got {val.GetType().FullName} deserializing {fieldName}"));
var builder =
typeof(ImmutableArray).GetMethod(nameof(ImmutableArray.CreateBuilder), Array.Empty<System.Type>())!
typeof(ImmutableArray).GetMethod(nameof(ImmutableArray.CreateBuilder), Array.Empty<Type>())!
.MakeGenericMethod(targetType.GenericTypeArguments)
.Invoke(obj: null, parameters: null)!;
@ -303,7 +305,7 @@ namespace Pulumi.Serialization
}
private static (object?, InvalidOperationException?) TryConvertDictionary(
string fieldName, object val, System.Type targetType)
string fieldName, object val, Type targetType)
{
if (!(val is ImmutableDictionary<string, object> dictionary))
return (null, new InvalidOperationException(
@ -319,7 +321,7 @@ namespace Pulumi.Serialization
$"Unexpected type {targetType.FullName} when deserializing {fieldName}. ImmutableDictionary's TKey type was not {typeof(string).FullName}"));
var builder =
typeof(ImmutableDictionary).GetMethod(nameof(ImmutableDictionary.CreateBuilder), Array.Empty<System.Type>())!
typeof(ImmutableDictionary).GetMethod(nameof(ImmutableDictionary.CreateBuilder), Array.Empty<Type>())!
.MakeGenericMethod(targetType.GenericTypeArguments)
.Invoke(obj: null, parameters: null)!;
@ -341,7 +343,7 @@ namespace Pulumi.Serialization
return (builderToImmutable.Invoke(builder, null), null);
}
public static void CheckTargetType(string context, System.Type targetType, HashSet<System.Type> seenTypes)
public static void CheckTargetType(string context, Type targetType, HashSet<Type> seenTypes)
{
// types can be recursive. So only dive into a type if it's the first time we're seeing it.
if (!seenTypes.Add(targetType))
@ -398,7 +400,7 @@ namespace Pulumi.Serialization
throw new InvalidOperationException(
$"{targetType.FullName} had [{nameof(EnumTypeAttribute)}], but did not contain constructor with a single String or Double parameter.");
static bool CheckEnumType(System.Type targetType, System.Type underlyingType)
static bool CheckEnumType(Type targetType, Type underlyingType)
{
var constructor = targetType.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { underlyingType }, null);
if (constructor == null)
@ -424,39 +426,34 @@ namespace Pulumi.Serialization
CheckTargetType(context, targetType.GenericTypeArguments.Single(), seenTypes);
return;
}
else if (targetType.GetGenericTypeDefinition() == typeof(Union<,>))
if (targetType.GetGenericTypeDefinition() == typeof(Union<,>))
{
CheckTargetType(context, targetType.GenericTypeArguments[0], seenTypes);
CheckTargetType(context, targetType.GenericTypeArguments[1], seenTypes);
return;
}
else if (targetType.GetGenericTypeDefinition() == typeof(ImmutableArray<>))
if (targetType.GetGenericTypeDefinition() == typeof(ImmutableArray<>))
{
CheckTargetType(context, targetType.GenericTypeArguments.Single(), seenTypes);
return;
}
else if (targetType.GetGenericTypeDefinition() == typeof(ImmutableDictionary<,>))
if (targetType.GetGenericTypeDefinition() == typeof(ImmutableDictionary<,>))
{
var dictTypeArgs = targetType.GenericTypeArguments;
if (dictTypeArgs[0] != typeof(string))
{
throw new InvalidOperationException(
$@"{context} contains invalid type {targetType.FullName}:
throw new InvalidOperationException($@"{context} contains invalid type {targetType.FullName}:
The only allowed ImmutableDictionary 'TKey' type is 'String'.");
}
CheckTargetType(context, dictTypeArgs[1], seenTypes);
return;
}
else
{
throw new InvalidOperationException(
$@"{context} contains invalid type {targetType.FullName}:
throw new InvalidOperationException($@"{context} contains invalid type {targetType.FullName}:
The only generic types allowed are ImmutableArray<...> and ImmutableDictionary<string, ...>");
}
}
var propertyTypeAttribute = (Attribute?)targetType.GetCustomAttribute<OutputTypeAttribute>();
var propertyTypeAttribute = targetType.GetCustomAttribute<OutputTypeAttribute>();
if (propertyTypeAttribute == null)
{
throw new InvalidOperationException(
@ -479,8 +476,8 @@ $@"{targetType.FullName} had [{nameof(OutputTypeAttribute)}], but did not contai
}
}
private static ConstructorInfo GetPropertyConstructor(System.Type outputTypeArg)
private static ConstructorInfo? GetPropertyConstructor(Type outputTypeArg)
=> outputTypeArg.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(
c => c.GetCustomAttributes<OutputConstructorAttribute>() != null);
c => c.GetCustomAttribute<OutputConstructorAttribute>() != null);
}
}

Some files were not shown because too many files have changed in this diff Show more