fix: Clone/update config repo in config create command

pull/201/head
Robert Dailey 11 months ago
parent 01baaa2be5
commit 58927728f8

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

@ -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<MigrationAutofacModule>();
builder.RegisterModule<TrashLibAutofacModule>();
builder.RegisterModule(new TrashLibAutofacModule {AdditionalMapperProfileAssembly = thisAssembly});
builder.RegisterModule<ServiceProcessorsAutofacModule>();
builder.RegisterModule<CacheAutofacModule>();
@ -49,10 +47,6 @@ public static class CompositionRoot
builder.RegisterAssemblyTypes(thisAssembly)
.AsClosedTypesOf(typeof(IValidator<>))
.As<IValidator>();
builder.RegisterAutoMapper(c => c.AddCollectionMappers(), false,
thisAssembly,
typeof(TrashLibAutofacModule).Assembly);
}
private static void PipelineRegistrations(ContainerBuilder builder)

@ -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<ConfigCategory, IConfigLister> _configListers;
private readonly IConfigTemplatesRepo _repo;
public ConfigListProcessor(
ILogger log,
IIndex<ConfigCategory, IConfigLister> configListers,
IConfigTemplatesRepo repo)
public ConfigListProcessor(ILogger log, IIndex<ConfigCategory, IConfigLister> 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))
{

@ -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;
}
}

@ -8,8 +8,6 @@
<PackageReference Include="Autofac" />
<PackageReference Include="Autofac.Extras.AggregateService" />
<PackageReference Include="Autofac.Extras.Ordering" />
<PackageReference Include="AutoMapper.Collection" />
<PackageReference Include="AutoMapper.Contrib.Autofac.DependencyInjection" />
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="Serilog" />
<PackageReference Include="Serilog.Expressions" />

@ -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<IValidator>();
builder.RegisterAssemblyTypes(thisAssembly)
builder.RegisterAssemblyTypes(ThisAssembly)
.AssignableTo<IYamlBehavior>()
.As<IYamlBehavior>();

@ -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<Markup> RenderTemplates(

@ -31,8 +31,10 @@ public class ConfigTemplateGuideService : IConfigTemplateGuideService
_repo = repo;
}
public IReadOnlyCollection<TemplatePath> LoadTemplateData()
public async Task<IReadOnlyCollection<TemplatePath>> LoadTemplateData()
{
await _repo.Update();
var templatesPath = _repo.Path.File("templates.json");
if (!templatesPath.Exists)
{

@ -2,5 +2,5 @@ namespace Recyclarr.TrashLib.Config.Services;
public interface IConfigTemplateGuideService
{
IReadOnlyCollection<TemplatePath> LoadTemplateData();
Task<IReadOnlyCollection<TemplatePath>> LoadTemplateData();
}

@ -4,6 +4,8 @@
<PackageReference Include="Autofac.Extras.AggregateService" />
<PackageReference Include="Autofac.Extras.Ordering" />
<PackageReference Include="AutoMapper" />
<PackageReference Include="AutoMapper.Collection" />
<PackageReference Include="AutoMapper.Contrib.Autofac.DependencyInjection" />
<PackageReference Include="CliWrap" />
<PackageReference Include="FluentValidation" />
<PackageReference Include="Flurl" />

@ -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<ConfigAutofacModule>();
builder.RegisterType<ServiceRequestBuilder>().As<IServiceRequestBuilder>();
builder.RegisterType<FlurlClientFactory>().As<IFlurlClientFactory>().SingleInstance();
var mapperAssemblies = new List<Assembly> {ThisAssembly};
if (AdditionalMapperProfileAssembly is not null)
{
mapperAssemblies.Add(AdditionalMapperProfileAssembly);
}
builder.RegisterAutoMapper(c => c.AddCollectionMappers(), false, mapperAssemblies.ToArray());
}
private static void CommonRegistrations(ContainerBuilder builder)

@ -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);
}
}

@ -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<IConfigTemplatesRepo>(x =>
{
x.Path.Returns(_ => Fs.CurrentDirectory());
});
}
[Test]
public async Task Repo_update_is_called_on_config_list()
{
var repo = Resolve<IConfigTemplatesRepo>();
// 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<ConfigListCommand>();
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<IConfigTemplatesRepo>();
// 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<ConfigCreateCommand>();
await sut.ExecuteAsync(default!, new ConfigCreateCommand.CliSettings
{
TemplatesOption = new[] {"some-template"}
});
await repo.Received().Update();
}
}

@ -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<TemplateConfigCreator>();
sut.Create(settings);
await sut.Create(settings);
Fs.AllFiles.Should().Contain(new[]
{

@ -4,8 +4,4 @@
<ProjectReference Include="..\Recyclarr.TestLibrary\Recyclarr.TestLibrary.csproj" />
<ProjectReference Include="..\..\Recyclarr.TrashLib\Recyclarr.TrashLib.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoMapper.Collection" />
<PackageReference Include="AutoMapper.Contrib.Autofac.DependencyInjection" />
</ItemGroup>
</Project>

@ -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()

@ -17,11 +17,11 @@ public class ConfigTemplateGuideServiceTest : TrashLibIntegrationFixture
{
var act = () => _ = sut.LoadTemplateData();
act.Should().Throw<InvalidDataException>().WithMessage("Recyclarr*templates*");
act.Should().ThrowAsync<InvalidDataException>().WithMessage("Recyclarr*templates*");
}
[Test]
public void Normal_behavior()
public async Task Normal_behavior()
{
var repo = Resolve<IConfigTemplatesRepo>();
var templateDir = repo.Path;
@ -43,7 +43,7 @@ public class ConfigTemplateGuideServiceTest : TrashLibIntegrationFixture
var sut = Resolve<ConfigTemplateGuideService>();
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));

Loading…
Cancel
Save