diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0bfed6af..4150e7d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,9 +20,14 @@ changes you need to make.
`api_key` and `base_url` in a `secrets.yml` file. See [the secrets docs][secrets] for more info.
Huge thanks to @voltron4lyfe for this one. (#105, #139)
- Named instances are now supported in configuration YAML.
+- New optional setting `repository.git_path` may be used to specify the path to a `git` executable.
+ If not used, `PATH` will be searched.
### Changed
+- **BREAKING**: Recyclarr now requires `git` to be installed on host systems when using manual
+ installation. If using Docker, there is no breaking change since git will be bundled with the
+ image.
- Deprecated array-style instances in configuration YAML. Read more about this in the v3.0 Upgrade
Guide.
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index 3b5c69d3..4040406a 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -2,7 +2,6 @@
true
-
@@ -12,12 +11,12 @@
+
-
@@ -33,7 +32,6 @@
-
@@ -54,11 +52,10 @@
-
-
+
\ No newline at end of file
diff --git a/src/Recyclarr.Gui/Recyclarr.Gui.csproj b/src/Recyclarr.Gui/Recyclarr.Gui.csproj
index ea021c2f..4b10ac4d 100644
--- a/src/Recyclarr.Gui/Recyclarr.Gui.csproj
+++ b/src/Recyclarr.Gui/Recyclarr.Gui.csproj
@@ -17,7 +17,6 @@
-
diff --git a/src/Recyclarr.TestLibrary/IntegrationFixture.cs b/src/Recyclarr.TestLibrary/IntegrationFixture.cs
index e1273218..fbad9df8 100644
--- a/src/Recyclarr.TestLibrary/IntegrationFixture.cs
+++ b/src/Recyclarr.TestLibrary/IntegrationFixture.cs
@@ -11,9 +11,8 @@ using Recyclarr.Command;
using Serilog;
using Serilog.Events;
using TrashLib;
+using TrashLib.Repo.VersionControl;
using TrashLib.Startup;
-using VersionControl;
-using VersionControl.Wrappers;
namespace Recyclarr.TestLibrary;
@@ -35,7 +34,6 @@ public abstract class IntegrationFixture : IDisposable
RegisterMockFor(builder);
RegisterMockFor(builder);
RegisterMockFor(builder);
- RegisterMockFor(builder);
RegisterExtraTypes(builder);
diff --git a/src/Recyclarr.Tests/CompositionRootTest.cs b/src/Recyclarr.Tests/CompositionRootTest.cs
index 2bdad295..2bceb4c0 100644
--- a/src/Recyclarr.Tests/CompositionRootTest.cs
+++ b/src/Recyclarr.Tests/CompositionRootTest.cs
@@ -13,8 +13,8 @@ using Recyclarr.Command;
using Serilog;
using TrashLib;
using TrashLib.Config.Services;
+using TrashLib.Repo.VersionControl;
using TrashLib.Startup;
-using VersionControl;
namespace Recyclarr.Tests;
diff --git a/src/Recyclarr.sln b/src/Recyclarr.sln
index 9f19b0df..85831cf4 100644
--- a/src/Recyclarr.sln
+++ b/src/Recyclarr.sln
@@ -29,10 +29,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrashLib", "TrashLib\TrashL
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrashLib.Tests", "TrashLib.Tests\TrashLib.Tests.csproj", "{A4EC7E0D-C591-4874-B9AC-EB12A96F3E83}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VersionControl", "VersionControl\VersionControl.csproj", "{CF5BB1A7-3D21-48CB-B6B0-526612B2D94D}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VersionControl.Tests", "VersionControl.Tests\VersionControl.Tests.csproj", "{F81C7EA3-4ACA-4171-8A60-531F129A33C5}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Recyclarr.TestLibrary", "Recyclarr.TestLibrary\Recyclarr.TestLibrary.csproj", "{77D1C695-94D4-46A9-8F12-41E54AF97750}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Recyclarr.Gui", "Recyclarr.Gui\Recyclarr.Gui.csproj", "{53EECBC0-E0EA-4D6C-925C-5DB8C42CCB85}"
@@ -81,14 +77,6 @@ Global
{A4EC7E0D-C591-4874-B9AC-EB12A96F3E83}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4EC7E0D-C591-4874-B9AC-EB12A96F3E83}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4EC7E0D-C591-4874-B9AC-EB12A96F3E83}.Release|Any CPU.Build.0 = Release|Any CPU
- {CF5BB1A7-3D21-48CB-B6B0-526612B2D94D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CF5BB1A7-3D21-48CB-B6B0-526612B2D94D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CF5BB1A7-3D21-48CB-B6B0-526612B2D94D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CF5BB1A7-3D21-48CB-B6B0-526612B2D94D}.Release|Any CPU.Build.0 = Release|Any CPU
- {F81C7EA3-4ACA-4171-8A60-531F129A33C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F81C7EA3-4ACA-4171-8A60-531F129A33C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F81C7EA3-4ACA-4171-8A60-531F129A33C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F81C7EA3-4ACA-4171-8A60-531F129A33C5}.Release|Any CPU.Build.0 = Release|Any CPU
{77D1C695-94D4-46A9-8F12-41E54AF97750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77D1C695-94D4-46A9-8F12-41E54AF97750}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77D1C695-94D4-46A9-8F12-41E54AF97750}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/src/Recyclarr/Command/ServiceCommand.cs b/src/Recyclarr/Command/ServiceCommand.cs
index 4c466cba..c83286ba 100644
--- a/src/Recyclarr/Command/ServiceCommand.cs
+++ b/src/Recyclarr/Command/ServiceCommand.cs
@@ -13,6 +13,7 @@ using Serilog;
using TrashLib.Config.Settings;
using TrashLib.Extensions;
using TrashLib.Repo;
+using TrashLib.Repo.VersionControl;
using YamlDotNet.Core;
namespace Recyclarr.Command;
@@ -62,13 +63,17 @@ public abstract class ServiceCommand : BaseCommand, IServiceCommand
throw new CommandException(
$"HTTP error while communicating with {Name}: {e.SanitizedExceptionMessage()}");
}
+ catch (GitCmdException e)
+ {
+ await console.Output.WriteLineAsync(e.ToString());
+ }
catch (Exception e) when (e is not CommandException)
{
throw new CommandException(e.ToString());
}
}
- public override Task Process(ILifetimeScope container)
+ public override async Task Process(ILifetimeScope container)
{
var log = container.Resolve();
var settingsProvider = container.Resolve();
@@ -81,9 +86,7 @@ public abstract class ServiceCommand : BaseCommand, IServiceCommand
migration.CheckNeededMigrations();
SetupHttp(log, settingsProvider);
- repoUpdater.UpdateRepo();
-
- return Task.CompletedTask;
+ await repoUpdater.UpdateRepo();
}
private static void SetupHttp(ILogger log, ISettingsProvider settingsProvider)
diff --git a/src/Recyclarr/CompositionRoot.cs b/src/Recyclarr/CompositionRoot.cs
index 70de5324..10e2e4ff 100644
--- a/src/Recyclarr/CompositionRoot.cs
+++ b/src/Recyclarr/CompositionRoot.cs
@@ -14,13 +14,13 @@ using TrashLib.Cache;
using TrashLib.Config;
using TrashLib.Config.Services;
using TrashLib.Repo;
+using TrashLib.Repo.VersionControl;
using TrashLib.Services.Common;
using TrashLib.Services.CustomFormat;
using TrashLib.Services.Radarr;
using TrashLib.Services.Sonarr;
using TrashLib.Services.System;
using TrashLib.Startup;
-using VersionControl;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.ObjectFactories;
diff --git a/src/TrashLib.Tests/Repo/VersionControl/GitPathTest.cs b/src/TrashLib.Tests/Repo/VersionControl/GitPathTest.cs
new file mode 100644
index 00000000..b7156ba3
--- /dev/null
+++ b/src/TrashLib.Tests/Repo/VersionControl/GitPathTest.cs
@@ -0,0 +1,39 @@
+using AutoFixture.NUnit3;
+using FluentAssertions;
+using NSubstitute;
+using NUnit.Framework;
+using TestLibrary.AutoFixture;
+using TrashLib.Config.Settings;
+using TrashLib.Repo.VersionControl;
+
+namespace TrashLib.Tests.Repo.VersionControl;
+
+[TestFixture]
+[Parallelizable(ParallelScope.All)]
+public class GitPathTest
+{
+ [Test, AutoMockData]
+ public void Default_path_used_when_setting_is_null(
+ [Frozen] ISettingsProvider settings,
+ GitPath sut)
+ {
+ settings.Settings.Returns(new SettingsValues {Repository = new TrashRepository {GitPath = null}});
+
+ var result = sut.Path;
+
+ result.Should().Be(GitPath.Default);
+ }
+
+ [Test, AutoMockData]
+ public void User_specified_path_used_instead_of_default(
+ [Frozen] ISettingsProvider settings,
+ GitPath sut)
+ {
+ var expectedPath = "/usr/local/bin/git";
+ settings.Settings.Returns(new SettingsValues {Repository = new TrashRepository {GitPath = expectedPath}});
+
+ var result = sut.Path;
+
+ result.Should().Be(expectedPath);
+ }
+}
diff --git a/src/TrashLib/Config/Settings/SettingsValues.cs b/src/TrashLib/Config/Settings/SettingsValues.cs
index 7ed72403..5b394308 100644
--- a/src/TrashLib/Config/Settings/SettingsValues.cs
+++ b/src/TrashLib/Config/Settings/SettingsValues.cs
@@ -7,6 +7,7 @@ public record TrashRepository
public string CloneUrl { get; [UsedImplicitly] init; } = "https://github.com/TRaSH-/Guides.git";
public string Branch { get; [UsedImplicitly] init; } = "master";
public string? Sha1 { get; [UsedImplicitly] init; }
+ public string? GitPath { get; [UsedImplicitly] init; }
}
public record LogJanitorSettings
diff --git a/src/TrashLib/Repo/IRepoUpdater.cs b/src/TrashLib/Repo/IRepoUpdater.cs
index 4aba8784..ceeee954 100644
--- a/src/TrashLib/Repo/IRepoUpdater.cs
+++ b/src/TrashLib/Repo/IRepoUpdater.cs
@@ -5,5 +5,5 @@ namespace TrashLib.Repo;
public interface IRepoUpdater
{
IDirectoryInfo RepoPath { get; }
- void UpdateRepo();
+ Task UpdateRepo();
}
diff --git a/src/TrashLib/Repo/RepoUpdater.cs b/src/TrashLib/Repo/RepoUpdater.cs
index dd0d9b70..5a810957 100644
--- a/src/TrashLib/Repo/RepoUpdater.cs
+++ b/src/TrashLib/Repo/RepoUpdater.cs
@@ -1,10 +1,9 @@
using System.IO.Abstractions;
using Common;
-using LibGit2Sharp;
using Serilog;
using TrashLib.Config.Settings;
+using TrashLib.Repo.VersionControl;
using TrashLib.Startup;
-using VersionControl;
namespace TrashLib.Repo;
@@ -32,17 +31,17 @@ public class RepoUpdater : IRepoUpdater
public IDirectoryInfo RepoPath => _paths.RepoDirectory;
- public void UpdateRepo()
+ public async Task UpdateRepo()
{
// Retry only once if there's a failure. This gives us an opportunity to delete the git repository and start
// fresh.
- var exception = CheckoutAndUpdateRepo();
+ var exception = await CheckoutAndUpdateRepo();
if (exception is not null)
{
_log.Information("Deleting local git repo and retrying git operation...");
_fileUtils.DeleteReadOnlyDirectory(RepoPath.FullName);
- exception = CheckoutAndUpdateRepo();
+ exception = await CheckoutAndUpdateRepo();
if (exception is not null)
{
throw exception;
@@ -50,7 +49,7 @@ public class RepoUpdater : IRepoUpdater
}
}
- private Exception? CheckoutAndUpdateRepo()
+ private async Task CheckoutAndUpdateRepo()
{
var repoSettings = _settingsProvider.Settings.Repository;
var cloneUrl = repoSettings.CloneUrl;
@@ -64,12 +63,12 @@ public class RepoUpdater : IRepoUpdater
try
{
- using var repo = _repositoryFactory.CreateAndCloneIfNeeded(cloneUrl, RepoPath.FullName, branch);
- repo.ForceCheckout(branch);
- repo.Fetch();
- repo.ResetHard(repoSettings.Sha1 ?? $"origin/{branch}");
+ using var repo = await _repositoryFactory.CreateAndCloneIfNeeded(cloneUrl, RepoPath.FullName, branch);
+ await repo.ForceCheckout(branch);
+ await repo.Fetch();
+ await repo.ResetHard(repoSettings.Sha1 ?? $"origin/{branch}");
}
- catch (LibGit2SharpException e)
+ catch (GitCmdException e)
{
_log.Error(e, "An exception occurred during git operations on path: {RepoPath}", RepoPath);
return e;
diff --git a/src/TrashLib/Repo/VersionControl/GitCmdException.cs b/src/TrashLib/Repo/VersionControl/GitCmdException.cs
new file mode 100644
index 00000000..c5a485f6
--- /dev/null
+++ b/src/TrashLib/Repo/VersionControl/GitCmdException.cs
@@ -0,0 +1,17 @@
+namespace TrashLib.Repo.VersionControl;
+
+public class GitCmdException : Exception
+{
+ // ReSharper disable UnusedAutoPropertyAccessor.Global
+ public string Error { get; }
+
+ public int ExitCode { get; }
+ // ReSharper restore UnusedAutoPropertyAccessor.Global
+
+ public GitCmdException(int exitCode, string error)
+ : base("Git command failed with a non-zero exit code")
+ {
+ Error = error;
+ ExitCode = exitCode;
+ }
+}
diff --git a/src/TrashLib/Repo/VersionControl/GitPath.cs b/src/TrashLib/Repo/VersionControl/GitPath.cs
new file mode 100644
index 00000000..19d7cc43
--- /dev/null
+++ b/src/TrashLib/Repo/VersionControl/GitPath.cs
@@ -0,0 +1,16 @@
+using TrashLib.Config.Settings;
+
+namespace TrashLib.Repo.VersionControl;
+
+public class GitPath : IGitPath
+{
+ private readonly ISettingsProvider _settings;
+
+ public GitPath(ISettingsProvider settings)
+ {
+ _settings = settings;
+ }
+
+ public static string Default => "git";
+ public string Path => _settings.Settings.Repository.GitPath ?? Default;
+}
diff --git a/src/TrashLib/Repo/VersionControl/GitRepository.cs b/src/TrashLib/Repo/VersionControl/GitRepository.cs
new file mode 100644
index 00000000..61437391
--- /dev/null
+++ b/src/TrashLib/Repo/VersionControl/GitRepository.cs
@@ -0,0 +1,84 @@
+using System.IO.Abstractions;
+using System.Text;
+using CliWrap;
+using Serilog;
+using TrashLib.Startup;
+
+namespace TrashLib.Repo.VersionControl;
+
+public sealed class GitRepository : IGitRepository
+{
+ private readonly ILogger _log;
+ private readonly IAppPaths _paths;
+ private readonly IGitPath _gitPath;
+
+ public GitRepository(ILogger log, IAppPaths paths, IGitPath gitPath)
+ {
+ _log = log;
+ _paths = paths;
+ _gitPath = gitPath;
+ }
+
+ private async Task RunGitCmd(string args)
+ {
+ _log.Debug("Executing command: git {Args}", args);
+
+ var output = new StringBuilder();
+ var error = new StringBuilder();
+
+ var result = await Cli.Wrap(_gitPath.Path)
+ .WithArguments(args)
+ .WithValidation(CommandResultValidation.None)
+ .WithStandardOutputPipe(PipeTarget.ToStringBuilder(output))
+ .WithStandardErrorPipe(PipeTarget.ToStringBuilder(error))
+ .WithWorkingDirectory(_paths.RepoDirectory.FullName)
+ .ExecuteAsync();
+
+ _log.Debug("{Output}", output.ToString());
+
+ if (result.ExitCode != 0)
+ {
+ throw new GitCmdException(result.ExitCode, error.ToString());
+ }
+ }
+
+ public IDirectoryInfo Path => _paths.RepoDirectory;
+
+ public void Dispose()
+ {
+ // Nothing to do here
+ }
+
+ public async Task ForceCheckout(string branch)
+ {
+ await RunGitCmd($"checkout -f {branch}");
+ }
+
+ public async Task Fetch(string remote = "origin")
+ {
+ await RunGitCmd($"fetch {remote}");
+ }
+
+ public async Task ResetHard(string toBranchOrSha1)
+ {
+ await RunGitCmd($"reset --hard {toBranchOrSha1}");
+ }
+
+ public async Task SetRemote(string name, string newUrl)
+ {
+ await RunGitCmd($"remote set-url {name} {newUrl}");
+ }
+
+ public async Task Clone(string cloneUrl, string? branch = null)
+ {
+ var args = new StringBuilder("clone");
+ if (branch is not null)
+ {
+ args.Append($" -b {branch}");
+ }
+
+ _paths.RepoDirectory.Create();
+ args.Append($" {cloneUrl} .");
+ await RunGitCmd(args.ToString());
+ }
+}
diff --git a/src/TrashLib/Repo/VersionControl/GitRepositoryFactory.cs b/src/TrashLib/Repo/VersionControl/GitRepositoryFactory.cs
new file mode 100644
index 00000000..64a88fb5
--- /dev/null
+++ b/src/TrashLib/Repo/VersionControl/GitRepositoryFactory.cs
@@ -0,0 +1,52 @@
+using System.IO.Abstractions;
+using CliWrap;
+using Common;
+
+namespace TrashLib.Repo.VersionControl;
+
+public class GitRepositoryFactory : IGitRepositoryFactory
+{
+ private readonly IFileUtilities _fileUtils;
+ private readonly Func _repoFactory;
+ private readonly IGitPath _gitPath;
+
+ public GitRepositoryFactory(
+ IFileUtilities fileUtils,
+ Func repoFactory,
+ IGitPath gitPath)
+ {
+ _fileUtils = fileUtils;
+ _repoFactory = repoFactory;
+ _gitPath = gitPath;
+ }
+
+ private async Task IsValid(IDirectoryInfo repoPath)
+ {
+ var result = await Cli.Wrap(_gitPath.Path)
+ .WithArguments("status")
+ .WithValidation(CommandResultValidation.None)
+ .WithWorkingDirectory(repoPath.FullName)
+ .ExecuteAsync();
+
+ return result.ExitCode == 0;
+ }
+
+ public async Task CreateAndCloneIfNeeded(string repoUrl, string repoPath, string branch)
+ {
+ var repo = _repoFactory(repoPath);
+
+ if (!await IsValid(repo.Path))
+ {
+ await DeleteAndCloneRepo(repo, repoUrl, branch);
+ }
+
+ await repo.SetRemote("origin", repoUrl);
+ return repo;
+ }
+
+ private async Task DeleteAndCloneRepo(IGitRepository repo, string repoUrl, string branch)
+ {
+ _fileUtils.DeleteReadOnlyDirectory(repo.Path.FullName);
+ await repo.Clone(repoUrl, branch);
+ }
+}
diff --git a/src/TrashLib/Repo/VersionControl/IGitPath.cs b/src/TrashLib/Repo/VersionControl/IGitPath.cs
new file mode 100644
index 00000000..42c50d6b
--- /dev/null
+++ b/src/TrashLib/Repo/VersionControl/IGitPath.cs
@@ -0,0 +1,6 @@
+namespace TrashLib.Repo.VersionControl;
+
+public interface IGitPath
+{
+ string Path { get; }
+}
diff --git a/src/TrashLib/Repo/VersionControl/IGitRepository.cs b/src/TrashLib/Repo/VersionControl/IGitRepository.cs
new file mode 100644
index 00000000..bc894ab9
--- /dev/null
+++ b/src/TrashLib/Repo/VersionControl/IGitRepository.cs
@@ -0,0 +1,13 @@
+using System.IO.Abstractions;
+
+namespace TrashLib.Repo.VersionControl;
+
+public interface IGitRepository : IDisposable
+{
+ Task ForceCheckout(string branch);
+ Task Fetch(string remote = "origin");
+ Task ResetHard(string toBranchOrSha1);
+ Task SetRemote(string name, string newUrl);
+ IDirectoryInfo Path { get; }
+ Task Clone(string cloneUrl, string? branch = null);
+}
diff --git a/src/TrashLib/Repo/VersionControl/IGitRepositoryFactory.cs b/src/TrashLib/Repo/VersionControl/IGitRepositoryFactory.cs
new file mode 100644
index 00000000..fe17a38b
--- /dev/null
+++ b/src/TrashLib/Repo/VersionControl/IGitRepositoryFactory.cs
@@ -0,0 +1,6 @@
+namespace TrashLib.Repo.VersionControl;
+
+public interface IGitRepositoryFactory
+{
+ Task CreateAndCloneIfNeeded(string repoUrl, string repoPath, string branch);
+}
diff --git a/src/VersionControl/VersionControlAutofacModule.cs b/src/TrashLib/Repo/VersionControl/VersionControlAutofacModule.cs
similarity index 67%
rename from src/VersionControl/VersionControlAutofacModule.cs
rename to src/TrashLib/Repo/VersionControl/VersionControlAutofacModule.cs
index beedf248..d12e1754 100644
--- a/src/VersionControl/VersionControlAutofacModule.cs
+++ b/src/TrashLib/Repo/VersionControl/VersionControlAutofacModule.cs
@@ -1,15 +1,14 @@
using Autofac;
-using VersionControl.Wrappers;
-namespace VersionControl;
+namespace TrashLib.Repo.VersionControl;
public class VersionControlAutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType().As();
- builder.RegisterType().As();
builder.RegisterType().As();
+ builder.RegisterType().As();
base.Load(builder);
}
}
diff --git a/src/TrashLib/TrashLib.csproj b/src/TrashLib/TrashLib.csproj
index 2d3bd0c1..10ec1d06 100644
--- a/src/TrashLib/TrashLib.csproj
+++ b/src/TrashLib/TrashLib.csproj
@@ -5,6 +5,7 @@
+
@@ -19,6 +20,5 @@
-
diff --git a/src/VersionControl.Tests/GitRepositoryFactoryTest.cs b/src/VersionControl.Tests/GitRepositoryFactoryTest.cs
deleted file mode 100644
index 5791f894..00000000
--- a/src/VersionControl.Tests/GitRepositoryFactoryTest.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using AutoFixture.NUnit3;
-using Common;
-using FluentAssertions;
-using LibGit2Sharp;
-using NSubstitute;
-using NUnit.Framework;
-using TestLibrary.AutoFixture;
-using TestLibrary.NSubstitute;
-using VersionControl.Wrappers;
-
-namespace VersionControl.Tests;
-
-[TestFixture]
-[Parallelizable(ParallelScope.All)]
-public class GitRepositoryFactoryTest
-{
- [Test, AutoMockData]
- public void Delete_and_clone_when_repo_is_not_valid(
- [Frozen] IRepositoryStaticWrapper wrapper,
- [Frozen] IFileUtilities fileUtils,
- GitRepositoryFactory sut)
- {
- wrapper.IsValid(Arg.Any()).Returns(false);
-
- sut.CreateAndCloneIfNeeded("repo_url", "repo_path", "branch");
-
- Received.InOrder(() =>
- {
- wrapper.IsValid("repo_path");
- fileUtils.DeleteReadOnlyDirectory("repo_path");
- wrapper.Clone("repo_url", "repo_path",
- Verify.That(x => x.BranchName.Should().Be("branch")));
- });
- }
-
- [Test, AutoMockData]
- public void No_delete_and_clone_when_repo_is_valid(
- [Frozen] IRepositoryStaticWrapper wrapper,
- [Frozen] IFileUtilities fileUtils,
- GitRepositoryFactory sut)
- {
- wrapper.IsValid(Arg.Any()).Returns(true);
-
- sut.CreateAndCloneIfNeeded("repo_url", "repo_path", "branch");
-
- wrapper.Received().IsValid("repo_path");
- fileUtils.DidNotReceiveWithAnyArgs().DeleteReadOnlyDirectory(default!);
- wrapper.DidNotReceiveWithAnyArgs().Clone(default!, default!, default!);
- }
-
- [Test, AutoMockData]
- public void Set_remote_when_creating_repository(
- [Frozen] IGitRepository repo,
- GitRepositoryFactory sut)
- {
- sut.CreateAndCloneIfNeeded("repo_url", "repo_path", "branch");
- repo.Received().SetRemote("origin", "repo_url");
- }
-}
diff --git a/src/VersionControl.Tests/VersionControl.Tests.csproj b/src/VersionControl.Tests/VersionControl.Tests.csproj
deleted file mode 100644
index 3001b8a1..00000000
--- a/src/VersionControl.Tests/VersionControl.Tests.csproj
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- false
-
-
-
-
-
-
diff --git a/src/VersionControl/GitRepository.cs b/src/VersionControl/GitRepository.cs
deleted file mode 100644
index fd6f4c71..00000000
--- a/src/VersionControl/GitRepository.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using Common.Extensions;
-using LibGit2Sharp;
-
-namespace VersionControl;
-
-public sealed class GitRepository : IGitRepository
-{
- private readonly Lazy _repo;
-
- public GitRepository(string repoPath)
- {
- // Lazily construct the Repository object because it does too much work in its constructor
- // We want to keep our own constructor here as thin as possible for DI and testability.
- _repo = new Lazy(() => new Repository(repoPath));
- }
-
- public void Dispose()
- {
- if (_repo.IsValueCreated)
- {
- _repo.Value.Dispose();
- }
- }
-
- public void ForceCheckout(string branch)
- {
- Commands.Checkout(_repo.Value, branch, new CheckoutOptions
- {
- CheckoutModifiers = CheckoutModifiers.Force
- });
- }
-
- public void Fetch(string remote = "origin")
- {
- var origin = _repo.Value.Network.Remotes[remote];
- Commands.Fetch(_repo.Value, origin.Name, origin.FetchRefSpecs.Select(s => s.Specification), null, "");
- }
-
- public void ResetHard(string toBranchOrSha1)
- {
- var branch = _repo.Value.Branches.FirstOrDefault(b => b.FriendlyName.ContainsIgnoreCase(toBranchOrSha1));
- var commit = branch is not null ? branch.Tip : _repo.Value.Lookup(toBranchOrSha1);
- _repo.Value.Reset(ResetMode.Hard, commit);
- }
-
- public void SetRemote(string name, string newUrl)
- {
- _repo.Value.Network.Remotes.Update(name, updater => updater.Url = newUrl);
- }
-}
diff --git a/src/VersionControl/GitRepositoryFactory.cs b/src/VersionControl/GitRepositoryFactory.cs
deleted file mode 100644
index 0886c58a..00000000
--- a/src/VersionControl/GitRepositoryFactory.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using Common;
-using LibGit2Sharp;
-using VersionControl.Wrappers;
-
-namespace VersionControl;
-
-public class GitRepositoryFactory : IGitRepositoryFactory
-{
- private readonly IFileUtilities _fileUtils;
- private readonly IRepositoryStaticWrapper _staticWrapper;
- private readonly Func _repoFactory;
- private readonly Func _progressBarFactory;
-
- public GitRepositoryFactory(
- IFileUtilities fileUtils,
- IRepositoryStaticWrapper staticWrapper,
- Func repoFactory,
- Func progressBarFactory)
- {
- _fileUtils = fileUtils;
- _staticWrapper = staticWrapper;
- _repoFactory = repoFactory;
- _progressBarFactory = progressBarFactory;
- }
-
- public IGitRepository CreateAndCloneIfNeeded(string repoUrl, string repoPath, string branch)
- {
- if (!_staticWrapper.IsValid(repoPath))
- {
- DeleteAndCloneRepo(repoUrl, repoPath, branch);
- }
-
- var repo = _repoFactory(repoPath);
- repo.SetRemote("origin", repoUrl);
- return repo;
- }
-
- private void DeleteAndCloneRepo(string repoUrl, string repoPath, string branch)
- {
- _fileUtils.DeleteReadOnlyDirectory(repoPath);
-
- var progress = _progressBarFactory();
- progress.Description = "Fetching guide data\n";
-
- _staticWrapper.Clone(repoUrl, repoPath, new CloneOptions
- {
- RecurseSubmodules = false,
- BranchName = branch,
- OnTransferProgress = gitProgress =>
- {
- progress.ReportProgress.OnNext((float) gitProgress.ReceivedObjects / gitProgress.TotalObjects);
- return true;
- }
- });
- }
-}
diff --git a/src/VersionControl/IGitRepository.cs b/src/VersionControl/IGitRepository.cs
deleted file mode 100644
index 9c9c7e3a..00000000
--- a/src/VersionControl/IGitRepository.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace VersionControl;
-
-public interface IGitRepository : IDisposable
-{
- void ForceCheckout(string branch);
- void Fetch(string remote = "origin");
- void ResetHard(string toBranchOrSha1);
- void SetRemote(string name, string newUrl);
-}
diff --git a/src/VersionControl/IGitRepositoryFactory.cs b/src/VersionControl/IGitRepositoryFactory.cs
deleted file mode 100644
index 028454d3..00000000
--- a/src/VersionControl/IGitRepositoryFactory.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace VersionControl;
-
-public interface IGitRepositoryFactory
-{
- IGitRepository CreateAndCloneIfNeeded(string repoUrl, string repoPath, string branch);
-}
diff --git a/src/VersionControl/VersionControl.csproj b/src/VersionControl/VersionControl.csproj
deleted file mode 100644
index 5e937997..00000000
--- a/src/VersionControl/VersionControl.csproj
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/src/VersionControl/Wrappers/IRepositoryStaticWrapper.cs b/src/VersionControl/Wrappers/IRepositoryStaticWrapper.cs
deleted file mode 100644
index 31faa559..00000000
--- a/src/VersionControl/Wrappers/IRepositoryStaticWrapper.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using LibGit2Sharp;
-
-namespace VersionControl.Wrappers;
-
-public interface IRepositoryStaticWrapper
-{
- string Clone(string sourceUrl, string workdirPath, CloneOptions options);
- bool IsValid(string path);
-}
diff --git a/src/VersionControl/Wrappers/LibGit2SharpRepositoryStaticWrapper.cs b/src/VersionControl/Wrappers/LibGit2SharpRepositoryStaticWrapper.cs
deleted file mode 100644
index b523ad9b..00000000
--- a/src/VersionControl/Wrappers/LibGit2SharpRepositoryStaticWrapper.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using LibGit2Sharp;
-
-namespace VersionControl.Wrappers;
-
-public class LibGit2SharpRepositoryStaticWrapper : IRepositoryStaticWrapper
-{
- public string Clone(string sourceUrl, string workdirPath, CloneOptions options)
- => Repository.Clone(sourceUrl, workdirPath, options);
-
- public bool IsValid(string path)
- => Repository.IsValid(path);
-}