fix: Refactor and re-introduce capability enforcement

Fixes #189
pull/201/head
Robert Dailey 11 months ago
parent f020459023
commit 406e0590a4

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- When using `sync`, continue processing other instances when there's a failure. - When using `sync`, continue processing other instances when there's a failure.
- Regression: Perform Sonarr compatibility checks again (#189).
## [5.0.2] - 2023-06-24 ## [5.0.2] - 2023-06-24

@ -12,16 +12,16 @@ namespace Recyclarr.Cli.Pipelines.ReleaseProfile.Api;
public class SonarrReleaseProfileCompatibilityHandler : ISonarrReleaseProfileCompatibilityHandler public class SonarrReleaseProfileCompatibilityHandler : ISonarrReleaseProfileCompatibilityHandler
{ {
private readonly ILogger _log; private readonly ILogger _log;
private readonly ISonarrCapabilityChecker _capabilityChecker; private readonly ISonarrCapabilityFetcher _capabilityFetcher;
private readonly IMapper _mapper; private readonly IMapper _mapper;
public SonarrReleaseProfileCompatibilityHandler( public SonarrReleaseProfileCompatibilityHandler(
ILogger log, ILogger log,
ISonarrCapabilityChecker capabilityChecker, ISonarrCapabilityFetcher capabilityFetcher,
IMapper mapper) IMapper mapper)
{ {
_log = log; _log = log;
_capabilityChecker = capabilityChecker; _capabilityFetcher = capabilityFetcher;
_mapper = mapper; _mapper = mapper;
} }
@ -29,7 +29,7 @@ public class SonarrReleaseProfileCompatibilityHandler : ISonarrReleaseProfileCom
IServiceConfiguration config, IServiceConfiguration config,
SonarrReleaseProfile profile) SonarrReleaseProfile profile)
{ {
var capabilities = await _capabilityChecker.GetCapabilities(config); var capabilities = await _capabilityFetcher.GetCapabilities(config);
if (capabilities is null) if (capabilities is null)
{ {
throw new ServiceIncompatibilityException("Capabilities could not be obtained"); throw new ServiceIncompatibilityException("Capabilities could not be obtained");

@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Flurl.Http; using Flurl.Http;
using Recyclarr.Cli.Console.Settings; using Recyclarr.Cli.Console.Settings;
using Recyclarr.TrashLib.Compatibility;
using Recyclarr.TrashLib.Config; using Recyclarr.TrashLib.Config;
using Recyclarr.TrashLib.Config.Parsing; using Recyclarr.TrashLib.Config.Parsing;
using Recyclarr.TrashLib.Config.Services; using Recyclarr.TrashLib.Config.Services;
@ -18,19 +19,22 @@ public class SyncProcessor : ISyncProcessor
private readonly IConfigurationFinder _configFinder; private readonly IConfigurationFinder _configFinder;
private readonly IConfigurationLoader _configLoader; private readonly IConfigurationLoader _configLoader;
private readonly SyncPipelineExecutor _pipelines; private readonly SyncPipelineExecutor _pipelines;
private readonly ServiceAgnosticCapabilityEnforcer _capabilityEnforcer;
public SyncProcessor( public SyncProcessor(
IAnsiConsole console, IAnsiConsole console,
ILogger log, ILogger log,
IConfigurationFinder configFinder, IConfigurationFinder configFinder,
IConfigurationLoader configLoader, IConfigurationLoader configLoader,
SyncPipelineExecutor pipelines) SyncPipelineExecutor pipelines,
ServiceAgnosticCapabilityEnforcer capabilityEnforcer)
{ {
_console = console; _console = console;
_log = log; _log = log;
_configFinder = configFinder; _configFinder = configFinder;
_configLoader = configLoader; _configLoader = configLoader;
_pipelines = pipelines; _pipelines = pipelines;
_capabilityEnforcer = capabilityEnforcer;
} }
public async Task<ExitStatus> ProcessConfigs(ISyncSettings settings) public async Task<ExitStatus> ProcessConfigs(ISyncSettings settings)
@ -74,6 +78,7 @@ public class SyncProcessor : ISyncProcessor
try try
{ {
PrintProcessingHeader(config.ServiceType, config); PrintProcessingHeader(config.ServiceType, config);
await _capabilityEnforcer.Check(config);
await _pipelines.Process(settings, config); await _pipelines.Process(settings, config);
} }
catch (Exception e) catch (Exception e)

@ -10,12 +10,14 @@ public class CompatibilityAutofacModule : Module
{ {
base.Load(builder); base.Load(builder);
builder.RegisterType<ServiceAgnosticCapabilityEnforcer>();
// Sonarr // Sonarr
builder.RegisterType<SonarrCapabilityFetcher>().As<ISonarrCapabilityFetcher>();
builder.RegisterType<SonarrCapabilityEnforcer>(); builder.RegisterType<SonarrCapabilityEnforcer>();
builder.RegisterType<SonarrCapabilityChecker>().As<ISonarrCapabilityChecker>()
.InstancePerLifetimeScope();
// Radarr // Radarr
builder.RegisterType<RadarrCapabilityChecker>().InstancePerLifetimeScope(); builder.RegisterType<RadarrCapabilityFetcher>().As<IRadarrCapabilityFetcher>();
builder.RegisterType<RadarrCapabilityEnforcer>();
} }
} }

@ -0,0 +1,8 @@
using Recyclarr.TrashLib.Config.Services;
namespace Recyclarr.TrashLib.Compatibility.Radarr;
public interface IRadarrCapabilityFetcher
{
Task<RadarrCapabilities?> GetCapabilities(IServiceConfiguration config);
}

@ -0,0 +1,25 @@
using Recyclarr.TrashLib.Config.Services;
using Recyclarr.TrashLib.ExceptionTypes;
namespace Recyclarr.TrashLib.Compatibility.Radarr;
public class RadarrCapabilityEnforcer
{
private readonly IRadarrCapabilityFetcher _capabilityFetcher;
public RadarrCapabilityEnforcer(IRadarrCapabilityFetcher capabilityFetcher)
{
_capabilityFetcher = capabilityFetcher;
}
public async Task Check(RadarrConfiguration config)
{
var capabilities = await _capabilityFetcher.GetCapabilities(config);
if (capabilities is null)
{
throw new ServiceIncompatibilityException("Capabilities could not be obtained");
}
// For the future: Add more capability checks here as needed
}
}

@ -2,9 +2,9 @@ using Recyclarr.TrashLib.ApiServices.System;
namespace Recyclarr.TrashLib.Compatibility.Radarr; namespace Recyclarr.TrashLib.Compatibility.Radarr;
public class RadarrCapabilityChecker : ServiceCapabilityChecker<RadarrCapabilities> public class RadarrCapabilityFetcher : ServiceCapabilityFetcher<RadarrCapabilities>, IRadarrCapabilityFetcher
{ {
public RadarrCapabilityChecker(IServiceInformation info) public RadarrCapabilityFetcher(IServiceInformation info)
: base(info) : base(info)
{ {
} }

@ -0,0 +1,33 @@
using Recyclarr.TrashLib.Compatibility.Radarr;
using Recyclarr.TrashLib.Compatibility.Sonarr;
using Recyclarr.TrashLib.Config.Services;
namespace Recyclarr.TrashLib.Compatibility;
public class ServiceAgnosticCapabilityEnforcer
{
private readonly SonarrCapabilityEnforcer _sonarrEnforcer;
private readonly RadarrCapabilityEnforcer _radarrEnforcer;
public ServiceAgnosticCapabilityEnforcer(
SonarrCapabilityEnforcer sonarrEnforcer,
RadarrCapabilityEnforcer radarrEnforcer)
{
_sonarrEnforcer = sonarrEnforcer;
_radarrEnforcer = radarrEnforcer;
}
public async Task Check(IServiceConfiguration config)
{
switch (config)
{
case SonarrConfiguration c:
await _sonarrEnforcer.Check(c);
break;
case RadarrConfiguration c:
await _radarrEnforcer.Check(c);
break;
}
}
}

@ -3,11 +3,11 @@ using Recyclarr.TrashLib.Config.Services;
namespace Recyclarr.TrashLib.Compatibility; namespace Recyclarr.TrashLib.Compatibility;
public abstract class ServiceCapabilityChecker<T> where T : class public abstract class ServiceCapabilityFetcher<T> where T : class
{ {
private readonly IServiceInformation _info; private readonly IServiceInformation _info;
protected ServiceCapabilityChecker(IServiceInformation info) protected ServiceCapabilityFetcher(IServiceInformation info)
{ {
_info = info; _info = info;
} }

@ -2,7 +2,7 @@ using Recyclarr.TrashLib.Config.Services;
namespace Recyclarr.TrashLib.Compatibility.Sonarr; namespace Recyclarr.TrashLib.Compatibility.Sonarr;
public interface ISonarrCapabilityChecker public interface ISonarrCapabilityFetcher
{ {
Task<SonarrCapabilities?> GetCapabilities(IServiceConfiguration config); Task<SonarrCapabilities?> GetCapabilities(IServiceConfiguration config);
} }

@ -1,8 +1,10 @@
namespace Recyclarr.TrashLib.Compatibility.Sonarr; namespace Recyclarr.TrashLib.Compatibility.Sonarr;
public record SonarrCapabilities(Version Version) public record SonarrCapabilities
{ {
public static Version MinimumVersion => new("3.0.4.1098"); public static Version MinimumVersion { get; } = new("3.0.4.1098");
public Version Version { get; init; } = new();
public bool SupportsNamedReleaseProfiles { get; init; } public bool SupportsNamedReleaseProfiles { get; init; }

@ -6,16 +6,16 @@ namespace Recyclarr.TrashLib.Compatibility.Sonarr;
public class SonarrCapabilityEnforcer public class SonarrCapabilityEnforcer
{ {
private readonly ISonarrCapabilityChecker _capabilityChecker; private readonly ISonarrCapabilityFetcher _capabilityFetcher;
public SonarrCapabilityEnforcer(ISonarrCapabilityChecker capabilityChecker) public SonarrCapabilityEnforcer(ISonarrCapabilityFetcher capabilityFetcher)
{ {
_capabilityChecker = capabilityChecker; _capabilityFetcher = capabilityFetcher;
} }
public async Task Check(SonarrConfiguration config) public async Task Check(SonarrConfiguration config)
{ {
var capabilities = await _capabilityChecker.GetCapabilities(config); var capabilities = await _capabilityFetcher.GetCapabilities(config);
if (capabilities is null) if (capabilities is null)
{ {
throw new ServiceIncompatibilityException("Capabilities could not be obtained"); throw new ServiceIncompatibilityException("Capabilities could not be obtained");

@ -2,17 +2,19 @@ using Recyclarr.TrashLib.ApiServices.System;
namespace Recyclarr.TrashLib.Compatibility.Sonarr; namespace Recyclarr.TrashLib.Compatibility.Sonarr;
public class SonarrCapabilityChecker : ServiceCapabilityChecker<SonarrCapabilities>, ISonarrCapabilityChecker public class SonarrCapabilityFetcher : ServiceCapabilityFetcher<SonarrCapabilities>, ISonarrCapabilityFetcher
{ {
public SonarrCapabilityChecker(IServiceInformation info) public SonarrCapabilityFetcher(IServiceInformation info)
: base(info) : base(info)
{ {
} }
protected override SonarrCapabilities BuildCapabilitiesObject(Version version) protected override SonarrCapabilities BuildCapabilitiesObject(Version version)
{ {
return new SonarrCapabilities(version) return new SonarrCapabilities
{ {
Version = version,
SupportsNamedReleaseProfiles = SupportsNamedReleaseProfiles =
version >= SonarrCapabilities.MinimumVersion, version >= SonarrCapabilities.MinimumVersion,

@ -28,7 +28,7 @@ public class SonarrReleaseProfileCompatibilityHandlerTest : CliIntegrationFixtur
protected override void RegisterTypes(ContainerBuilder builder) protected override void RegisterTypes(ContainerBuilder builder)
{ {
base.RegisterTypes(builder); base.RegisterTypes(builder);
builder.RegisterMockFor<ISonarrCapabilityChecker>(); builder.RegisterMockFor<ISonarrCapabilityFetcher>();
} }
[Test] [Test]
@ -59,8 +59,8 @@ public class SonarrReleaseProfileCompatibilityHandlerTest : CliIntegrationFixtur
[Test] [Test]
public async Task Send_v2_to_v1() public async Task Send_v2_to_v1()
{ {
var capabilityChecker = Resolve<ISonarrCapabilityChecker>(); var capabilityChecker = Resolve<ISonarrCapabilityFetcher>();
capabilityChecker.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities(new Version()) capabilityChecker.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
{ {
ArraysNeededForReleaseProfileRequiredAndIgnored = false ArraysNeededForReleaseProfileRequiredAndIgnored = false
}); });
@ -76,8 +76,8 @@ public class SonarrReleaseProfileCompatibilityHandlerTest : CliIntegrationFixtur
[Test] [Test]
public async Task Send_v2_to_v2() public async Task Send_v2_to_v2()
{ {
var capabilityChecker = Resolve<ISonarrCapabilityChecker>(); var capabilityChecker = Resolve<ISonarrCapabilityFetcher>();
capabilityChecker.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities(new Version()) capabilityChecker.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
{ {
ArraysNeededForReleaseProfileRequiredAndIgnored = true ArraysNeededForReleaseProfileRequiredAndIgnored = true
}); });

@ -11,12 +11,12 @@ public class SonarrCapabilityEnforcerTest
{ {
[Test, AutoMockData] [Test, AutoMockData]
public void Fail_when_capabilities_not_obtained( public void Fail_when_capabilities_not_obtained(
[Frozen] ISonarrCapabilityChecker checker, [Frozen] ISonarrCapabilityFetcher fetcher,
SonarrCapabilityEnforcer sut) SonarrCapabilityEnforcer sut)
{ {
var config = NewConfig.Sonarr(); var config = NewConfig.Sonarr();
checker.GetCapabilities(default!).ReturnsForAnyArgs((SonarrCapabilities?) null); fetcher.GetCapabilities(default!).ReturnsForAnyArgs((SonarrCapabilities?) null);
var act = () => sut.Check(config); var act = () => sut.Check(config);
@ -25,12 +25,12 @@ public class SonarrCapabilityEnforcerTest
[Test, AutoMockData] [Test, AutoMockData]
public void Minimum_version_not_met( public void Minimum_version_not_met(
[Frozen] ISonarrCapabilityChecker checker, [Frozen] ISonarrCapabilityFetcher fetcher,
SonarrCapabilityEnforcer sut) SonarrCapabilityEnforcer sut)
{ {
var config = NewConfig.Sonarr(); var config = NewConfig.Sonarr();
checker.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities(new Version()) fetcher.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
{ {
SupportsNamedReleaseProfiles = false SupportsNamedReleaseProfiles = false
}); });
@ -42,7 +42,7 @@ public class SonarrCapabilityEnforcerTest
[Test, AutoMockData] [Test, AutoMockData]
public void Release_profiles_not_allowed_in_v4( public void Release_profiles_not_allowed_in_v4(
[Frozen] ISonarrCapabilityChecker checker, [Frozen] ISonarrCapabilityFetcher fetcher,
SonarrCapabilityEnforcer sut) SonarrCapabilityEnforcer sut)
{ {
var config = NewConfig.Sonarr() with var config = NewConfig.Sonarr() with
@ -53,7 +53,7 @@ public class SonarrCapabilityEnforcerTest
} }
}; };
checker.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities(new Version()) fetcher.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
{ {
SupportsNamedReleaseProfiles = true, SupportsNamedReleaseProfiles = true,
SupportsCustomFormats = true SupportsCustomFormats = true
@ -66,7 +66,7 @@ public class SonarrCapabilityEnforcerTest
[Test, AutoMockData] [Test, AutoMockData]
public void Custom_formats_not_allowed_in_v3( public void Custom_formats_not_allowed_in_v3(
[Frozen] ISonarrCapabilityChecker checker, [Frozen] ISonarrCapabilityFetcher fetcher,
SonarrCapabilityEnforcer sut) SonarrCapabilityEnforcer sut)
{ {
var config = NewConfig.Sonarr() with var config = NewConfig.Sonarr() with
@ -77,7 +77,7 @@ public class SonarrCapabilityEnforcerTest
} }
}; };
checker.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities(new Version()) fetcher.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
{ {
SupportsNamedReleaseProfiles = true, SupportsNamedReleaseProfiles = true,
SupportsCustomFormats = false SupportsCustomFormats = false

Loading…
Cancel
Save