diff --git a/source/Calamari.Common/CalamariFlavourProgram.cs b/source/Calamari.Common/CalamariFlavourProgram.cs index f14f3b4fac..c659d4986b 100644 --- a/source/Calamari.Common/CalamariFlavourProgram.cs +++ b/source/Calamari.Common/CalamariFlavourProgram.cs @@ -4,11 +4,11 @@ using System.Linq; using System.Reflection; using System.Threading; +using System.Threading.Tasks; using Autofac; using Autofac.Core; using Autofac.Core.Registration; using Calamari.Common.Commands; -using Calamari.Common.Features.Behaviours; using Calamari.Common.Features.ConfigurationTransforms; using Calamari.Common.Features.ConfigurationVariables; using Calamari.Common.Features.EmbeddedResources; @@ -21,18 +21,20 @@ using Calamari.Common.Features.Substitutions; using Calamari.Common.Plumbing; using Calamari.Common.Plumbing.Commands; +using Calamari.Common.Plumbing.Deployment.Journal; using Calamari.Common.Plumbing.Extensions; using Calamari.Common.Plumbing.FileSystem; using Calamari.Common.Plumbing.Logging; using Calamari.Common.Plumbing.Pipeline; using Calamari.Common.Plumbing.Proxies; using Calamari.Common.Plumbing.Variables; +using Calamari.Common.Util; namespace Calamari.Common; public abstract class CalamariFlavourProgram(ILog log) { - protected int Run(string[] args) + protected async Task Run(string[] args) { try { @@ -44,7 +46,9 @@ protected int Run(string[] args) log.Verbose($"Calamari Version: {GetType().Assembly.GetInformationalVersion()}"); if (options.Command.Equals("version", StringComparison.OrdinalIgnoreCase)) + { return 0; + } var envInfo = string.Join($"{Environment.NewLine} ", EnvironmentHelper.SafelyGetEnvironmentInformation()); @@ -67,13 +71,13 @@ protected int Run(string[] args) while (!Debugger.IsAttached) { - Thread.Sleep(1000); + await Task.Delay(1000); } } #endif var isolation = container.Resolve(); - using var _ = isolation.Enforce(options.ScriptIsolation); - return ResolveAndExecuteCommand(container, options); + await using var _ = await isolation.EnforceAsync(options.ScriptIsolation, CancellationToken.None); + return await ResolveAndExecuteCommand(container, options); } catch (Exception ex) { @@ -81,31 +85,58 @@ protected int Run(string[] args) } } - protected abstract int ResolveAndExecuteCommand(IContainer container, CommonOptions options); + async Task ResolveAndExecuteCommand(IContainer container, CommonOptions options) + { + try + { + if (container.IsRegisteredWithName(options.Command)) + { + try + { + var pipeline = container.ResolveNamed(options.Command); + var variables = container.Resolve(); + await pipeline.Execute(container, variables); + return 0; + } + catch (Exception ex) + { + return ConsoleFormatter.PrintError(log, ex); + } + } + + return await ResolveAndExecuteCommandWithArgs(container, options); + } + catch (Exception e) when (e is ComponentNotRegisteredException or DependencyResolutionException) + { + throw new CommandException($"Could not find the command {options.Command}"); + } + } + + protected abstract Task ResolveAndExecuteCommandWithArgs(IContainer container, CommonOptions options); protected virtual void ConfigureContainer(ContainerBuilder builder, CommonOptions options) - { + { //register the options into the DI builder.RegisterInstance(options).AsSelf(); - - var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem(); - builder.RegisterInstance(fileSystem).As(); - builder.RegisterType().As(); - builder.RegisterType().AsSelf(); - builder.RegisterInstance(log).As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().SingleInstance(); - builder.RegisterType().As(); - - // For Pipeline Commands - builder.RegisterType().As(); - builder.Register(context => ConfigurationTransformer.FromVariables(context.Resolve(), context.Resolve())).As(); - builder.RegisterType().As(); - - + + var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem(); + builder.RegisterInstance(fileSystem).As(); + builder.RegisterType().As(); + builder.RegisterType().AsSelf(); + builder.RegisterInstance(log).As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().SingleInstance(); + builder.RegisterType().As(); + + // For Pipeline Commands + builder.RegisterType().As(); + builder.Register(context => ConfigurationTransformer.FromVariables(context.Resolve(), context.Resolve())).As(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterModule(); builder.RegisterModule(); builder.RegisterModule(); @@ -119,28 +150,35 @@ protected virtual void ConfigureContainer(ContainerBuilder builder, CommonOption .Except() .As() .SingleInstance(); - - // Register Behaviors - builder.RegisterAssemblyTypes(assemblies) - .Where(t => t.IsAssignableTo() && !t.IsAbstract) - .AsSelf() - .InstancePerDependency(); - builder.RegisterInstance(options).AsSelf().SingleInstance(); + // Register Behaviors + builder.RegisterAssemblyTypes(assemblies) + .Where(t => t.IsAssignableTo() && !t.IsAbstract) + .AsSelf() + .InstancePerDependency(); + + // Register Pipeline commands + builder.RegisterAssemblyTypes(assemblies) + .AssignableTo() + .WithMetadataFrom() + .Where(t => t.GetCustomAttribute() is not null) + .Named(t => t.GetCommandNameFromAttribute()); builder.RegisterModule(); } - protected virtual Assembly GetProgramAssemblyToRegister() + protected virtual IEnumerable GetProgramAssembliesToRegister() { - return GetType().Assembly; + yield return GetType().Assembly; } protected virtual IEnumerable GetAllAssembliesToRegister() { - var programAssembly = GetProgramAssemblyToRegister(); - - yield return programAssembly; // Calamari Flavour + var programAssemblies = GetProgramAssembliesToRegister(); + + foreach (var assembly in programAssemblies) + yield return assembly; // Calamari Flavour & dependencies + yield return typeof(CalamariFlavourProgram).Assembly; // Calamari.Common } -} +} \ No newline at end of file diff --git a/source/Calamari.Common/CalamariFlavourProgramAsync.cs b/source/Calamari.Common/CalamariFlavourProgramAsync.cs index 589ab8dbd2..730825957e 100644 --- a/source/Calamari.Common/CalamariFlavourProgramAsync.cs +++ b/source/Calamari.Common/CalamariFlavourProgramAsync.cs @@ -34,60 +34,6 @@ namespace Calamari.Common; public abstract class CalamariFlavourProgramAsync(ILog log) { - protected virtual void ConfigureContainer(ContainerBuilder builder, CommonOptions options) - { - //register the options into the DI - builder.RegisterInstance(options).AsSelf(); - - var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem(); - builder.RegisterInstance(fileSystem).As(); - builder.RegisterType().As(); - builder.RegisterType().AsSelf(); - builder.RegisterInstance(log).As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.Register(context => ConfigurationTransformer.FromVariables(context.Resolve(), context.Resolve())).As(); - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().SingleInstance(); - - builder.RegisterModule(); - builder.RegisterModule(); - builder.RegisterModule(); - - var assemblies = GetAllAssembliesToRegister().ToArray(); - - builder.RegisterAssemblyTypes(assemblies).AssignableTo().As().SingleInstance(); - - builder.RegisterAssemblyTypes(assemblies) - .AssignableTo() - .Except() - .As() - .SingleInstance(); - - builder.RegisterAssemblyTypes(assemblies) - .Where(t => t.IsAssignableTo() && !t.IsAbstract) - .AsSelf() - .InstancePerDependency(); - - builder.RegisterAssemblyTypes(assemblies) - .AssignableTo() - .Where(t => t.GetCommandNameFromAttribute() - .Equals(options.Command, StringComparison.OrdinalIgnoreCase)) - .Named(t => t.GetCommandNameFromAttribute()); - - builder.RegisterModule(); - } - - protected virtual IEnumerable GetProgramAssembliesToRegister() - { - yield return GetType().Assembly; - } - protected async Task Run(string[] args) { try @@ -121,7 +67,7 @@ protected async Task Run(string[] args) if (CalamariEnvironment.ShouldWaitForDebugger(container.Resolve())) { using var proc = Process.GetCurrentProcess(); - Log.Info($"Waiting for debugger to attach... (PID: {proc.Id})"); + log.Info($"Waiting for debugger to attach... (PID: {proc.Id})"); while (!Debugger.IsAttached) { @@ -131,26 +77,16 @@ protected async Task Run(string[] args) #endif var isolation = container.Resolve(); await using var _ = await isolation.EnforceAsync(options.ScriptIsolation, CancellationToken.None); - await ResolveAndExecuteCommand(container, options); - return 0; + return await ResolveAndExecuteCommand(container, options); + } catch (Exception ex) { - return ConsoleFormatter.PrintError(ConsoleLog.Instance, ex); + return ConsoleFormatter.PrintError(log, ex); } } - IEnumerable GetAllAssembliesToRegister() - { - var programAssemblies = GetProgramAssembliesToRegister(); - - foreach (var assembly in programAssemblies) - yield return assembly; // Calamari Flavour & dependencies - - yield return typeof(CalamariFlavourProgramAsync).Assembly; // Calamari.Common - } - - static Task ResolveAndExecuteCommand(ILifetimeScope container, CommonOptions options) + static async Task ResolveAndExecuteCommand(ILifetimeScope container, CommonOptions options) { try { @@ -158,7 +94,8 @@ static Task ResolveAndExecuteCommand(ILifetimeScope container, CommonOptions opt { var pipeline = container.ResolveNamed(options.Command); var variables = container.Resolve(); - return pipeline.Execute(container, variables); + await pipeline.Execute(container, variables); + return 0; } throw new CommandException($"Could not find the command {options.Command}"); @@ -168,4 +105,69 @@ static Task ResolveAndExecuteCommand(ILifetimeScope container, CommonOptions opt throw new CommandException($"Could not find the command {options.Command}"); } } + + protected virtual void ConfigureContainer(ContainerBuilder builder, CommonOptions options) + { + //register the options into the DI + builder.RegisterInstance(options).AsSelf(); + + var fileSystem = CalamariPhysicalFileSystem.GetPhysicalFileSystem(); + builder.RegisterInstance(fileSystem).As(); + builder.RegisterType().As(); + builder.RegisterType().AsSelf(); + builder.RegisterInstance(log).As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.Register(context => ConfigurationTransformer.FromVariables(context.Resolve(), context.Resolve())).As(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + + builder.RegisterModule(); + builder.RegisterModule(); + builder.RegisterModule(); + + var assemblies = GetAllAssembliesToRegister().ToArray(); + + builder.RegisterAssemblyTypes(assemblies).AssignableTo().As().SingleInstance(); + + builder.RegisterAssemblyTypes(assemblies) + .AssignableTo() + .Except() + .As() + .SingleInstance(); + + builder.RegisterAssemblyTypes(assemblies) + .Where(t => t.IsAssignableTo() && !t.IsAbstract) + .AsSelf() + .InstancePerDependency(); + + builder.RegisterAssemblyTypes(assemblies) + .AssignableTo() + .Where(t => t.GetCommandNameFromAttribute() + .Equals(options.Command, StringComparison.OrdinalIgnoreCase)) + .Named(t => t.GetCommandNameFromAttribute()); + + builder.RegisterModule(); + } + + protected virtual IEnumerable GetProgramAssembliesToRegister() + { + yield return GetType().Assembly; + } + + + IEnumerable GetAllAssembliesToRegister() + { + var programAssemblies = GetProgramAssembliesToRegister(); + + foreach (var assembly in programAssemblies) + yield return assembly; // Calamari Flavour & dependencies + + yield return typeof(CalamariFlavourProgramAsync).Assembly; // Calamari.Common + } } \ No newline at end of file diff --git a/source/Calamari.Tests/CommitToGitCommandTest.cs b/source/Calamari.Tests/CommitToGitCommandTest.cs index c6758454fc..d767f24c0b 100644 --- a/source/Calamari.Tests/CommitToGitCommandTest.cs +++ b/source/Calamari.Tests/CommitToGitCommandTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; +using System.Threading.Tasks; using Calamari.ArgoCD.Git; using Calamari.Common.Features.Scripts; using Calamari.Common.Plumbing.Extensions; @@ -36,7 +37,7 @@ public class CommitToGitCommandTest CalamariExecutionVariableCollection variables; [SetUp] - public void setUp() + public void SetUp() { executionDirectory = fileSystem.CreateTemporaryDirectory(); @@ -57,19 +58,19 @@ public void setUp() } [Test] - public void CommitToGitRunsScriptWithNoDependenciesToCreateFileWhichIsCommitedToRepository() + public async Task CommitToGitRunsScriptWithNoDependenciesToCreateFileWhichIsCommitedToRepository() { variables.AddRange([ new CalamariExecutionVariable(ScriptVariables.ScriptBody, "touch \"$(get_octopusvariable 'Octopus.Calamari.Git.RepositoryPath')/proof.txt\"", false), new CalamariExecutionVariable(ScriptVariables.Syntax, ScriptSyntax.Bash.ToString(), false), ]); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent("proof.txt").Should().NotBeNull("the transform script should have created and committed the file to the repository"); } [Test] - public void CommitToGitRunsInlineScriptWithPackageDependencyToCreateFileWhichIsCommitedToRepository() + public async Task CommitToGitRunsInlineScriptWithPackageDependencyToCreateFileWhichIsCommitedToRepository() { const string packageReferenceName = "my-scripts"; @@ -83,12 +84,12 @@ public void CommitToGitRunsInlineScriptWithPackageDependencyToCreateFileWhichIsC new CalamariExecutionVariable(PackageVariables.IndexedExtract(packageReferenceName), "True", false), ]); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent("proof.txt").Should().NotBeNull("the helper script should have created and committed the file to the repository"); } [Test] - public void CommitToGitRunsPackageBasedScriptWithNoDependenciesToCreateFileWhichIsCommitedToRepository() + public async Task CommitToGitRunsPackageBasedScriptWithNoDependenciesToCreateFileWhichIsCommitedToRepository() { var zipPath = CreateZipWithEntry("transform-script", "script.sh", "touch \"$(get_octopusvariable 'Octopus.Calamari.Git.RepositoryPath')/proof.txt\""); @@ -96,12 +97,12 @@ public void CommitToGitRunsPackageBasedScriptWithNoDependenciesToCreateFileWhich new CalamariExecutionVariable(ScriptVariables.ScriptFileName, "script.sh", false), ]); - RunCommitToGit("--package", zipPath).Should().Be(0); + (await RunCommitToGit("--package", zipPath)).Should().Be(0); GetCommittedFileContent("proof.txt").Should().NotBeNull("the package-based script should have created and committed the file to the repository"); } [Test] - public void CommitToGitRunsPackageBasedScriptWithScriptParameters() + public async Task CommitToGitRunsPackageBasedScriptWithScriptParameters() { var proofFile = Path.Combine(executionDirectory, "script_ran.txt"); var zipPath = CreateZipWithEntry("transform-script", "script.sh", @@ -111,12 +112,12 @@ public void CommitToGitRunsPackageBasedScriptWithScriptParameters() new CalamariExecutionVariable(ScriptVariables.ScriptFileName, "script.sh", false), ]); - RunCommitToGit("--package", zipPath, "--scriptParameters", "expected-arg").Should().Be(0); + (await RunCommitToGit("--package", zipPath, "--scriptParameters", "expected-arg")).Should().Be(0); File.Exists(proofFile).Should().BeTrue("the transform script should have run with the expected argument"); } [Test] - public void CanCopyPackageFilesIntoGitRepository() + public async Task CanCopyPackageFilesIntoGitRepository() { const string packageReferenceName = "my-configs"; const string destinationPath = "output-dir"; @@ -124,14 +125,14 @@ public void CanCopyPackageFilesIntoGitRepository() var zipPath = CreateZipWithEntry(packageReferenceName, "configs/settings.json", "{\"setting\": \"value\"}"); AddInputPackageVariables(packageReferenceName, zipPath, destinationPath); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent($"{destinationPath}/configs/settings.json") .Should().NotBeNull("the package files should have been copied into the repository under the destination path"); } [Test] - public void SubstitutesNonSensitiveVariablesIntoAnExpandedPackageThenCopiesToGitRepository() + public async Task SubstitutesNonSensitiveVariablesIntoAnExpandedPackageThenCopiesToGitRepository() { const string packageReferenceName = "my-configs"; const string destinationPath = "output-dir"; @@ -144,7 +145,7 @@ public void SubstitutesNonSensitiveVariablesIntoAnExpandedPackageThenCopiesToGit new CalamariExecutionVariable("MyVar", "production-value", false), ]); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); var content = GetCommittedFileContent($"{destinationPath}/configs/settings.json"); content.Should().NotBeNull("the package file should have been copied into the repository"); @@ -153,7 +154,7 @@ public void SubstitutesNonSensitiveVariablesIntoAnExpandedPackageThenCopiesToGit } [Test] - public void OnlyCopiesFilesMatchingInputPathsFromPackageIntoGitRepository() + public async Task OnlyCopiesFilesMatchingInputPathsFromPackageIntoGitRepository() { const string packageReferenceName = "my-configs"; const string destinationPath = "output-dir"; @@ -165,7 +166,7 @@ public void OnlyCopiesFilesMatchingInputPathsFromPackageIntoGitRepository() }); AddInputPackageVariables(packageReferenceName, zipPath, destinationPath); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent($"{destinationPath}/configs/settings.json") .Should().NotBeNull("files matching the InputFilePaths glob should be copied"); @@ -174,7 +175,7 @@ public void OnlyCopiesFilesMatchingInputPathsFromPackageIntoGitRepository() } [Test] - public void CopiesAllGitReferenceFilesIntoGitRepository() + public async Task CopiesAllGitReferenceFilesIntoGitRepository() { const string gitDependencyName = "my-git-dep"; const string destinationPath = "output-dir"; @@ -182,14 +183,14 @@ public void CopiesAllGitReferenceFilesIntoGitRepository() var zipPath = CreateZipWithEntry(gitDependencyName, "manifests/deployment.yaml", "apiVersion: apps/v1"); AddInputGitReferenceVariables(gitDependencyName, zipPath, destinationPath); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent($"{destinationPath}/manifests/deployment.yaml") .Should().NotBeNull("git reference files should be copied into the repository under the destination path"); } [Test] - public void FailsWhenSensitiveVariableTemplatesAreEncounteredDuringSubstitution() + public async Task FailsWhenSensitiveVariableTemplatesAreEncounteredDuringSubstitution() { const string packageReferenceName = "my-configs"; const string destinationPath = "output-dir"; @@ -202,14 +203,14 @@ public void FailsWhenSensitiveVariableTemplatesAreEncounteredDuringSubstitution( new CalamariExecutionVariable("MySecret", "super-secret-value", true), ]); - RunCommitToGit().Should().NotBe(0); + (await RunCommitToGit()).Should().NotBe(0); var content = GetCommittedFileContent($"{destinationPath}/configs/settings.json"); content.Should().BeNull("the package file should not be committed when sensitive variable substitution throws"); } [Test] - public void CommitMessageSummaryIsUsedAsCommitMessage() + public async Task CommitMessageSummaryIsUsedAsCommitMessage() { const string packageReferenceName = "my-configs"; const string destinationPath = "output-dir"; @@ -217,25 +218,25 @@ public void CommitMessageSummaryIsUsedAsCommitMessage() var zipPath = CreateZipWithEntry(packageReferenceName, "configs/settings.json", "{}"); AddInputPackageVariables(packageReferenceName, zipPath, destinationPath); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); using var repo = new Repository(OriginPath); repo.Branches[targetBranchFriendlyName].Tip.Message.Should().StartWith("Git Commit Summary"); } [Test] - public void FailingScriptResultsInNonZeroExitCode() + public async Task FailingScriptResultsInNonZeroExitCode() { variables.AddRange([ new CalamariExecutionVariable(ScriptVariables.ScriptBody, "exit 1", false), - new CalamariExecutionVariable(ScriptVariables.Syntax, ScriptSyntax.Bash.ToString(), false), + new CalamariExecutionVariable(ScriptVariables.Syntax, nameof(ScriptSyntax.Bash), false), ]); - RunCommitToGit().Should().NotBe(0); + (await RunCommitToGit()).Should().NotBe(0); } [Test] - public void BothPackageCopyAndScriptTransformProduceFilesInRepository() + public async Task BothPackageCopyAndScriptTransformProduceFilesInRepository() { const string packageReferenceName = "my-configs"; const string destinationPath = "output-dir"; @@ -245,16 +246,16 @@ public void BothPackageCopyAndScriptTransformProduceFilesInRepository() variables.AddRange([ new CalamariExecutionVariable(ScriptVariables.ScriptBody, "touch \"$(get_octopusvariable 'Octopus.Calamari.Git.RepositoryPath')/script-output.txt\"", false), - new CalamariExecutionVariable(ScriptVariables.Syntax, ScriptSyntax.Bash.ToString(), false), + new CalamariExecutionVariable(ScriptVariables.Syntax, nameof(ScriptSyntax.Bash), false), ]); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent($"{destinationPath}/configs/settings.json").Should().NotBeNull("package files should be copied to the repository"); GetCommittedFileContent("script-output.txt").Should().NotBeNull("the script should have created and committed the file"); } [Test] - public void MultiplePackagesAreAllCopiedToGitRepository() + public async Task MultiplePackagesAreAllCopiedToGitRepository() { const string package1Name = "configs-package"; const string package2Name = "templates-package"; @@ -280,13 +281,13 @@ public void MultiplePackagesAreAllCopiedToGitRepository() new CalamariExecutionVariable(Deployment.SpecialVariables.Action.Git.DestinationPath, destinationPath, false), ]); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent($"{destinationPath}/configs/settings.json").Should().NotBeNull("files from the first package should be copied"); GetCommittedFileContent($"{destinationPath}/configs/template.yaml").Should().NotBeNull("files from the second package should be copied"); } [Test] - public void PackageFilesAreCopiedToDestinationSubFolderDefinedInMetadata() + public async Task PackageFilesAreCopiedToDestinationSubFolderDefinedInMetadata() { const string packageReferenceName = "my-configs"; const string destinationPath = "base-dir"; @@ -303,7 +304,7 @@ public void PackageFilesAreCopiedToDestinationSubFolderDefinedInMetadata() new CalamariExecutionVariable(Deployment.SpecialVariables.Action.Git.DestinationPath, destinationPath, false), ]); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent($"{destinationPath}/{destinationSubFolder}/configs/settings.json") .Should().NotBeNull("package files should be placed under the DestinationSubFolder from the source metadata"); @@ -312,7 +313,7 @@ public void PackageFilesAreCopiedToDestinationSubFolderDefinedInMetadata() } [Test] - public void GitDependencyFilesAreCopiedToDestinationSubFolderDefinedInMetadata() + public async Task GitDependencyFilesAreCopiedToDestinationSubFolderDefinedInMetadata() { const string gitDependencyName = "my-git-dep"; const string destinationPath = "base-dir"; @@ -321,7 +322,7 @@ public void GitDependencyFilesAreCopiedToDestinationSubFolderDefinedInMetadata() var zipPath = CreateZipWithEntry(gitDependencyName, "deployment.yaml", "apiVersion: apps/v1"); AddInputGitReferenceVariables(gitDependencyName, zipPath, destinationPath, destinationSubFolder); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent($"{destinationPath}/{destinationSubFolder}/deployment.yaml") .Should().NotBeNull("git dependency files should be placed under the DestinationSubFolder from the source metadata"); @@ -330,24 +331,24 @@ public void GitDependencyFilesAreCopiedToDestinationSubFolderDefinedInMetadata() } [Test] - public void CommitToGitRunsScriptProvidedViaScriptBodyBySyntaxVariable() + public async Task CommitToGitRunsScriptProvidedViaScriptBodyBySyntaxVariable() { variables.AddRange([ new CalamariExecutionVariable(Deployment.SpecialVariables.Action.Script.ScriptBodyBySyntax(ScriptSyntax.Bash), "touch \"$(get_octopusvariable 'Octopus.Calamari.Git.RepositoryPath')/proof.txt\"", false), ]); - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); GetCommittedFileContent("proof.txt").Should().NotBeNull("script provided via syntax-specific variable should run and commit the file"); } [Test] - public void WhenNoScriptAndNoPackagesCommandSucceedsWithZeroExitCode() + public async Task WhenNoScriptAndNoPackagesCommandSucceedsWithZeroExitCode() { - RunCommitToGit().Should().Be(0); + (await RunCommitToGit()).Should().Be(0); } [Test] - public void WhenBothScriptParametersArgAndVariableAreSetVariableTakesPrecedence() + public async Task WhenBothScriptParametersArgAndVariableAreSetVariableTakesPrecedence() { var proofFile = Path.Combine(executionDirectory, "arg_check.txt"); var zipPath = CreateZipWithEntry("transform-script", "script.sh", @@ -358,46 +359,46 @@ public void WhenBothScriptParametersArgAndVariableAreSetVariableTakesPrecedence( new CalamariExecutionVariable(ScriptVariables.ScriptParameters, "from-variable", false), ]); - RunCommitToGit("--package", zipPath, "--scriptParameters", "from-arg").Should().Be(0); + (await RunCommitToGit("--package", zipPath, "--scriptParameters", "from-arg")).Should().Be(0); File.Exists(proofFile).Should().BeTrue("the variable value should take precedence over the --scriptParameters arg"); } [Test] - public void CommitToGit_FailsWithCommandException_WhenCustomPropertiesFileOptionIsMissing() + public async Task CommitToGit_FailsWithCommandException_WhenCustomPropertiesFileOptionIsMissing() { - RunCommitToGit(includeCustomProperties: false) + (await RunCommitToGit(includeCustomProperties: false)) .Should().NotBe(0, "the command must reject runs that do not supply --customPropertiesFile"); } [Test] - public void CommitToGit_FailsWithCommandException_WhenCustomPropertiesPasswordOptionIsMissing() + public async Task CommitToGit_FailsWithCommandException_WhenCustomPropertiesPasswordOptionIsMissing() { var propsPath = WriteCustomPropertiesFile("n", OriginPath, "u", "p"); - RunCommitToGit(includeCustomProperties: false, "--customPropertiesFile", propsPath) + (await RunCommitToGit(includeCustomProperties: false, "--customPropertiesFile", propsPath)) .Should().NotBe(0, "the command must reject runs that do not supply --customPropertiesPassword"); } [Test] - public void CommitToGit_FailsWithCommandException_WhenCustomPropertiesFileDoesNotExist() + public async Task CommitToGit_FailsWithCommandException_WhenCustomPropertiesFileDoesNotExist() { var missingPath = Path.Combine(executionDirectory, "does-not-exist.json"); - RunCommitToGit(includeCustomProperties: false, + (await RunCommitToGit(includeCustomProperties: false, "--customPropertiesFile", missingPath, - "--customPropertiesPassword", customPropertiesPassword) + "--customPropertiesPassword", customPropertiesPassword)) .Should().NotBe(0, "the command must reject runs whose --customPropertiesFile path does not exist"); } // --- Helpers --- - int RunCommitToGit(params string[] extraArgs) - => RunCommitToGit(includeCustomProperties: true, extraArgs); + async Task RunCommitToGit(params string[] extraArgs) + => await RunCommitToGit(includeCustomProperties: true, extraArgs); - int RunCommitToGit(bool includeCustomProperties, params string[] extraArgs) + async Task RunCommitToGit(bool includeCustomProperties, params string[] extraArgs) { var absPathToVariables = Path.Combine(executionDirectory, variableFileName); - File.WriteAllBytes(absPathToVariables, AesEncryption.ForServerVariables(variablePassword).Encrypt(variables.ToJsonString())); + await File.WriteAllBytesAsync(absPathToVariables, AesEncryption.ForServerVariables(variablePassword).Encrypt(variables.ToJsonString())); var args = new List { @@ -414,7 +415,7 @@ int RunCommitToGit(bool includeCustomProperties, params string[] extraArgs) args.AddRange(extraArgs); - return Program.Main(args.ToArray()); + return await Program.Main(args.ToArray()); } string WriteCustomPropertiesFile(string credentialName, string repositoryUrl, string username, string password) diff --git a/source/Calamari.Tests/Fixtures/Certificates/ImportCertificateCommandFixture.cs b/source/Calamari.Tests/Fixtures/Certificates/ImportCertificateCommandFixture.cs index c65ddc3722..dc48bd0f5c 100644 --- a/source/Calamari.Tests/Fixtures/Certificates/ImportCertificateCommandFixture.cs +++ b/source/Calamari.Tests/Fixtures/Certificates/ImportCertificateCommandFixture.cs @@ -2,6 +2,7 @@ using System.IO; using System.Runtime.Versioning; using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; using Calamari.Common.Plumbing.Extensions; using Calamari.Common.Plumbing.FileSystem; using Calamari.Common.Plumbing.Variables; @@ -25,20 +26,20 @@ public class ImportCertificateCommandFixture : CalamariFixture readonly SampleCertificate cert = SampleCertificate.CapiWithPrivateKey; [Test] - public void AddingCertToRoot_ThrowsError() + public async Task AddingCertToRoot_ThrowsError() { var variables = CreateInitialVariables(); variables.Add(SpecialVariables.Action.Certificate.StoreName, StoreName.Root.ToString()); variables.Add(SpecialVariables.Action.Certificate.StoreLocation, StoreLocation.CurrentUser.ToString()); - var result = Invoke(variables); + var result = await Invoke(variables); result.AssertFailure(); result.AssertErrorOutput("When importing certificate into Root store, location must be 'LocalMachine'. Windows security restrictions prevent importing into the Root store for a user."); } [Test] - public void AddingCertToStore_AddsCert() + public async Task AddingCertToStore_AddsCert() { var certificateStoreLocation = StoreLocation.LocalMachine; var storeName = StoreName.My.ToString(); @@ -47,7 +48,7 @@ public void AddingCertToStore_AddsCert() variables.Add(SpecialVariables.Action.Certificate.StoreLocation, certificateStoreLocation.ToString()); cert.EnsureCertificateNotInStore(storeName, certificateStoreLocation); - var result = Invoke(variables); + var result = await Invoke(variables); result.AssertSuccess(); result.AssertOutputContains($"Importing certificate '{randomSubject}' with thumbprint '{cert.Thumbprint}' into store 'LocalMachine\\My'"); @@ -59,7 +60,7 @@ public void AddingCertToStore_AddsCert() } [Test] - public void NoStoreLocationProvided_StoresInUserName() + public async Task NoStoreLocationProvided_StoresInUserName() { var storeName = StoreName.My.ToString(); var storeLocation = StoreLocation.CurrentUser; @@ -69,7 +70,7 @@ public void NoStoreLocationProvided_StoresInUserName() variables.Add(SpecialVariables.Action.Certificate.StoreUser, userName); cert.EnsureCertificateNotInStore(storeName, storeLocation); - var result = Invoke(variables); + var result = await Invoke(variables); result.AssertSuccess(); result.AssertOutputContains($"Importing certificate '{randomSubject}' with thumbprint '{cert.Thumbprint}' into store 'My' for user '{userName}'"); @@ -80,13 +81,13 @@ public void NoStoreLocationProvided_StoresInUserName() cert.EnsureCertificateNotInStore(storeName, storeLocation); } - CalamariResult Invoke(VariableDictionary variables) + async Task Invoke(VariableDictionary variables) { using (var variablesFile = new TemporaryFile(Path.GetTempFileName())) { var encryptionKey = variables.SaveAsEncryptedExecutionVariables(variablesFile.FilePath); - return InvokeInProcess(Calamari() + return await InvokeInProcess(Calamari() .Action("import-certificate") .VariablesFileArguments(variablesFile.FilePath, encryptionKey)); } diff --git a/source/Calamari.Tests/Fixtures/ProgramFixture.cs b/source/Calamari.Tests/Fixtures/ProgramFixture.cs index 9453e36982..4519032cf0 100644 --- a/source/Calamari.Tests/Fixtures/ProgramFixture.cs +++ b/source/Calamari.Tests/Fixtures/ProgramFixture.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Calamari.Common; using Calamari.Common.Plumbing; using Calamari.Common.Plumbing.Extensions; @@ -20,20 +21,20 @@ public void RunScript() Assert.AreEqual(1, retCode); } - static int RunProgram() - => Program.Main(new[] {"run-script"}); + static async Task RunProgram() + => await Program.Main(["run-script"]); [Test] - public void OctopusCalamariWorkingDirectoryEnvironmentVariableIsSet() + public async Task OctopusCalamariWorkingDirectoryEnvironmentVariableIsSet() { EnvironmentHelper.SetEnvironmentVariable("OctopusCalamariWorkingDirectory", null); - RunProgram(); + await RunProgram(); // This usage of Environment.GetEnvironmentVariable is fine as it's not accessing a test dependency variable Environment.GetEnvironmentVariable("OctopusCalamariWorkingDirectory").Should().NotBeNullOrWhiteSpace(); } [Test] - public void ProxyIsInitialized() + public async Task ProxyIsInitialized() { var existingProxy = WebRequest.DefaultWebProxy; try @@ -41,7 +42,7 @@ public void ProxyIsInitialized() EnvironmentHelper.SetEnvironmentVariable("TentacleProxyHost", "localhost"); WebRequest.DefaultWebProxy = null; - RunProgram(); + await RunProgram(); WebRequest.DefaultWebProxy.Should().NotBeNull(); } finally @@ -52,9 +53,9 @@ public void ProxyIsInitialized() } [Test] - public void DefaultRegexMatchTimeoutIsSet() + public async Task DefaultRegexMatchTimeoutIsSet() { - RunProgram(); + await RunProgram(); var regexTimeout = AppDomain.CurrentDomain.GetData("REGEX_DEFAULT_MATCH_TIMEOUT"); regexTimeout.Should().Be(AppDomainConfiguration.DefaultRegexMatchTimeout); } diff --git a/source/Calamari.Tests/Fixtures/Variables/VariablesFixture.cs b/source/Calamari.Tests/Fixtures/Variables/VariablesFixture.cs index 75563d79fd..6980212fb3 100644 --- a/source/Calamari.Tests/Fixtures/Variables/VariablesFixture.cs +++ b/source/Calamari.Tests/Fixtures/Variables/VariablesFixture.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading.Tasks; using Calamari.Common.Plumbing.Variables; using Calamari.Testing.Helpers; using Calamari.Tests.Helpers; @@ -12,7 +13,7 @@ public class VariablesFixture { [Test] - public void ShouldLogVariables() + public async Task ShouldLogVariables() { var variables = new CalamariVariables(); variables.Set(KnownVariables.PrintVariables, true.ToString()); @@ -26,7 +27,7 @@ public void ShouldLogVariables() { VariablesOverride = variables }; - program.RunStubCommand(); + await program.RunStubCommand(); var messages = program.TestLog.Messages; var messagesAsString = string.Join(Environment.NewLine, program.TestLog.Messages.Select(m => m.FormattedMessage)); diff --git a/source/Calamari.Tests/Helpers/CalamariFixture.cs b/source/Calamari.Tests/Helpers/CalamariFixture.cs index 99098d69bd..3d177da67b 100644 --- a/source/Calamari.Tests/Helpers/CalamariFixture.cs +++ b/source/Calamari.Tests/Helpers/CalamariFixture.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; using Calamari.Commands; //Required when NETFX is defined using Calamari.Common.Features.Processes; using Calamari.Common.Plumbing; @@ -40,21 +41,14 @@ protected CommandLine Calamari() return new CommandLine(calamariFullPath).UseDotnet().OutputToLog(false); } - protected CommandLine OctoDiff() - { - var octoDiffExe = OctoDiffCommandLineRunner.FindOctoDiffExecutable(); - - return new CommandLine(octoDiffExe); - } - - protected CalamariResult InvokeInProcess(CommandLine command, IVariables variables = null) + protected async Task InvokeInProcess(CommandLine command, IVariables variables = null) { var args = command.GetRawArgs(); var program = new TestProgram(Log); int exitCode; try { - exitCode = program.RunWithArgs(args); + exitCode = await program.RunWithArgs(args); } catch (Exception ex) { diff --git a/source/Calamari.Tests/Helpers/TestProgram.cs b/source/Calamari.Tests/Helpers/TestProgram.cs index e185e78376..036689efdc 100644 --- a/source/Calamari.Tests/Helpers/TestProgram.cs +++ b/source/Calamari.Tests/Helpers/TestProgram.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using Autofac; using Calamari.Commands.Support; using Calamari.Common.Commands; @@ -10,6 +11,7 @@ using Calamari.Common.Plumbing.Logging; using Calamari.Common.Plumbing.Variables; using Calamari.Testing.Helpers; +using JetBrains.Annotations; namespace Calamari.Tests.Helpers { @@ -27,21 +29,21 @@ class TestProgram : Program public bool StubWasCalled { get; set; } public IVariables VariablesOverride { get; set; } - public int RunWithArgs(string[] args) + public async Task RunWithArgs(string[] args) { - return Run(args); + return await Run(args); } - public int RunStubCommand() + public async Task RunStubCommand() { registerTestAssembly = false; CommandOverride = new StubCommand(() => StubWasCalled = true); - return Run(new [] {"stub"}); + return await Run(["stub"]); } - protected override Assembly GetProgramAssemblyToRegister() + protected override IEnumerable GetProgramAssembliesToRegister() { - return typeof(Program).Assembly; + yield return typeof(Program).Assembly; } protected override IEnumerable GetAllAssembliesToRegister() diff --git a/source/Calamari.Tests/KubernetesFixtures/Helm3UpgradeFixture.cs b/source/Calamari.Tests/KubernetesFixtures/Helm3UpgradeFixture.cs index a6e2130ab5..24e9d67f0c 100644 --- a/source/Calamari.Tests/KubernetesFixtures/Helm3UpgradeFixture.cs +++ b/source/Calamari.Tests/KubernetesFixtures/Helm3UpgradeFixture.cs @@ -17,9 +17,9 @@ public class Helm3UpgradeFixture : HelmUpgradeFixture [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void Upgrade_Succeeds() + public async Task Upgrade_Succeeds() { - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); result.AssertOutputMatches($"NAMESPACE: {Namespace}"); @@ -43,12 +43,12 @@ public async Task CustomHelmExeInPackage_RelativePath() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void HelmVersionNewerThanMinimumVersion_ReportsObjectStatus() + public async Task HelmVersionNewerThanMinimumVersion_ReportsObjectStatus() { Variables.AddFlag(SpecialVariables.ResourceStatusCheck, true); Variables.Set(SpecialVariables.Helm.Timeout, "2m30s"); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); result.AssertOutputMatches($"NAMESPACE: {Namespace}"); @@ -87,7 +87,7 @@ public async Task HelmVersionOlderThanMinimumVersion_DoesNotRunObjectStatus() Variables.AddFlag(SpecialVariables.ResourceStatusCheck, true); Variables.Set(SpecialVariables.Helm.Timeout, "2m30s"); - var result = DeployPackage(); + var result =await DeployPackage(); result.AssertSuccess(); result.AssertOutputMatches($"NAMESPACE: {Namespace}"); @@ -109,12 +109,12 @@ public async Task HelmVersionOlderThanMinimumVersion_DoesNotRunObjectStatus() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void HooksOnlyPackage_RetrievesEmptyManifestButDoesNotReportObjectStatus() + public async Task HooksOnlyPackage_RetrievesEmptyManifestButDoesNotReportObjectStatus() { Variables.AddFlag(SpecialVariables.ResourceStatusCheck, true); Variables.Set(SpecialVariables.Helm.Timeout, "2m30s"); - var result = DeployPackage("hooks-only-1.0.0.tgz"); + var result = await DeployPackage("hooks-only-1.0.0.tgz"); result.AssertSuccess(); result.AssertOutputMatches($"NAMESPACE: {Namespace}"); @@ -137,12 +137,12 @@ public void HooksOnlyPackage_RetrievesEmptyManifestButDoesNotReportObjectStatus( [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void EmptyChart_RetrievesEmptyManifestButDoesNotReportObjectStatus() + public async Task EmptyChart_RetrievesEmptyManifestButDoesNotReportObjectStatus() { Variables.AddFlag(SpecialVariables.ResourceStatusCheck, true); Variables.Set(SpecialVariables.Helm.Timeout, "2m30s"); - var result = DeployPackage("empty-chart-1.0.0.tgz"); + var result =await DeployPackage("empty-chart-1.0.0.tgz"); result.AssertSuccess(); result.AssertOutputMatches($"NAMESPACE: {Namespace}"); @@ -166,13 +166,13 @@ public void EmptyChart_RetrievesEmptyManifestButDoesNotReportObjectStatus() [RequiresNon32BitWindows] [RequiresNonMac] [Category(TestCategory.PlatformAgnostic)] - public void TargetingANamespaceThatDoesNotExistAbortsTheManifestSearchingLoop() + public async Task TargetingANamespaceThatDoesNotExistAbortsTheManifestSearchingLoop() { Variables.AddFlag(SpecialVariables.ResourceStatusCheck, true); Variables.Set(SpecialVariables.Helm.Timeout, "2m30s"); Variables.Set(SpecialVariables.Helm.Namespace, "this-namespace-does-not-exist"); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertFailure(); result.AssertOutputMatches($"Retrieving manifest for {ReleaseName}"); diff --git a/source/Calamari.Tests/KubernetesFixtures/HelmInstalledVersionUpgradeFixture.cs b/source/Calamari.Tests/KubernetesFixtures/HelmInstalledVersionUpgradeFixture.cs index fa0cd8aaf4..b94d5c191c 100644 --- a/source/Calamari.Tests/KubernetesFixtures/HelmInstalledVersionUpgradeFixture.cs +++ b/source/Calamari.Tests/KubernetesFixtures/HelmInstalledVersionUpgradeFixture.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using Calamari.Testing.Helpers; using Calamari.Testing.Requirements; using NUnit.Framework; @@ -12,9 +13,9 @@ public class HelmInstalledVersionUpgradeFixture : HelmUpgradeFixture [RequiresNon32BitWindows] [RequiresNonMac] [Category(TestCategory.PlatformAgnostic)] - public void Upgrade_Succeeds() + public async Task Upgrade_Succeeds() { - var result = DeployPackage(); + var result =await DeployPackage(); result.AssertSuccess(); result.AssertNoOutput("Using custom helm executable at"); diff --git a/source/Calamari.Tests/KubernetesFixtures/HelmUpgradeFixture.cs b/source/Calamari.Tests/KubernetesFixtures/HelmUpgradeFixture.cs index 9e5252673b..2ea3c068ea 100644 --- a/source/Calamari.Tests/KubernetesFixtures/HelmUpgradeFixture.cs +++ b/source/Calamari.Tests/KubernetesFixtures/HelmUpgradeFixture.cs @@ -139,9 +139,9 @@ public virtual void SetUp() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void NoValues_EmbeddedValuesUsed() + public async Task NoValues_EmbeddedValuesUsed() { - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); @@ -152,13 +152,13 @@ public void NoValues_EmbeddedValuesUsed() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void MismatchPackageIDAndHelmArchivePathWorks() + public async Task MismatchPackageIDAndHelmArchivePathWorks() { var packageName = $"{Variables.Get(PackageVariables.PackageId)}-{Variables.Get(PackageVariables.PackageVersion)}.tgz"; Variables.Set(PackageVariables.PackageId, "thisisnotamatch"); Variables.Set(PackageVariables.PackageVersion, "0.3.7"); - var result = DeployPackage(packageName); + var result =await DeployPackage(packageName); result.AssertSuccess(); @@ -169,12 +169,12 @@ public void MismatchPackageIDAndHelmArchivePathWorks() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void ExplicitValues_NewValuesUsed() + public async Task ExplicitValues_NewValuesUsed() { //Helm Config Variables.Set(Kubernetes.SpecialVariables.Helm.KeyValues, "{\"SpecialMessage\": \"FooBar\"}"); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); Assert.AreEqual("Hello FooBar", result.CapturedOutput.OutputVariables["Message"]); } @@ -183,7 +183,7 @@ public void ExplicitValues_NewValuesUsed() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void ValuesFromPackage_NewValuesUsed() + public async Task ValuesFromPackage_NewValuesUsed() { //Additional Package Variables.Set(PackageVariables.IndexedPackageId("Pack-1"), "CustomValues"); @@ -194,7 +194,7 @@ public void ValuesFromPackage_NewValuesUsed() //Variable that will replace packaged value in package Variables.Set("MySecretMessage", "Variable Replaced In Package"); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); Assert.AreEqual("Hello Variable Replaced In Package", result.CapturedOutput.OutputVariables["Message"]); } @@ -203,12 +203,12 @@ public void ValuesFromPackage_NewValuesUsed() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void ValuesFromChartPackage_NewValuesUsed() + public async Task ValuesFromChartPackage_NewValuesUsed() { //Additional Package Variables.Set(Kubernetes.SpecialVariables.Helm.Packages.ValuesFilePath(""), Path.Combine("mychart", "secondary.Development.yaml")); - var result = DeployPackage(); + var result =await DeployPackage(); result.AssertSuccess(); Assert.AreEqual("Hello I am in a secondary", result.CapturedOutput.OutputVariables["Message"]); } @@ -217,12 +217,12 @@ public void ValuesFromChartPackage_NewValuesUsed() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void ValuesFromChartPackage_GetSubstituted() + public async Task ValuesFromChartPackage_GetSubstituted() { Variables.Set(PackageVariables.PackageVersion, "0.3.8"); Variables.Set("SpecialMessage", "octostache is working"); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); Assert.AreEqual("Hello octostache is working", result.CapturedOutput.OutputVariables["Message"]); } @@ -231,12 +231,12 @@ public void ValuesFromChartPackage_GetSubstituted() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void ValuesFromChartPackageWithoutSubDirectory_NewValuesUsed() + public async Task ValuesFromChartPackageWithoutSubDirectory_NewValuesUsed() { //Additional Package Variables.Set(Kubernetes.SpecialVariables.Helm.Packages.ValuesFilePath(""), "secondary.Development.yaml"); - var result = DeployPackage(); + var result =await DeployPackage(); result.AssertSuccess(); Assert.AreEqual("Hello I am in a secondary", result.CapturedOutput.OutputVariables["Message"]); } @@ -245,7 +245,7 @@ public void ValuesFromChartPackageWithoutSubDirectory_NewValuesUsed() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void ValuesFromPackageAndExplicit_ExplicitTakesPrecedence() + public async Task ValuesFromPackageAndExplicit_ExplicitTakesPrecedence() { //Helm Config (lets make sure Explicit values take precedence Variables.Set(Kubernetes.SpecialVariables.Helm.KeyValues, "{\"SpecialMessage\": \"FooBar\"}"); @@ -260,7 +260,7 @@ public void ValuesFromPackageAndExplicit_ExplicitTakesPrecedence() //Variable that will replace packaged value in package Variables.Set("MySecretMessage", "From A Variable Replaced In Package"); - var result = DeployPackage(); + var result =await DeployPackage(); result.AssertSuccess(); Assert.AreEqual("Hello FooBar", result.CapturedOutput.OutputVariables["Message"]); } @@ -269,11 +269,11 @@ public void ValuesFromPackageAndExplicit_ExplicitTakesPrecedence() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void ValuesFromRawYaml_ValuesAdded() + public async Task ValuesFromRawYaml_ValuesAdded() { Variables.Set(Kubernetes.SpecialVariables.Helm.YamlValues, "\"SpecialMessage\": \"YAML\""); - var result = DeployPackage(); + var result =await DeployPackage(); result.AssertSuccess(); Assert.AreEqual("Hello YAML", result.CapturedOutput.OutputVariables["Message"]); } @@ -284,7 +284,7 @@ protected async Task TestCustomHelmExeInPackage_RelativePath(string version) { AddPostDeployMessageCheckAndCleanup(); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); result.AssertOutput($"Using custom helm executable at {HelmOsPlatform}\\helm from inside package. Full path at"); } @@ -314,13 +314,13 @@ protected async Task UseCustomHelmExeInPackage(string version) [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void Namespace_Override_Used() + public async Task Namespace_Override_Used() { const string @namespace = "calamari-testing-foo"; Variables.Set(Kubernetes.SpecialVariables.Helm.Namespace, @namespace); AddPostDeployMessageCheckAndCleanup(@namespace); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); Assert.AreEqual("Hello Embedded Variables", result.CapturedOutput.OutputVariables["Message"]); } @@ -329,12 +329,12 @@ public void Namespace_Override_Used() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void AdditionalArgumentsPassed() + public async Task AdditionalArgumentsPassed() { Variables.Set(Kubernetes.SpecialVariables.Helm.AdditionalArguments, "--dry-run"); AddPostDeployMessageCheckAndCleanup(explicitNamespace: null, dryRun: true); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); result.AssertOutputMatches("[helm|\\\\helm\"] upgrade (.*) --dry-run"); } @@ -343,13 +343,13 @@ public void AdditionalArgumentsPassed() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void DoesNotReportManifestsWhenDryRunIsSet() + public async Task DoesNotReportManifestsWhenDryRunIsSet() { Variables.Set(Kubernetes.SpecialVariables.Helm.AdditionalArguments, "--dry-run"); Variables.Set(Kubernetes.SpecialVariables.ResourceStatusCheck, "true"); AddPostDeployMessageCheckAndCleanup(explicitNamespace: null, dryRun: true); - var result = DeployPackage(); + var result = await DeployPackage(); result.AssertSuccess(); result.AssertOutputMatches("[helm|\\\\helm\"] upgrade (.*) --dry-run"); result.AssertOutputContains("Helm --dry-run is enabled, no object statuses will be reported"); @@ -360,10 +360,10 @@ public void DoesNotReportManifestsWhenDryRunIsSet() [RequiresNon32BitWindows] [RequiresNonMac] [Category(TestCategory.PlatformAgnostic)] - public void WhenTheChartDirectoryVariableIsSet_TheChartAtThatLocationIsUsed() + public async Task WhenTheChartDirectoryVariableIsSet_TheChartAtThatLocationIsUsed() { Variables.Set(Kubernetes.SpecialVariables.Helm.ChartDirectory, "specific/location/for/my/chart"); - var result = DeployPackage("mychart-with-specific-location-0.3.8.tar.gz"); + var result =await DeployPackage("mychart-with-specific-location-0.3.8.tar.gz"); result.AssertSuccess(); } @@ -371,10 +371,10 @@ public void WhenTheChartDirectoryVariableIsSet_TheChartAtThatLocationIsUsed() [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void WhenTheChartDirectoryVariableIsSet_AndTheChartDoesNotExist_AnErrorIsReturned() + public async Task WhenTheChartDirectoryVariableIsSet_AndTheChartDoesNotExist_AnErrorIsReturned() { Variables.Set(Kubernetes.SpecialVariables.Helm.ChartDirectory, "specific/location/for/my/chart"); - var result = DeployPackage(); // This package doesn't have the specific location, should go :boom: + var result =await DeployPackage(); // This package doesn't have the specific location, should go :boom: result.AssertFailure(); result.AssertOutputContains("Chart was not found in 'specific/location/for/my/chart'"); } @@ -383,9 +383,9 @@ public void WhenTheChartDirectoryVariableIsSet_AndTheChartDoesNotExist_AnErrorIs [RequiresNonFreeBSDPlatform] [RequiresNon32BitWindows] [Category(TestCategory.PlatformAgnostic)] - public void WhenChartIsInRootOfPackage_ShouldUseTheRootStagingDirectory() + public async Task WhenChartIsInRootOfPackage_ShouldUseTheRootStagingDirectory() { - var result = DeployPackage("mychart-with-no-root-folder-0.3.8.tgz"); + var result = await DeployPackage("mychart-with-no-root-folder-0.3.8.tgz"); result.AssertSuccess(); } @@ -421,7 +421,7 @@ void AddPostDeployMessageCheckAndCleanup(string explicitNamespace = null, bool d static string DeleteCommand(string @namespace, string releaseName) => $"uninstall {releaseName} --namespace {@namespace}"; - protected CalamariResult DeployPackage(string packageName = null) + protected async Task DeployPackage(string packageName = null) { using (var variablesFile = new TemporaryFile(Path.GetTempFileName())) { @@ -435,7 +435,7 @@ protected CalamariResult DeployPackage(string packageName = null) var encryptionKey = Variables.SaveAsEncryptedExecutionVariables(variablesFile.FilePath); - return InvokeInProcess(Calamari() + return await InvokeInProcess(Calamari() .Action("helm-upgrade") .Argument("package", pkg) .VariablesFileArguments(variablesFile.FilePath, encryptionKey)); diff --git a/source/Calamari.Tests/TestProgramWrapper.cs b/source/Calamari.Tests/TestProgramWrapper.cs index 76c6b69faa..7534910919 100644 --- a/source/Calamari.Tests/TestProgramWrapper.cs +++ b/source/Calamari.Tests/TestProgramWrapper.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Calamari.Common.Plumbing.Logging; using Calamari.Tests.Helpers; @@ -8,9 +9,10 @@ public static class TestProgramWrapper { //This is a shell around Calamari.exe so we can use it in .net core testing, since in .net core when we reference the //Calamari project we only get the dll, not the exe - public static int Main(string[] args) + public static async Task Main(string[] args) { - return new TestProgram(ConsoleLog.Instance).Execute(args); + var program = new TestProgram(ConsoleLog.Instance); + return await program.Execute(args); } } } \ No newline at end of file diff --git a/source/Calamari/Program.cs b/source/Calamari/Program.cs index fb4121e5bf..9e92292d4d 100644 --- a/source/Calamari/Program.cs +++ b/source/Calamari/Program.cs @@ -5,6 +5,7 @@ using System.ComponentModel; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using Autofac.Features.Metadata; using Calamari.ArgoCD; using Calamari.ArgoCD.Conventions; @@ -44,48 +45,34 @@ protected Program(ILog log) : base(log) { } - public static int Main(string[] args) + public static async Task Main(string[] args) { - return new Program(ConsoleLog.Instance).Execute(args); + var program = new Program(ConsoleLog.Instance); + return await program.Execute(args); } - public int Execute(params string[] args) + public async Task Execute(params string[] args) { // Backward compatibility fix for v4 collections to ensure they are not null // from https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-v4.html#net-dg-v4-collections Amazon.AWSConfigs.InitializeCollections = true; - return Run(args); + return await Run(args); } - protected override int ResolveAndExecuteCommand(IContainer container, CommonOptions options) + protected override async Task ResolveAndExecuteCommandWithArgs(IContainer container, CommonOptions options) { - // Handle Pipeline commands such as Target Discovery - if (container.IsRegisteredWithName(options.Command)) - { - try - { - var pipeline = container.ResolveNamed(options.Command); - var variables = container.Resolve(); - pipeline.Execute(container, variables).GetAwaiter().GetResult(); - return 0; - } - catch (Exception ex) - { - return ConsoleFormatter.PrintError(ConsoleLog.Instance, ex); - } - } - + await Task.CompletedTask; var commands = container.Resolve, CommandMeta>>>(); var commandCandidates = commands.Where(x => x.Metadata.Name.Equals(options.Command, StringComparison.OrdinalIgnoreCase)).ToArray(); - if (commandCandidates.Length == 0) - throw new CommandException($"Could not find the command {options.Command}"); - if (commandCandidates.Length > 1) - throw new CommandException($"Multiple commands found with the name {options.Command}"); - - return commandCandidates[0].Value.Value.Execute(options.RemainingArguments.ToArray()); + return commandCandidates.Length switch + { + 0 => throw new CommandException($"Could not find the command {options.Command}"), + 1 => commandCandidates[0].Value.Value.Execute(options.RemainingArguments.ToArray()), + _ => throw new CommandException($"Multiple commands found with the name {options.Command}") + }; } protected override void ConfigureContainer(ContainerBuilder builder, CommonOptions options) @@ -93,7 +80,6 @@ protected override void ConfigureContainer(ContainerBuilder builder, CommonOptio base.ConfigureContainer(builder, options); builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); @@ -111,12 +97,12 @@ protected override void ConfigureContainer(ContainerBuilder builder, CommonOptio builder.RegisterType().AsSelf().SingleInstance(); if (OperatingSystem.IsWindows()) builder.RegisterType().As().SingleInstance(); - else + else builder.RegisterType().As().SingleInstance(); - + builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().InstancePerLifetimeScope(); - + builder.RegisterType() .As() .SingleInstance(); @@ -143,15 +129,7 @@ protected override void ConfigureContainer(ContainerBuilder builder, CommonOptio .WithMetadataFrom() .As(); - // Register Pipeline commands - builder.RegisterAssemblyTypes(assembliesToRegister) - .AssignableTo() - .WithMetadataFrom() - .Where(t => t.GetCustomAttribute() is not null) - .Named(t => t.GetCustomAttribute()!.Name); - - - builder.RegisterAssemblyTypes(GetProgramAssemblyToRegister()) + builder.RegisterAssemblyTypes(GetProgramAssembliesToRegister().ToArray()) .Where(x => typeof(ILaunchTool).IsAssignableFrom(x) && !x.IsAbstract && !x.IsInterface) .WithMetadataFrom() .As(); @@ -186,4 +164,4 @@ protected override IEnumerable GetAllAssembliesToRegister() } } } -} +} \ No newline at end of file