diff --git a/README.md b/README.md index cad34c74..a043cd57 100644 --- a/README.md +++ b/README.md @@ -74,4 +74,6 @@ RepoM uses plugins to extend functionality. At this moment, when a plugin is ava - [LuceneQueryParser](docs/RepoM.Plugin.LuceneQueryParser.md) - [SonarCloud](docs/RepoM.Plugin.SonarCloud.md) - [Statistics](docs/RepoM.Plugin.Statistics.md) + - [WebBrowser](docs/RepoM.Plugin.WebBrowser.md) - [WindowsExplorerGitInfo](docs/RepoM.Plugin.WindowsExplorerGitInfo.md) + diff --git a/README.source.md b/README.source.md index cad34c74..5a040b6d 100644 --- a/README.source.md +++ b/README.source.md @@ -74,4 +74,6 @@ RepoM uses plugins to extend functionality. At this moment, when a plugin is ava - [LuceneQueryParser](docs/RepoM.Plugin.LuceneQueryParser.md) - [SonarCloud](docs/RepoM.Plugin.SonarCloud.md) - [Statistics](docs/RepoM.Plugin.Statistics.md) + - [WebBrowser](docs/RepoM.Plugin.WebBrowser.md) - [WindowsExplorerGitInfo](docs/RepoM.Plugin.WindowsExplorerGitInfo.md) + \ No newline at end of file diff --git a/RepoM.sln b/RepoM.sln index 8141252d..87aa8f73 100644 --- a/RepoM.sln +++ b/RepoM.sln @@ -51,6 +51,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoM.App.Tests", "tests\Re EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoM.Plugin.Misc.Tests", "tests\RepoM.Plugin.Misc.Tests\RepoM.Plugin.Misc.Tests.csproj", "{A2264CB6-39DE-4EA2-8C1D-BA28115351E7}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoM.Plugin.WebBrowser", "src\RepoM.Plugin.WebBrowser\RepoM.Plugin.WebBrowser.csproj", "{23D796D1-1902-4357-9C95-4FB120A24A6E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoM.Plugin.WebBrowser.Tests", "tests\RepoM.Plugin.WebBrowser.Tests\RepoM.Plugin.WebBrowser.Tests.csproj", "{E976587E-F48E-4647-A307-91EFEC8F571C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -525,6 +529,46 @@ Global {A2264CB6-39DE-4EA2-8C1D-BA28115351E7}.Release|x64.Build.0 = Release|Any CPU {A2264CB6-39DE-4EA2-8C1D-BA28115351E7}.Release|x86.ActiveCfg = Release|Any CPU {A2264CB6-39DE-4EA2-8C1D-BA28115351E7}.Release|x86.Build.0 = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|ARM.ActiveCfg = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|ARM.Build.0 = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|ARM64.Build.0 = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|x64.ActiveCfg = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|x64.Build.0 = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|x86.ActiveCfg = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Debug|x86.Build.0 = Debug|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|Any CPU.Build.0 = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|ARM.ActiveCfg = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|ARM.Build.0 = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|ARM64.ActiveCfg = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|ARM64.Build.0 = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|x64.ActiveCfg = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|x64.Build.0 = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|x86.ActiveCfg = Release|Any CPU + {23D796D1-1902-4357-9C95-4FB120A24A6E}.Release|x86.Build.0 = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|ARM.Build.0 = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|ARM64.Build.0 = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|x64.ActiveCfg = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|x64.Build.0 = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|x86.ActiveCfg = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Debug|x86.Build.0 = Debug|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|Any CPU.Build.0 = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|ARM.ActiveCfg = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|ARM.Build.0 = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|ARM64.ActiveCfg = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|ARM64.Build.0 = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|x64.ActiveCfg = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|x64.Build.0 = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|x86.ActiveCfg = Release|Any CPU + {E976587E-F48E-4647-A307-91EFEC8F571C}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -547,6 +591,8 @@ Global {ED155806-81AD-49CC-B150-2C17F4902A1D} = {D6E372DC-10D3-4997-9DFC-568B4666635A} {85BA3DD7-8589-4020-A7DF-7E9F5D1A9C1A} = {D6E372DC-10D3-4997-9DFC-568B4666635A} {A2264CB6-39DE-4EA2-8C1D-BA28115351E7} = {D6E372DC-10D3-4997-9DFC-568B4666635A} + {23D796D1-1902-4357-9C95-4FB120A24A6E} = {D6E372DC-10D3-4997-9DFC-568B4666635A} + {E976587E-F48E-4647-A307-91EFEC8F571C} = {D6E372DC-10D3-4997-9DFC-568B4666635A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1765ABAA-0652-4DA5-ABBF-05396F2957D7} diff --git a/docs/ActionList.md b/docs/ActionList.md index 2e45fab2..27fe2fdd 100644 --- a/docs/ActionList.md +++ b/docs/ActionList.md @@ -91,34 +91,6 @@ repository-actions: snippet source | anchor -## browser@1 - -Action opening a webbrowser with the provided url. - -Action specific properties: - -- `url`: The url to browse to. (required, evaluated, string) - -Example: - - - -```yaml -repository-actions: - actions: - - type: browser@1 - active: true - variables: [] - name: 'My Github' - url: 'https://github.com/coenm' - - - type: browser@1 - name: 'My Github' - url: 'https://github.com/coenm' -``` -snippet source | anchor - - ## command@1 Action to excute a command (related the the repository) @@ -276,11 +248,10 @@ repository-actions: variable: environment skip: '' actions: - - type: browser@1 - name: '{var.environment.key}' - url: '{var.environment.url}' + - type: just-text@1 + name: '{var.environment.key} - {var.environment.url}' ``` -snippet source | anchor +snippet source | anchor ## git-checkout@1 @@ -652,6 +623,10 @@ repository-actions: See the [Heidi](RepoM.Plugin.Heidi.md) plugin for more information. +include _plugins.webbrowser.action + +See the [WebBrowser](RepoM.Plugin.WebBrowser.md) plugin for more information. + # Repository Actions These actions are part of the Repository Actions config file described in [Repository Actions](RepositoryActions.md). diff --git a/docs/RepoM.Plugin.WebBrowser.md b/docs/RepoM.Plugin.WebBrowser.md new file mode 100644 index 00000000..ebd3c870 --- /dev/null +++ b/docs/RepoM.Plugin.WebBrowser.md @@ -0,0 +1,85 @@ +# WebBrowser + +The WebBrowser module provides a repository action to open an URL in a given webbrowser. + +To use this module, make sure it is enabled in RepoM by opening the menu and navigate to 'Plugins'. When enabling or disabling a plugin, you should restart RepoM. + +## Configuration + +This plugin has specific configuration stored in a separate configuration file stored in `%APPDATA%/RepoM/Module/` directory. This configuration file should be edit manually. The safest way to do this is, is when RepoM is not running. + +The following default configuration is used: + +```json +{ + "Version": 1, + "Settings": { + "Browsers": null, + "Profiles": null + } +} +``` + +For example: + +```json +{ + "Version": 1, + "Settings": { + "Browsers": { + "Edge": "C:\\PathTo\\msedge.exe", + "FireFox": "C:\\PathTo\\Mozilla\\firefox.exe" + }, + "Profiles": { + "Work": { + "BrowserName": "Edge", + "CommandLineArguments": "\"--profile-directory=Profile 4\" {url}" + }, + "Incognito": { + "BrowserName": "Edge", + "CommandLineArguments": "-inprivate" + }, + "Incognito2": { + "BrowserName": "FireFox", + "CommandLineArguments": "-inprivate {url}" + } + } + } +} +``` + +Properties: + +- `Browsers`: Dictionary of known browsers and their path to use for opening urls. +- `Profiles`: Profiles to use. + +## browser@1 + +Action opening a webbrowser with the provided url. + +Action specific properties: + +- `url`: The url to browse to. (required, evaluated, string) +- `profile`: profile name used to select browser and browser profile (optional, evaluated, string) + +Example: + + + +```yaml +repository-actions: + actions: + - type: browser@1 + active: true + variables: [] + name: My Github + url: https://github.com/coenm + + - type: browser@1 + name: My Github + url: https://github.com/coenm + profile: edge +``` +snippet source | anchor + + diff --git a/docs/mdsource/ActionList.source.md b/docs/mdsource/ActionList.source.md index df645d5d..da28b788 100644 --- a/docs/mdsource/ActionList.source.md +++ b/docs/mdsource/ActionList.source.md @@ -30,14 +30,6 @@ Example: snippet: RepositoryActionsBrowseRepository01 -## browser@1 - -include: DocsRepositoryActionsTests.DocsRepositoryActionsSettings_RepositoryActionBrowserV1.verified.md - -Example: - -snippet: RepositoryActionsBrowser01 - ## command@1 include: DocsRepositoryActionsTests.DocsRepositoryActionsSettings_RepositoryActionCommandV1.verified.md @@ -150,6 +142,10 @@ include: _plugins.heidi.action See the [Heidi](RepoM.Plugin.Heidi.md) plugin for more information. +include _plugins.webbrowser.action + +See the [WebBrowser](RepoM.Plugin.WebBrowser.md) plugin for more information. + # Repository Actions These actions are part of the Repository Actions config file described in [Repository Actions](RepositoryActions.md). diff --git a/docs/mdsource/RepoM.Plugin.WebBrowser.source.md b/docs/mdsource/RepoM.Plugin.WebBrowser.source.md new file mode 100644 index 00000000..94d655ac --- /dev/null +++ b/docs/mdsource/RepoM.Plugin.WebBrowser.source.md @@ -0,0 +1,9 @@ +# WebBrowser + +The WebBrowser module provides a repository action to open an URL in a given webbrowser. + +include: _plugin_enable + +include: DocsModuleSettingsTests.DocsModuleSettings_WebBrowserPackage#desc.verified.md + +include: _plugins.webbrowser.action diff --git a/docs/mdsource/_plugins.webbrowser.action.include.md b/docs/mdsource/_plugins.webbrowser.action.include.md new file mode 100644 index 00000000..1fa7e570 --- /dev/null +++ b/docs/mdsource/_plugins.webbrowser.action.include.md @@ -0,0 +1,7 @@ +## browser@1 + +include: DocsRepositoryActionsTests.DocsRepositoryActionsSettings_RepositoryActionBrowserV1.verified.md + +Example: + +snippet: RepositoryActionsBrowser01 \ No newline at end of file diff --git a/src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/RepositorySpecificConfiguration.cs b/src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/RepositorySpecificConfiguration.cs index 10905dfd..cb8b081d 100644 --- a/src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/RepositorySpecificConfiguration.cs +++ b/src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/RepositorySpecificConfiguration.cs @@ -9,7 +9,6 @@ namespace RepoM.Api.IO.ModuleBasedRepositoryActionProvider; using DotNetEnv; using Microsoft.Extensions.Logging; using RepoM.Api.Common; -using RepoM.Api.Git; using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.ActionMappers; using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data; using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Deserialization; @@ -93,7 +92,7 @@ private string GetRepositoryActionsFilename(string basePath) var tags = new List(); // load default file - RepositoryActionConfiguration? rootFile = null; + RepositoryActionConfiguration? rootFile; RepositoryActionConfiguration? repoSpecificConfig = null; var filename = GetRepositoryActionsFilename(_appDataPathProvider.AppDataPath); @@ -273,7 +272,7 @@ private bool IsEnabled(string? booleanExpression, bool defaultWhenNullOrEmpty, I { return string.IsNullOrWhiteSpace(booleanExpression) ? defaultWhenNullOrEmpty - : _repoExpressionEvaluator.EvaluateBooleanExpression(booleanExpression!, repository); + : _repoExpressionEvaluator.EvaluateBooleanExpression(booleanExpression, repository); } } @@ -281,13 +280,16 @@ public class RepositoryTagsConfigurationFactory : IRepositoryTagsFactory { private readonly IRepositoryExpressionEvaluator _repoExpressionEvaluator; private readonly RepositoryConfigurationReader _repoConfigReader; + private readonly ILogger _logger; public RepositoryTagsConfigurationFactory( IRepositoryExpressionEvaluator repoExpressionEvaluator, - RepositoryConfigurationReader repoConfigReader) + RepositoryConfigurationReader repoConfigReader, + ILogger logger) { _repoExpressionEvaluator = repoExpressionEvaluator ?? throw new ArgumentNullException(nameof(repoExpressionEvaluator)); _repoConfigReader = repoConfigReader ?? throw new ArgumentNullException(nameof(repoConfigReader)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public IEnumerable GetTags(Repository repository) @@ -297,23 +299,6 @@ public IEnumerable GetTags(Repository repository) private IEnumerable GetTagsInner(IRepository repository) { - List EvaluateVariables(IEnumerable? vars) - { - if (vars == null) - { - return new List(0); - } - - return vars - .Where(v => IsEnabled(v.Enabled, true, repository)) - .Select(v => new EvaluatedVariable - { - Name = v.Name, - Value = Evaluate(v.Value, repository), - }) - .ToList(); - } - Dictionary? repositoryEnvVars; List? variables; List? tags; @@ -322,10 +307,10 @@ List EvaluateVariables(IEnumerable? vars) { (repositoryEnvVars, variables, _, tags) = _repoConfigReader.Get(repository); } - catch (Exception) + catch (Exception e) { - // todo, log - yield break; + _logger.LogError(e, "Could not get the configuration for repository {repository} {message}.", repository.Name, e.Message); + yield break; } using IDisposable d1 = RepoMVariableProviderStore.Push(variables ?? new List(0)); @@ -333,7 +318,7 @@ List EvaluateVariables(IEnumerable? vars) foreach (TagsCollection tagsCollection in ((IEnumerable?)tags) ?? Array.Empty()) { - using IDisposable d3 = RepoMVariableProviderStore.Push(EvaluateVariables(tagsCollection.Variables)); + using IDisposable d3 = RepoMVariableProviderStore.Push(EvaluateVariables(tagsCollection.Variables, repository)); foreach (RepositoryActionTag action in tagsCollection.Tags) { @@ -350,6 +335,23 @@ List EvaluateVariables(IEnumerable? vars) } } + private List EvaluateVariables(IEnumerable? vars, IRepository repository) + { + if (vars == null) + { + return new List(0); + } + + return vars + .Where(v => IsEnabled(v.Enabled, true, repository)) + .Select(v => new EvaluatedVariable + { + Name = v.Name, + Value = Evaluate(v.Value, repository), + }) + .ToList(); + } + private object? Evaluate(object? input, IRepository repository) { if (input is string s) diff --git a/src/RepoM.Api/IO/ProcessHelper.cs b/src/RepoM.Api/IO/ProcessHelper.cs index 1a188b6a..5cf0550c 100644 --- a/src/RepoM.Api/IO/ProcessHelper.cs +++ b/src/RepoM.Api/IO/ProcessHelper.cs @@ -9,7 +9,6 @@ public static void StartProcess(string process, string arguments) { try { - Debug.WriteLine("Starting: " + process + arguments); Process.Start(process, arguments); return; } diff --git a/src/RepoM.Api/IO/VariableProviders/RepositoryVariableProvider.cs b/src/RepoM.Api/IO/VariableProviders/RepositoryVariableProvider.cs index bd22e642..38022b09 100644 --- a/src/RepoM.Api/IO/VariableProviders/RepositoryVariableProvider.cs +++ b/src/RepoM.Api/IO/VariableProviders/RepositoryVariableProvider.cs @@ -1,6 +1,7 @@ namespace RepoM.Api.IO.VariableProviders; using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using RepoM.Core.Plugin.Repository; @@ -32,82 +33,115 @@ private static string ProvideString(RepositoryContext context, string key) var startIndex = "Repository.".Length; var keySuffix = key[startIndex..]; - if ("Name".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) + if (TryProvideProperties(repository, keySuffix, out string? result)) { - return repository.Name; + return result; } - if ("Path".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) + // legacy + if ("RemoteUrls".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) { - return repository.Path; + return string.Join("|", repository.Remotes.Select(x => x.Url)); } - - if ("SafePath".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) + + if (keySuffix.StartsWith("Remote.", StringComparison.CurrentCultureIgnoreCase)) { - return repository.SafePath; + startIndex = "Remote.".Length; + keySuffix = keySuffix[startIndex..]; + + var splits = keySuffix.Split('.'); + if (splits.Length != 2) + { + return string.Empty; + } + + if (TryProvideRemoteProperty(repository, splits[0], splits[1], out result)) + { + return result; + } + + return string.Empty; } - if ("Location".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) + throw new NotImplementedException(); + } + + private static bool TryProvideProperties(IRepository repository, string key, [NotNullWhen(true)] out string? result) + { + if ("Name".Equals(key, StringComparison.CurrentCultureIgnoreCase)) { - return repository.Location; + result = repository.Name; + return true; } - if ("CurrentBranch".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) + if ("Path".Equals(key, StringComparison.CurrentCultureIgnoreCase)) { - return repository.CurrentBranch; + result = repository.Path; + return true; } - if ("Branches".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) + if ("SafePath".Equals(key, StringComparison.CurrentCultureIgnoreCase)) { - return string.Join("|", repository.Branches); + result = repository.SafePath; + return true; } - if ("LocalBranches".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) + if ("Location".Equals(key, StringComparison.CurrentCultureIgnoreCase)) { - return string.Join("|", repository.LocalBranches); + result = repository.Location; + return true; } - // legacy - if ("RemoteUrls".Equals(keySuffix, StringComparison.CurrentCultureIgnoreCase)) + if ("CurrentBranch".Equals(key, StringComparison.CurrentCultureIgnoreCase)) { - return string.Join("|", repository.Remotes.Select(x => x.Url)); + result = repository.CurrentBranch; + return true; } - if (keySuffix.StartsWith("Remote.", StringComparison.CurrentCultureIgnoreCase)) + if ("Branches".Equals(key, StringComparison.CurrentCultureIgnoreCase)) { - startIndex = "Remote.".Length; - keySuffix = keySuffix[startIndex..]; + result = string.Join("|", repository.Branches); + return true; + } - var splits = keySuffix.Split('.'); - if (splits.Length != 2) - { - return string.Empty; - } + if ("LocalBranches".Equals(key, StringComparison.CurrentCultureIgnoreCase)) + { + result = string.Join("|", repository.LocalBranches); + return true; + } - Remote? remote = repository.Remotes.Find(x => x.Key.Equals(splits[0], StringComparison.CurrentCultureIgnoreCase)); - if (remote == null) - { - return string.Empty; - } + result = null; + return false; + } - if ("url".Equals(splits[1], StringComparison.CurrentCultureIgnoreCase)) - { - return remote.Url; - } + private static bool TryProvideRemoteProperty(IRepository repository, string remoteName, string property, [NotNullWhen(true)] out string? result) + { + Remote? remote = repository.Remotes.Find(x => x.Key.Equals(remoteName, StringComparison.CurrentCultureIgnoreCase)); + if (remote == null) + { + result = string.Empty; + return true; + } - if ("key".Equals(splits[1], StringComparison.CurrentCultureIgnoreCase)) - { - return remote.Key; - } + if ("url".Equals(property, StringComparison.CurrentCultureIgnoreCase)) + { + result = remote.Url; + return true; + } - if ("name".Equals(splits[1], StringComparison.CurrentCultureIgnoreCase)) - { - return remote.Name; - } + if ("key".Equals(property, StringComparison.CurrentCultureIgnoreCase)) + { + result = remote.Key; + return true; + } - return string.Empty; + if ("name".Equals(property, StringComparison.CurrentCultureIgnoreCase)) + { + result = remote.Name; + return true; } - throw new NotImplementedException(); + result = null; + return false; } } \ No newline at end of file diff --git a/src/RepoM.Api/IO/VariableProviders/VariableProviderAdapter.cs b/src/RepoM.Api/IO/VariableProviders/VariableProviderAdapter.cs index d5c15965..eb8056bc 100644 --- a/src/RepoM.Api/IO/VariableProviders/VariableProviderAdapter.cs +++ b/src/RepoM.Api/IO/VariableProviders/VariableProviderAdapter.cs @@ -47,6 +47,6 @@ public bool CanProvide(string key) private PluginVariableProvider? GetProvider(string key) { - return _variableProviderImplementation.FirstOrDefault(x => x.CanProvide(key)); + return Array.Find(_variableProviderImplementation, item => item.CanProvide(key)); } } \ No newline at end of file diff --git a/src/RepoM.Api/RepositoryActions/Executors/BrowseActionExecutor.cs b/src/RepoM.Api/RepositoryActions/Executors/BrowseActionExecutor.cs deleted file mode 100644 index f7a31326..00000000 --- a/src/RepoM.Api/RepositoryActions/Executors/BrowseActionExecutor.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace RepoM.Api.RepositoryActions.Executors; - -using System; -using JetBrains.Annotations; -using RepoM.Core.Plugin.Repository; -using RepoM.Core.Plugin.RepositoryActions; -using RepoM.Core.Plugin.RepositoryActions.Actions; - -[UsedImplicitly] -public class BrowseActionExecutor : IActionExecutor -{ - public void Execute(IRepository repository, BrowseAction action) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/src/RepoM.App/Bootstrapper.cs b/src/RepoM.App/Bootstrapper.cs index 1590cd82..4a545c1d 100644 --- a/src/RepoM.App/Bootstrapper.cs +++ b/src/RepoM.App/Bootstrapper.cs @@ -181,7 +181,7 @@ static IEnumerable GetExportedTypesFrom(Assembly assembly) Container.Register, SumRepositoryComparerFactory>(Lifestyle.Singleton); Container.RegisterSingleton(); - Container.Register(typeof(IActionExecutor<>), new[] { typeof(BrowseActionExecutor).Assembly, }, Lifestyle.Singleton); + Container.Register(typeof(IActionExecutor<>), new[] { typeof(DelegateActionExecutor).Assembly, }, Lifestyle.Singleton); Container.RegisterDecorator( typeof(IActionExecutor<>), typeof(LoggerActionExecutorDecorator<>), diff --git a/src/RepoM.App/RepoM.App.csproj b/src/RepoM.App/RepoM.App.csproj index 977e013d..19677793 100644 --- a/src/RepoM.App/RepoM.App.csproj +++ b/src/RepoM.App/RepoM.App.csproj @@ -29,6 +29,7 @@ + diff --git a/src/RepoM.Core.Plugin/RepositoryActions/Actions/BrowseAction.cs b/src/RepoM.Core.Plugin/RepositoryActions/Actions/BrowseAction.cs deleted file mode 100644 index 48920f0c..00000000 --- a/src/RepoM.Core.Plugin/RepositoryActions/Actions/BrowseAction.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace RepoM.Core.Plugin.RepositoryActions.Actions; - -using RepoM.Core.Plugin.RepositoryActions; - -public sealed class BrowseAction : IAction -{ -} \ No newline at end of file diff --git a/src/RepoM.Plugin.AzureDevOps/Internal/AzureDevOpsPullRequestService.cs b/src/RepoM.Plugin.AzureDevOps/Internal/AzureDevOpsPullRequestService.cs index 97d0c9ea..2e515862 100644 --- a/src/RepoM.Plugin.AzureDevOps/Internal/AzureDevOpsPullRequestService.cs +++ b/src/RepoM.Plugin.AzureDevOps/Internal/AzureDevOpsPullRequestService.cs @@ -88,7 +88,12 @@ public Task InitializeAsync() public async Task CreatePullRequestWithAutoCompleteAsync(IRepository repository, string projectId, List reviewersIds, string toBranch, int mergeStrategy, string? title = null, bool isDraft = false, bool includeWorkItems = true, bool openInBrowser = false, bool deleteSourceBranch = true, bool transitionWorkItems = true, CancellationToken cancellationToken = default) { - GitPullRequest pr = await CreatePullRequestInternalAsync(repository, projectId, reviewersIds, toBranch, title, isDraft, includeWorkItems, cancellationToken); + GitPullRequest? pr = await CreatePullRequestInternalAsync(repository, projectId, reviewersIds, toBranch, title, isDraft, includeWorkItems, cancellationToken); + + if (pr == null) + { + return; + } Guid repoId = FindRepositoryGuid(repository); @@ -117,7 +122,12 @@ public async Task CreatePullRequestWithAutoCompleteAsync(IRepository repository, public async Task CreatePullRequestAsync(IRepository repository, string projectId, List reviewersIds, string toBranch, string? title = null, bool isDraft = false, bool includeWorkItems = true, bool openInBrowser = false, CancellationToken cancellationToken = default) { - GitPullRequest pr = await CreatePullRequestInternalAsync(repository, projectId, reviewersIds, toBranch, title, isDraft, includeWorkItems, cancellationToken); + GitPullRequest? pr = await CreatePullRequestInternalAsync(repository, projectId, reviewersIds, toBranch, title, isDraft, includeWorkItems, cancellationToken); + + if (pr == null) + { + return; + } if (openInBrowser) { @@ -125,7 +135,7 @@ public async Task CreatePullRequestAsync(IRepository repository, string projectI } } - private async Task CreatePullRequestInternalAsync(IRepository repository, string projectId, List reviewersIds, string toBranch, string? title = null, bool isDraft = false, bool includeWorkItems = true, CancellationToken cancellationToken = default) + private async Task CreatePullRequestInternalAsync(IRepository repository, string projectId, List reviewersIds, string toBranch, string? title = null, bool isDraft = false, bool includeWorkItems = true, CancellationToken cancellationToken = default) { title ??= repository.CurrentBranch[(repository.CurrentBranch.IndexOf('/') + 1)..]; @@ -172,7 +182,14 @@ private async Task CreatePullRequestInternalAsync(IRepository re _ = response.EnsureSuccessStatusCode(); var responseContent = await response.Content.ReadAsStringAsync(cancellationToken) ?? throw new Exception("Invalid return type"); - return JsonConvert.DeserializeObject(responseContent); + GitPullRequest? result = JsonConvert.DeserializeObject(responseContent); + + if (result == null) + { + _logger.LogWarning($"Could not Deserialize as {nameof(GetPullRequests)}."); + } + + return result; } public int CountPullRequests(IRepository repository) diff --git a/src/RepoM.Plugin.Clipboard/ClipboardPackage.cs b/src/RepoM.Plugin.Clipboard/ClipboardPackage.cs index 5f4b0b78..50eede7e 100644 --- a/src/RepoM.Plugin.Clipboard/ClipboardPackage.cs +++ b/src/RepoM.Plugin.Clipboard/ClipboardPackage.cs @@ -26,7 +26,6 @@ private static void RegisterPluginHooks(Container container) { // repository actions container.RegisterDefaultRepositoryActionDeserializerForType(); - // container.Collection.Append(Lifestyle.Singleton); container.Collection.Append(Lifestyle.Singleton); // ordering diff --git a/src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/ActionMappers/ActionBrowserV1Mapper.cs b/src/RepoM.Plugin.WebBrowser/ActionProvider/ActionBrowserV1Mapper.cs similarity index 61% rename from src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/ActionMappers/ActionBrowserV1Mapper.cs rename to src/RepoM.Plugin.WebBrowser/ActionProvider/ActionBrowserV1Mapper.cs index c56da6bb..b823ca97 100644 --- a/src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/ActionMappers/ActionBrowserV1Mapper.cs +++ b/src/RepoM.Plugin.WebBrowser/ActionProvider/ActionBrowserV1Mapper.cs @@ -1,15 +1,19 @@ -namespace RepoM.Api.IO.ModuleBasedRepositoryActionProvider.ActionMappers; +namespace RepoM.Plugin.WebBrowser.ActionProvider; using System; using System.Collections.Generic; +using JetBrains.Annotations; using RepoM.Api.Git; -using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data.Actions; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.ActionMappers; using RepoM.Api.RepositoryActions; using RepoM.Core.Plugin.Expressions; -using RepoM.Core.Plugin.RepositoryActions.Actions; +using RepoM.Core.Plugin.Repository; +using RepoM.Plugin.WebBrowser.RepositoryActions.Actions; using RepositoryAction = RepoM.Api.RepositoryActions.RepositoryAction; -public class ActionBrowserV1Mapper : IActionToRepositoryActionMapper +[UsedImplicitly] +internal class ActionBrowserV1Mapper : IActionToRepositoryActionMapper { private readonly IRepositoryExpressionEvaluator _expressionEvaluator; @@ -18,17 +22,17 @@ public ActionBrowserV1Mapper(IRepositoryExpressionEvaluator expressionEvaluator) _expressionEvaluator = expressionEvaluator ?? throw new ArgumentNullException(nameof(expressionEvaluator)); } - bool IActionToRepositoryActionMapper.CanMap(Data.RepositoryAction action) + bool IActionToRepositoryActionMapper.CanMap(Api.IO.ModuleBasedRepositoryActionProvider.Data.RepositoryAction action) { return action is RepositoryActionBrowserV1; } - IEnumerable IActionToRepositoryActionMapper.Map(Data.RepositoryAction action, Repository repository, ActionMapperComposition actionMapperComposition) + IEnumerable IActionToRepositoryActionMapper.Map(Api.IO.ModuleBasedRepositoryActionProvider.Data.RepositoryAction action, Repository repository, ActionMapperComposition actionMapperComposition) { return Map(action as RepositoryActionBrowserV1, repository); } - private IEnumerable Map(RepositoryActionBrowserV1? action, Repository repository) + private IEnumerable Map(RepositoryActionBrowserV1? action, IRepository repository) { if (action == null) { @@ -47,9 +51,11 @@ private IEnumerable Map(RepositoryActionBrowserV1? action, Rep var name = _expressionEvaluator.EvaluateNullStringExpression(action.Name, repository); var url = _expressionEvaluator.EvaluateStringExpression(action.Url, repository); + var profile = _expressionEvaluator.EvaluateNullStringExpression(action.Profile, repository); + yield return new RepositoryAction(name, repository) { - Action = new DelegateAction((_, _) => ProcessHelper.StartProcess(url, string.Empty)), + Action = new BrowseAction(url, profile), }; } } \ No newline at end of file diff --git a/src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/Data/Actions/RepositoryActionBrowserV1.cs b/src/RepoM.Plugin.WebBrowser/ActionProvider/RepositoryActionBrowserV1.cs similarity index 62% rename from src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/Data/Actions/RepositoryActionBrowserV1.cs rename to src/RepoM.Plugin.WebBrowser/ActionProvider/RepositoryActionBrowserV1.cs index b05310bb..95f110a9 100644 --- a/src/RepoM.Api/IO/ModuleBasedRepositoryActionProvider/Data/Actions/RepositoryActionBrowserV1.cs +++ b/src/RepoM.Plugin.WebBrowser/ActionProvider/RepositoryActionBrowserV1.cs @@ -1,6 +1,7 @@ -namespace RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data.Actions; +namespace RepoM.Plugin.WebBrowser.ActionProvider; using System.ComponentModel.DataAnnotations; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data; /// /// Action opening a webbrowser with the provided url. @@ -21,4 +22,12 @@ public sealed class RepositoryActionBrowserV1 : RepositoryAction [Required] [PropertyType(typeof(string))] public string? Url { get; set; } + + + /// + /// profile name used to select browser and browser profile + /// + [EvaluatedProperty] + [PropertyType(typeof(string))] + public string? Profile { get; set; } } \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/CurrentVersion.cs b/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/CurrentVersion.cs new file mode 100644 index 00000000..d72390b4 --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/CurrentVersion.cs @@ -0,0 +1,6 @@ +namespace RepoM.Plugin.WebBrowser.PersistentConfiguration; + +internal static class CurrentConfigVersion +{ + public const int VERSION = 1; +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/StatisticsConfigV1.cs b/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/StatisticsConfigV1.cs new file mode 100644 index 00000000..79b5367f --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/StatisticsConfigV1.cs @@ -0,0 +1,14 @@ +namespace RepoM.Plugin.WebBrowser.PersistentConfiguration; + +public class ProfileConfig +{ + /// + /// Name of the browser. Should be listed in the Browsers dictionary. + /// + public string? BrowserName { get; set; } + + /// + /// Command line arguments + /// + public string? CommandLineArguments { get; set; } +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/WebBrowserConfigV1.cs b/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/WebBrowserConfigV1.cs new file mode 100644 index 00000000..c5a72a67 --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/PersistentConfiguration/WebBrowserConfigV1.cs @@ -0,0 +1,18 @@ +namespace RepoM.Plugin.WebBrowser.PersistentConfiguration; + +using System.Collections.Generic; + +/// DO NOT CHANGE PROPERTYNAMES, TYPES, or VISIBILITIES +/// Module configuration (version 1) +public class WebBrowserConfigV1 +{ + /// + /// Dictionary of known browsers and their path to use for opening urls. + /// + public Dictionary? Browsers { get; set; } + + /// + /// Profiles to use. + /// + public Dictionary? Profiles { get; set; } +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/PluginInformation.cs b/src/RepoM.Plugin.WebBrowser/PluginInformation.cs new file mode 100644 index 00000000..62f5a308 --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/PluginInformation.cs @@ -0,0 +1,5 @@ +using RepoM.Core.Plugin.AssemblyInformation; + +[assembly: Package( + "WebBrowser", + "Provides functionality to start a web browser from an action with profile information.")] \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/RepoM.Plugin.WebBrowser.csproj b/src/RepoM.Plugin.WebBrowser/RepoM.Plugin.WebBrowser.csproj new file mode 100644 index 00000000..6f096259 --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/RepoM.Plugin.WebBrowser.csproj @@ -0,0 +1,22 @@ + + + + net7.0 + + + + + + + + + + + + + + + + + + diff --git a/src/RepoM.Plugin.WebBrowser/RepositoryActions/Actions/BrowseAction.cs b/src/RepoM.Plugin.WebBrowser/RepositoryActions/Actions/BrowseAction.cs new file mode 100644 index 00000000..417dfa82 --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/RepositoryActions/Actions/BrowseAction.cs @@ -0,0 +1,16 @@ +namespace RepoM.Plugin.WebBrowser.RepositoryActions.Actions; + +using RepoM.Core.Plugin.RepositoryActions; + +public sealed class BrowseAction : IAction +{ + public BrowseAction(string url, string? profileName) + { + Url = url; + ProfileName = profileName; + } + + public string Url { get; } + + public string? ProfileName { get; } +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/RepositoryActions/BrowseActionExecutor.cs b/src/RepoM.Plugin.WebBrowser/RepositoryActions/BrowseActionExecutor.cs new file mode 100644 index 00000000..0473bfe2 --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/RepositoryActions/BrowseActionExecutor.cs @@ -0,0 +1,31 @@ +namespace RepoM.Plugin.WebBrowser.RepositoryActions; + +using System; +using JetBrains.Annotations; +using RepoM.Core.Plugin.Repository; +using RepoM.Core.Plugin.RepositoryActions; +using RepoM.Plugin.WebBrowser.RepositoryActions.Actions; +using RepoM.Plugin.WebBrowser.Services; + +[UsedImplicitly] +internal class BrowseActionExecutor : IActionExecutor +{ + private readonly IWebBrowserService _webBrowserService; + + public BrowseActionExecutor(IWebBrowserService webBrowserService) + { + _webBrowserService = webBrowserService ?? throw new ArgumentNullException(nameof(webBrowserService)); + } + + public void Execute(IRepository repository, BrowseAction action) + { + if (action.ProfileName == null) + { + _webBrowserService.OpenUrl(action.Url); + } + else + { + _webBrowserService.OpenUrl(action.Url, action.ProfileName); + } + } +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/Services/IWebBrowserService.cs b/src/RepoM.Plugin.WebBrowser/Services/IWebBrowserService.cs new file mode 100644 index 00000000..d871686b --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/Services/IWebBrowserService.cs @@ -0,0 +1,8 @@ +namespace RepoM.Plugin.WebBrowser.Services; + +internal interface IWebBrowserService +{ + void OpenUrl(string url); + + void OpenUrl(string url, string profile); +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/Services/WebBrowserConfiguration.cs b/src/RepoM.Plugin.WebBrowser/Services/WebBrowserConfiguration.cs new file mode 100644 index 00000000..eaa8786b --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/Services/WebBrowserConfiguration.cs @@ -0,0 +1,17 @@ +namespace RepoM.Plugin.WebBrowser.Services; + +using System.Collections.Generic; + +internal class WebBrowserConfiguration +{ + public Dictionary Browsers { get; init; } = new(); + + public Dictionary Profiles { get; init; } = new(); +} + +internal class BrowserProfileConfig +{ + public string? BrowserName { get; set; } + + public string? CommandLineArguments { get; set; } +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/Services/WebBrowserService.cs b/src/RepoM.Plugin.WebBrowser/Services/WebBrowserService.cs new file mode 100644 index 00000000..c226205d --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/Services/WebBrowserService.cs @@ -0,0 +1,65 @@ +namespace RepoM.Plugin.WebBrowser.Services; + +using System; +using RepoM.Api.IO; + +internal class WebBrowserService : IWebBrowserService +{ + private readonly WebBrowserConfiguration _configuration; + + public WebBrowserService(WebBrowserConfiguration configuration) + { + _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); + } + + public bool ProfileExist(string name) + { + return _configuration.Profiles.ContainsKey(name); + } + + public void OpenUrl(string url) + { + StartProcess(url, string.Empty); + } + + public void OpenUrl(string url, string profile) + { + + if (!_configuration.Profiles.TryGetValue(profile, out BrowserProfileConfig? profileConfig)) + { + OpenUrl(url); + return; + } + + if (!_configuration.Browsers.TryGetValue(profileConfig.BrowserName!, out string? browser)) + { + OpenUrl(url); + return; + } + + + if (string.IsNullOrWhiteSpace(profileConfig.CommandLineArguments)) + { + StartProcess(browser, url); + return; + } + + var commandLinesArgs = profileConfig.CommandLineArguments; + if (commandLinesArgs.Contains("{url}")) + { + commandLinesArgs = commandLinesArgs.Replace("{url}", url); + } + else + { + commandLinesArgs += " " + url; + } + + StartProcess(browser, commandLinesArgs); + } + + // virtual because of testing + protected virtual void StartProcess(string process, string arguments) + { + ProcessHelper.StartProcess(process, arguments); + } +} \ No newline at end of file diff --git a/src/RepoM.Plugin.WebBrowser/WebBrowserPackage.cs b/src/RepoM.Plugin.WebBrowser/WebBrowserPackage.cs new file mode 100644 index 00000000..641dd6e1 --- /dev/null +++ b/src/RepoM.Plugin.WebBrowser/WebBrowserPackage.cs @@ -0,0 +1,117 @@ +namespace RepoM.Plugin.WebBrowser; + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using JetBrains.Annotations; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data; +using RepoM.Core.Plugin; +using RepoM.Core.Plugin.RepositoryActions; +using RepoM.Plugin.WebBrowser.ActionProvider; +using RepoM.Plugin.WebBrowser.PersistentConfiguration; +using RepoM.Plugin.WebBrowser.Services; +using SimpleInjector; + +[UsedImplicitly] +public class WebBrowserPackage : IPackage +{ + public string Name => "WebBrowserPackage"; // do not change this name, it is part of the persistant filename + + public async Task RegisterServicesAsync(Container container, IPackageConfiguration packageConfiguration) + { + await ExtractAndRegisterConfiguration(container, packageConfiguration).ConfigureAwait(false); + RegisterPluginHooks(container); + RegisterInternals(container); + } + + private static async Task ExtractAndRegisterConfiguration(Container container, IPackageConfiguration packageConfiguration) + { + var version = await packageConfiguration.GetConfigurationVersionAsync().ConfigureAwait(false); + + WebBrowserConfigV1 config; + + if (version == CurrentConfigVersion.VERSION) + { + WebBrowserConfigV1? result = await packageConfiguration.LoadConfigurationAsync().ConfigureAwait(false); + if (result == null) + { + config = await PersistDefaultConfigAsync(packageConfiguration).ConfigureAwait(false); + } + else + { + config = result; + } + } + else + { + config = await PersistDefaultConfigAsync(packageConfiguration).ConfigureAwait(false); + } + + container.RegisterInstance( + new WebBrowserConfiguration + { + Browsers = config.Browsers?.ToDictionary(x => x.Key, x => x.Value) ?? new Dictionary(0), + Profiles = config.Profiles?.ToDictionary( + x => x.Key, + x => new BrowserProfileConfig + { + BrowserName = x.Value.BrowserName, + CommandLineArguments = x.Value.CommandLineArguments, + }) ?? new Dictionary(0), + }); + } + + private static void RegisterPluginHooks(Container container) + { + // repository actions + container.RegisterDefaultRepositoryActionDeserializerForType(); + container.Collection.Append(Lifestyle.Singleton); + + // action executor + container.Register(typeof(IActionExecutor<>), new[] { typeof(WebBrowserPackage).Assembly, }, Lifestyle.Singleton); + } + + private static void RegisterInternals(Container container) + { + container.Register(Lifestyle.Singleton); + } + + /// This method is used by reflection to generate documentation file> + private static async Task PersistDefaultConfigAsync(IPackageConfiguration packageConfiguration) + { + var config = new WebBrowserConfigV1 + { + Browsers = null, + Profiles = null, + }; + + await packageConfiguration.PersistConfigurationAsync(config, CurrentConfigVersion.VERSION).ConfigureAwait(false); + return config; + } + + + /// This method is used by reflection to generate documentation file> + [UsedImplicitly] + [System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Reflection")] + private static async Task PersistExampleConfigAsync(IPackageConfiguration packageConfiguration) + { + var config = new WebBrowserConfigV1 + { + Browsers = new Dictionary + { + { "Edge", "C:\\PathTo\\msedge.exe" }, + { "FireFox", "C:\\PathTo\\Mozilla\\firefox.exe" }, + }, + Profiles = new Dictionary + { + { "Work", new ProfileConfig { BrowserName = "Edge", CommandLineArguments = "\"--profile-directory=Profile 4\" {url}", } }, + { "Incognito", new ProfileConfig { BrowserName = "Edge", CommandLineArguments = "-inprivate", } }, + { "Incognito2", new ProfileConfig { BrowserName = "FireFox", CommandLineArguments = "-inprivate {url}", } }, + }, + }; + + await packageConfiguration.PersistConfigurationAsync(config, CurrentConfigVersion.VERSION).ConfigureAwait(false); + return config; + } +} \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/DynamicRepositoryActionDeserializerFactory.cs b/tests/RepoM.Api.Tests/DynamicRepositoryActionDeserializerFactory.cs index 403e4e69..c4f07cf1 100644 --- a/tests/RepoM.Api.Tests/DynamicRepositoryActionDeserializerFactory.cs +++ b/tests/RepoM.Api.Tests/DynamicRepositoryActionDeserializerFactory.cs @@ -28,7 +28,6 @@ private static ActionDeserializerComposition CreateActionDeserializerComposition { new ActionExecutableV1Deserializer(), new DefaultActionDeserializer(), - new DefaultActionDeserializer(), new ActionFolderV1Deserializer(), new DefaultActionDeserializer(), new DefaultActionDeserializer(), diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/CommandV1Test.Deserialize_CommandV1.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/CommandV1Test.Deserialize_CommandV1.testfile.yaml index 96996882..566d49fd 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/CommandV1Test.Deserialize_CommandV1.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/CommandV1Test.Deserialize_CommandV1.testfile.yaml @@ -1,11 +1,11 @@ repository-actions: actions: - type: command@1 - name: '{OpenIn} Windows Terminal' + name: 'Open in Windows Terminal' command: wt arguments: -d "{Repository.SafePath}" - type: command@1 - name: '{OpenIn} Windows Command Shell' + name: 'Open in Windows Command Shell' command: cmd arguments: /K "cd /d {Repository.SafePath}" active: false diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/ExecutableV1Test.Deserialize_ExecutableV1.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/ExecutableV1Test.Deserialize_ExecutableV1.testfile.yaml index 7a7efb81..86b437ec 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/ExecutableV1Test.Deserialize_ExecutableV1.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/ExecutableV1Test.Deserialize_ExecutableV1.testfile.yaml @@ -1,21 +1,21 @@ repository-actions: actions: - type: executable@1 - name: '{OpenIn} Sourcetree' + name: 'Open in Sourcetree' executables: - '%LocalAppData%/SourceTree/SourceTree.exe' - '%PROGRAMFILES(X86)%/Atlassian/SourceTree/SourceTree.exe' arguments: -f "{Repository.Location}{backslash}{Repository.Name}" active: true - type: executable@1 - name: '{OpenIn} Sourcetree 1' + name: 'Open in Sourcetree 1' executable: '%PROGRAMFILES(X86)%/Atlassian/SourceTree/SourceTree.exe' - type: executable@1 - name: '{OpenIn} Sourcetree 1.1' + name: 'Open in Sourcetree 1.1' executables: [] executable: '%PROGRAMFILES(X86)%/Atlassian/SourceTree/SourceTree.exe' - type: executable@1 - name: '{OpenIn} Sourcetree 2' + name: 'Open in Sourcetree 2' executables: - '%LocalAppData%/SourceTree/SourceTree.exe' - '%PROGRAMFILES(X86)%/Atlassian/SourceTree/SourceTree.exe' diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/ForEachV1Test.Deserialize_ForEachV1.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/ForEachV1Test.Deserialize_ForEachV1.testfile.yaml index 7d9c1c76..ce86792b 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/ForEachV1Test.Deserialize_ForEachV1.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/ForEachV1Test.Deserialize_ForEachV1.testfile.yaml @@ -4,6 +4,5 @@ repository-actions: enumerable: '{var.DTAP}' variable: environment actions: - - type: browser@1 - name: '{var.environment}' - url: '{var.url}' + - type: just-text@1 + name: '{var.environment} {var.url}' diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/CommandV1Test.Deserialize_CommandV1.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/CommandV1Test.Deserialize_CommandV1.verified.txt index 56d90fa1..a714a566 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/CommandV1Test.Deserialize_CommandV1.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/CommandV1Test.Deserialize_CommandV1.verified.txt @@ -7,14 +7,14 @@ Command: wt, Arguments: -d "{Repository.SafePath}", Type: command@1, - Name: {OpenIn} Windows Terminal + Name: Open in Windows Terminal }, { $type: RepositoryActionCommandV1, Command: cmd, Arguments: /K "cd /d {Repository.SafePath}", Type: command@1, - Name: {OpenIn} Windows Command Shell, + Name: Open in Windows Command Shell, Active: false } ] diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/ExecutableV1Test.Deserialize_ExecutableV1.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/ExecutableV1Test.Deserialize_ExecutableV1.verified.txt index 7b477bf8..aab8d9fa 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/ExecutableV1Test.Deserialize_ExecutableV1.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/ExecutableV1Test.Deserialize_ExecutableV1.verified.txt @@ -10,7 +10,7 @@ ], Arguments: -f "{Repository.Location}{backslash}{Repository.Name}", Type: executable@1, - Name: {OpenIn} Sourcetree, + Name: Open in Sourcetree, Active: true }, { @@ -19,7 +19,7 @@ %PROGRAMFILES(X86)%/Atlassian/SourceTree/SourceTree.exe ], Type: executable@1, - Name: {OpenIn} Sourcetree 1 + Name: Open in Sourcetree 1 }, { $type: RepositoryActionExecutableV1, @@ -27,7 +27,7 @@ %PROGRAMFILES(X86)%/Atlassian/SourceTree/SourceTree.exe ], Type: executable@1, - Name: {OpenIn} Sourcetree 1.1 + Name: Open in Sourcetree 1.1 }, { $type: RepositoryActionExecutableV1, @@ -36,7 +36,7 @@ %PROGRAMFILES(X86)%/Atlassian/SourceTree/SourceTree.exe ], Type: executable@1, - Name: {OpenIn} Sourcetree 2 + Name: Open in Sourcetree 2 } ] } diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/ActionMapperCompositionFactory.cs b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/ActionMapperCompositionFactory.cs index cb172580..3992931c 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/ActionMapperCompositionFactory.cs +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/ActionMapperCompositionFactory.cs @@ -19,7 +19,6 @@ public static ActionMapperComposition Create( var mappers = new IActionToRepositoryActionMapper[] { new ActionBrowseRepositoryV1Mapper(expressionEvaluator, translationService), - new ActionBrowserV1Mapper(expressionEvaluator), new ActionCommandV1Mapper(expressionEvaluator), new ActionExecutableV1Mapper(expressionEvaluator, fileSystem), new ActionFolderV1Mapper(expressionEvaluator), diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFiles/Foreach01.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFiles/Foreach01.testfile.yaml index f5f504ea..e3fb37d4 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFiles/Foreach01.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFiles/Foreach01.testfile.yaml @@ -20,8 +20,7 @@ repository-actions: variable: environment skip: '' actions: - - type: browser@1 - name: '{var.environment.key}' - url: '{var.environment.url}' + - type: just-text@1 + name: '{var.environment.key} - {var.environment.url}' # end-snippet \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Foreach01.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Foreach01.verified.txt index d4fc8dc2..4b34671b 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Foreach01.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Foreach01.verified.txt @@ -39,10 +39,9 @@ Skip: , Actions: [ { - $type: RepositoryActionBrowserV1, - Url: {var.environment.url}, - Type: browser@1, - Name: {var.environment.key} + $type: RepositoryActionJustTextV1, + Type: just-text@1, + Name: {var.environment.key} - {var.environment.url} } ], Type: foreach@1 diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationTests.cs b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationTests.cs index 3f53509e..280cb08d 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationTests.cs +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationTests.cs @@ -38,7 +38,6 @@ public DocumentationTests() [InlineData("GitPush01")] [InlineData("BrowseRepository01")] [InlineData("Separator01")] - [InlineData("Browser01")] [InlineData("Folder01")] [InlineData("AssociateFile01")] [InlineData("Command01")] diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/RepositorySpecificConfigurationTest.cs b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/RepositorySpecificConfigurationTest.cs index 167ba882..2e84a50b 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/RepositorySpecificConfigurationTest.cs +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/RepositorySpecificConfigurationTest.cs @@ -4,6 +4,7 @@ namespace RepoM.Api.Tests.IO.ModuleBasedRepositoryActionProvider; using System.Collections.Generic; using System.IO; using System.IO.Abstractions.TestingHelpers; +using System.Linq; using System.Runtime.Caching; using System.Text; using System.Threading.Tasks; diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach1.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach1.testfile.yaml index f91b6d89..20ffaa19 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach1.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach1.testfile.yaml @@ -16,6 +16,5 @@ repository-actions: enumerable: '{var.DTAP}' variable: environment actions: - - type: browser@1 - name: '{var.environment.key}' - url: '{var.environment.url}' \ No newline at end of file + - type: just-text@1 + name: '{var.key} - {var.environment.url}' \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach2.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach2.testfile.yaml index 6c603714..30a62afb 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach2.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach2.testfile.yaml @@ -15,6 +15,5 @@ repository-actions: enumerable: '{var.DTAP}' variable: environment actions: - - type: browser@1 - name: '{var.environment.key}' - url: '{var.environment.url}' \ No newline at end of file + - type: just-text@1 + name: '{var.key} - {var.environment.url}' \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach3.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach3.testfile.yaml index 2377e227..118b3618 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach3.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/ForEach3.testfile.yaml @@ -16,6 +16,5 @@ repository-actions: variable: environment skip: '{IsNull({var.environment.x})}' actions: - - type: browser@1 - name: '{var.environment.key}' - url: '{var.environment.url}' \ No newline at end of file + - type: just-text@1 + name: '{var.key} - {var.environment.url}' \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions1.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions1.testfile.yaml index a3707bc2..4c48d6f9 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions1.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions1.testfile.yaml @@ -1,10 +1,10 @@ repository-actions: -- type: browser@1 - name: '{OpenIn} Windows File Explorer' +- type: command@1 + name: 'Open in Windows File Explorer' active: false variables: - name: name value: '{StringContains({Repository.SafePath}, "abc")}' -- type: browser@1 - name: '{OpenIn} Windows File Explorer' +- type: command@1 + name: 'Open in Windows File Explorer' active: false \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions2.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions2.testfile.yaml index da1b7144..4acd8cb4 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions2.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions2.testfile.yaml @@ -1,11 +1,11 @@ repository-actions: actions: - - type: browser@1 - name: '{OpenIn} Windows File Explorer' + - type: command@1 + name: 'Open in Windows File Explorer' active: false variables: - name: name value: '{StringContains({Repository.SafePath}, "abc")}' - - type: browser@1 - name: '{OpenIn} Windows File Explorer' + - type: command@1 + name: 'Open in Windows File Explorer' active: false \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions3.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions3.testfile.yaml index fe359830..f99bb999 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions3.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActions3.testfile.yaml @@ -7,13 +7,12 @@ repository-actions: value: true enabled: false actions: - - type: browser@1 - name: '{OpenIn} Windows File Explorer' + - type: command@1 + name: 'Open in Windows File Explorer' active: false variables: - name: name value: '{StringContains({Repository.SafePath}, "abc")}' - url: https://google.com - - type: browser@1 - name: '{OpenIn} Windows File Explorer' + - type: command@1 + name: 'Open in Windows File Explorer' active: false \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActionsWithSeparator1.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActionsWithSeparator1.testfile.yaml index 72865cbb..6ea61fdb 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActionsWithSeparator1.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/RepositoryActionsWithSeparator1.testfile.yaml @@ -1,8 +1,9 @@ repository-actions: -- type: browser@1 - name: Google 1 - url: https://google.com +- type: just-text@1 + name: 'Open in Windows File Explorer' + active: true + - type: separator@1 -- type: browser@1 - name: Google 2 - url: https://google.com \ No newline at end of file + +- type: just-text@1 + name: 'Open in Windows File Explorer 2' \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/Sample2.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/Sample2.testfile.yaml index 3983ec0a..c3880ed4 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/Sample2.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/Sample2.testfile.yaml @@ -36,12 +36,12 @@ repository-actions: value: true enabled: false actions: - - type: browser@1 - name: '{OpenIn} Windows File Explorer' + - type: command@1 + name: 'Open in Windows File Explorer' active: false variables: - name: name value: '{StringContains({Repository.SafePath}, "abc")}' - - type: browser@1 - name: '{OpenIn} Windows File Explorer' + - type: command@1 + name: 'Open in Windows File Explorer' active: false \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/Sample3.testfile.yaml b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/Sample3.testfile.yaml index c862f665..e06dafc7 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/Sample3.testfile.yaml +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/TestFiles/Sample3.testfile.yaml @@ -45,12 +45,12 @@ repository-actions: value: true enabled: false actions: - - type: browser@1 - name: '{OpenIn} Windows File Explorer' + - type: command@1 + name: 'Open in Windows File Explorer' active: false variables: - name: name value: '{StringContains({Repository.SafePath}, "abc")}' - - type: browser@1 - name: '{OpenIn} Windows File Explorer' + - type: command@1 + name: 'Open in Windows File Explorer' active: false diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach1.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach1.verified.txt index 8ae10178..3cd3cfab 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach1.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach1.verified.txt @@ -38,10 +38,9 @@ Variable: environment, Actions: [ { - $type: RepositoryActionBrowserV1, - Url: {var.environment.url}, - Type: browser@1, - Name: {var.environment.key} + $type: RepositoryActionJustTextV1, + Type: just-text@1, + Name: {var.key} - {var.environment.url} } ], Type: foreach@1 diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach2.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach2.verified.txt index 3a4edbae..96b2b9f8 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach2.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach2.verified.txt @@ -38,10 +38,9 @@ Variable: environment, Actions: [ { - $type: RepositoryActionBrowserV1, - Url: {var.environment.url}, - Type: browser@1, - Name: {var.environment.key} + $type: RepositoryActionJustTextV1, + Type: just-text@1, + Name: {var.key} - {var.environment.url} } ], Type: foreach@1 diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach3.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach3.verified.txt index 601cccad..bf465427 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach3.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ForEach3.verified.txt @@ -39,10 +39,9 @@ Skip: {IsNull({var.environment.x})}, Actions: [ { - $type: RepositoryActionBrowserV1, - Url: {var.environment.url}, - Type: browser@1, - Name: {var.environment.key} + $type: RepositoryActionJustTextV1, + Type: just-text@1, + Name: {var.key} - {var.environment.url} } ], Type: foreach@1 diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_Sample2.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_Sample2.verified.txt index 0036fa21..bdeb29eb 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_Sample2.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_Sample2.verified.txt @@ -66,9 +66,9 @@ ], Actions: [ { - $type: RepositoryActionBrowserV1, - Type: browser@1, - Name: {OpenIn} Windows File Explorer, + $type: RepositoryActionCommandV1, + Type: command@1, + Name: Open in Windows File Explorer, Active: false, Variables: [ { @@ -78,9 +78,9 @@ ] }, { - $type: RepositoryActionBrowserV1, - Type: browser@1, - Name: {OpenIn} Windows File Explorer, + $type: RepositoryActionCommandV1, + Type: command@1, + Name: Open in Windows File Explorer, Active: false } ] diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_Sample3.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_Sample3.verified.txt index ffe78fed..43963572 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_Sample3.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_Sample3.verified.txt @@ -84,9 +84,9 @@ ], Actions: [ { - $type: RepositoryActionBrowserV1, - Type: browser@1, - Name: {OpenIn} Windows File Explorer, + $type: RepositoryActionCommandV1, + Type: command@1, + Name: Open in Windows File Explorer, Active: false, Variables: [ { @@ -96,9 +96,9 @@ ] }, { - $type: RepositoryActionBrowserV1, - Type: browser@1, - Name: {OpenIn} Windows File Explorer, + $type: RepositoryActionCommandV1, + Type: command@1, + Name: Open in Windows File Explorer, Active: false } ] diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ShouldReturnObjectWithRepositoryActions_WhenContentIsRepositoryActions1.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ShouldReturnObjectWithRepositoryActions_WhenContentIsRepositoryActions1.verified.txt index 9277d29c..ee7c2c9a 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ShouldReturnObjectWithRepositoryActions_WhenContentIsRepositoryActions1.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ShouldReturnObjectWithRepositoryActions_WhenContentIsRepositoryActions1.verified.txt @@ -3,9 +3,9 @@ ActionsCollection: { Actions: [ { - $type: RepositoryActionBrowserV1, - Type: browser@1, - Name: {OpenIn} Windows File Explorer, + $type: RepositoryActionCommandV1, + Type: command@1, + Name: Open in Windows File Explorer, Active: false, Variables: [ { @@ -15,9 +15,9 @@ ] }, { - $type: RepositoryActionBrowserV1, - Type: browser@1, - Name: {OpenIn} Windows File Explorer, + $type: RepositoryActionCommandV1, + Type: command@1, + Name: Open in Windows File Explorer, Active: false } ] diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ShouldReturnObjectWithRepositoryActions_WhenContentIsRepositoryActions3.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ShouldReturnObjectWithRepositoryActions_WhenContentIsRepositoryActions3.verified.txt index 32d94bfb..5feb71e1 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ShouldReturnObjectWithRepositoryActions_WhenContentIsRepositoryActions3.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/DynamicRepositoryActionDeserializerTest.Deserialize_ShouldReturnObjectWithRepositoryActions_WhenContentIsRepositoryActions3.verified.txt @@ -15,10 +15,9 @@ ], Actions: [ { - $type: RepositoryActionBrowserV1, - Url: https://google.com, - Type: browser@1, - Name: {OpenIn} Windows File Explorer, + $type: RepositoryActionCommandV1, + Type: command@1, + Name: Open in Windows File Explorer, Active: false, Variables: [ { @@ -28,9 +27,9 @@ ] }, { - $type: RepositoryActionBrowserV1, - Type: browser@1, - Name: {OpenIn} Windows File Explorer, + $type: RepositoryActionCommandV1, + Type: command@1, + Name: Open in Windows File Explorer, Active: false } ] diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/RepositorySpecificConfigurationTest.Create_ShouldProcessSeparator1.verified.txt b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/RepositorySpecificConfigurationTest.Create_ShouldProcessSeparator1.verified.txt index 1fe689a1..e840496e 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/RepositorySpecificConfigurationTest.Create_ShouldProcessSeparator1.verified.txt +++ b/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Verified/RepositorySpecificConfigurationTest.Create_ShouldProcessSeparator1.verified.txt @@ -1,14 +1,9 @@ [ { $type: RepositoryAction, - Name: Google 1, + Name: Open in Windows File Explorer, Action: { - $type: DelegateAction, - Action: { - Type: Action, - Target: ActionBrowserV1Mapper.<>c__DisplayClass4_0, - Method: Void Map(System.Object, System.Object) - } + $type: NullAction }, ExecutionCausesSynchronizing: false, CanExecute: true @@ -23,14 +18,9 @@ }, { $type: RepositoryAction, - Name: Google 2, + Name: Open in Windows File Explorer 2, Action: { - $type: DelegateAction, - Action: { - Type: Action, - Target: ActionBrowserV1Mapper.<>c__DisplayClass4_0, - Method: Void Map(System.Object, System.Object) - } + $type: NullAction }, ExecutionCausesSynchronizing: false, CanExecute: true diff --git a/tests/RepoM.Plugin.Misc.Tests/Configuration/DocsModuleSettingsTests.cs b/tests/RepoM.Plugin.Misc.Tests/Configuration/DocsModuleSettingsTests.cs index ec7b7295..9a119d21 100644 --- a/tests/RepoM.Plugin.Misc.Tests/Configuration/DocsModuleSettingsTests.cs +++ b/tests/RepoM.Plugin.Misc.Tests/Configuration/DocsModuleSettingsTests.cs @@ -46,6 +46,12 @@ public async Task VerifyChanges() { var (config, _) = await PersistDefaultConfigAsync(p); results.Add(p.GetType().Name, config); + + var (configExample, _) = await PersistExampleConfigAsync(p); + if (configExample != null) + { + results.Add(p.GetType().Name + "_Example", configExample); + } } // assert @@ -71,6 +77,8 @@ public async Task DocsModuleSettings(IPackage package) } else { + (_, string? examplePersistedConfig) = await PersistExampleConfigAsync(package); + var builtinClassNames = new Dictionary { [config!.GetType().Name] = "config", @@ -105,7 +113,7 @@ public async Task DocsModuleSettings(IPackage package) sb.Append(classWriter.Properties); } - var configWithSnippetDocumentationMarkdown = CreateConfigWithSnippetDocumentationMarkdown(persistedConfig/*$"Generated_DefaultConfig_{packageName}"*/); + var configWithSnippetDocumentationMarkdown = CreateConfigWithSnippetDocumentationMarkdown(persistedConfig, examplePersistedConfig); if (!string.IsNullOrWhiteSpace(sb.ToString())) { @@ -122,36 +130,55 @@ public async Task DocsModuleSettings(IPackage package) } } - private static string CreateConfigWithSnippetDocumentationMarkdown(string? snippet) + private static string CreateConfigWithSnippetDocumentationMarkdown(string? snippet, string? exampleSnippet = null) { - return new StringBuilder() - .AppendLine("## Configuration") - .AppendLine(string.Empty) - .AppendLine("This plugin has specific configuration stored in a separate configuration file stored in `%APPDATA%/RepoM/Module/` directory. This configuration file should be edit manually. The safest way to do this is, is when RepoM is not running.") - .AppendLine(string.Empty) - .AppendLine("The following default configuration is used:") - .AppendLine(string.Empty) - .AppendLine("```json") - .AppendLine(snippet) - .AppendLine("```") - .ToString(); + StringBuilder sb = new StringBuilder() + .AppendLine("## Configuration") + .AppendLine(string.Empty) + .AppendLine("This plugin has specific configuration stored in a separate configuration file stored in `%APPDATA%/RepoM/Module/` directory. This configuration file should be edit manually. The safest way to do this is, is when RepoM is not running.") + .AppendLine(string.Empty) + .AppendLine("The following default configuration is used:") + .AppendLine(string.Empty) + .AppendLine("```json") + .AppendLine(snippet) + .AppendLine("```"); + + if (!string.IsNullOrWhiteSpace(exampleSnippet)) + { + sb.AppendLine(string.Empty) + .AppendLine("For example:") + .AppendLine(string.Empty) + .AppendLine("```json") + .AppendLine(exampleSnippet) + .AppendLine("```"); + } + + return sb.ToString(); } private static string CreateConfigWithoutSnippetDocumentationMarkdown() { return new StringBuilder() - .AppendLine("## Configuration") - .AppendLine(string.Empty) - .AppendLine("This module has no configuration.") - .ToString(); - + .AppendLine("## Configuration") + .AppendLine(string.Empty) + .AppendLine("This module has no configuration.") + .ToString(); } private async Task> PersistDefaultConfigAsync(IPackage package) { - Type type = package.GetType(); - MethodInfo? methodInfo = type.GetMethod("PersistDefaultConfigAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + MethodInfo? methodInfo = package.GetType().GetMethod("PersistDefaultConfigAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + return await PersistUsingMethodAsync(package, methodInfo).ConfigureAwait(false); + } + private async Task> PersistExampleConfigAsync(IPackage package) + { + MethodInfo? methodInfo = package.GetType().GetMethod("PersistExampleConfigAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + return await PersistUsingMethodAsync(package, methodInfo).ConfigureAwait(false); + } + + private async Task> PersistUsingMethodAsync(IPackage package, MethodInfo? methodInfo) + { if (methodInfo == null) { return new Tuple(null, null); diff --git a/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.DocsModuleSettings_WebBrowserPackage#desc.verified.md b/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.DocsModuleSettings_WebBrowserPackage#desc.verified.md new file mode 100644 index 00000000..8122defe --- /dev/null +++ b/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.DocsModuleSettings_WebBrowserPackage#desc.verified.md @@ -0,0 +1,48 @@ +## Configuration + +This plugin has specific configuration stored in a separate configuration file stored in `%APPDATA%/RepoM/Module/` directory. This configuration file should be edit manually. The safest way to do this is, is when RepoM is not running. + +The following default configuration is used: + +```json +{ + "Version": 1, + "Settings": { + "Browsers": null, + "Profiles": null + } +} +``` + +For example: + +```json +{ + "Version": 1, + "Settings": { + "Browsers": { + "Edge": "C:\\PathTo\\msedge.exe", + "FireFox": "C:\\PathTo\\Mozilla\\firefox.exe" + }, + "Profiles": { + "Work": { + "BrowserName": "Edge", + "CommandLineArguments": "\"--profile-directory=Profile 4\" {url}" + }, + "Incognito": { + "BrowserName": "Edge", + "CommandLineArguments": "-inprivate" + }, + "Incognito2": { + "BrowserName": "FireFox", + "CommandLineArguments": "-inprivate {url}" + } + } + } +} +``` + +Properties: + +- `Browsers`: Dictionary of known browsers and their path to use for opening urls. +- `Profiles`: Profiles to use. diff --git a/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.DocsModuleSettings_WebBrowserPackage.verified.json b/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.DocsModuleSettings_WebBrowserPackage.verified.json new file mode 100644 index 00000000..6577532a --- /dev/null +++ b/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.DocsModuleSettings_WebBrowserPackage.verified.json @@ -0,0 +1,7 @@ +{ + "Version": 1, + "Settings": { + "Browsers": null, + "Profiles": null + } +} \ No newline at end of file diff --git a/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.VerifyChanges.verified.txt b/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.VerifyChanges.verified.txt index 2552127b..dad15fde 100644 --- a/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.VerifyChanges.verified.txt +++ b/tests/RepoM.Plugin.Misc.Tests/Configuration/ModuleSettingsDocs/DocsModuleSettingsTests.VerifyChanges.verified.txt @@ -17,5 +17,29 @@ PersistenceBuffer: 00:05:00, RetentionDays: 30 }, + WebBrowserPackage: { + $type: WebBrowserConfigV1 + }, + WebBrowserPackage_Example: { + $type: WebBrowserConfigV1, + Browsers: { + Edge: C:\PathTo\msedge.exe, + FireFox: C:\PathTo\Mozilla\firefox.exe + }, + Profiles: { + Incognito: { + BrowserName: Edge, + CommandLineArguments: -inprivate + }, + Incognito2: { + BrowserName: FireFox, + CommandLineArguments: -inprivate {url} + }, + Work: { + BrowserName: Edge, + CommandLineArguments: "--profile-directory=Profile 4" {url} + } + } + }, WindowsExplorerGitInfoPackage: null } \ No newline at end of file diff --git a/tests/RepoM.Plugin.Misc.Tests/Configuration/RepositoryActionsDocs/DocsRepositoryActionsTests.DocsRepositoryActionsSettings_RepositoryActionBrowserV1.verified.md b/tests/RepoM.Plugin.Misc.Tests/Configuration/RepositoryActionsDocs/DocsRepositoryActionsTests.DocsRepositoryActionsSettings_RepositoryActionBrowserV1.verified.md index 20a27168..935dae51 100644 --- a/tests/RepoM.Plugin.Misc.Tests/Configuration/RepositoryActionsDocs/DocsRepositoryActionsTests.DocsRepositoryActionsSettings_RepositoryActionBrowserV1.verified.md +++ b/tests/RepoM.Plugin.Misc.Tests/Configuration/RepositoryActionsDocs/DocsRepositoryActionsTests.DocsRepositoryActionsSettings_RepositoryActionBrowserV1.verified.md @@ -3,3 +3,4 @@ Action specific properties: - `url`: The url to browse to. (required, evaluated, string) +- `profile`: profile name used to select browser and browser profile (optional, evaluated, string) diff --git a/tests/RepoM.Plugin.Misc.Tests/Configuration/RepositoryActionsDocs/DocsRepositoryActionsTests.VerifyChanges.verified.txt b/tests/RepoM.Plugin.Misc.Tests/Configuration/RepositoryActionsDocs/DocsRepositoryActionsTests.VerifyChanges.verified.txt index 5daa5e1f..395138f9 100644 --- a/tests/RepoM.Plugin.Misc.Tests/Configuration/RepositoryActionsDocs/DocsRepositoryActionsTests.VerifyChanges.verified.txt +++ b/tests/RepoM.Plugin.Misc.Tests/Configuration/RepositoryActionsDocs/DocsRepositoryActionsTests.VerifyChanges.verified.txt @@ -3,7 +3,6 @@ RepositoryAction, RepositoryActionAssociateFileV1, RepositoryActionBrowseRepositoryV1, - RepositoryActionBrowserV1, RepositoryActionCommandV1, RepositoryActionExecutableV1, RepositoryActionFolderV1, @@ -29,5 +28,8 @@ ], RepoM.Plugin.SonarCloud: [ RepositoryActionSonarCloudSetFavoriteV1 + ], + RepoM.Plugin.WebBrowser: [ + RepositoryActionBrowserV1 ] } \ No newline at end of file diff --git a/tests/RepoM.Plugin.Misc.Tests/PluginStore.cs b/tests/RepoM.Plugin.Misc.Tests/PluginStore.cs index 42a6f90f..8feeb26e 100644 --- a/tests/RepoM.Plugin.Misc.Tests/PluginStore.cs +++ b/tests/RepoM.Plugin.Misc.Tests/PluginStore.cs @@ -11,6 +11,7 @@ namespace RepoM.Plugin.Misc.Tests; using RepoM.Plugin.LuceneQueryParser; using RepoM.Plugin.SonarCloud; using RepoM.Plugin.Statistics; +using RepoM.Plugin.WebBrowser; using RepoM.Plugin.WindowsExplorerGitInfo; internal static class PluginStore @@ -27,6 +28,7 @@ public static IEnumerable Packages yield return new SonarCloudPackage(); yield return new StatisticsPackage(); yield return new WindowsExplorerGitInfoPackage(); + yield return new WebBrowserPackage(); } } diff --git a/tests/RepoM.Plugin.Misc.Tests/RepoM.Plugin.Misc.Tests.csproj b/tests/RepoM.Plugin.Misc.Tests/RepoM.Plugin.Misc.Tests.csproj index 5852eff4..791cf277 100644 --- a/tests/RepoM.Plugin.Misc.Tests/RepoM.Plugin.Misc.Tests.csproj +++ b/tests/RepoM.Plugin.Misc.Tests/RepoM.Plugin.Misc.Tests.csproj @@ -47,6 +47,7 @@ + diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/BrowserV1Test.cs b/tests/RepoM.Plugin.WebBrowser.Tests/ActionProvider/BrowserV1Test.cs similarity index 74% rename from tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/BrowserV1Test.cs rename to tests/RepoM.Plugin.WebBrowser.Tests/ActionProvider/BrowserV1Test.cs index 4134af7c..0c0f3a28 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/BrowserV1Test.cs +++ b/tests/RepoM.Plugin.WebBrowser.Tests/ActionProvider/BrowserV1Test.cs @@ -1,12 +1,15 @@ -namespace RepoM.Api.Tests.IO.ModuleBasedRepositoryActionProvider.Action; +namespace RepoM.Plugin.WebBrowser.Tests.ActionProvider; +using System; using System.Threading.Tasks; using EasyTestFile; using EasyTestFileXunit; using FluentAssertions; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.ActionDeserializers; using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data; -using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data.Actions; using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Deserialization; +using RepoM.Core.Plugin.RepositoryOrdering.Configuration; +using RepoM.Plugin.WebBrowser.ActionProvider; using VerifyTests; using VerifyXunit; using Xunit; @@ -21,7 +24,8 @@ public class BrowserV1Test public BrowserV1Test() { - _sut = DynamicRepositoryActionDeserializerFactory.CreateWithDeserializer(new DefaultActionDeserializer()); + var actionDeserializerComposition = new ActionDeserializerComposition(new[] { new DefaultActionDeserializer(), }, Array.Empty>()); + _sut = new YamlDynamicRepositoryActionDeserializer(actionDeserializerComposition); _testFileSettings = new EasyTestFileSettings(); _testFileSettings.UseDirectory("TestFiles"); diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/BrowserV1Test.Deserialize_ActionBrowserV1.testfile.yaml b/tests/RepoM.Plugin.WebBrowser.Tests/ActionProvider/TestFiles/BrowserV1Test.Deserialize_ActionBrowserV1.testfile.yaml similarity index 100% rename from tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/TestFiles/BrowserV1Test.Deserialize_ActionBrowserV1.testfile.yaml rename to tests/RepoM.Plugin.WebBrowser.Tests/ActionProvider/TestFiles/BrowserV1Test.Deserialize_ActionBrowserV1.testfile.yaml diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/BrowserV1Test.Deserialize_ActionBrowserV1.verified.txt b/tests/RepoM.Plugin.WebBrowser.Tests/ActionProvider/Verified/BrowserV1Test.Deserialize_ActionBrowserV1.verified.txt similarity index 100% rename from tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/Action/Verified/BrowserV1Test.Deserialize_ActionBrowserV1.verified.txt rename to tests/RepoM.Plugin.WebBrowser.Tests/ActionProvider/Verified/BrowserV1Test.Deserialize_ActionBrowserV1.verified.txt diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFiles/Browser01.testfile.yaml b/tests/RepoM.Plugin.WebBrowser.Tests/DocumentationFiles/Browser01.testfile.yaml similarity index 58% rename from tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFiles/Browser01.testfile.yaml rename to tests/RepoM.Plugin.WebBrowser.Tests/DocumentationFiles/Browser01.testfile.yaml index defd0474..cfc5f46d 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFiles/Browser01.testfile.yaml +++ b/tests/RepoM.Plugin.WebBrowser.Tests/DocumentationFiles/Browser01.testfile.yaml @@ -7,11 +7,12 @@ repository-actions: - type: browser@1 active: true variables: [] - name: 'My Github' - url: 'https://github.com/coenm' + name: My Github + url: https://github.com/coenm - type: browser@1 - name: 'My Github' - url: 'https://github.com/coenm' + name: My Github + url: https://github.com/coenm + profile: edge # end-snippet \ No newline at end of file diff --git a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Browser01.verified.txt b/tests/RepoM.Plugin.WebBrowser.Tests/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Browser01.verified.txt similarity index 94% rename from tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Browser01.verified.txt rename to tests/RepoM.Plugin.WebBrowser.Tests/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Browser01.verified.txt index 52d84955..f57ff865 100644 --- a/tests/RepoM.Api.Tests/IO/ModuleBasedRepositoryActionProvider/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Browser01.verified.txt +++ b/tests/RepoM.Plugin.WebBrowser.Tests/DocumentationFilesVerified/DocumentationTests.Deserialize_Documentation_Browser01.verified.txt @@ -12,6 +12,7 @@ { $type: RepositoryActionBrowserV1, Url: https://github.com/coenm, + Profile: edge, Type: browser@1, Name: My Github } diff --git a/tests/RepoM.Plugin.WebBrowser.Tests/DocumentationTests.cs b/tests/RepoM.Plugin.WebBrowser.Tests/DocumentationTests.cs new file mode 100644 index 00000000..6d8bc92d --- /dev/null +++ b/tests/RepoM.Plugin.WebBrowser.Tests/DocumentationTests.cs @@ -0,0 +1,47 @@ +namespace RepoM.Plugin.WebBrowser.Tests; + +using System.Threading.Tasks; +using EasyTestFile; +using EasyTestFileXunit; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Deserialization; +using RepoM.Plugin.WebBrowser.Tests.TestFramework; +using VerifyTests; +using VerifyXunit; +using Xunit; + +[UsesEasyTestFile] +[UsesVerify] +public class DocumentationTests +{ + private readonly EasyTestFileSettings _testFileSettings; + private readonly VerifySettings _verifySettings; + private readonly YamlDynamicRepositoryActionDeserializer _sut; + + public DocumentationTests() + { + _sut = DynamicRepositoryActionDeserializerFactory.Create(); + + _testFileSettings = new EasyTestFileSettings(); + _testFileSettings.UseDirectory("DocumentationFiles"); + _testFileSettings.UseExtension("yaml"); + + _verifySettings = new VerifySettings(); + _verifySettings.UseDirectory("DocumentationFilesVerified"); + } + + [Theory] + [InlineData("Browser01")] + public async Task Deserialize_Documentation(string filename) + { + // arrange + _testFileSettings.UseFileName(filename); + var content = await EasyTestFile.LoadAsText(_testFileSettings); + + // act + RepositoryActionConfiguration result = _sut.Deserialize(content); + + // assert + await Verifier.Verify(result, _verifySettings).UseTextForParameters(filename); + } +} \ No newline at end of file diff --git a/tests/RepoM.Plugin.WebBrowser.Tests/RepoM.Plugin.WebBrowser.Tests.csproj b/tests/RepoM.Plugin.WebBrowser.Tests/RepoM.Plugin.WebBrowser.Tests.csproj new file mode 100644 index 00000000..d16fe9b5 --- /dev/null +++ b/tests/RepoM.Plugin.WebBrowser.Tests/RepoM.Plugin.WebBrowser.Tests.csproj @@ -0,0 +1,42 @@ + + + + net7.0 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/tests/RepoM.Plugin.WebBrowser.Tests/RepositoryActions/BrowseActionExecutorTests.cs b/tests/RepoM.Plugin.WebBrowser.Tests/RepositoryActions/BrowseActionExecutorTests.cs new file mode 100644 index 00000000..6566c35b --- /dev/null +++ b/tests/RepoM.Plugin.WebBrowser.Tests/RepositoryActions/BrowseActionExecutorTests.cs @@ -0,0 +1,65 @@ +namespace RepoM.Plugin.WebBrowser.Tests.RepositoryActions; + +using System; +using FakeItEasy; +using FluentAssertions; +using RepoM.Core.Plugin.Repository; +using RepoM.Plugin.WebBrowser.RepositoryActions; +using RepoM.Plugin.WebBrowser.RepositoryActions.Actions; +using RepoM.Plugin.WebBrowser.Services; +using Xunit; + +public class BrowseActionExecutorTests +{ + private readonly IRepository _repository; + private readonly IWebBrowserService _service; + private readonly BrowseActionExecutor _sut; + + public BrowseActionExecutorTests() + { + _repository = A.Fake(); + _service = A.Fake(); + _sut = new BrowseActionExecutor(_service); + } + + [Fact] + public void Ctor_ShouldThrow_WhenArgumentNull() + { + // arrange + + // act + Func act1 = () => new BrowseActionExecutor(null!); + + // assert + act1.Should().Throw(); + } + + [Fact] + public void Execute_ShouldCallOpenUrlWithoutProfile_WhenProfileIsNull() + { + // arrange + + // act + _sut.Execute(_repository, new BrowseAction("url", null)); + + // assert + A.CallTo(() => _service.OpenUrl("url")).MustHaveHappenedOnceExactly(); + A.CallTo(() => _service.OpenUrl(A._, A._)).MustNotHaveHappened(); + } + + [Theory] + [InlineData("profile")] + [InlineData("")] + [InlineData(" ")] + public void Execute_ShouldCallOpenUrlWithProfile_WhenProfileIsNotNull(string profile) + { + // arrange + + // act + _sut.Execute(_repository, new BrowseAction("url", profile)); + + // assert + A.CallTo(() => _service.OpenUrl(A._)).MustNotHaveHappened(); + A.CallTo(() => _service.OpenUrl("url", profile)).MustHaveHappenedOnceExactly(); + } +} \ No newline at end of file diff --git a/tests/RepoM.Plugin.WebBrowser.Tests/TestFramework/DynamicRepositoryActionDeserializerFactory.cs b/tests/RepoM.Plugin.WebBrowser.Tests/TestFramework/DynamicRepositoryActionDeserializerFactory.cs new file mode 100644 index 00000000..be3b8da3 --- /dev/null +++ b/tests/RepoM.Plugin.WebBrowser.Tests/TestFramework/DynamicRepositoryActionDeserializerFactory.cs @@ -0,0 +1,28 @@ +namespace RepoM.Plugin.WebBrowser.Tests.TestFramework; + +using System; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.ActionDeserializers; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Data; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider.Deserialization; +using RepoM.Core.Plugin.RepositoryOrdering.Configuration; +using RepoM.Plugin.WebBrowser.ActionProvider; + +internal static class DynamicRepositoryActionDeserializerFactory +{ + public static YamlDynamicRepositoryActionDeserializer Create() + { + return new YamlDynamicRepositoryActionDeserializer( + new ActionDeserializerComposition( + new IActionDeserializer[] + { + new DefaultActionDeserializer(), + }, + Array.Empty>())); + } + + public static YamlDynamicRepositoryActionDeserializer CreateWithDeserializer(IActionDeserializer actionDeserializer) + { + return new YamlDynamicRepositoryActionDeserializer(new ActionDeserializerComposition(new[] { actionDeserializer, }, Array.Empty>())); + } +} \ No newline at end of file diff --git a/tests/RepoM.Plugin.WebBrowser.Tests/TestFramework/VerifierInitializer.cs b/tests/RepoM.Plugin.WebBrowser.Tests/TestFramework/VerifierInitializer.cs new file mode 100644 index 00000000..6ba48f5e --- /dev/null +++ b/tests/RepoM.Plugin.WebBrowser.Tests/TestFramework/VerifierInitializer.cs @@ -0,0 +1,15 @@ +namespace RepoM.Plugin.Statistics.Tests.TestFramework; + +using System.Runtime.CompilerServices; +using Argon; +using VerifyTests; + +public static class VerifierInitializer +{ + [ModuleInitializer] + public static void Initialize() + { + VerifierSettings.DisableRequireUniquePrefix(); + VerifierSettings.AddExtraSettings(serializerSettings => serializerSettings.TypeNameHandling = TypeNameHandling.Auto); + } +} \ No newline at end of file diff --git a/tests/RepoM.Plugin.WebBrowser.Tests/WebBrowserPackageTest.cs b/tests/RepoM.Plugin.WebBrowser.Tests/WebBrowserPackageTest.cs new file mode 100644 index 00000000..c014bc2e --- /dev/null +++ b/tests/RepoM.Plugin.WebBrowser.Tests/WebBrowserPackageTest.cs @@ -0,0 +1,99 @@ +namespace RepoM.Plugin.WebBrowser.Tests; + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using FakeItEasy; +using Microsoft.Extensions.Logging; +using RepoM.Api.IO.ModuleBasedRepositoryActionProvider; +using RepoM.Core.Plugin; +using RepoM.Core.Plugin.Expressions; +using RepoM.Plugin.WebBrowser; +using RepoM.Plugin.WebBrowser.PersistentConfiguration; +using SimpleInjector; +using Xunit; + +public class WebBrowserPackageTest +{ + private readonly Container _container; + private readonly IPackageConfiguration _packageConfiguration; + + public WebBrowserPackageTest() + { + _packageConfiguration = A.Fake(); + _container = new Container(); + + var webBrowserConfigV1 = new WebBrowserConfigV1 + { + Browsers = new Dictionary + { + { "Edge", "msedge.exe" }, + }, + Profiles = new Dictionary + { + { + "incognito", + new ProfileConfig { BrowserName = "Edge", CommandLineArguments = "--incognito", } + }, + }, + }; + A.CallTo(() => _packageConfiguration.GetConfigurationVersionAsync()).Returns(Task.FromResult(1 as int?)); + A.CallTo(() => _packageConfiguration.LoadConfigurationAsync()).ReturnsLazily(() => webBrowserConfigV1); + A.CallTo(() => _packageConfiguration.PersistConfigurationAsync(A._, 1)).Returns(Task.CompletedTask); + } + + [Fact] + public async Task RegisterServices_ShouldBeSuccessful_WhenExternalDependenciesAreRegistered() + { + // arrange + RegisterExternals(_container); + var sut = new WebBrowserPackage(); + + // act + await sut.RegisterServicesAsync(_container, _packageConfiguration); + + // assert + // implicit, Verify throws when container is not valid. + _container.Verify(VerificationOption.VerifyAndDiagnose); + } + + [Theory] + [InlineData(null)] + [InlineData(2)] + [InlineData(10)] + public async Task RegisterServices_ShouldPersistNewConfig_WhenVersionIsNotCorrect(int? version) + { + // arrange + A.CallTo(() => _packageConfiguration.GetConfigurationVersionAsync()).Returns(Task.FromResult(version)); + RegisterExternals(_container); + var sut = new WebBrowserPackage(); + + // act + await sut.RegisterServicesAsync(_container, _packageConfiguration); + + // assert + A.CallTo(() => _packageConfiguration.PersistConfigurationAsync(A._, 1)).MustHaveHappenedOnceExactly(); + + // implicit, Verify throws when container is not valid. + _container.Verify(VerificationOption.VerifyAndDiagnose); + } + + [Fact] + public async Task RegisterServices_ShouldFail_WhenExternalDependenciesAreNotRegistered() + { + // arrange + var sut = new WebBrowserPackage(); + + // act + await sut.RegisterServicesAsync(_container, _packageConfiguration); + + // assert + Assert.Throws(() => _container.Verify(VerificationOption.VerifyAndDiagnose)); + } + + private static void RegisterExternals(Container container) + { + container.RegisterSingleton(A.Dummy); + container.RegisterSingleton(A.Dummy); + } +} \ No newline at end of file diff --git a/tests/RepoM.Plugin.WebBrowser.Tests/WebBrowserServiceTest.cs b/tests/RepoM.Plugin.WebBrowser.Tests/WebBrowserServiceTest.cs new file mode 100644 index 00000000..f1fcc170 --- /dev/null +++ b/tests/RepoM.Plugin.WebBrowser.Tests/WebBrowserServiceTest.cs @@ -0,0 +1,191 @@ +namespace RepoM.Plugin.WebBrowser.Tests; + +using System; +using System.Collections.Generic; +using FluentAssertions; +using RepoM.Plugin.WebBrowser.Services; +using VerifyXunit; +using Xunit; + +[UsesVerify] +public class WebBrowserServiceTest +{ + [Fact] + public void Ctor_ShouldThrow_WhenArgumentNull() + { + // arrange + + // act + Func act1 = () => new WebBrowserService(null!); + + // assert + act1.Should().Throw(); + } + + [Fact] + public void ProfileExist_ShouldReturnFalse_WhenNoProfilesDefined() + { + + // arrange + var config = new WebBrowserConfiguration(); + var sut = new WebBrowserService(config); + + // act + var result = sut.ProfileExist("name"); + + // assert + _ = result.Should().BeFalse(); + } + + [Fact] + public void ProfileExist_ShouldReturnFalse_WhenNoProfileNameDoesNotMatchCase() + { + + // arrange + var config = new WebBrowserConfiguration + { + Profiles = new() + { + { "Name", new BrowserProfileConfig() }, + }, + }; + var sut = new WebBrowserService(config); + + // act + var result = sut.ProfileExist("name"); + + // assert + _ = result.Should().BeFalse(); + } + + [Fact] + public void ProfileExist_ShouldReturnTrue_WhenProfileExists() + { + + // arrange + var config = new WebBrowserConfiguration + { + Profiles = new() + { + { "name1", new BrowserProfileConfig() }, + { "name2", new BrowserProfileConfig() }, + { "name3", new BrowserProfileConfig() }, + }, + }; + var sut = new WebBrowserService(config); + + // act + var result = sut.ProfileExist("name2"); + + // assert + _ = result.Should().BeTrue(); + } + + [Fact] + public void OpenUrl_ShouldStartProcess() + { + // arrange + var config = new WebBrowserConfiguration + { + Profiles = new() + { + { "name1", new BrowserProfileConfig() }, + { "name2", new BrowserProfileConfig() }, + { "name3", new BrowserProfileConfig() }, + }, + }; + var sut = new DummyWebBrowserService(config); + + // act + sut.OpenUrl("https://google.com"); + + // assert + sut.StartProcessCalled.Should().BeEquivalentTo("https://google.com - "); + } + + [Fact] + public void OpenUrl_WithProfile_ShouldStartProcess() + { + // arrange + var config = new WebBrowserConfiguration + { + Profiles = new() + { + { "Private", new BrowserProfileConfig { BrowserName = "Edge", CommandLineArguments = "\"--profile 23 \" {url}", } }, + }, + Browsers = new() + { + { "Edge", "msedge.exe" }, + }, + }; + var sut = new DummyWebBrowserService(config); + + // act + sut.OpenUrl("https://google.com", "Private"); + + // assert + sut.StartProcessCalled.Should().BeEquivalentTo("msedge.exe - \"--profile 23 \" https://google.com"); + } + + [Fact] + public void OpenUrl_WithProfile_ShouldStartProcessWithoutProfile_WhenProfileNotExists() + { + // arrange + var config = new WebBrowserConfiguration + { + Profiles = new() + { + { "Private", new BrowserProfileConfig { BrowserName = "Edge", CommandLineArguments = "\"--profile 23 \" {url}", } }, + }, + Browsers = new() + { + { "Edge", "msedge.exe" }, + }, + }; + var sut = new DummyWebBrowserService(config); + + // act + sut.OpenUrl("https://google.com", "Private-Not-Exists"); + + // assert + sut.StartProcessCalled.Should().BeEquivalentTo("https://google.com - "); + } + + [Fact] + public void OpenUrl_WithProfile_ShouldStartProcessWithoutProfile_WhenBrowserNotExists() + { + // arrange + var config = new WebBrowserConfiguration + { + Profiles = new() + { + { "Private", new BrowserProfileConfig { BrowserName = "InvalidBrowser", CommandLineArguments = "\"--profile 23 \" {url}", } }, + }, + Browsers = new() + { + { "Edge", "msedge.exe" }, + }, + }; + var sut = new DummyWebBrowserService(config); + + // act + sut.OpenUrl("https://google.com", "Private"); + + // assert + sut.StartProcessCalled.Should().BeEquivalentTo("https://google.com - "); + } +} + +file class DummyWebBrowserService : WebBrowserService +{ + public DummyWebBrowserService(WebBrowserConfiguration configuration) : base(configuration) + { + } + + public List StartProcessCalled { get; } = new(1); + + protected override void StartProcess(string process, string arguments) + { + StartProcessCalled.Add(process + " - " + arguments); + } +} \ No newline at end of file