From 58927728f83c0e595e779c5a02757f0b65d86274 Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Tue, 27 Jun 2023 12:23:02 -0500 Subject: [PATCH] fix: Clone/update config repo in config create command --- CHANGELOG.md | 4 ++ src/Recyclarr.Cli/CompositionRoot.cs | 8 +-- .../Processors/Config/ConfigListProcessor.cs | 13 +--- .../Config/TemplateConfigCreator.cs | 6 +- src/Recyclarr.Cli/Recyclarr.Cli.csproj | 2 - .../Config/ConfigAutofacModule.cs | 6 +- .../Config/Listers/ConfigTemplateLister.cs | 5 +- .../Services/ConfigTemplateGuideService.cs | 4 +- .../Services/IConfigTemplateGuideService.cs | 2 +- .../Recyclarr.TrashLib.csproj | 2 + .../TrashLibAutofacModule.cs | 14 +++++ .../CliIntegrationFixture.cs | 2 + .../Commands/ConfigCommandsIntegrationTest.cs | 60 +++++++++++++++++++ .../Config/TemplateConfigCreatorTest.cs | 4 +- .../Recyclarr.TrashLib.TestLibrary.csproj | 4 -- .../TrashLibIntegrationFixture.cs | 3 - .../ConfigTemplateGuideServiceTest.cs | 6 +- 17 files changed, 99 insertions(+), 46 deletions(-) create mode 100644 src/tests/Recyclarr.Cli.Tests/Console/Commands/ConfigCommandsIntegrationTest.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 5018d586..f9ae0c66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Clone config template repo when `config create -t` is used. + ## [5.1.0] - 2023-06-26 ### Added diff --git a/src/Recyclarr.Cli/CompositionRoot.cs b/src/Recyclarr.Cli/CompositionRoot.cs index 46d5294c..3d06d525 100644 --- a/src/Recyclarr.Cli/CompositionRoot.cs +++ b/src/Recyclarr.Cli/CompositionRoot.cs @@ -2,8 +2,6 @@ using System.IO.Abstractions; using System.Reflection; using Autofac; using Autofac.Extras.Ordering; -using AutoMapper.Contrib.Autofac.DependencyInjection; -using AutoMapper.EquivalencyExpression; using FluentValidation; using Recyclarr.Cli.Cache; using Recyclarr.Cli.Console.Helpers; @@ -35,7 +33,7 @@ public static class CompositionRoot RegisterLogger(builder); builder.RegisterModule(); - builder.RegisterModule(); + builder.RegisterModule(new TrashLibAutofacModule {AdditionalMapperProfileAssembly = thisAssembly}); builder.RegisterModule(); builder.RegisterModule(); @@ -49,10 +47,6 @@ public static class CompositionRoot builder.RegisterAssemblyTypes(thisAssembly) .AsClosedTypesOf(typeof(IValidator<>)) .As(); - - builder.RegisterAutoMapper(c => c.AddCollectionMappers(), false, - thisAssembly, - typeof(TrashLibAutofacModule).Assembly); } private static void PipelineRegistrations(ContainerBuilder builder) diff --git a/src/Recyclarr.Cli/Processors/Config/ConfigListProcessor.cs b/src/Recyclarr.Cli/Processors/Config/ConfigListProcessor.cs index ac403ad9..56791e47 100644 --- a/src/Recyclarr.Cli/Processors/Config/ConfigListProcessor.cs +++ b/src/Recyclarr.Cli/Processors/Config/ConfigListProcessor.cs @@ -1,6 +1,5 @@ using Autofac.Features.Indexed; using Recyclarr.TrashLib.Config.Listers; -using Recyclarr.TrashLib.Repo; namespace Recyclarr.Cli.Processors.Config; @@ -8,25 +7,15 @@ public class ConfigListProcessor { private readonly ILogger _log; private readonly IIndex _configListers; - private readonly IConfigTemplatesRepo _repo; - public ConfigListProcessor( - ILogger log, - IIndex configListers, - IConfigTemplatesRepo repo) + public ConfigListProcessor(ILogger log, IIndex configListers) { _log = log; _configListers = configListers; - _repo = repo; } public async Task Process(ConfigCategory listCategory) { - if (listCategory == ConfigCategory.Templates) - { - await _repo.Update(); - } - _log.Debug("Listing configuration for category {Category}", listCategory); if (!_configListers.TryGetValue(listCategory, out var lister)) { diff --git a/src/Recyclarr.Cli/Processors/Config/TemplateConfigCreator.cs b/src/Recyclarr.Cli/Processors/Config/TemplateConfigCreator.cs index 421e4db8..e342384d 100644 --- a/src/Recyclarr.Cli/Processors/Config/TemplateConfigCreator.cs +++ b/src/Recyclarr.Cli/Processors/Config/TemplateConfigCreator.cs @@ -35,11 +35,11 @@ public class TemplateConfigCreator : IConfigCreator } [SuppressMessage("Design", "CA1031:Do not catch general exception types")] - public Task Create(ICreateConfigSettings settings) + public async Task Create(ICreateConfigSettings settings) { _log.Debug("Creating config from templates: {Templates}", settings.Templates); - var matchingTemplateData = _templates.LoadTemplateData() + var matchingTemplateData = (await _templates.LoadTemplateData()) .IntersectBy(settings.Templates, path => path.Id, StringComparer.CurrentCultureIgnoreCase) .Select(x => x.TemplateFile); @@ -94,7 +94,5 @@ public class TemplateConfigCreator : IConfigCreator _log.Error(e, "Unable to save configuration template file"); } } - - return Task.CompletedTask; } } diff --git a/src/Recyclarr.Cli/Recyclarr.Cli.csproj b/src/Recyclarr.Cli/Recyclarr.Cli.csproj index 43d28082..f20fcd33 100644 --- a/src/Recyclarr.Cli/Recyclarr.Cli.csproj +++ b/src/Recyclarr.Cli/Recyclarr.Cli.csproj @@ -8,8 +8,6 @@ - - diff --git a/src/Recyclarr.TrashLib/Config/ConfigAutofacModule.cs b/src/Recyclarr.TrashLib/Config/ConfigAutofacModule.cs index 37780591..9319c492 100644 --- a/src/Recyclarr.TrashLib/Config/ConfigAutofacModule.cs +++ b/src/Recyclarr.TrashLib/Config/ConfigAutofacModule.cs @@ -15,13 +15,11 @@ public class ConfigAutofacModule : Module { protected override void Load(ContainerBuilder builder) { - var thisAssembly = typeof(ConfigAutofacModule).Assembly; - - builder.RegisterAssemblyTypes(thisAssembly) + builder.RegisterAssemblyTypes(ThisAssembly) .AsClosedTypesOf(typeof(IValidator<>)) .As(); - builder.RegisterAssemblyTypes(thisAssembly) + builder.RegisterAssemblyTypes(ThisAssembly) .AssignableTo() .As(); diff --git a/src/Recyclarr.TrashLib/Config/Listers/ConfigTemplateLister.cs b/src/Recyclarr.TrashLib/Config/Listers/ConfigTemplateLister.cs index 1227b416..f1f1ba12 100644 --- a/src/Recyclarr.TrashLib/Config/Listers/ConfigTemplateLister.cs +++ b/src/Recyclarr.TrashLib/Config/Listers/ConfigTemplateLister.cs @@ -16,9 +16,9 @@ public class ConfigTemplateLister : IConfigLister _guideService = guideService; } - public Task List() + public async Task List() { - var data = _guideService.LoadTemplateData(); + var data = await _guideService.LoadTemplateData(); var table = new Table(); var empty = new Markup(""); @@ -34,7 +34,6 @@ public class ConfigTemplateLister : IConfigLister } _console.Write(table); - return Task.CompletedTask; } private static IEnumerable RenderTemplates( diff --git a/src/Recyclarr.TrashLib/Config/Services/ConfigTemplateGuideService.cs b/src/Recyclarr.TrashLib/Config/Services/ConfigTemplateGuideService.cs index 19f4eec2..782925c0 100644 --- a/src/Recyclarr.TrashLib/Config/Services/ConfigTemplateGuideService.cs +++ b/src/Recyclarr.TrashLib/Config/Services/ConfigTemplateGuideService.cs @@ -31,8 +31,10 @@ public class ConfigTemplateGuideService : IConfigTemplateGuideService _repo = repo; } - public IReadOnlyCollection LoadTemplateData() + public async Task> LoadTemplateData() { + await _repo.Update(); + var templatesPath = _repo.Path.File("templates.json"); if (!templatesPath.Exists) { diff --git a/src/Recyclarr.TrashLib/Config/Services/IConfigTemplateGuideService.cs b/src/Recyclarr.TrashLib/Config/Services/IConfigTemplateGuideService.cs index 3c8d232e..40ca0a00 100644 --- a/src/Recyclarr.TrashLib/Config/Services/IConfigTemplateGuideService.cs +++ b/src/Recyclarr.TrashLib/Config/Services/IConfigTemplateGuideService.cs @@ -2,5 +2,5 @@ namespace Recyclarr.TrashLib.Config.Services; public interface IConfigTemplateGuideService { - IReadOnlyCollection LoadTemplateData(); + Task> LoadTemplateData(); } diff --git a/src/Recyclarr.TrashLib/Recyclarr.TrashLib.csproj b/src/Recyclarr.TrashLib/Recyclarr.TrashLib.csproj index 4d20eac7..0832554c 100644 --- a/src/Recyclarr.TrashLib/Recyclarr.TrashLib.csproj +++ b/src/Recyclarr.TrashLib/Recyclarr.TrashLib.csproj @@ -4,6 +4,8 @@ + + diff --git a/src/Recyclarr.TrashLib/TrashLibAutofacModule.cs b/src/Recyclarr.TrashLib/TrashLibAutofacModule.cs index a6afa266..371a6f79 100644 --- a/src/Recyclarr.TrashLib/TrashLibAutofacModule.cs +++ b/src/Recyclarr.TrashLib/TrashLibAutofacModule.cs @@ -1,5 +1,8 @@ +using System.Reflection; using Autofac; using Autofac.Extras.Ordering; +using AutoMapper.Contrib.Autofac.DependencyInjection; +using AutoMapper.EquivalencyExpression; using Recyclarr.Common; using Recyclarr.Common.FluentValidation; using Recyclarr.TrashLib.ApiServices; @@ -9,11 +12,14 @@ using Recyclarr.TrashLib.Http; using Recyclarr.TrashLib.Repo; using Recyclarr.TrashLib.Repo.VersionControl; using Recyclarr.TrashLib.Startup; +using Module = Autofac.Module; namespace Recyclarr.TrashLib; public class TrashLibAutofacModule : Module { + public Assembly? AdditionalMapperProfileAssembly { get; init; } + protected override void Load(ContainerBuilder builder) { base.Load(builder); @@ -31,6 +37,14 @@ public class TrashLibAutofacModule : Module builder.RegisterModule(); builder.RegisterType().As(); builder.RegisterType().As().SingleInstance(); + + var mapperAssemblies = new List {ThisAssembly}; + if (AdditionalMapperProfileAssembly is not null) + { + mapperAssemblies.Add(AdditionalMapperProfileAssembly); + } + + builder.RegisterAutoMapper(c => c.AddCollectionMappers(), false, mapperAssemblies.ToArray()); } private static void CommonRegistrations(ContainerBuilder builder) diff --git a/src/tests/Recyclarr.Cli.TestLibrary/CliIntegrationFixture.cs b/src/tests/Recyclarr.Cli.TestLibrary/CliIntegrationFixture.cs index f0b5b81a..9b51b62b 100644 --- a/src/tests/Recyclarr.Cli.TestLibrary/CliIntegrationFixture.cs +++ b/src/tests/Recyclarr.Cli.TestLibrary/CliIntegrationFixture.cs @@ -8,6 +8,8 @@ public abstract class CliIntegrationFixture : TrashLibIntegrationFixture { protected override void RegisterTypes(ContainerBuilder builder) { + // Do NOT invoke the base method here! + // We are deliberately REPLACING those registrations (the composition root here is a SUPERSET). CompositionRoot.Setup(builder); } } diff --git a/src/tests/Recyclarr.Cli.Tests/Console/Commands/ConfigCommandsIntegrationTest.cs b/src/tests/Recyclarr.Cli.Tests/Console/Commands/ConfigCommandsIntegrationTest.cs new file mode 100644 index 00000000..3b30515b --- /dev/null +++ b/src/tests/Recyclarr.Cli.Tests/Console/Commands/ConfigCommandsIntegrationTest.cs @@ -0,0 +1,60 @@ +using System.IO.Abstractions; +using System.IO.Abstractions.Extensions; +using Autofac; +using Recyclarr.Cli.Console.Commands; +using Recyclarr.Cli.TestLibrary; +using Recyclarr.TestLibrary.Autofac; +using Recyclarr.TrashLib.Config.Listers; +using Recyclarr.TrashLib.Repo; + +namespace Recyclarr.Cli.Tests.Console.Commands; + +[TestFixture] +[Parallelizable(ParallelScope.All)] +public class ConfigCommandsIntegrationTest : CliIntegrationFixture +{ + protected override void RegisterTypes(ContainerBuilder builder) + { + base.RegisterTypes(builder); + builder.RegisterMockFor(x => + { + x.Path.Returns(_ => Fs.CurrentDirectory()); + }); + } + + [Test] + public async Task Repo_update_is_called_on_config_list() + { + var repo = Resolve(); + + // Create this to make ConfigTemplateGuideService happy. It tries to parse this file, but + // it won't exist because we don't operate with real Git objects (so a clone never happens). + Fs.AddFile(repo.Path.File("templates.json"), new MockFileData("{}")); + + var sut = Resolve(); + await sut.ExecuteAsync(default!, new ConfigListCommand.CliSettings + { + ListCategory = ConfigCategory.Templates + }); + + await repo.Received().Update(); + } + + [Test] + public async Task Repo_update_is_called_on_config_create() + { + var repo = Resolve(); + + // Create this to make ConfigTemplateGuideService happy. It tries to parse this file, but + // it won't exist because we don't operate with real Git objects (so a clone never happens). + Fs.AddFile(repo.Path.File("templates.json"), new MockFileData("{}")); + + var sut = Resolve(); + await sut.ExecuteAsync(default!, new ConfigCreateCommand.CliSettings + { + TemplatesOption = new[] {"some-template"} + }); + + await repo.Received().Update(); + } +} diff --git a/src/tests/Recyclarr.Cli.Tests/Processors/Config/TemplateConfigCreatorTest.cs b/src/tests/Recyclarr.Cli.Tests/Processors/Config/TemplateConfigCreatorTest.cs index 47ae9c02..ab5fbc0a 100644 --- a/src/tests/Recyclarr.Cli.Tests/Processors/Config/TemplateConfigCreatorTest.cs +++ b/src/tests/Recyclarr.Cli.Tests/Processors/Config/TemplateConfigCreatorTest.cs @@ -91,7 +91,7 @@ public class TemplateConfigCreatorTest : CliIntegrationFixture } [Test] - public void Template_id_matching_works() + public async Task Template_id_matching_works() { const string templatesJson = @" { @@ -131,7 +131,7 @@ public class TemplateConfigCreatorTest : CliIntegrationFixture }); var sut = Resolve(); - sut.Create(settings); + await sut.Create(settings); Fs.AllFiles.Should().Contain(new[] { diff --git a/src/tests/Recyclarr.TrashLib.TestLibrary/Recyclarr.TrashLib.TestLibrary.csproj b/src/tests/Recyclarr.TrashLib.TestLibrary/Recyclarr.TrashLib.TestLibrary.csproj index 51b85e2e..eed24abe 100644 --- a/src/tests/Recyclarr.TrashLib.TestLibrary/Recyclarr.TrashLib.TestLibrary.csproj +++ b/src/tests/Recyclarr.TrashLib.TestLibrary/Recyclarr.TrashLib.TestLibrary.csproj @@ -4,8 +4,4 @@ - - - - diff --git a/src/tests/Recyclarr.TrashLib.TestLibrary/TrashLibIntegrationFixture.cs b/src/tests/Recyclarr.TrashLib.TestLibrary/TrashLibIntegrationFixture.cs index 31414212..352929ac 100644 --- a/src/tests/Recyclarr.TrashLib.TestLibrary/TrashLibIntegrationFixture.cs +++ b/src/tests/Recyclarr.TrashLib.TestLibrary/TrashLibIntegrationFixture.cs @@ -2,8 +2,6 @@ using System.IO.Abstractions; using System.IO.Abstractions.Extensions; using Autofac; using Autofac.Features.ResolveAnything; -using AutoMapper.Contrib.Autofac.DependencyInjection; -using AutoMapper.EquivalencyExpression; using Recyclarr.Common; using Recyclarr.TestLibrary.Autofac; using Recyclarr.TrashLib.ApiServices.System; @@ -62,7 +60,6 @@ public abstract class TrashLibIntegrationFixture : IDisposable // Normally, the CLI's composition root registers this (because we can only do it once, and it must include // dependent assemblies). The TrashLib assembly does have its own mapping profiles. We register those here, but // not in the TrashLibAutofacModule. - builder.RegisterAutoMapper(c => c.AddCollectionMappers(), false, typeof(TrashLibAutofacModule).Assembly); } private static ILogger CreateLogger() diff --git a/src/tests/Recyclarr.TrashLib.Tests/Config/Services/ConfigTemplateGuideServiceTest.cs b/src/tests/Recyclarr.TrashLib.Tests/Config/Services/ConfigTemplateGuideServiceTest.cs index dfd1422e..03cd2390 100644 --- a/src/tests/Recyclarr.TrashLib.Tests/Config/Services/ConfigTemplateGuideServiceTest.cs +++ b/src/tests/Recyclarr.TrashLib.Tests/Config/Services/ConfigTemplateGuideServiceTest.cs @@ -17,11 +17,11 @@ public class ConfigTemplateGuideServiceTest : TrashLibIntegrationFixture { var act = () => _ = sut.LoadTemplateData(); - act.Should().Throw().WithMessage("Recyclarr*templates*"); + act.Should().ThrowAsync().WithMessage("Recyclarr*templates*"); } [Test] - public void Normal_behavior() + public async Task Normal_behavior() { var repo = Resolve(); var templateDir = repo.Path; @@ -43,7 +43,7 @@ public class ConfigTemplateGuideServiceTest : TrashLibIntegrationFixture var sut = Resolve(); - var data = sut.LoadTemplateData(); + var data = await sut.LoadTemplateData(); data.Should().BeEquivalentTo(expectedPaths, o => o.Excluding(x => x.TemplateFile)); data.Select(x => x.TemplateFile.FullName) .Should().BeEquivalentTo(expectedPaths.Select(x => x.TemplateFile.FullName));