diff --git a/README.md b/README.md index 3027d887..9c86b5b9 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ docker run -it --rm clio reg-web-app -help - [Get package list](#get-package-list) - [Set package version](#set-package-version) - [Set application version](#set-application-version) + - [Set application icon](#set-application-icon) - [NuGet Packages](#nuget-packages) - [Pack NuGet package](#pack-nuget-package) - [Push NuGet package](#push-nuget-package) @@ -423,6 +424,29 @@ clio set-app-versin -f -v ``` + +## Set Application Icon + +The `set-app-icon` command is used to set the icon for a specified application +by updating the `app-descriptor.json` file. + +### Usage + +```bash +clio set-app-icon [options] +``` +-p, --app-name (required): The name or code of the application. +-i, --app-icon (required): The path to the SVG icon file to be set. +-f, --package-folder (required): The path to the folder containing the application packages. + +Examples +Set the icon for an application with a specified name: + +```bash +clio set-app-icon -p MyAppName -i /path/to/icon.svg -f /path/to/package/folder +``` + + ## Enable/Disable pkg hotfix mode To see full description about Hot Fix mode visit [Creatio Academy](https://academy.creatio.com/docs/8.x/dev/development-on-creatio-platform/development-tools/delivery/hotfix-mode diff --git a/clio.tests/Command/ApplicationCommand/SetApplicationIconCommand.Tests.cs b/clio.tests/Command/ApplicationCommand/SetApplicationIconCommand.Tests.cs index a13aa293..f0b699d8 100644 --- a/clio.tests/Command/ApplicationCommand/SetApplicationIconCommand.Tests.cs +++ b/clio.tests/Command/ApplicationCommand/SetApplicationIconCommand.Tests.cs @@ -1,72 +1,48 @@ using System; -using System.Collections.Generic; using System.IO; -using System.IO.Abstractions.TestingHelpers; -using System.Json; using Autofac; using Clio.Command.ApplicationCommand; using Clio.ComposableApplication; -using FluentAssertions; -using ICSharpCode.SharpZipLib.Zip; using NSubstitute; using NUnit.Framework; -namespace Clio.Tests.Command.ApplicationCommand +namespace Clio.Tests.Command.ApplicationCommand; + +internal class SetApplicationIconCommandTestCase : BaseCommandTests { - internal class SetApplicationIconCommandTestCase : BaseCommandTests - { - private static string mockPackageFolderPath = Path.Combine("C:", "MockPackageFolder"); - private static string mockPackageAppDescriptorPath = Path.Combine(mockPackageFolderPath, "Files", "app-descriptor.json"); - private static string mockWorspacePath = Path.Combine("C:", "MockWorkspaceFolder"); - private static string mockWorkspaceAppPackageFolderPath = Path.Combine(mockWorspacePath, "packages", "IFrameSample"); - private static string mockWorkspaceAppDescriptorPath = Path.Combine(mockWorkspaceAppPackageFolderPath, "Files", "app-descriptor.json"); + #region Fields: Private + + private static readonly string MockWorkspacePath = Path.Combine("C:", "MockWorkspaceFolder"); - private static MockFileSystem CreateFs(string filePath, string packagePath) { - string originClioSourcePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory); - string appDescriptorExamplesDescriptorPath = Path.Combine(originClioSourcePath, "Examples", "AppDescriptors", filePath); - string mockAppDescriptorFilePath = Path.Combine(packagePath, "Files", "app-descriptor.json"); - return new MockFileSystem(new Dictionary { - { - mockAppDescriptorFilePath, - new MockFileData(File.ReadAllText(appDescriptorExamplesDescriptorPath)) - } - }); - } + private static readonly string MockWorkspaceAppPackageFolderPath + = Path.Combine(MockWorkspacePath, "packages", "IFrameSample"); - private static MockFileSystem CreateFs(Dictionary appDescriptors) { - string originClioSourcePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory); - MockFileSystem mockFileSystem = new MockFileSystem(); - foreach (var appDescriptor in appDescriptors) { - string appDescriptorExamplesDescriptorPath = Path.Combine(originClioSourcePath, "Examples", "AppDescriptors", appDescriptor.Value); - string mockAppDescriptorJsonPath = Path.Combine(mockWorspacePath, "packages", appDescriptor.Key, "Files", "app-descriptor.json"); - mockFileSystem.AddFile(mockAppDescriptorJsonPath, new MockFileData(File.ReadAllText(appDescriptorExamplesDescriptorPath))); - } - return mockFileSystem; - } + private IComposableApplicationManager _composableApplicationManager; - private MockFileSystem _fileSystem; - private IComposableApplicationManager composableApplicationManager; + #endregion - protected override void AdditionalRegistrations(ContainerBuilder containerBuilder) { - composableApplicationManager = Substitute.For(); - containerBuilder.RegisterInstance(composableApplicationManager); - base.AdditionalRegistrations(containerBuilder); - } + #region Methods: Protected - [Test] - public void SetApplicationIconCommand_CallsComposableAppmanager() { - string iconPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Files", "icon.svg"); - string appName = "ExampleAppName"; - var command = Container.Resolve(); - command.Execute(new SetApplicationIconOption { - IconPath = iconPath, - WorspaceFolderPath = mockWorspacePath, - PackageFolderPath = mockWorkspaceAppPackageFolderPath, - AppName = appName - }); - composableApplicationManager.Received(1).SetIcon(mockWorkspaceAppPackageFolderPath, iconPath, appName); - } + protected override void AdditionalRegistrations(ContainerBuilder containerBuilder){ + _composableApplicationManager = Substitute.For(); + containerBuilder.RegisterInstance(_composableApplicationManager); + base.AdditionalRegistrations(containerBuilder); + } + #endregion + + [Test] + public void SetApplicationIconCommand_CallsComposableAppmanager(){ + string iconPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Files", "icon.svg"); + string appName = "ExampleAppName"; + SetApplicationIconCommand command = Container.Resolve(); + command.Execute(new SetApplicationIconOption { + IconPath = iconPath, + PackageFolderPath = MockWorkspaceAppPackageFolderPath, + AppName = appName + }); + _composableApplicationManager.Received(1).SetIcon(MockWorkspaceAppPackageFolderPath, iconPath, appName); } -} + +} \ No newline at end of file diff --git a/clio.tests/Command/ApplicationCommand/SetApplicationVersionCommand.Tests.cs b/clio.tests/Command/ApplicationCommand/SetApplicationVersionCommand.Tests.cs index f297f646..50fa2c75 100644 --- a/clio.tests/Command/ApplicationCommand/SetApplicationVersionCommand.Tests.cs +++ b/clio.tests/Command/ApplicationCommand/SetApplicationVersionCommand.Tests.cs @@ -51,7 +51,7 @@ private static MockFileSystem CreateFs(Dictionary appDescriptors public void SetVersion_WhenWorkspaceContainsOneApplication(string descriptorPath) { _fileSystem = CreateFs(descriptorPath, mockWorkspaceAppPackageFolderPath); string expectedVersion = "8.1.1"; - var composableApplicationManager = new ComposableApplicationManager(_fileSystem); + var composableApplicationManager = new ComposableApplicationManager(_fileSystem, null); var command = new SetApplicationVersionCommand(composableApplicationManager); string worspaceFolderPath = mockWorspacePath; command.Execute(new SetApplicationVersionOption() { @@ -70,7 +70,7 @@ public void SetVersion_ThrowException_WhenWorkspaceContainsMoreThanOneApplicatio appDescriptions.Add("Package1", "app1-app-descriptor.json"); appDescriptions.Add("Package2", "app2-app-descriptor.json"); _fileSystem = CreateFs(appDescriptions); - var composableApplicationManager = new ComposableApplicationManager(_fileSystem); + var composableApplicationManager = new ComposableApplicationManager(_fileSystem, null); var command = new SetApplicationVersionCommand(composableApplicationManager); string expectedVersion = "8.1.1"; string worspaceFolderPath = mockWorspacePath; @@ -87,7 +87,7 @@ public void SetVersion_ThrowExceptionWhenAplicationExtendedAndPackageNotDefined( appDescriptions.Add("Package2", "app1-ext-app-descriptor.json"); _fileSystem = CreateFs(appDescriptions); string expectedVersion = "8.1.1"; - var composableApplicationManager = new ComposableApplicationManager(_fileSystem); + var composableApplicationManager = new ComposableApplicationManager(_fileSystem, null); var command = new SetApplicationVersionCommand(composableApplicationManager); string worspaceFolderPath = mockWorspacePath; var exception = Assert.Throws(() => command.Execute(new SetApplicationVersionOption() { @@ -104,7 +104,7 @@ public void SetVersion_WhenAplicationExtendedAndPackageDefined() { appDescriptions.Add(extendPackageName, "app1-ext-app-descriptor.json"); _fileSystem = CreateFs(appDescriptions); string expectedVersion = "8.1.1"; - var composableApplicationManager = new ComposableApplicationManager(_fileSystem); + var composableApplicationManager = new ComposableApplicationManager(_fileSystem, null); var command = new SetApplicationVersionCommand(composableApplicationManager); string worspaceFolderPath = mockWorspacePath; command.Execute(new SetApplicationVersionOption() { @@ -120,7 +120,7 @@ public void SetVersion_WhenAplicationExtendedAndPackageDefined() { public void SetVersion_WhenSetAppFolderPathForOneApplication(string descriptorPath) { _fileSystem = CreateFs(descriptorPath, mockPackageFolderPath); string expectedVersion = "8.1.1"; - var composableApplicationManager = new ComposableApplicationManager(_fileSystem); + var composableApplicationManager = new ComposableApplicationManager(_fileSystem, null); var command = new SetApplicationVersionCommand(composableApplicationManager); command.Execute(new SetApplicationVersionOption() { Version = expectedVersion, diff --git a/clio.tests/ComposableApplication/ComposableApplicationManagerTestCase.cs b/clio.tests/ComposableApplication/ComposableApplicationManagerTestCase.cs index ed29a3ad..3f8837f4 100644 --- a/clio.tests/ComposableApplication/ComposableApplicationManagerTestCase.cs +++ b/clio.tests/ComposableApplication/ComposableApplicationManagerTestCase.cs @@ -1,10 +1,12 @@ -using System.IO; +using System; +using System.IO; using Autofac; using Clio.ComposableApplication; using Clio.Package; using Clio.Tests.Command; using Clio.Tests.Extensions; using FluentAssertions; +using FluentValidation; using Newtonsoft.Json; using NUnit.Framework; @@ -15,6 +17,8 @@ public class ComposableApplicationManagerTestCase : BaseClioModuleTests #region Constants: Private + private const string IconPath = @"T:\SVG_Icons\Partner.svg"; + private const string PartnerSvgBase64 = "PHN2ZyB3aWR0aD0iMjI5IiBoZWlnaHQ9IjIxOSIgdmlld0JveD0iMCAwIDIyOSAyMTkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+DQo8ZyBjbGlwLXBhdGg9InVybCgjY2xpcDBfMTczXzIpIj4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTAyLjAzIDBDODcuMzYgNC42MiA3Mi42OSA5LjIzIDU4LjAzIDEzLjgzQzU5LjY2IDMxLjc0IDYxLjI5IDQ5LjY2IDYyLjkxIDY3LjU3Qzc0LjQxIDc1LjE5IDg1Ljg3IDgyLjg3IDk3LjQ0IDkwLjM4QzEwMS43NiA4NS40MyAxMDMuOTEgODQuNSAxMTAuNDggODMuNTRDMTA5LjY4IDc4LjM3IDEwOC45IDczLjE3IDEwOC4xNCA2OEwxMDYuOTkgNjcuNTRDOTcuNDIgNjMuNjEgODguNDMgNTQuMDIgODcuMTEgNDMuNTRDODUuNjYgMzIuMDQgOTQuMzYgMjYuMjYgMTA1LjEzIDI4LjQxQzExNi40IDMwLjY1IDEyNy42IDQxLjE3IDEyOS44MyA1Mi41NUMxMzEuNDYgNjAuOTUgMTI3LjY0IDY4LjIyIDExOC44MiA2OS40MUwxMTYuNTggNjkuNzFDMTE3LjQ3IDc0Ljg3IDExOC4zNCA4MCAxMTkuMTkgODUuMTZDMTI1LjM2IDg3LjY0IDEyOC44MSA5MC4zIDEzMy4zNiA5NS4xMkMxNDEuOTggOTAuNTIgMTUwLjU5IDg1Ljg5IDE1OS4xOSA4MS4yNUMxNTUuNSA2NC42MiAxNTEuODEgNDggMTQ4LjEgMzEuMzdDMTMyLjc1IDIwLjk1IDExNy4zOSAxMC41MSAxMDIuMDYgMC4wM0wxMDIuMDQgMC4wMUgxMDIuMDNWMFoiIGZpbGw9IndoaXRlIi8+DQo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTE2My4zOSA4Ni45NDk5QzE1NC44NCA5MS43ODk5IDE0Ni4yNyA5Ni42Mjk5IDEzNy43NCAxMDEuNTNDMTQwLjYgMTA3LjU4IDE0MS43OCAxMTEuNDMgMTQxLjQ5IDExOC4xNEMxNDYuMjQgMTIxLjMxIDE1MSAxMjQuNDggMTU1LjczIDEyNy42N0wxNTYuOTcgMTI2LjA0QzE2NC4xNiAxMTYuNTggMTc3LjExIDEyMS43IDE4NC40NSAxMjguMjFDMTg5LjE4IDEzMi40IDE5Mi45OCAxMzcuODkgMTk1LjMgMTQzLjc1QzE5OS44OCAxNTUuNCAxOTguNTUgMTczLjQ2IDE4Mi42NyAxNzIuNzNDMTY2LjU0IDE3Mi4wMSAxNTMuMDIgMTUyLjExIDE1My41MiAxMzYuOTJMMTUzLjU2IDEzNS43QzE0OC43IDEzMi41MSAxNDMuODggMTI5LjMgMTM5LjA0IDEyNi4wOUMxMzUuNDggMTMxLjE1IDEzMi42OCAxMzIuNDkgMTI1Ljg3IDEzMy42MkMxMjguMyAxNDguMDMgMTMwLjYgMTYyLjQ2IDEzMi45NyAxNzYuODhDMTUyLjM1IDE4OS41NSAxNzEuNjkgMjAyLjIzIDE5MS4xIDIxNC44MkMyMDMuNzcgMjAzLjI5IDIxNi4zNCAxOTEuNjQgMjI4Ljk3IDE4MC4wOUMyMjMuMzEgMTYwLjAxIDIxNy42OCAxMzkuOTEgMjEyLjAyIDExOS44MkMxOTUuNzkgMTA4LjkgMTc5LjU5IDk3LjkxOTkgMTYzLjM4IDg2Ljk1OTlWODYuOTM5OUwxNjMuMzkgODYuOTQ5OVoiIGZpbGw9IndoaXRlIi8+DQo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTEwMy40NiAxMjIuOTFDOTguODYgMTI1LjU4IDk0LjIzIDEyOC4yMSA4OS42MSAxMzAuODNMOTAuMjIgMTMyLjU1Qzk2LjIxIDE0OS41OSA4Ny4wOSAxNjguNTIgNjcuNjMgMTY3LjcxQzUwLjc2IDE2Ny4wMSAzNi44MSAxNTEuNDMgMzYuMTggMTM0Ljg3QzM1LjU5IDExOS41MyA0Ni44OCAxMDcuNzggNjIuMzYgMTA5LjQxQzY5Ljc0IDExMC4xOSA3Ni41NSAxMTMuODYgODEuNzIgMTE5LjExTDgyLjg3IDEyMC4yOEM4Ny41MiAxMTcuNzggOTIuMTggMTE1LjI3IDk2Ljg3IDExMi44MUM5NC41NSAxMDYuMyA5My43NyAxMDIuMzkgOTUuMTYgOTUuNTYwMUM4My41MyA4Ny44ODAxIDcxLjg3IDgwLjIyMDEgNjAuMjIgNzIuNTcwMUM0MS4wOCA4MC43NzAxIDIxLjk1IDg4Ljk4MDEgMi44Mjk5NiA5Ny4yMTAxVjE3MS42NkMyNS40OSAxODYuMDMgNDguMTMgMjAwLjQgNzAuODUgMjE0LjdDODkuMTUgMjAxLjg5IDEwNy4zNiAxODguOTYgMTI1LjY1IDE3Ni4xM0MxMjMuNSAxNjEuNjggMTIxLjMxIDE0Ny4yNiAxMTkuMjIgMTMyLjgxQzExMi4yOCAxMzAuNjQgMTA4LjUgMTI3Ljk5IDEwMy40NiAxMjIuOTNWMTIyLjkxWiIgZmlsbD0id2hpdGUiLz4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTAyLjY4IDEuMDYwMDZDODguOSA1LjM4MDA2IDc1LjE0IDkuNzQwMDYgNjEuMzcgMTQuMDQwMUM2Mi45MSAzMS4wMzAxIDY0LjQ3IDQ3Ljk5MDEgNjUuOTkgNjQuOTgwMUM3Ni42NSA3Mi4wNTAxIDg3LjMxIDc5LjIwMDEgOTguMDMgODYuMTgwMUMxMDAuNzYgODMuMDYwMSAxMDQuNTQgODEuMDEwMSAxMDguOTkgODAuMzYwMUMxMDguMzYgNzYuMjYwMSAxMDcuNzcgNzIuMjIwMSAxMDcuMTUgNjguMjEwMUM5Ni4yNiA2My43NDAxIDg3LjI5IDUzLjIzMDEgODUuOTQgNDIuNDUwMUM4NC4zOCAyOS45NzAxIDkzLjc3IDIyLjM1MDEgMTA2LjU0IDI0LjkxMDFDMTE4LjkzIDI3LjM4MDEgMTMwLjYxIDM4Ljc0MDEgMTMyLjk1IDUwLjc4MDFDMTM0Ljk1IDYxLjEzMDEgMTI5LjU0IDY4LjkzMDEgMTIwLjA4IDcwLjIxMDFDMTIwLjc3IDc0LjE2MDEgMTIxLjQzIDc4LjE3MDEgMTIyLjEyIDgyLjIzMDFDMTI2Ljc5IDg0LjEwMDEgMTMxLjE1IDg3LjIyMDEgMTM0Ljc5IDkxLjA2MDFDMTQyLjQzIDg2Ljk4MDEgMTUwLjA1IDgyLjg2MDEgMTU3LjY5IDc4Ljc3MDFDMTU0LjE5IDYyLjk1MDEgMTUwLjY2IDQ3LjE1MDEgMTQ3LjE2IDMxLjM1MDFDMTMyLjMzIDIxLjI4MDEgMTE3LjUxIDExLjIxMDEgMTAyLjcxIDEuMTEwMDZMMTAyLjY5IDEuMDcwMDZIMTAyLjY4VjEuMDYwMDZaIiBmaWxsPSJ3aGl0ZSIvPg0KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNjQuMyA4OC4xNjk5QzE1Ni43MyA5Mi40NDk5IDE0OS4xMyA5Ni43MTk5IDE0MS41OCAxMDEuMDZDMTQzLjcxIDEwNS41NyAxNDQuOTUgMTEwLjY1IDE0NC43MyAxMTUuNjVDMTQ4LjU3IDExOC4yMSAxNTIuNDEgMTIwLjc3IDE1Ni4yNSAxMjMuMzVDMTU5LjU1IDExOS4wMSAxNjQuNzEgMTE2Ljc1IDE3MC45NCAxMTcuNDVDMTgzLjMzIDExOC44IDE5Ni4wNyAxMzEuNDUgMTk5Ljg1IDE0Ni4yNUMyMDMuOCAxNjEuNjggMTk2LjcyIDE3NC4xNiAxODMuNTkgMTczLjU2QzE2Ni4zOCAxNzIuNzggMTUxLjgzIDE1Mi4wNSAxNTIuMzYgMTM1LjUxQzE0OC40MSAxMzIuOTEgMTQ0LjQ0IDEzMC4yOCAxNDAuNTEgMTI3LjY3QzEzNy44NCAxMzEuMDEgMTM0LjAyIDEzMy4zMSAxMjkuNCAxMzQuMDdDMTMxLjY2IDE0Ny40NCAxMzMuNzggMTYwLjg1IDEzNS45OCAxNzQuMjRDMTU0LjYyIDE4Ni40IDE3My4yMiAxOTguNjIgMTkxLjkxIDIxMC43M0MyMDMuODMgMTk5Ljg4IDIxNS42NSAxODguOTIgMjI3LjU1IDE3OC4wNEMyMjIuMSAxNTguNjQgMjE2LjY1IDEzOS4yMyAyMTEuMTggMTE5LjgzQzE5NS41NSAxMDkuMzIgMTc5LjkzIDk4LjcyOTkgMTY0LjMyIDg4LjE3OTlIMTY0LjNWODguMTY5OVoiIGZpbGw9IndoaXRlIi8+DQo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTEwNC4xMSAxMjQuM0MxMDAuNTUgMTI2LjM2IDk2Ljk1IDEyOC40MiA5My4yOCAxMzAuNDlDOTkuNyAxNDguNzcgODkuODEgMTY5LjQ1IDY4LjU0IDE2OC41NEM1MC45OCAxNjcuODIgMzUuNyAxNTEuOCAzNC45OSAxMzMuNkMzNC4zMiAxMTYuMjYgNDcuMzggMTA0LjE5IDYzLjU4IDEwNS45QzcxLjQxIDEwNi43MyA3OC42OSAxMTAuNTkgODQuMjYgMTE2LjIzQzg3Ljk1IDExNC4yNSA5MS41NyAxMTIuMyA5NS4xNiAxMTAuNDFDOTMuNDUgMTA1LjYxIDkyLjY4IDEwMC4yNSA5My43MSA5NS4yMTk5QzgyLjgyIDg4LjAyOTkgNzEuOSA4MC44Njk5IDYxIDczLjY4OTlDNDIuNjYgODEuNTI5OSAyNC4zMiA4OS40MDk5IDYgOTcuMjk5OVYxNjkuMTJDMjcuOSAxODMuMDEgNDkuODIgMTk2Ljk0IDcxLjc3IDIxMC43M0M4OS4zMSAxOTguNDUgMTA2Ljc2IDE4Ni4wNyAxMjQuMjkgMTczLjc3QzEyMi4yNyAxNjAuMjMgMTIwLjIxIDE0Ni43IDExOC4yNiAxMzMuMTRDMTEzLjA5IDEzMS41MyAxMDguMTkgMTI4LjM5IDEwNC4xMSAxMjQuMjlWMTI0LjNaIiBmaWxsPSJ3aGl0ZSIvPg0KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik05Ny40MTAxIDkwLjM2MDFDODUuODQwMSA4Mi44NTAxIDc0LjM4MDEgNzUuMTcwMSA2Mi44ODAxIDY3LjU1MDFDNjEuMjcwMSA0OS42NDAxIDU5LjYzMDEgMzEuNzIwMSA1OC4wMDAxIDEzLjgxMDFMNTUuMTgwMSAxNy40MTAxQzU2LjgxMDEgMzUuMzIwMSA1OC40NDAxIDUzLjI0MDEgNjAuMDYwMSA3MS4xNTAxQzcxLjU2MDEgNzguNzcwMSA4My4wMjAxIDg2LjQ1MDEgOTQuNTkgOTMuOTYwMUM5OC45MSA4OS4wMTAxIDEwMS4wNiA4OC4wODAxIDEwNy42MyA4Ny4xMjAxTDExMC40NSA4My41MjAxQzEwNC4xNiA4NC40NTAxIDEwMS44MyA4NS4zMjAxIDk3LjQxMDEgOTAuMzYwMVoiIGZpbGw9IndoaXRlIi8+DQo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTEwNS4xMSAyOC4zN0M5Ny42IDI2Ljg3IDkxLjA5IDI5LjI0IDg4LjMzIDM0LjcxQzkxLjY3IDMxLjg1IDk2LjcxIDMwLjgzIDEwMi4yOSAzMS45NUMxMTMuNTYgMzQuMTkgMTI0Ljc2IDQ0LjcxIDEyNi45OSA1Ni4wOUMxMjcuNzMgNTkuODkgMTI3LjM0IDYzLjQ3IDEyNS45IDY2LjM2QzEyOS41NSA2My4yMyAxMzAuOTEgNTguMTMgMTI5LjgxIDUyLjUxQzEyNy42IDQxLjEyIDExNi40IDMwLjYzIDEwNS4xMSAyOC4zN1oiIGZpbGw9IndoaXRlIi8+DQo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTExOS4xNyA4NS4xMDk5QzExOC4zMiA3OS45NDk5IDExNy40NSA3NC43OTk5IDExNi41NiA2OS42NTk5TDExMy43NCA3My4yNTk5QzExNC42MyA3OC40MTk5IDExNS41IDgzLjU0OTkgMTE2LjM1IDg4LjcwOTlDMTIyLjUyIDkxLjE4OTkgMTI1Ljk2IDkzLjg0OTkgMTMwLjUyIDk4LjY2OTlDMTM5LjE0IDk0LjA2OTkgMTQ3Ljc1IDg5LjQzOTkgMTU2LjM1IDg0Ljc5OTlMMTU5LjE3IDgxLjE5OTlDMTUwLjU3IDg1LjgzOTkgMTQxLjk2IDkwLjQ2OTkgMTMzLjM0IDk1LjA2OTlDMTI4Ljc4IDkwLjI0OTkgMTI1LjMzIDg3LjU3OTkgMTE5LjE3IDg1LjEwOTlaIiBmaWxsPSJ3aGl0ZSIvPg0KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yLjgyIDE3MS42NFY5Ny4xODk5TDAgMTAwLjc5VjE3NS4yNEMyMi42NiAxODkuNjEgNDUuMyAyMDMuOTggNjguMDIgMjE4LjI4Qzg2LjMyIDIwNS40NyAxMDQuNTMgMTkyLjU0IDEyMi44MiAxNzkuNzFMMTI1LjY0IDE3Ni4xMUMxMDguMzggMTg4LjI0IDg4LjEzIDIwMi41NyA3MC44NCAyMTQuNjhDNDguMTIgMjAwLjQgMjUuNDggMTg2LjAxIDIuODIgMTcxLjY0WiIgZmlsbD0id2hpdGUiLz4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNODEuNzMwMSAxMTkuMUM3Ni41NjAxIDExMy44NyA2OS43MzAxIDExMC4xOCA2Mi4zNzAxIDEwOS40QzUyLjYzMDEgMTA4LjM4IDQ0LjU3MDEgMTEyLjYzIDQwLjA2MDEgMTE5LjczQzQ0Ljc1MDEgMTE0LjgzIDUxLjU5MDEgMTEyLjE1IDU5LjU1MDEgMTEzQzY2LjkzMDEgMTEzLjc4IDczLjc0MDEgMTE3LjQ1IDc4LjkxMDEgMTIyLjdMODAuMDYwMSAxMjMuODdDODQuNzEwMSAxMjEuMzcgODkuMzcwMSAxMTguODYgOTQuMDYwMSAxMTYuNEw5Ni44ODAxIDExMi44QzkzLjM2MDEgMTE0LjY3IDg2LjQwMDEgMTE4LjM4IDgyLjg4MDEgMTIwLjI3TDgxLjczMDEgMTE5LjFaIiBmaWxsPSJ3aGl0ZSIvPg0KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik04OS42MSAxMzAuODRMODYuNzkgMTM0LjQ0Qzg5Ljk2IDE0My40NyA5MC41NSAxNTIuNzEgODUuMjEgMTYxLjEyQzkxLjg1IDE1NC4yNCA5My44OSAxNDMuMDQgOTAuMiAxMzIuNTZMODkuNTkgMTMwLjg0SDg5LjYxWiIgZmlsbD0id2hpdGUiLz4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTMyLjk2IDE3Ni44N0MxMzAuNzUgMTYzLjQzIDEyOC4xMiAxNDcuMDUgMTI1Ljg2IDEzMy42MUwxMjMuMDQgMTM3LjIxQzEyNS40NyAxNTEuNjIgMTI3Ljc3IDE2Ni4wNSAxMzAuMTQgMTgwLjQ3QzE0OS41MiAxOTMuMTQgMTY4Ljg2IDIwNS44MiAxODguMjcgMjE4LjQxQzIwMC45NCAyMDYuODggMjEzLjUxIDE5NS4yMyAyMjYuMTQgMTgzLjY4TDIyOC45NiAxODAuMDhDMjE3LjM1IDE5MC43MiAyMDIuNzQgMjA0LjIxIDE5MS4wOSAyMTQuODFDMTcxLjY4IDIwMi4yMiAxNTIuMzIgMTg5LjU0IDEzMi45NiAxNzYuODdaIiBmaWxsPSJ3aGl0ZSIvPg0KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMzcuNzUgMTAxLjUzTDEzNC45MyAxMDUuMTNDMTM3Ljc5IDExMS4xOCAxMzguOTcgMTE1LjAzIDEzOC42OCAxMjEuNzRDMTQzLjQzIDEyNC45MSAxNDguMTkgMTI4LjA4IDE1Mi45MiAxMzEuMjdMMTU1Ljc0IDEyNy42N0MxNTAuOTkgMTI0LjQ4IDE0Ni4yNSAxMjEuMzEgMTQxLjUgMTE4LjE0QzE0MS44IDExMS40OCAxNDAuNTQgMTA3LjQyIDEzNy43NSAxMDEuNTNaIiBmaWxsPSJ3aGl0ZSIvPg0KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xODQuNDYgMTI4LjE5QzE3Ny4xNCAxMjEuNjggMTY0LjE3IDExNi41NiAxNTYuOTggMTI2LjAyTDE1NS43NCAxMjcuNjVMMTU0LjkyIDEyOC42OUMxNjIuMjQgMTIwLjUxIDE3NC41NiAxMjUuNSAxODEuNjQgMTMxLjc5QzE4Ni4zNyAxMzUuOTggMTkwLjE3IDE0MS40NyAxOTIuNDkgMTQ3LjMzQzE5NS4yMiAxNTQuMjggMTk1Ljg1IDE2My41MiAxOTIuNTMgMTY5LjY5QzE5OC44MyAxNjQuMTUgMTk4LjY1IDE1Mi4yNCAxOTUuMzEgMTQzLjc1QzE5My4wMSAxMzcuODcgMTg5LjE5IDEzMi40IDE4NC40NiAxMjguMjFWMTI4LjE5WiIgZmlsbD0id2hpdGUiLz4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTA2LjU2IDI0Ljg5MDFDOTMuNzggMjIuMzMwMSA4NC4zOCAyOS45NzAxIDg1Ljk2IDQyLjQzMDFDODcuMzEgNTMuMTkwMSA5Ni4zMSA2My43MjAxIDEwNy4xNyA2OC4xOTAxTDEwOC4xMyA2Ny45OTAxTDEwNi45OCA2Ny41MzAxQzk3LjQxIDYzLjYwMDEgODguNDIgNTQuMDEwMSA4Ny4xIDQzLjUzMDFDODUuNjUgMzIuMDMwMSA5NC4zNSAyNi4yNTAxIDEwNS4xMiAyOC40MDAxQzExNi4zOSAzMC42NDAxIDEyNy41OSA0MS4xNjAxIDEyOS44MiA1Mi41NDAxQzEzMS40NSA2MC45NDAxIDEyNy42MyA2OC4yMTAxIDExOC44MSA2OS40MDAxTDExNi41NyA2OS43MDAxTDEyMC4xMSA3MC4yMjAxQzEyOS41NyA2OC45NjAxIDEzNC45OCA2MS4xMzAxIDEzMi45OCA1MC43OTAxQzEzMC42NCAzOC43NzAxIDExOC45NiAyNy4zOTAxIDEwNi41NyAyNC45MjAxTDEwNi41NSAyNC45MDAxSDEwNi41NlYyNC44OTAxWiIgZmlsbD0id2hpdGUiLz4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTcwLjk0IDExNy40NUMxNjQuNzEgMTE2Ljc2IDE1OS41NSAxMTkuMDMgMTU2LjI1IDEyMy4zNUwxNTUuNzMgMTI3LjY1TDE1Ni45NyAxMjYuMDJDMTY0LjE2IDExNi41NiAxNzcuMTEgMTIxLjY4IDE4NC40NSAxMjguMTlDMTg5LjE4IDEzMi4zOCAxOTIuOTggMTM3Ljg3IDE5NS4zIDE0My43M0MxOTkuODggMTU1LjM4IDE5OC41NSAxNzMuNDQgMTgyLjY3IDE3Mi43MUMxNjYuNTQgMTcxLjk5IDE1My4wMiAxNTIuMDkgMTUzLjUyIDEzNi45TDE1My41NiAxMzUuNjhMMTUyLjM1IDEzNS40OUMxNTEuODEgMTUyLjAzIDE2Ni4zNyAxNzIuNzggMTgzLjU4IDE3My41NEMxOTYuNzMgMTc0LjEzIDIwMy43OSAxNjEuNjUgMTk5Ljg0IDE0Ni4yM0MxOTYuMDYgMTMxLjQzIDE4My4zMiAxMTguNzkgMTcwLjkzIDExNy40M1YxMTcuNDVIMTcwLjk0WiIgZmlsbD0id2hpdGUiLz4NCjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNODkuNjEwMSAxMzAuODRMOTAuMjIwMSAxMzIuNTZDOTYuMjEwMSAxNDkuNiA4Ny4wOSAxNjguNTMgNjcuNjMgMTY3LjcyQzUwLjc2IDE2Ny4wMiAzNi44MSAxNTEuNDQgMzYuMTggMTM0Ljg4QzM1LjU5IDExOS41NCA0Ni44OCAxMDcuNzkgNjIuMzYgMTA5LjQyQzY5Ljc0IDExMC4yIDc2LjU1MDEgMTEzLjg3IDgxLjcyMDEgMTE5LjEyTDgyLjg3MDEgMTIwLjI5TDg0LjI4IDExNi4yNUM3OC43IDExMC42MSA3MS40MSAxMDYuNzYgNjMuNiAxMDUuOTJDNDcuMzkgMTA0LjIxIDM0LjM0IDExNi4yOSAzNS4wMSAxMzMuNjJDMzUuNzEgMTUxLjgzIDUwLjk5IDE2Ny44NSA2OC41NiAxNjguNTZDODkuODEgMTY5LjQ3IDk5LjcxMDEgMTQ4Ljc5IDkzLjMwMDEgMTMwLjUxTDg5LjYzIDEzMC44Nkw4OS42MTAxIDEzMC44NFoiIGZpbGw9IndoaXRlIi8+DQo8L2c+DQo8ZGVmcz4NCjxjbGlwUGF0aCBpZD0iY2xpcDBfMTczXzIiPg0KPHJlY3Qgd2lkdGg9IjIyOC45NyIgaGVpZ2h0PSIyMTguNDEiIGZpbGw9IndoaXRlIi8+DQo8L2NsaXBQYXRoPg0KPC9kZWZzPg0KPC9zdmc+DQo="; @@ -23,6 +27,7 @@ private const string PartnerSvgBase64 #region Fields: Private private IComposableApplicationManager _sut; + private readonly string workspacesFolderPath = Path.Combine("T:\\", "workspaces"); #endregion @@ -39,23 +44,118 @@ public override void Setup(){ [Test] public void SetIcon_ShouldSetCorrectFileNameAndIcon(){ - // Arrange - string workspacesFolderPath = Path.Combine("T:\\", "workspaces"); - const string expectedFilePath = @"T:\workspaces\ApolloAppWorkspace\packages\MrktApolloApp\Files\app-descriptor.json"; - const string iconPath = @"T:\SVG_Icons\Partner.svg"; + const string expectedFilePath + = @"T:\workspaces\ApolloAppWorkspace\packages\MrktApolloApp\Files\app-descriptor.json"; const string appName = "MrktApolloApp"; // Act - _sut.SetIcon(workspacesFolderPath, iconPath, appName); + _sut.SetIcon(workspacesFolderPath, IconPath, appName); // Assert FileSystem.FileExists(expectedFilePath); string appDescriptorContent = FileSystem.File.ReadAllText(expectedFilePath); AppDescriptorJson appDescriptor = JsonConvert.DeserializeObject(appDescriptorContent); - appDescriptor.IconName.Should().Be("Partner.svg"); + string iconFileName = Path.GetFileName(IconPath); + string timestampPattern = @"\d{14}$"; // Matches the datetime format "yyyyMMddHHmmss" + appDescriptor.IconName.Should().MatchRegex($"{iconFileName}_{timestampPattern}"); appDescriptor.Icon.Should().Be(PartnerSvgBase64); } + [Test] + public void SetIcon_ShouldThrow_When_AppNotFound(){ + // Arrange + const string appName = "NonExistingApp"; + + // Act + Action act = () => _sut.SetIcon(workspacesFolderPath, IconPath, appName); + + // Assert + act.Should().Throw() + .WithMessage($"App {appName} not found."); + } + + [Test] + public void SetIcon_ShouldThrow_When_MultipleAppDescriptorFoundWithAppCode(){ + // Arrange + const string appName = "MyAppCode"; + + // Act + Action act = () => _sut.SetIcon(workspacesFolderPath, IconPath, appName); + + // Assert + act.Should().Throw() + .WithMessage("More than one app-descriptor.json file found with the same Code:\n" + + "T:\\workspaces\\MyAppV1\\packages\\MrktApolloApp\\Files\\app-descriptor.json\n" + + "T:\\workspaces\\MyAppV2\\packages\\MrktApolloApp\\Files\\app-descriptor.json\n"); + } + + [Test] + public void SetIcon_ShouldThrow_When_IconPathNonExistant(){ + // Arrange + const string appName = "MyAppCode"; + + // Act + Action act = () => _sut.SetIcon(workspacesFolderPath, "C:\\1.svg", appName); + + // Assert + act.Should().Throw() + .WithMessage($"Validation failed: {Environment.NewLine} -- IconPath: Icon file 'C:\\1.svg' must exist. Severity: Error"); + } + + [Test] + public void SetIcon_ShouldThrow_When_IconPathIsEmpty(){ + // Arrange + const string appName = "MyAppCode"; + + // Act + Action act = () => _sut.SetIcon(workspacesFolderPath, string.Empty, appName); + + // Assert + act.Should().Throw() + .WithMessage($"Validation failed: {Environment.NewLine} -- IconPath: Icon path is required. Severity: Error"); + } + + [Test] + public void SetIcon_ShouldThrow_When_PackagesFolderPathNonExistant(){ + // Arrange + const string appName = "MyAppCode"; + + // Act + Action act = () => _sut.SetIcon("C:\\NonRealDir", IconPath, appName); + + // Assert + act.Should().Throw() + .WithMessage($"Validation failed: {Environment.NewLine} -- PackagesFolderPath: Packages folder path 'C:\\NonRealDir' must exist. Severity: Error"); + } + + [Test] + public void SetIcon_ShouldThrow_When_PackagesFolderPathIsEmpty(){ + // Arrange + const string appName = "MyAppCode"; + + // Act + Action act = () => _sut.SetIcon(string.Empty, IconPath, appName); + + // Assert + act.Should().Throw() + .WithMessage($"Validation failed: {Environment.NewLine} -- PackagesFolderPath: Packages folder path is required. Severity: Error"); + } + + + [Test] + public void SetIcon_ShouldThrow_When_AppDescriptorDoesNotExist(){ + // Arrange + const string appName = "iframe-sample"; + + string packagesFolderPath = Path.Combine(workspacesFolderPath, "iframe-sample"); + // Act + Action act = () => _sut.SetIcon(packagesFolderPath, IconPath, appName); + + // Assert + act.Should().Throw() + .WithMessage($"No app-descriptor.json file found in the specified packages folder path. {packagesFolderPath}"); + } + } \ No newline at end of file diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Assemblies/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Assemblies/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Data/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Data/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Files/app-descriptor.json b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Files/app-descriptor.json new file mode 100644 index 00000000..7b95c044 --- /dev/null +++ b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Files/app-descriptor.json @@ -0,0 +1,24 @@ +{ + "Name": "Apollo.io connector for Creatio", + "Description": "Apollo connector allows you to enrich contact and account records.", + "Maintainer": "Creatio", + "Icon": "", + "IconName": "", + "Color": "#FFAC07", + "Version": "1.1.4", + "MarketplaceLink": "", + "HelpLink": "", + "OrderLink": "", + "SupportEmail": "", + "Code": "MyAppCode", + "Packages": [ + { + "UId": "d40c3488-7718-4ddc-9173-949868871326", + "Name": "MrktApolloApp" + }, + { + "UId": "a2a415ef-1679-4f0e-85a3-92c34ac5fdbe", + "Name": "MrktApolloInC360" + } + ] +} \ No newline at end of file diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Resources/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/Resources/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/SqlScripts/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/SqlScripts/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/descriptor.json b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/descriptor.json new file mode 100644 index 00000000..93b20f5e --- /dev/null +++ b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloApp/descriptor.json @@ -0,0 +1,23 @@ +{ + "Descriptor": { + "UId": "d40c3488-7718-4ddc-9173-949868871326", + "PackageVersion": "1.0.0", + "Name": "MrktApolloApp", + "Type": 1, + "ModifiedOnUtc": "\/Date(1701358154000)\/", + "Maintainer": "Creatio", + "ProjectPath": "Files/MrktApolloApp.csproj", + "DependsOn": [ + { + "UId": "06d9ef10-51d8-122c-8933-9212e84236c9", + "PackageVersion": "7.8.0", + "Name": "CrtBase" + }, + { + "UId": "a17d52e6-97ab-6f7f-17aa-f0e197e488ea", + "PackageVersion": "7.8.0", + "Name": "CrtUIv2" + } + ] + } +} \ No newline at end of file diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/Assemblies/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/Assemblies/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/Data/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/Data/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/SqlScripts/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/SqlScripts/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/descriptor.json b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/descriptor.json new file mode 100644 index 00000000..99338351 --- /dev/null +++ b/clio.tests/Examples/workspaces/MyAppV1/packages/MrktApolloInC360/descriptor.json @@ -0,0 +1,26 @@ +{ + "Descriptor": { + "UId": "a2a415ef-1679-4f0e-85a3-92c34ac5fdbe", + "PackageVersion": "1.0.0", + "Name": "MrktApolloInC360", + "Type": 1, + "InstallBehavior": 1, + "ModifiedOnUtc": "\/Date(1701358165000)\/", + "Maintainer": "Creatio", + "ProjectPath": "Files/MrktApolloInC360.csproj", + "DependsOn": [ + { + "UId": "2ecba2bd-b810-47a5-a1b1-08c888529d6c", + "PackageVersion": "7.8.0", + "Name": "CrtCustomer360App", + "Type": 1 + }, + { + "UId": "d40c3488-7718-4ddc-9173-949868871326", + "PackageVersion": "1.0.0", + "Name": "MrktApolloApp", + "Type": 1 + } + ] + } +} \ No newline at end of file diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Assemblies/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Assemblies/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Data/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Data/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Files/app-descriptor.json b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Files/app-descriptor.json new file mode 100644 index 00000000..7b95c044 --- /dev/null +++ b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Files/app-descriptor.json @@ -0,0 +1,24 @@ +{ + "Name": "Apollo.io connector for Creatio", + "Description": "Apollo connector allows you to enrich contact and account records.", + "Maintainer": "Creatio", + "Icon": "", + "IconName": "", + "Color": "#FFAC07", + "Version": "1.1.4", + "MarketplaceLink": "", + "HelpLink": "", + "OrderLink": "", + "SupportEmail": "", + "Code": "MyAppCode", + "Packages": [ + { + "UId": "d40c3488-7718-4ddc-9173-949868871326", + "Name": "MrktApolloApp" + }, + { + "UId": "a2a415ef-1679-4f0e-85a3-92c34ac5fdbe", + "Name": "MrktApolloInC360" + } + ] +} \ No newline at end of file diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Resources/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/Resources/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/SqlScripts/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/SqlScripts/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/descriptor.json b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/descriptor.json new file mode 100644 index 00000000..93b20f5e --- /dev/null +++ b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloApp/descriptor.json @@ -0,0 +1,23 @@ +{ + "Descriptor": { + "UId": "d40c3488-7718-4ddc-9173-949868871326", + "PackageVersion": "1.0.0", + "Name": "MrktApolloApp", + "Type": 1, + "ModifiedOnUtc": "\/Date(1701358154000)\/", + "Maintainer": "Creatio", + "ProjectPath": "Files/MrktApolloApp.csproj", + "DependsOn": [ + { + "UId": "06d9ef10-51d8-122c-8933-9212e84236c9", + "PackageVersion": "7.8.0", + "Name": "CrtBase" + }, + { + "UId": "a17d52e6-97ab-6f7f-17aa-f0e197e488ea", + "PackageVersion": "7.8.0", + "Name": "CrtUIv2" + } + ] + } +} \ No newline at end of file diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/Assemblies/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/Assemblies/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/Data/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/Data/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/SqlScripts/placeholder.txt b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/SqlScripts/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/descriptor.json b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/descriptor.json new file mode 100644 index 00000000..99338351 --- /dev/null +++ b/clio.tests/Examples/workspaces/MyAppV2/packages/MrktApolloInC360/descriptor.json @@ -0,0 +1,26 @@ +{ + "Descriptor": { + "UId": "a2a415ef-1679-4f0e-85a3-92c34ac5fdbe", + "PackageVersion": "1.0.0", + "Name": "MrktApolloInC360", + "Type": 1, + "InstallBehavior": 1, + "ModifiedOnUtc": "\/Date(1701358165000)\/", + "Maintainer": "Creatio", + "ProjectPath": "Files/MrktApolloInC360.csproj", + "DependsOn": [ + { + "UId": "2ecba2bd-b810-47a5-a1b1-08c888529d6c", + "PackageVersion": "7.8.0", + "Name": "CrtCustomer360App", + "Type": 1 + }, + { + "UId": "d40c3488-7718-4ddc-9173-949868871326", + "PackageVersion": "1.0.0", + "Name": "MrktApolloApp", + "Type": 1 + } + ] + } +} \ No newline at end of file diff --git a/clio.tests/clio.tests.csproj b/clio.tests/clio.tests.csproj index 716b2e96..94f8664f 100644 --- a/clio.tests/clio.tests.csproj +++ b/clio.tests/clio.tests.csproj @@ -32,6 +32,63 @@ + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + @@ -228,6 +285,12 @@ + + + + + + diff --git a/clio/BindingsModule.cs b/clio/BindingsModule.cs index e16a02c9..754eec8a 100644 --- a/clio/BindingsModule.cs +++ b/clio/BindingsModule.cs @@ -22,6 +22,7 @@ using System; using System.Reflection; using Clio.Command.CreatioInstallCommand; +using Clio.ComposableApplication; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; using FileSystem = System.IO.Abstractions.FileSystem; @@ -141,6 +142,7 @@ public IContainer Register(EnvironmentSettings settings = null, bool registerNul containerBuilder.RegisterType(); containerBuilder.RegisterType(); containerBuilder.RegisterType(); + containerBuilder.RegisterType(); containerBuilder.RegisterType(); containerBuilder.RegisterType(); containerBuilder.RegisterType(); diff --git a/clio/Command/ApplicationCommand/SetApplicationIconCommand.cs b/clio/Command/ApplicationCommand/SetApplicationIconCommand.cs index eb705766..94a01e87 100644 --- a/clio/Command/ApplicationCommand/SetApplicationIconCommand.cs +++ b/clio/Command/ApplicationCommand/SetApplicationIconCommand.cs @@ -19,9 +19,7 @@ internal class SetApplicationIconOption [Option('f', "package-folder", Required = false, HelpText = "Package folder path")] public string PackageFolderPath { get; internal set; } - - [Value(0, MetaName = "workspace", Required = false, HelpText = "Workspace folder path")] - public string WorspaceFolderPath { get; internal set; } + #endregion @@ -47,9 +45,7 @@ public SetApplicationIconCommand(IComposableApplicationManager composableApplica #region Methods: Public public override int Execute(SetApplicationIconOption options){ - string packagesFolderPath = options.PackageFolderPath.IsNotNullOrEmpty() ? - options.PackageFolderPath : Path.Combine(options.WorspaceFolderPath, "packages"); - _composableApplicationManager.SetIcon(packagesFolderPath, options.IconPath, options.AppName); + _composableApplicationManager.SetIcon(options.PackageFolderPath, options.IconPath, options.AppName); return 0; } diff --git a/clio/ComposableApplication/ComposableApplicationManager.cs b/clio/ComposableApplication/ComposableApplicationManager.cs index c737a6c9..3c14d135 100644 --- a/clio/ComposableApplication/ComposableApplicationManager.cs +++ b/clio/ComposableApplication/ComposableApplicationManager.cs @@ -2,49 +2,128 @@ using System.IO; using System.IO.Abstractions; using System.Json; +using System.Linq; using System.Text; using Clio.Package; +using FluentValidation; +using FluentValidation.Results; using Newtonsoft.Json; namespace Clio.ComposableApplication; +public class SetIconParameters +{ + + #region Properties: Public + + public string AppName { get; set; } + + public string IconPath { get; set; } + + public string PackagesFolderPath { get; set; } + + #endregion + +} + +public class SetIconParametersValidator : AbstractValidator +{ + + #region Constructors: Public + + public SetIconParametersValidator(IFileSystem fileSystem){ + RuleFor(x => x.PackagesFolderPath) + .Cascade(CascadeMode.Stop) + .NotEmpty().WithMessage("Packages folder path is required.") + .Must(fileSystem.Directory.Exists) + .WithMessage(x => $"Packages folder path '{x.PackagesFolderPath}' must exist."); + + RuleFor(x => x.IconPath) + .Cascade(CascadeMode.Stop) + .NotEmpty() + .WithMessage("Icon path is required.") + .Must(fileSystem.File.Exists) + .WithMessage(x => $"Icon file '{x.IconPath}' must exist."); + + RuleFor(x => x.AppName) + .Cascade(CascadeMode.Stop) + .NotEmpty() + .WithMessage("App name is required."); + } + + #endregion + +} + public class ComposableApplicationManager : IComposableApplicationManager { #region Fields: Private private readonly IFileSystem _fileSystem; + private readonly IValidator _validator; #endregion #region Constructors: Public - public ComposableApplicationManager(IFileSystem fileSystem1){ - _fileSystem = fileSystem1; + public ComposableApplicationManager(IFileSystem fileSystem, IValidator validator){ + _fileSystem = fileSystem; + _validator = validator; } #endregion #region Methods: Public - public void SetIcon(string packagesFolderPath, string iconPath, string appName){ + SetIconParameters parameters = new() { + PackagesFolderPath = packagesFolderPath, + IconPath = iconPath, + AppName = appName + }; + + ValidationResult validationResult = _validator.Validate(parameters); + if (!validationResult.IsValid) { + throw new ValidationException(validationResult.Errors); + } + string[] files = _fileSystem.Directory .GetFiles(packagesFolderPath, "app-descriptor.json", SearchOption.AllDirectories); - foreach (string file in files) { - string appDescriptorContent = _fileSystem.File.ReadAllText(file); - AppDescriptorJson appDescriptor = JsonConvert.DeserializeObject(appDescriptorContent); - if (appDescriptor.Name == appName || appDescriptor.Code == appName) { - string iconFileName = Path.GetFileName(iconPath); - appDescriptor.IconName = iconFileName; - - string base64EncodedIcon = Convert.ToBase64String(_fileSystem.File.ReadAllBytes(iconPath)); - appDescriptor.Icon = base64EncodedIcon; - string formattedJsonString = JsonConvert.SerializeObject(appDescriptor, Formatting.Indented); - _fileSystem.File.WriteAllText(file, formattedJsonString); + if (files.Length == 0) { + throw new FileNotFoundException($"No app-descriptor.json file found in the specified packages folder path. {packagesFolderPath}"); + } + + var matchingFiles = files + .Select(file => new {File = file, Content = _fileSystem.File.ReadAllText(file)}) + .Select(fileContent => new { + fileContent.File, AppDescriptor = JsonConvert.DeserializeObject(fileContent.Content) + }) + .Where(fileDescriptor => fileDescriptor.AppDescriptor.Code == appName) + .ToList(); + + if (matchingFiles.Count > 1) { + StringBuilder exceptionMessage = new("More than one app-descriptor.json file found with the same Code:\n"); + foreach (var file in matchingFiles) { + exceptionMessage.AppendLine(file.File); } + throw new InvalidOperationException(exceptionMessage.ToString()); } + + if (matchingFiles.Count == 0) { + throw new ValidationException($"App {appName} not found."); + } + + var matchingFile = matchingFiles[0]; + string iconFileName = Path.GetFileName(iconPath); + string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); + matchingFile.AppDescriptor.IconName = $"{iconFileName}_{timestamp}"; + + string base64EncodedIcon = Convert.ToBase64String(_fileSystem.File.ReadAllBytes(iconPath)); + matchingFile.AppDescriptor.Icon = base64EncodedIcon; + string formattedJsonString = JsonConvert.SerializeObject(matchingFile.AppDescriptor, Formatting.Indented); + _fileSystem.File.WriteAllText(matchingFile.File, formattedJsonString); } public void SetVersion(string appPackagesFolderPath, string version, string packageName = null){ @@ -101,7 +180,7 @@ public interface IComposableApplicationManager #region Methods: Public /// - /// Sets the icon for the specified application by updating the app-descriptor.json file. + /// Sets the icon for the specified application by updating the app-descriptor.json file. /// /// The path to the folder containing the application packages. /// The path to the icon file to be set. diff --git a/clio/Wiki/WikiAnchors.txt b/clio/Wiki/WikiAnchors.txt index 74d8c694..ed73ac07 100644 --- a/clio/Wiki/WikiAnchors.txt +++ b/clio/Wiki/WikiAnchors.txt @@ -17,4 +17,5 @@ pkg-hotfix:enable/disable-pkg-hotfix-mode save-state:create-manifest-from-creatio-instance show-diff:show-difference-in-settings-for-two-creatio-intances mock-dat:mock-data-for-unit-tests -deploy-creatio:run-creatio-installation \ No newline at end of file +deploy-creatio:run-creatio-installation +set-app-icon:set-application-icon \ No newline at end of file