From 3950cd9846b695cbf4456d79a27baa202a4f0dfa Mon Sep 17 00:00:00 2001 From: jan Date: Tue, 7 May 2024 16:22:39 +0200 Subject: [PATCH 1/3] - added copy file Plugin.File.Tests.csproj - added tests - fixed client variabe provider --- .../Nox.Cli.Plugin.File/FileCopyFile_v1.cs | 114 ++++++++++++++++++ .../Nox.Cli.Plugin.File/FileCopyFolder_v1.cs | 44 ++++++- .../ClientVariableProvider.cs | 11 +- .../ServerVariableProvider.cs | 12 +- src/Plugin.File.Tests/CopyFileTests.cs | 102 ++++++++++++++++ src/Plugin.File.Tests/Helpers.cs | 37 ++++++ .../Plugin.File.Tests.csproj | 10 ++ .../files/copy-file/source/Sample.txt | 0 .../files/copy-file/source/child/Sample.txt | 0 9 files changed, 322 insertions(+), 8 deletions(-) create mode 100644 src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs create mode 100644 src/Plugin.File.Tests/CopyFileTests.cs create mode 100644 src/Plugin.File.Tests/Helpers.cs create mode 100644 src/Plugin.File.Tests/files/copy-file/source/Sample.txt create mode 100644 src/Plugin.File.Tests/files/copy-file/source/child/Sample.txt diff --git a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs new file mode 100644 index 00000000..d36bfb54 --- /dev/null +++ b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs @@ -0,0 +1,114 @@ +using Nox.Cli.Abstractions; +using Nox.Cli.Abstractions.Extensions; + +namespace Nox.Cli.Plugin.File; + +public class FileCopyFile_v1: INoxCliAddin +{ + public NoxActionMetaData Discover() + { + return new NoxActionMetaData + { + Name = "file/copy-file@v1", + Author = "Jan Schutte", + Description = "Copy a file from one folder to another.", + + Inputs = + { + ["source-path"] = new NoxActionInput { + Id = "source-path", + Description = "The path to the file to copy", + Default = string.Empty, + IsRequired = true + }, + + ["target-path"] = new NoxActionInput { + Id = "target-path", + Description = "The path of the folder into which to copy the source file", + Default = string.Empty, + IsRequired = true + }, + ["is-overwrite"] = new NoxActionInput { + Id = "is-overwrite", + Description = "Indicate whether the copy must overwrite the target file, if it exists.", + Default = false, + IsRequired = false + } + } + }; + } + + private string? _sourcePath; + private string? _targetPath; + private bool? _isOverwrite; + + public Task BeginAsync(IDictionary inputs) + { + _sourcePath = inputs.Value("source-path"); + _targetPath = inputs.Value("target-path"); + _isOverwrite = inputs.ValueOrDefault("is-overwrite", this); + return Task.CompletedTask; + } + + public Task> ProcessAsync(INoxWorkflowContext ctx) + { + var outputs = new Dictionary(); + var isValid = true; + + ctx.SetState(ActionState.Error); + + if (string.IsNullOrEmpty(_sourcePath) || + string.IsNullOrEmpty(_targetPath)) + { + ctx.SetErrorMessage("The File copy-file action was not initialized"); + } + else + { + try + { + var fullSourcePath = Path.GetFullPath(_sourcePath); + var filename = Path.GetFileName(fullSourcePath); + if (!System.IO.File.Exists(fullSourcePath)) + { + ctx.SetErrorMessage($"Source file: {fullSourcePath} does not exist!"); + isValid = false; + } + else + { + var fullTargetPath = Path.Combine(Path.GetFullPath(_targetPath), filename); + Directory.CreateDirectory(Path.GetDirectoryName(fullTargetPath)!); + if (System.IO.File.Exists(fullTargetPath)) + { + if (_isOverwrite!.Value) + { + System.IO.File.Delete(fullTargetPath); + } + else + { + ctx.SetErrorMessage($"File: {fullTargetPath} already exists, and is-overwrite was not specified."); + isValid = false; + } + + } + if (isValid) + { + System.IO.File.Copy(fullSourcePath, fullTargetPath); + ctx.SetState(ActionState.Success); + } + } + + } + catch (Exception ex) + { + ctx.SetErrorMessage(ex.Message); + } + } + + return Task.FromResult>(outputs); + } + + public Task EndAsync() + { + return Task.CompletedTask; + } +} diff --git a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs index bebc90fb..4d764316 100755 --- a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs +++ b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs @@ -35,6 +35,12 @@ public NoxActionMetaData Discover() Default = true, IsRequired = false }, + ["is-overwrite"] = new NoxActionInput { + Id = "is-overwrite", + Description = "Indicate whether the copy must overwrite the target path.", + Default = false, + IsRequired = false + } } }; } @@ -42,18 +48,21 @@ public NoxActionMetaData Discover() private string? _sourcePath; private string? _targetPath; private bool? _isRecursive; + private bool? _isOverwrite; public Task BeginAsync(IDictionary inputs) { _sourcePath = inputs.Value("source-path"); _targetPath = inputs.Value("target-path"); _isRecursive = inputs.ValueOrDefault("is-recursive", this); + _isOverwrite = inputs.ValueOrDefault("is-overwrite", this); return Task.CompletedTask; } public Task> ProcessAsync(INoxWorkflowContext ctx) { var outputs = new Dictionary(); + var isValid = true; ctx.SetState(ActionState.Error); @@ -70,6 +79,7 @@ public Task> ProcessAsync(INoxWorkflowContext ctx) if (!Directory.Exists(fullSourcePath)) { ctx.SetErrorMessage($"Folder {fullSourcePath} does not exist!"); + isValid = false; } else { @@ -78,8 +88,24 @@ public Task> ProcessAsync(INoxWorkflowContext ctx) { Directory.CreateDirectory(fullTargetPath); } - CopyFiles(fullSourcePath, fullTargetPath); - ctx.SetState(ActionState.Success); + else + { + if (_isOverwrite!.Value) + { + PurgeFolder(fullTargetPath); + } + else + { + ctx.SetErrorMessage($"Folder {fullTargetPath} already exists, and is-overwrite was not specified."); + isValid = false; + } + } + + if (isValid) + { + CopyFiles(fullSourcePath, fullTargetPath); + ctx.SetState(ActionState.Success); + } } } @@ -117,4 +143,18 @@ private void CopyFiles(string sourceFolder, string targetFolder) } } } + + private void PurgeFolder(string path) + { + var di = new DirectoryInfo(path); + foreach (var file in di.GetFiles()) + { + file.Delete(); + } + + foreach (var dir in di.GetDirectories()) + { + dir.Delete(true); + } + } } diff --git a/src/Nox.Cli.Variables/ClientVariableProvider.cs b/src/Nox.Cli.Variables/ClientVariableProvider.cs index 150340b3..57678d76 100755 --- a/src/Nox.Cli.Variables/ClientVariableProvider.cs +++ b/src/Nox.Cli.Variables/ClientVariableProvider.cs @@ -217,15 +217,18 @@ private object ReplaceVariable(object value, bool isIfCondition = false, bool is { var result = value; - var match = _variableRegex.Match(result.ToString()!); + var matches = _variableRegex.Matches(result.ToString()!); - while (match.Success) + foreach (var match in matches.ToList()) { var fullPhrase = match.Groups[0].Value; var variable = match.Groups["variable"].Value; - if (isServer && _serverVariables.Contains(variable)) return result; + if (isServer && _serverVariables.Contains(variable)) + { + continue; + } var resolvedValue = LookupValue(variable); @@ -259,8 +262,6 @@ private object ReplaceVariable(object value, bool isIfCondition = false, bool is } result = result.ToString()!.Replace(fullPhrase, "NULL"); } - - match = _variableRegex.Match(result.ToString()!); } return result; diff --git a/src/Nox.Cli.Variables/ServerVariableProvider.cs b/src/Nox.Cli.Variables/ServerVariableProvider.cs index a58d37f0..20ef0ece 100755 --- a/src/Nox.Cli.Variables/ServerVariableProvider.cs +++ b/src/Nox.Cli.Variables/ServerVariableProvider.cs @@ -154,7 +154,17 @@ private void ResolveServerVariables() { //Find the variable value var lookupValue = LookupValue(match.Groups[2].Value); - if (lookupValue != null) item.Value = lookupValue; + if (lookupValue != null) + { + if (lookupValue is string) + { + item.Value = item.Value.ToString()!.Replace(match.Value, lookupValue.ToString()); + } + else + { + item.Value = lookupValue; + } + } } } } diff --git a/src/Plugin.File.Tests/CopyFileTests.cs b/src/Plugin.File.Tests/CopyFileTests.cs new file mode 100644 index 00000000..d6e88c4a --- /dev/null +++ b/src/Plugin.File.Tests/CopyFileTests.cs @@ -0,0 +1,102 @@ +using Moq; +using Nox.Cli.Abstractions.Caching; +using Nox.Cli.Actions; +using Nox.Cli.Configuration; +using Nox.Cli.Plugin.File; +using Nox.Cli.Variables.Secrets; +using Nox.Secrets.Abstractions; +using Nox.Solution; +using Xunit; + +namespace Plugin.File.Tests; + +public class CopyFileTests +{ + [Fact] + public async Task Can_copy_a_File_if_destination_folder_does_not_exist() + { + var path = "./files/copy-file"; + //Ensure the target folder does not exist + Helpers.PurgeFolderRecursive(Path.Combine(path, "new-target"), true); + + var plugin = new FileCopyFile_v1(); + var inputs = new Dictionary + { + {"source-path", Path.Combine(path, "source/Sample.txt")}, + {"target-path", Path.Combine(path, "new-target")} + }; + await plugin.BeginAsync(inputs); + var wfConfig = new WorkflowConfiguration(); + var sln = Mock.Of(); + var orgResolver = Mock.Of(); + var cacheMan = Mock.Of(); + var lteConfig = Mock.Of(); + var secretsResolver = Mock.Of(); + var ctx = new NoxWorkflowContext(wfConfig, sln, orgResolver, cacheMan, lteConfig, secretsResolver); + await plugin.ProcessAsync(ctx); + Assert.True(System.IO.File.Exists(Path.Combine(path, "new-target/Sample.txt"))); + } + + [Fact] + public async Task Must_not_copy_if_destination_folder_exists_and_overwrite_not_specified() + { + var path = "./files/copy-file"; + //Ensure the target folder exists + Helpers.PurgeFolderRecursive(Path.Combine(path, "new-target"), true); + Directory.CreateDirectory(Path.Combine(path, "new-target")); + await System.IO.File.WriteAllTextAsync(Path.Combine(path, "new-target/Sample.txt"), "Hello World"); + + var plugin = new FileCopyFile_v1(); + var inputs = new Dictionary + { + {"source-path", Path.Combine(path, "source/Sample.txt")}, + {"target-path", Path.Combine(path, "new-target")} + }; + await plugin.BeginAsync(inputs); + var wfConfig = new WorkflowConfiguration(); + var sln = Mock.Of(); + var orgResolver = Mock.Of(); + var cacheMan = Mock.Of(); + var lteConfig = Mock.Of(); + var secretsResolver = Mock.Of(); + var ctx = new NoxWorkflowContext(wfConfig, sln, orgResolver, cacheMan, lteConfig, secretsResolver); + await plugin.ProcessAsync(ctx); + await plugin.EndAsync(); + Assert.True(System.IO.File.Exists(Path.Combine(path, "new-target/Sample.txt"))); + var fileSize = new FileInfo(Path.Combine(path, "new-target/Sample.txt")).Length; + Assert.Equal(11, fileSize); + } + + [Fact] + public async Task Can_copy_a_File_if_destination_folder_exists_and_overwrite_specified() + { + var path = "./files/copy-file"; + //Ensure the target folder exists + Helpers.PurgeFolderRecursive(Path.Combine(path, "new-target"), true); + Directory.CreateDirectory(Path.Combine(path, "new-target")); + await System.IO.File.WriteAllTextAsync(Path.Combine(path, "new-target/Sample.txt"), "Hello World"); + + var plugin = new FileCopyFile_v1(); + var inputs = new Dictionary + { + {"source-path", Path.Combine(path, "source/Sample.txt")}, + {"target-path", Path.Combine(path, "new-target")}, + {"is-overwrite", true} + }; + await plugin.BeginAsync(inputs); + var wfConfig = new WorkflowConfiguration(); + var sln = Mock.Of(); + var orgResolver = Mock.Of(); + var cacheMan = Mock.Of(); + var lteConfig = Mock.Of(); + var secretsResolver = Mock.Of(); + var ctx = new NoxWorkflowContext(wfConfig, sln, orgResolver, cacheMan, lteConfig, secretsResolver); + await plugin.ProcessAsync(ctx); + await plugin.EndAsync(); + Assert.True(System.IO.File.Exists(Path.Combine(path, "new-target/Sample.txt"))); + var fileSize = new FileInfo(Path.Combine(path, "new-target/Sample.txt")).Length; + Assert.Equal(0, fileSize); + } + + +} \ No newline at end of file diff --git a/src/Plugin.File.Tests/Helpers.cs b/src/Plugin.File.Tests/Helpers.cs new file mode 100644 index 00000000..69e40183 --- /dev/null +++ b/src/Plugin.File.Tests/Helpers.cs @@ -0,0 +1,37 @@ +namespace Plugin.File.Tests; + +public static class Helpers +{ + public static void PurgeFolderRecursive(string path, bool includeRoot) + { + if (Directory.Exists(path)) + { + PurgeFolder(path); + var di = new DirectoryInfo(path); + + foreach (var dir in di.GetDirectories()) + { + PurgeFolder(dir.FullName); + dir.Delete(true); + } + + if (includeRoot) + { + Directory.Delete(path); + } + } + } + + public static void PurgeFolder(string path) + { + if (Directory.Exists(path)) + { + var di = new DirectoryInfo(path); + + foreach (var file in di.GetFiles()) + { + file.Delete(); + } + } + } +} \ No newline at end of file diff --git a/src/Plugin.File.Tests/Plugin.File.Tests.csproj b/src/Plugin.File.Tests/Plugin.File.Tests.csproj index bd3e8ab3..292fcb88 100644 --- a/src/Plugin.File.Tests/Plugin.File.Tests.csproj +++ b/src/Plugin.File.Tests/Plugin.File.Tests.csproj @@ -27,6 +27,12 @@ Always + + Always + + + Always + @@ -34,5 +40,9 @@ + + + + diff --git a/src/Plugin.File.Tests/files/copy-file/source/Sample.txt b/src/Plugin.File.Tests/files/copy-file/source/Sample.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/Plugin.File.Tests/files/copy-file/source/child/Sample.txt b/src/Plugin.File.Tests/files/copy-file/source/child/Sample.txt new file mode 100644 index 00000000..e69de29b From f001fe93a628ba635211186f5c79d3fee748b1ca Mon Sep 17 00:00:00 2001 From: jan Date: Wed, 8 May 2024 11:14:06 +0200 Subject: [PATCH 2/3] - fixes to Copy-file and Copy-folder --- .../Nox.Cli.Plugin.File/FileCopyFile_v1.cs | 10 ++++++---- .../Nox.Cli.Plugin.File/FileCopyFolder_v1.cs | 10 ++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs index d36bfb54..240d4cc6 100644 --- a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs +++ b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs @@ -33,7 +33,7 @@ public NoxActionMetaData Discover() Description = "Indicate whether the copy must overwrite the target file, if it exists.", Default = false, IsRequired = false - } + } } }; } @@ -53,7 +53,6 @@ public Task BeginAsync(IDictionary inputs) public Task> ProcessAsync(INoxWorkflowContext ctx) { var outputs = new Dictionary(); - var isValid = true; ctx.SetState(ActionState.Error); @@ -71,16 +70,18 @@ public Task> ProcessAsync(INoxWorkflowContext ctx) if (!System.IO.File.Exists(fullSourcePath)) { ctx.SetErrorMessage($"Source file: {fullSourcePath} does not exist!"); - isValid = false; } else { + var isValid = true; var fullTargetPath = Path.Combine(Path.GetFullPath(_targetPath), filename); - Directory.CreateDirectory(Path.GetDirectoryName(fullTargetPath)!); + Directory.CreateDirectory(Path.GetDirectoryName(Path.GetDirectoryName(fullTargetPath))!); + var createDate = DateTime.Now; if (System.IO.File.Exists(fullTargetPath)) { if (_isOverwrite!.Value) { + createDate = System.IO.File.GetCreationTime(fullTargetPath); System.IO.File.Delete(fullTargetPath); } else @@ -93,6 +94,7 @@ public Task> ProcessAsync(INoxWorkflowContext ctx) if (isValid) { System.IO.File.Copy(fullSourcePath, fullTargetPath); + System.IO.File.SetCreationTime(fullTargetPath, createDate); ctx.SetState(ActionState.Success); } } diff --git a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs index 4d764316..ac556a13 100755 --- a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs +++ b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs @@ -129,10 +129,16 @@ private void CopyFiles(string sourceFolder, string targetFolder) foreach (var file in di.GetFiles()) { - var targetFilePath = Path.Combine(targetFolder, file.Name); - if (System.IO.File.Exists(targetFilePath)) System.IO.File.Delete(targetFilePath); + var targetFilePath = Path.Combine(targetFolder, file.Name); + var createDate = DateTime.Now; + if (System.IO.File.Exists(targetFilePath)) + { + createDate = System.IO.File.GetCreationTime(targetFilePath); + System.IO.File.Delete(targetFilePath); + } Directory.CreateDirectory(targetFolder); file.CopyTo(targetFilePath); + System.IO.File.SetCreationTime(targetFilePath, createDate); } if (_isRecursive == true) From e4e8f829f4bedbfe2b41d3d3dc1ee763d8fb8628 Mon Sep 17 00:00:00 2001 From: jan Date: Wed, 8 May 2024 11:58:13 +0200 Subject: [PATCH 3/3] - fixed copy-file --- src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs | 2 +- src/Plugin.File.Tests/FolderRenameTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs index 240d4cc6..6765a1ed 100644 --- a/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs +++ b/src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs @@ -75,7 +75,7 @@ public Task> ProcessAsync(INoxWorkflowContext ctx) { var isValid = true; var fullTargetPath = Path.Combine(Path.GetFullPath(_targetPath), filename); - Directory.CreateDirectory(Path.GetDirectoryName(Path.GetDirectoryName(fullTargetPath))!); + Directory.CreateDirectory(Path.GetDirectoryName(fullTargetPath)!); var createDate = DateTime.Now; if (System.IO.File.Exists(fullTargetPath)) { diff --git a/src/Plugin.File.Tests/FolderRenameTests.cs b/src/Plugin.File.Tests/FolderRenameTests.cs index 409b9c77..9d0d43ae 100644 --- a/src/Plugin.File.Tests/FolderRenameTests.cs +++ b/src/Plugin.File.Tests/FolderRenameTests.cs @@ -25,7 +25,7 @@ public async Task Can_Rename_a_Folder() if (Directory.Exists(Path.Combine(path, "Sample-After"))) { - Directory.Delete(Path.Combine(path, "Sample-After")); + Helpers.PurgeFolderRecursive(Path.Combine(path, "Sample-After"), true); } CopyRecursively(Path.Combine(path, "Sample"), Path.Combine(path, "Sample-Before"));