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
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