refactor: Make custom format pipeline generic

spectre-console-remove-di-hacks
Robert Dailey 7 months ago
parent b14787e471
commit f4857c7050

@ -81,7 +81,7 @@ public static class CompositionRoot
// ORDER HERE IS IMPORTANT! // ORDER HERE IS IMPORTANT!
// There are indirect dependencies between pipelines. // There are indirect dependencies between pipelines.
typeof(GenericSyncPipeline<TagPipelineContext>), typeof(GenericSyncPipeline<TagPipelineContext>),
typeof(CustomFormatSyncPipeline), typeof(GenericSyncPipeline<CustomFormatPipelineContext>),
typeof(GenericSyncPipeline<QualityProfilePipelineContext>), typeof(GenericSyncPipeline<QualityProfilePipelineContext>),
typeof(GenericSyncPipeline<QualitySizePipelineContext>), typeof(GenericSyncPipeline<QualitySizePipelineContext>),
typeof(GenericSyncPipeline<ReleaseProfilePipelineContext>), typeof(GenericSyncPipeline<ReleaseProfilePipelineContext>),

@ -1,3 +1,4 @@
using Recyclarr.Cli.Pipelines.CustomFormat.Models;
using Recyclarr.TrashGuide.CustomFormat; using Recyclarr.TrashGuide.CustomFormat;
namespace Recyclarr.Cli.Pipelines.CustomFormat.Cache; namespace Recyclarr.Cli.Pipelines.CustomFormat.Cache;

@ -1,5 +1,4 @@
using Autofac; using Autofac;
using Autofac.Extras.AggregateService;
using Recyclarr.Cli.Pipelines.CustomFormat.Cache; using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
using Recyclarr.Cli.Pipelines.CustomFormat.Models; using Recyclarr.Cli.Pipelines.CustomFormat.Models;
using Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases; using Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
@ -10,16 +9,21 @@ public class CustomFormatAutofacModule : Module
{ {
protected override void Load(ContainerBuilder builder) protected override void Load(ContainerBuilder builder)
{ {
builder.RegisterType<ProcessedCustomFormatCache>().As<IPipelineCache>().AsSelf().InstancePerLifetimeScope(); builder.RegisterType<ProcessedCustomFormatCache>()
.As<IPipelineCache>()
.AsSelf()
.InstancePerLifetimeScope();
builder.RegisterType<CustomFormatCachePersister>().As<ICustomFormatCachePersister>(); builder.RegisterType<CustomFormatCachePersister>().As<ICustomFormatCachePersister>();
builder.RegisterType<CustomFormatDataLister>(); builder.RegisterType<CustomFormatDataLister>();
builder.RegisterAggregateService<ICustomFormatPipelinePhases>(); builder.RegisterTypes(
builder.RegisterType<CustomFormatConfigPhase>(); typeof(CustomFormatConfigPhase),
builder.RegisterType<CustomFormatApiFetchPhase>(); typeof(CustomFormatApiFetchPhase),
builder.RegisterType<CustomFormatTransactionPhase>(); typeof(CustomFormatTransactionPhase),
builder.RegisterType<CustomFormatPreviewPhase>(); typeof(CustomFormatPreviewPhase),
builder.RegisterType<CustomFormatApiPersistencePhase>(); typeof(CustomFormatApiPersistencePhase),
typeof(CustomFormatLogPhase))
.AsImplementedInterfaces();
} }
} }

@ -0,0 +1,23 @@
using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
using Recyclarr.Cli.Pipelines.CustomFormat.Models;
using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Common;
using Recyclarr.TrashGuide.CustomFormat;
namespace Recyclarr.Cli.Pipelines.CustomFormat;
public class CustomFormatPipelineContext : IPipelineContext
{
public string PipelineDescription => "Custom Format Pipeline";
public IReadOnlyCollection<SupportedServices> SupportedServiceTypes { get; } = new[]
{
SupportedServices.Sonarr,
SupportedServices.Radarr
};
public IList<CustomFormatData> ConfigOutput { get; init; } = [];
public IList<CustomFormatData> ApiFetchOutput { get; init; } = [];
public CustomFormatTransactionData TransactionOutput { get; set; } = default!;
public IReadOnlyCollection<string> InvalidFormats { get; set; } = default!;
public CustomFormatCache Cache { get; set; } = default!;
}

@ -1,65 +0,0 @@
using System.Collections.ObjectModel;
using Recyclarr.Cli.Console.Settings;
using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
using Recyclarr.Cli.Pipelines.CustomFormat.Models;
using Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
using Recyclarr.Common.Extensions;
using Recyclarr.Config.Models;
using Recyclarr.TrashGuide.CustomFormat;
namespace Recyclarr.Cli.Pipelines.CustomFormat;
public interface ICustomFormatPipelinePhases
{
CustomFormatConfigPhase ConfigPhase { get; }
CustomFormatApiFetchPhase ApiFetchPhase { get; }
CustomFormatTransactionPhase TransactionPhase { get; }
CustomFormatPreviewPhase PreviewPhase { get; }
CustomFormatApiPersistencePhase ApiPersistencePhase { get; }
}
public record CustomFormatTransactionData
{
public Collection<TrashIdMapping> DeletedCustomFormats { get; } = new();
public Collection<CustomFormatData> NewCustomFormats { get; } = new();
public Collection<CustomFormatData> UpdatedCustomFormats { get; } = new();
public Collection<ConflictingCustomFormat> ConflictingCustomFormats { get; } = new();
public Collection<CustomFormatData> UnchangedCustomFormats { get; } = new();
}
public class CustomFormatSyncPipeline(
ILogger log,
ICustomFormatCachePersister cachePersister,
ICustomFormatPipelinePhases phases)
: ISyncPipeline
{
public async Task Execute(ISyncSettings settings, IServiceConfiguration config)
{
var cache = cachePersister.Load(config);
var guideCfs = phases.ConfigPhase.Execute(config);
if (guideCfs.IsEmpty())
{
log.Debug("No custom formats to process");
return;
}
var serviceData = await phases.ApiFetchPhase.Execute(config);
cache.RemoveStale(serviceData);
var transactions = phases.TransactionPhase.Execute(config, guideCfs, serviceData, cache);
phases.PreviewPhase.Execute(transactions);
if (settings.Preview)
{
return;
}
await phases.ApiPersistencePhase.Execute(config, transactions);
cache.Update(transactions);
cachePersister.Save(config, cache);
}
}

@ -0,0 +1,14 @@
using System.Collections.ObjectModel;
using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
using Recyclarr.TrashGuide.CustomFormat;
namespace Recyclarr.Cli.Pipelines.CustomFormat.Models;
public record CustomFormatTransactionData
{
public Collection<TrashIdMapping> DeletedCustomFormats { get; } = new();
public Collection<CustomFormatData> NewCustomFormats { get; } = new();
public Collection<CustomFormatData> UpdatedCustomFormats { get; } = new();
public Collection<ConflictingCustomFormat> ConflictingCustomFormats { get; } = new();
public Collection<CustomFormatData> UnchangedCustomFormats { get; } = new();
}

@ -1,14 +1,17 @@
using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Common.Extensions;
using Recyclarr.Config.Models; using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.CustomFormat; using Recyclarr.ServarrApi.CustomFormat;
using Recyclarr.TrashGuide.CustomFormat;
namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases; namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
public class CustomFormatApiFetchPhase(ICustomFormatApiService api) public class CustomFormatApiFetchPhase(ICustomFormatApiService api)
: IApiFetchPipelinePhase<CustomFormatPipelineContext>
{ {
public async Task<IReadOnlyCollection<CustomFormatData>> Execute(IServiceConfiguration config) public async Task Execute(CustomFormatPipelineContext context, IServiceConfiguration config)
{ {
var result = await api.GetCustomFormats(config); var result = await api.GetCustomFormats(config);
return result.AsReadOnly(); context.ApiFetchOutput.AddRange(result);
context.Cache.RemoveStale(result);
} }
} }

@ -1,12 +1,17 @@
using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Config.Models; using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.CustomFormat; using Recyclarr.ServarrApi.CustomFormat;
namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases; namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
public class CustomFormatApiPersistencePhase(ICustomFormatApiService api) public class CustomFormatApiPersistencePhase(ICustomFormatApiService api, ICustomFormatCachePersister cachePersister)
: IApiPersistencePipelinePhase<CustomFormatPipelineContext>
{ {
public async Task Execute(IServiceConfiguration config, CustomFormatTransactionData transactions) public async Task Execute(CustomFormatPipelineContext context, IServiceConfiguration config)
{ {
var transactions = context.TransactionOutput;
foreach (var cf in transactions.NewCustomFormats) foreach (var cf in transactions.NewCustomFormats)
{ {
var response = await api.CreateCustomFormat(config, cf); var response = await api.CreateCustomFormat(config, cf);
@ -25,5 +30,8 @@ public class CustomFormatApiPersistencePhase(ICustomFormatApiService api)
{ {
await api.DeleteCustomFormat(config, map.CustomFormatId); await api.DeleteCustomFormat(config, map.CustomFormatId);
} }
context.Cache.Update(transactions);
cachePersister.Save(config, context.Cache);
} }
} }

@ -1,13 +1,19 @@
using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
using Recyclarr.Cli.Pipelines.CustomFormat.Models; using Recyclarr.Cli.Pipelines.CustomFormat.Models;
using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Common.Extensions; using Recyclarr.Common.Extensions;
using Recyclarr.Config.Models; using Recyclarr.Config.Models;
using Recyclarr.TrashGuide.CustomFormat; using Recyclarr.TrashGuide.CustomFormat;
namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases; namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
public class CustomFormatConfigPhase(ILogger log, ICustomFormatGuideService guide, ProcessedCustomFormatCache cache) public class CustomFormatConfigPhase(
ICustomFormatGuideService guide,
ProcessedCustomFormatCache cache,
ICustomFormatCachePersister cachePersister)
: IConfigPipelinePhase<CustomFormatPipelineContext>
{ {
public IReadOnlyCollection<CustomFormatData> Execute(IServiceConfiguration config) public Task Execute(CustomFormatPipelineContext context, IServiceConfiguration config)
{ {
// Match custom formats in the YAML config to those in the guide, by Trash ID // Match custom formats in the YAML config to those in the guide, by Trash ID
// //
@ -25,14 +31,11 @@ public class CustomFormatConfigPhase(ILogger log, ICustomFormatGuideService guid
(id, cf) => (Id: id, CustomFormats: cf)) (id, cf) => (Id: id, CustomFormats: cf))
.ToLookup(x => x.Item2.Any()); .ToLookup(x => x.Item2.Any());
var invalidCfs = processedCfs[false].Select(x => x.Id).ToList(); context.InvalidFormats = processedCfs[false].Select(x => x.Id).ToList();
if (invalidCfs.IsNotEmpty()) context.ConfigOutput.AddRange(processedCfs[true].SelectMany(x => x.CustomFormats));
{ context.Cache = cachePersister.Load(config);
log.Warning("These Custom Formats do not exist in the guide and will be skipped: {Cfs}", invalidCfs);
}
var validCfs = processedCfs[true].SelectMany(x => x.CustomFormats).ToList(); cache.AddCustomFormats(context.ConfigOutput);
cache.AddCustomFormats(validCfs); return Task.CompletedTask;
return validCfs;
} }
} }

@ -0,0 +1,33 @@
using Recyclarr.Cli.Pipelines.Generic;
namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
public class CustomFormatLogPhase(ILogger log) : ILogPipelinePhase<CustomFormatPipelineContext>
{
// Returning 'true' means to exit. 'false' means to proceed.
public bool LogConfigPhaseAndExitIfNeeded(CustomFormatPipelineContext context)
{
if (context.InvalidFormats.Count != 0)
{
log.Warning("These Custom Formats do not exist in the guide and will be skipped: {Cfs}",
context.InvalidFormats);
}
if (context.ConfigOutput.Count == 0)
{
log.Debug("No custom formats to process");
return true;
}
return false;
}
public void LogTransactionNotices(CustomFormatPipelineContext context)
{
}
public void LogPersistenceResults(CustomFormatPipelineContext context)
{
// Logging is done (and shared with) in CustomFormatPreviewPhase
}
}

@ -1,9 +1,13 @@
using Recyclarr.Cli.Pipelines.Generic;
namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases; namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
public class CustomFormatPreviewPhase(ILogger log) public class CustomFormatPreviewPhase(ILogger log) : IPreviewPipelinePhase<CustomFormatPipelineContext>
{ {
public void Execute(CustomFormatTransactionData transactions) public void Execute(CustomFormatPipelineContext context)
{ {
var transactions = context.TransactionOutput;
foreach (var (guideCf, conflictingId) in transactions.ConflictingCustomFormats) foreach (var (guideCf, conflictingId) in transactions.ConflictingCustomFormats)
{ {
log.Warning( log.Warning(
@ -66,4 +70,5 @@ public class CustomFormatPreviewPhase(ILogger log)
log.Information("All custom formats are already up to date!"); log.Information("All custom formats are already up to date!");
} }
} }
} }

@ -1,37 +1,31 @@
using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
using Recyclarr.Cli.Pipelines.CustomFormat.Models; using Recyclarr.Cli.Pipelines.CustomFormat.Models;
using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Common.Extensions; using Recyclarr.Common.Extensions;
using Recyclarr.Config.Models; using Recyclarr.Config.Models;
using Recyclarr.TrashGuide.CustomFormat; using Recyclarr.TrashGuide.CustomFormat;
namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases; namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
public class CustomFormatTransactionPhase(ILogger log) public class CustomFormatTransactionPhase(ILogger log) : ITransactionPipelinePhase<CustomFormatPipelineContext>
{ {
[SuppressMessage("Performance", "CA1822:Mark members as static")] public void Execute(CustomFormatPipelineContext context, IServiceConfiguration config)
public CustomFormatTransactionData Execute(
IServiceConfiguration config,
IReadOnlyCollection<CustomFormatData> guideCfs,
IReadOnlyCollection<CustomFormatData> serviceData,
CustomFormatCache cache)
{ {
var transactions = new CustomFormatTransactionData(); var transactions = new CustomFormatTransactionData();
foreach (var guideCf in guideCfs) foreach (var guideCf in context.ConfigOutput)
{ {
log.Debug("Process transaction for guide CF {TrashId} ({Name})", guideCf.TrashId, guideCf.Name); log.Debug("Process transaction for guide CF {TrashId} ({Name})", guideCf.TrashId, guideCf.Name);
guideCf.Id = cache.FindId(guideCf) ?? 0; guideCf.Id = context.Cache.FindId(guideCf) ?? 0;
var serviceCf = FindServiceCfByName(serviceData, guideCf.Name); var serviceCf = FindServiceCfByName(context.ApiFetchOutput, guideCf.Name);
if (serviceCf is not null) if (serviceCf is not null)
{ {
ProcessExistingCf(config, guideCf, serviceCf, transactions); ProcessExistingCf(config, guideCf, serviceCf, transactions);
continue; continue;
} }
serviceCf = FindServiceCfById(serviceData, guideCf.Id); serviceCf = FindServiceCfById(context.ApiFetchOutput, guideCf.Id);
if (serviceCf is not null) if (serviceCf is not null)
{ {
// We do not use AddUpdatedCustomFormat() here because it's impossible for the CFs to be identical if we // We do not use AddUpdatedCustomFormat() here because it's impossible for the CFs to be identical if we
@ -47,14 +41,14 @@ public class CustomFormatTransactionPhase(ILogger log)
if (config.DeleteOldCustomFormats) if (config.DeleteOldCustomFormats)
{ {
transactions.DeletedCustomFormats.AddRange(cache.Mappings transactions.DeletedCustomFormats.AddRange(context.Cache.Mappings
// Custom format must be in the cache but NOT in the user's config // Custom format must be in the cache but NOT in the user's config
.Where(map => guideCfs.All(cf => cf.TrashId != map.TrashId)) .Where(map => context.ConfigOutput.All(cf => cf.TrashId != map.TrashId))
// Also, that cache-only CF must exist in the service (otherwise there is nothing to delete) // Also, that cache-only CF must exist in the service (otherwise there is nothing to delete)
.Where(map => serviceData.Any(cf => cf.Id == map.CustomFormatId))); .Where(map => context.ApiFetchOutput.Any(cf => cf.Id == map.CustomFormatId)));
} }
return transactions; context.TransactionOutput = transactions;
} }
private void ProcessExistingCf( private void ProcessExistingCf(

@ -13,6 +13,7 @@ public class GenericSyncPipeline<TContext>(ILogger log, GenericPipelinePhases<TC
{ {
log.Debug("Skipping {Description} because it does not support service type {Service}", log.Debug("Skipping {Description} because it does not support service type {Service}",
context.PipelineDescription, config.ServiceType); context.PipelineDescription, config.ServiceType);
return;
} }
await phases.ConfigPhase.Execute(context, config); await phases.ConfigPhase.Execute(context, config);
@ -22,7 +23,7 @@ public class GenericSyncPipeline<TContext>(ILogger log, GenericPipelinePhases<TC
} }
await phases.ApiFetchPhase.Execute(context, config); await phases.ApiFetchPhase.Execute(context, config);
phases.TransactionPhase.Execute(context); phases.TransactionPhase.Execute(context, config);
phases.LogPhase.LogTransactionNotices(context); phases.LogPhase.LogTransactionNotices(context);

@ -1,7 +1,9 @@
using Recyclarr.Config.Models;
namespace Recyclarr.Cli.Pipelines.Generic; namespace Recyclarr.Cli.Pipelines.Generic;
public interface ITransactionPipelinePhase<in TContext> public interface ITransactionPipelinePhase<in TContext>
where TContext : IPipelineContext where TContext : IPipelineContext
{ {
void Execute(TContext context); void Execute(TContext context, IServiceConfiguration config);
} }

@ -1,11 +1,12 @@
using Recyclarr.Cli.Pipelines.Generic; using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.MediaNaming; using Recyclarr.ServarrApi.MediaNaming;
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases; namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
public class MediaNamingTransactionPhase : ITransactionPipelinePhase<MediaNamingPipelineContext> public class MediaNamingTransactionPhase : ITransactionPipelinePhase<MediaNamingPipelineContext>
{ {
public void Execute(MediaNamingPipelineContext context) public void Execute(MediaNamingPipelineContext context, IServiceConfiguration config)
{ {
context.TransactionOutput = context.ApiFetchOutput switch context.TransactionOutput = context.ApiFetchOutput switch
{ {

@ -10,7 +10,7 @@ namespace Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
public class QualityProfileTransactionPhase(QualityProfileStatCalculator statCalculator) public class QualityProfileTransactionPhase(QualityProfileStatCalculator statCalculator)
: ITransactionPipelinePhase<QualityProfilePipelineContext> : ITransactionPipelinePhase<QualityProfilePipelineContext>
{ {
public void Execute(QualityProfilePipelineContext context) public void Execute(QualityProfilePipelineContext context, IServiceConfiguration config)
{ {
var transactions = new QualityProfileTransactionData(); var transactions = new QualityProfileTransactionData();

@ -1,5 +1,4 @@
using Recyclarr.Cli.Pipelines.QualityProfile.Models; using Recyclarr.Cli.Pipelines.QualityProfile.Models;
using Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
using Recyclarr.Common.Extensions; using Recyclarr.Common.Extensions;
using Recyclarr.ServarrApi.QualityProfile; using Recyclarr.ServarrApi.QualityProfile;

@ -1,5 +1,4 @@
using Recyclarr.Cli.Pipelines.QualityProfile.Models; using Recyclarr.Cli.Pipelines.QualityProfile.Models;
using Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
using Recyclarr.ServarrApi.QualityProfile; using Recyclarr.ServarrApi.QualityProfile;
namespace Recyclarr.Cli.Pipelines.QualityProfile; namespace Recyclarr.Cli.Pipelines.QualityProfile;

@ -1,6 +1,5 @@
using FluentValidation; using FluentValidation;
using Recyclarr.Cli.Pipelines.QualityProfile.Models; using Recyclarr.Cli.Pipelines.QualityProfile.Models;
using Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
using Recyclarr.Common.Extensions; using Recyclarr.Common.Extensions;
namespace Recyclarr.Cli.Pipelines.QualityProfile; namespace Recyclarr.Cli.Pipelines.QualityProfile;

@ -1,5 +1,6 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Recyclarr.Cli.Pipelines.Generic; using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.QualityDefinition; using Recyclarr.ServarrApi.QualityDefinition;
using Recyclarr.TrashGuide.QualitySize; using Recyclarr.TrashGuide.QualitySize;
@ -7,7 +8,7 @@ namespace Recyclarr.Cli.Pipelines.QualitySize.PipelinePhases;
public class QualitySizeTransactionPhase(ILogger log) : ITransactionPipelinePhase<QualitySizePipelineContext> public class QualitySizeTransactionPhase(ILogger log) : ITransactionPipelinePhase<QualitySizePipelineContext>
{ {
public void Execute(QualitySizePipelineContext context) public void Execute(QualitySizePipelineContext context, IServiceConfiguration config)
{ {
// Do not check ConfigOutput for null since the LogPhase does it for us // Do not check ConfigOutput for null since the LogPhase does it for us
var guideQuality = context.ConfigOutput!.Qualities; var guideQuality = context.ConfigOutput!.Qualities;

@ -6,7 +6,7 @@ public class ReleaseProfileLogPhase(ILogger log) : ILogPipelinePhase<ReleaseProf
{ {
public bool LogConfigPhaseAndExitIfNeeded(ReleaseProfilePipelineContext context) public bool LogConfigPhaseAndExitIfNeeded(ReleaseProfilePipelineContext context)
{ {
if (context.ConfigOutput.Any()) if (context.ConfigOutput is {Count: > 0})
{ {
return false; return false;
} }
@ -26,19 +26,21 @@ public class ReleaseProfileLogPhase(ILogger log) : ILogPipelinePhase<ReleaseProf
if (transactions.UpdatedProfiles.Count != 0) if (transactions.UpdatedProfiles.Count != 0)
{ {
log.Information("Update existing profiles: {ProfileNames}", transactions.UpdatedProfiles); log.Information("Update existing profiles: {ProfileNames}",
transactions.UpdatedProfiles.Select(x => x.Name));
somethingChanged = true; somethingChanged = true;
} }
if (transactions.CreatedProfiles.Count != 0) if (transactions.CreatedProfiles.Count != 0)
{ {
log.Information("Create new profiles: {ProfileNames}", transactions.CreatedProfiles); log.Information("Create new profiles: {ProfileNames}", transactions.CreatedProfiles.Select(x => x.Name));
somethingChanged = true; somethingChanged = true;
} }
if (transactions.DeletedProfiles.Count != 0) if (transactions.DeletedProfiles.Count != 0)
{ {
log.Information("Deleting old release profiles: {ProfileNames}", transactions.DeletedProfiles); log.Information("Deleting old release profiles: {ProfileNames}",
transactions.DeletedProfiles.Select(x => x.Name));
somethingChanged = true; somethingChanged = true;
} }

@ -2,6 +2,7 @@ using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Cli.Pipelines.ReleaseProfile.Models; using Recyclarr.Cli.Pipelines.ReleaseProfile.Models;
using Recyclarr.Cli.Pipelines.Tags; using Recyclarr.Cli.Pipelines.Tags;
using Recyclarr.Common.Extensions; using Recyclarr.Common.Extensions;
using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.ReleaseProfile; using Recyclarr.ServarrApi.ReleaseProfile;
namespace Recyclarr.Cli.Pipelines.ReleaseProfile.PipelinePhases; namespace Recyclarr.Cli.Pipelines.ReleaseProfile.PipelinePhases;
@ -9,7 +10,7 @@ namespace Recyclarr.Cli.Pipelines.ReleaseProfile.PipelinePhases;
public class ReleaseProfileTransactionPhase(ServiceTagCache tagCache) public class ReleaseProfileTransactionPhase(ServiceTagCache tagCache)
: ITransactionPipelinePhase<ReleaseProfilePipelineContext> : ITransactionPipelinePhase<ReleaseProfilePipelineContext>
{ {
public void Execute(ReleaseProfilePipelineContext context) public void Execute(ReleaseProfilePipelineContext context, IServiceConfiguration config)
{ {
var created = new List<SonarrReleaseProfile>(); var created = new List<SonarrReleaseProfile>();
var updated = new List<SonarrReleaseProfile>(); var updated = new List<SonarrReleaseProfile>();

@ -1,11 +1,12 @@
using Recyclarr.Cli.Pipelines.Generic; using Recyclarr.Cli.Pipelines.Generic;
using Recyclarr.Common.Extensions; using Recyclarr.Common.Extensions;
using Recyclarr.Config.Models;
namespace Recyclarr.Cli.Pipelines.Tags.PipelinePhases; namespace Recyclarr.Cli.Pipelines.Tags.PipelinePhases;
public class TagTransactionPhase : ITransactionPipelinePhase<TagPipelineContext> public class TagTransactionPhase : ITransactionPipelinePhase<TagPipelineContext>
{ {
public void Execute(TagPipelineContext context) public void Execute(TagPipelineContext context, IServiceConfiguration config)
{ {
// List of tags in config that do not already exist in the service. The goal is to figure out which tags need to // List of tags in config that do not already exist in the service. The goal is to figure out which tags need to
// be created. // be created.

@ -15,20 +15,18 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var config = NewConfig.Radarr();
var context = new CustomFormatPipelineContext
{ {
NewCf.Data("one", "cf1") Cache = new CustomFormatCache([]),
ApiFetchOutput = [],
ConfigOutput = [NewCf.Data("one", "cf1")]
}; };
var serviceData = Array.Empty<CustomFormatData>(); sut.Execute(context, config);
var cache = new CustomFormatCache([]);
var config = NewConfig.Radarr();
var result = sut.Execute(config, guideCfs, serviceData, cache); context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
result.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
NewCustomFormats = NewCustomFormats =
{ {
@ -42,29 +40,27 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{
new CustomFormatData
{
Name = "one",
TrashId = "cf1",
// Only set the below value to make it different from the service CF
IncludeCustomFormatWhenRenaming = true
}
};
var serviceData = new[]
{ {
new CustomFormatData {Name = "one"} Cache = new CustomFormatCache([]),
ApiFetchOutput = [new CustomFormatData {Name = "one"}],
ConfigOutput =
[
new CustomFormatData
{
Name = "one",
TrashId = "cf1",
// Only set the below value to make it different from the service CF
IncludeCustomFormatWhenRenaming = true
}
]
}; };
var cache = new CustomFormatCache([]);
var config = NewConfig.Radarr(); var config = NewConfig.Radarr();
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
UpdatedCustomFormats = UpdatedCustomFormats =
{ {
@ -81,31 +77,27 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{
new CustomFormatData
{
Name = "different1",
TrashId = "cf1",
// Only set the below value to make it different from the service CF
IncludeCustomFormatWhenRenaming = true
}
};
var serviceData = new[]
{ {
new CustomFormatData {Name = "different2", Id = 2} Cache = new CustomFormatCache([new TrashIdMapping("cf1", "", 2)]),
ApiFetchOutput = [new CustomFormatData {Name = "different2", Id = 2}],
ConfigOutput =
[
new CustomFormatData
{
Name = "different1",
TrashId = "cf1",
// Only set the below value to make it different from the service CF
IncludeCustomFormatWhenRenaming = true
}
]
}; };
var cache = new CustomFormatCache([
new TrashIdMapping("cf1", "", 2)
]);
var config = NewConfig.Radarr(); var config = NewConfig.Radarr();
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
UpdatedCustomFormats = UpdatedCustomFormats =
{ {
@ -122,32 +114,30 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{
new CustomFormatData
{
Name = "different1",
TrashId = "cf1",
// Only set the below value to make it different from the service CF
IncludeCustomFormatWhenRenaming = true
}
};
var serviceData = new[]
{ {
new CustomFormatData {Name = "different1", Id = 2} Cache = new CustomFormatCache([]),
ApiFetchOutput = [new CustomFormatData {Name = "different1", Id = 2}],
ConfigOutput =
[
new CustomFormatData
{
Name = "different1",
TrashId = "cf1",
// Only set the below value to make it different from the service CF
IncludeCustomFormatWhenRenaming = true
}
]
}; };
var cache = new CustomFormatCache([]);
var config = NewConfig.Radarr() with var config = NewConfig.Radarr() with
{ {
ReplaceExistingCustomFormats = true ReplaceExistingCustomFormats = true
}; };
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
UpdatedCustomFormats = UpdatedCustomFormats =
{ {
@ -164,31 +154,29 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{ {
NewCf.Data("one", "cf1") Cache = new CustomFormatCache([]),
ApiFetchOutput =
[
new CustomFormatData {Name = "one", Id = 2},
new CustomFormatData {Name = "two", Id = 1}
],
ConfigOutput = [NewCf.Data("one", "cf1")]
}; };
var serviceData = new[]
{
new CustomFormatData {Name = "one", Id = 2},
new CustomFormatData {Name = "two", Id = 1}
};
var cache = new CustomFormatCache([]);
var config = NewConfig.Radarr() with var config = NewConfig.Radarr() with
{ {
ReplaceExistingCustomFormats = false ReplaceExistingCustomFormats = false
}; };
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
ConflictingCustomFormats = ConflictingCustomFormats =
{ {
new ConflictingCustomFormat(guideCfs[0], 2) new ConflictingCustomFormat(context.ConfigOutput[0], 2)
} }
}); });
} }
@ -198,33 +186,29 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{ {
NewCf.Data("one", "cf1") Cache = new CustomFormatCache([new TrashIdMapping("cf1", "one", 1)]),
ApiFetchOutput =
[
new CustomFormatData {Name = "one", Id = 2},
new CustomFormatData {Name = "two", Id = 1}
],
ConfigOutput = [NewCf.Data("one", "cf1")]
}; };
var serviceData = new[]
{
new CustomFormatData {Name = "one", Id = 2},
new CustomFormatData {Name = "two", Id = 1}
};
var cache = new CustomFormatCache([
new TrashIdMapping("cf1", "one", 1)
]);
var config = NewConfig.Radarr() with var config = NewConfig.Radarr() with
{ {
ReplaceExistingCustomFormats = false ReplaceExistingCustomFormats = false
}; };
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
ConflictingCustomFormats = ConflictingCustomFormats =
{ {
new ConflictingCustomFormat(guideCfs[0], 2) new ConflictingCustomFormat(context.ConfigOutput[0], 2)
} }
}); });
} }
@ -234,35 +218,34 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{
new CustomFormatData
{
Name = "one",
TrashId = "cf1",
// Only set the below value to make it different from the service CF
IncludeCustomFormatWhenRenaming = true
}
};
var serviceData = new[]
{ {
new CustomFormatData {Name = "two", Id = 2}, Cache = new CustomFormatCache([new TrashIdMapping("cf1", "one", 1)]),
new CustomFormatData {Name = "one", Id = 1} ApiFetchOutput =
[
new CustomFormatData {Name = "two", Id = 2},
new CustomFormatData {Name = "one", Id = 1}
],
ConfigOutput =
[
new CustomFormatData
{
Name = "one",
TrashId = "cf1",
// Only set the below value to make it different from the service CF
IncludeCustomFormatWhenRenaming = true
}
]
}; };
var cache = new CustomFormatCache([
new TrashIdMapping("cf1", "one", 1)
]);
var config = NewConfig.Radarr() with var config = NewConfig.Radarr() with
{ {
ReplaceExistingCustomFormats = false ReplaceExistingCustomFormats = false
}; };
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
UpdatedCustomFormats = UpdatedCustomFormats =
{ {
@ -276,28 +259,23 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{ {
NewCf.Data("one", "cf1") Cache = new CustomFormatCache([]),
ApiFetchOutput = [new CustomFormatData {Name = "one", Id = 1}],
ConfigOutput = [NewCf.Data("one", "cf1")]
}; };
var serviceData = new[]
{
new CustomFormatData {Name = "one", Id = 1}
};
var cache = new CustomFormatCache([]);
var config = NewConfig.Radarr() with var config = NewConfig.Radarr() with
{ {
ReplaceExistingCustomFormats = true ReplaceExistingCustomFormats = true
}; };
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
UnchangedCustomFormats = {guideCfs[0]} UnchangedCustomFormats = {context.ConfigOutput[0]}
}); });
} }
@ -306,30 +284,23 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{ {
NewCf.Data("one", "cf1") Cache = new CustomFormatCache([new TrashIdMapping("cf1", "one", 1)]),
ApiFetchOutput = [new CustomFormatData {Name = "one", Id = 1}],
ConfigOutput = [NewCf.Data("one", "cf1")]
}; };
var serviceData = new[]
{
new CustomFormatData {Name = "one", Id = 1}
};
var cache = new CustomFormatCache([
new TrashIdMapping("cf1", "one", 1)
]);
var config = NewConfig.Radarr() with var config = NewConfig.Radarr() with
{ {
ReplaceExistingCustomFormats = false ReplaceExistingCustomFormats = false
}; };
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
UnchangedCustomFormats = {guideCfs[0]} UnchangedCustomFormats = {context.ConfigOutput[0]}
}); });
} }
@ -338,25 +309,21 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = Array.Empty<CustomFormatData>(); var context = new CustomFormatPipelineContext
var serviceData = new[]
{ {
new CustomFormatData {Name = "two", Id = 2} Cache = new CustomFormatCache([new TrashIdMapping("cf2", "two", 2)]),
ApiFetchOutput = [new CustomFormatData {Name = "two", Id = 2}],
ConfigOutput = []
}; };
var cache = new CustomFormatCache([
new TrashIdMapping("cf2", "two", 2)
]);
var config = NewConfig.Radarr() with var config = NewConfig.Radarr() with
{ {
DeleteOldCustomFormats = true DeleteOldCustomFormats = true
}; };
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
DeletedCustomFormats = DeletedCustomFormats =
{ {
@ -370,25 +337,21 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = Array.Empty<CustomFormatData>(); var context = new CustomFormatPipelineContext
var serviceData = new[]
{ {
new CustomFormatData {Name = "two", Id = 2} Cache = new CustomFormatCache([new TrashIdMapping("cf2", "two", 2)]),
ApiFetchOutput = [new CustomFormatData {Name = "two", Id = 2}],
ConfigOutput = []
}; };
var cache = new CustomFormatCache([
new TrashIdMapping("cf2", "two", 2)
]);
var config = NewConfig.Radarr() with var config = NewConfig.Radarr() with
{ {
DeleteOldCustomFormats = false DeleteOldCustomFormats = false
}; };
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData()); context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData());
} }
[Test] [Test]
@ -396,25 +359,18 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{ {
NewCf.Data("two", "cf2", 2) Cache = new CustomFormatCache([new TrashIdMapping("cf2", "two", 2)]),
ApiFetchOutput = [new CustomFormatData {Name = "two", Id = 2}],
ConfigOutput = [NewCf.Data("two", "cf2", 2)]
}; };
var serviceData = new[]
{
new CustomFormatData {Name = "two", Id = 2}
};
var cache = new CustomFormatCache([
new TrashIdMapping("cf2", "two", 2)
]);
var config = NewConfig.Radarr(); var config = NewConfig.Radarr();
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.DeletedCustomFormats.Should().BeEmpty(); context.TransactionOutput.DeletedCustomFormats.Should().BeEmpty();
} }
[Test] [Test]
@ -422,22 +378,18 @@ internal class CustomFormatTransactionPhaseTest : CliIntegrationFixture
{ {
var sut = Resolve<CustomFormatTransactionPhase>(); var sut = Resolve<CustomFormatTransactionPhase>();
var guideCfs = new[] var context = new CustomFormatPipelineContext
{ {
NewCf.Data("two", "cf2", 2) Cache = new CustomFormatCache([new TrashIdMapping("cf2", "two", 200)]),
ApiFetchOutput = [],
ConfigOutput = [NewCf.Data("two", "cf2", 2)]
}; };
var serviceData = Array.Empty<CustomFormatData>();
var cache = new CustomFormatCache([
new TrashIdMapping("cf2", "two", 200)
]);
var config = NewConfig.Radarr(); var config = NewConfig.Radarr();
var result = sut.Execute(config, guideCfs, serviceData, cache); sut.Execute(context, config);
result.Should().BeEquivalentTo(new CustomFormatTransactionData context.TransactionOutput.Should().BeEquivalentTo(new CustomFormatTransactionData
{ {
NewCustomFormats = NewCustomFormats =
{ {

@ -1,5 +1,5 @@
using Recyclarr.Cli.Pipelines.CustomFormat;
using Recyclarr.Cli.Pipelines.CustomFormat.Cache; using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
using Recyclarr.Cli.Pipelines.CustomFormat.Models;
using Recyclarr.Tests.TestLibrary; using Recyclarr.Tests.TestLibrary;
namespace Recyclarr.Cli.Tests.Cache; namespace Recyclarr.Cli.Tests.Cache;

@ -1,7 +1,6 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Pipelines.QualityProfile; using Recyclarr.Cli.Pipelines.QualityProfile;
using Recyclarr.Cli.Pipelines.QualityProfile.Models; using Recyclarr.Cli.Pipelines.QualityProfile.Models;
using Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
using Recyclarr.Config.Models; using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.QualityProfile; using Recyclarr.ServarrApi.QualityProfile;

@ -1,3 +1,4 @@
using Recyclarr.Cli.Pipelines.CustomFormat;
using Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases; using Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
using Recyclarr.Config.Models; using Recyclarr.Config.Models;
using Recyclarr.Tests.TestLibrary; using Recyclarr.Tests.TestLibrary;
@ -34,9 +35,11 @@ public class CustomFormatConfigPhaseTest
} }
}; };
var result = sut.Execute(config); var context = new CustomFormatPipelineContext();
result.Should().BeEquivalentTo(new[] sut.Execute(context, config);
context.ConfigOutput.Should().BeEquivalentTo(new[]
{ {
NewCf.Data("one", "cf1"), NewCf.Data("one", "cf1"),
NewCf.Data("two", "cf2") NewCf.Data("two", "cf2")
@ -69,8 +72,10 @@ public class CustomFormatConfigPhaseTest
} }
}; };
var result = sut.Execute(config); var context = new CustomFormatPipelineContext();
sut.Execute(context, config);
result.Should().BeEmpty(); context.ConfigOutput.Should().BeEmpty();
} }
} }

@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Pipelines.MediaNaming; using Recyclarr.Cli.Pipelines.MediaNaming;
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases; using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.MediaNaming; using Recyclarr.ServarrApi.MediaNaming;
namespace Recyclarr.Cli.Tests.Pipelines.MediaNaming; namespace Recyclarr.Cli.Tests.Pipelines.MediaNaming;
@ -28,7 +29,7 @@ public class MediaNamingTransactionPhaseRadarrTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(context.ConfigOutput.Dto, o => o.RespectingRuntimeTypes()); context.TransactionOutput.Should().BeEquivalentTo(context.ConfigOutput.Dto, o => o.RespectingRuntimeTypes());
} }
@ -51,7 +52,7 @@ public class MediaNamingTransactionPhaseRadarrTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(context.ApiFetchOutput, o => o.RespectingRuntimeTypes()); context.TransactionOutput.Should().BeEquivalentTo(context.ApiFetchOutput, o => o.RespectingRuntimeTypes());
} }
@ -79,7 +80,7 @@ public class MediaNamingTransactionPhaseRadarrTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(context.ConfigOutput.Dto, o => o.RespectingRuntimeTypes()); context.TransactionOutput.Should().BeEquivalentTo(context.ConfigOutput.Dto, o => o.RespectingRuntimeTypes());
} }
@ -107,7 +108,7 @@ public class MediaNamingTransactionPhaseRadarrTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(new RadarrMediaNamingDto context.TransactionOutput.Should().BeEquivalentTo(new RadarrMediaNamingDto
{ {

@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Pipelines.MediaNaming; using Recyclarr.Cli.Pipelines.MediaNaming;
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases; using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.MediaNaming; using Recyclarr.ServarrApi.MediaNaming;
namespace Recyclarr.Cli.Tests.Pipelines.MediaNaming; namespace Recyclarr.Cli.Tests.Pipelines.MediaNaming;
@ -30,7 +31,7 @@ public class MediaNamingTransactionPhaseSonarrTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(context.ConfigOutput.Dto, o => o.RespectingRuntimeTypes()); context.TransactionOutput.Should().BeEquivalentTo(context.ConfigOutput.Dto, o => o.RespectingRuntimeTypes());
} }
@ -56,7 +57,7 @@ public class MediaNamingTransactionPhaseSonarrTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(context.ApiFetchOutput, o => o.RespectingRuntimeTypes()); context.TransactionOutput.Should().BeEquivalentTo(context.ApiFetchOutput, o => o.RespectingRuntimeTypes());
} }
@ -90,7 +91,7 @@ public class MediaNamingTransactionPhaseSonarrTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(context.ConfigOutput.Dto, o => o.RespectingRuntimeTypes()); context.TransactionOutput.Should().BeEquivalentTo(context.ConfigOutput.Dto, o => o.RespectingRuntimeTypes());
} }
@ -124,7 +125,7 @@ public class MediaNamingTransactionPhaseSonarrTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(new SonarrMediaNamingDto context.TransactionOutput.Should().BeEquivalentTo(new SonarrMediaNamingDto
{ {

@ -31,7 +31,7 @@ public class QualityProfileTransactionPhaseTest
ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto()) ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto())
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(new QualityProfileTransactionData context.TransactionOutput.Should().BeEquivalentTo(new QualityProfileTransactionData
{ {
@ -88,7 +88,7 @@ public class QualityProfileTransactionPhaseTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(new QualityProfileTransactionData context.TransactionOutput.Should().BeEquivalentTo(new QualityProfileTransactionData
{ {
@ -159,7 +159,7 @@ public class QualityProfileTransactionPhaseTest
ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto()) ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto())
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.ChangedProfiles.Should() context.TransactionOutput.ChangedProfiles.Should()
.ContainSingle().Which.Profile.UpdatedScores.Should() .ContainSingle().Which.Profile.UpdatedScores.Should()
@ -203,7 +203,7 @@ public class QualityProfileTransactionPhaseTest
ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto()) ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto())
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(new QualityProfileTransactionData()); context.TransactionOutput.Should().BeEquivalentTo(new QualityProfileTransactionData());
} }
@ -246,7 +246,7 @@ public class QualityProfileTransactionPhaseTest
ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto()) ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto())
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.UnchangedProfiles.Should() context.TransactionOutput.UnchangedProfiles.Should()
.ContainSingle().Which.Profile.UpdatedScores.Should() .ContainSingle().Which.Profile.UpdatedScores.Should()
@ -293,7 +293,7 @@ public class QualityProfileTransactionPhaseTest
ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto()) ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto())
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.ChangedProfiles.Should() context.TransactionOutput.ChangedProfiles.Should()
.ContainSingle().Which.Profile.UpdatedScores.Should() .ContainSingle().Which.Profile.UpdatedScores.Should()
@ -352,7 +352,7 @@ public class QualityProfileTransactionPhaseTest
ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto()) ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto())
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.ChangedProfiles.Should() context.TransactionOutput.ChangedProfiles.Should()
.ContainSingle().Which.Profile.UpdatedScores.Should() .ContainSingle().Which.Profile.UpdatedScores.Should()
@ -409,7 +409,7 @@ public class QualityProfileTransactionPhaseTest
ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto()) ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto())
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.ChangedProfiles.Should() context.TransactionOutput.ChangedProfiles.Should()
.ContainSingle().Which.Profile.UpdatedScores.Should() .ContainSingle().Which.Profile.UpdatedScores.Should()
@ -465,7 +465,7 @@ public class QualityProfileTransactionPhaseTest
ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto()) ApiFetchOutput = new QualityProfileServiceData(dtos, new QualityProfileDto())
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.ChangedProfiles.Should() context.TransactionOutput.ChangedProfiles.Should()
.ContainSingle().Which.Profile.InvalidExceptCfNames.Should() .ContainSingle().Which.Profile.InvalidExceptCfNames.Should()

@ -1,6 +1,5 @@
using Recyclarr.Cli.Pipelines.QualityProfile; using Recyclarr.Cli.Pipelines.QualityProfile;
using Recyclarr.Cli.Pipelines.QualityProfile.Models; using Recyclarr.Cli.Pipelines.QualityProfile.Models;
using Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
using Recyclarr.Config.Models; using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.QualityProfile; using Recyclarr.ServarrApi.QualityProfile;

@ -1,7 +1,6 @@
using FluentValidation.TestHelper; using FluentValidation.TestHelper;
using Recyclarr.Cli.Pipelines.QualityProfile; using Recyclarr.Cli.Pipelines.QualityProfile;
using Recyclarr.Cli.Pipelines.QualityProfile.Models; using Recyclarr.Cli.Pipelines.QualityProfile.Models;
using Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
using Recyclarr.Config.Models; using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.QualityProfile; using Recyclarr.ServarrApi.QualityProfile;

@ -1,5 +1,6 @@
using Recyclarr.Cli.Pipelines.QualitySize; using Recyclarr.Cli.Pipelines.QualitySize;
using Recyclarr.Cli.Pipelines.QualitySize.PipelinePhases; using Recyclarr.Cli.Pipelines.QualitySize.PipelinePhases;
using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.QualityDefinition; using Recyclarr.ServarrApi.QualityDefinition;
using Recyclarr.TrashGuide.QualitySize; using Recyclarr.TrashGuide.QualitySize;
@ -31,7 +32,7 @@ public class QualitySizeTransactionPhaseTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEmpty(); context.TransactionOutput.Should().BeEmpty();
} }
@ -69,7 +70,7 @@ public class QualitySizeTransactionPhaseTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEmpty(); context.TransactionOutput.Should().BeEmpty();
} }
@ -107,7 +108,7 @@ public class QualitySizeTransactionPhaseTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo(new List<ServiceQualityDefinitionItem> context.TransactionOutput.Should().BeEquivalentTo(new List<ServiceQualityDefinitionItem>
{ {

@ -1,5 +1,6 @@
using Recyclarr.Cli.Pipelines.Tags; using Recyclarr.Cli.Pipelines.Tags;
using Recyclarr.Cli.Pipelines.Tags.PipelinePhases; using Recyclarr.Cli.Pipelines.Tags.PipelinePhases;
using Recyclarr.Config.Models;
using Recyclarr.ServarrApi.Tag; using Recyclarr.ServarrApi.Tag;
namespace Recyclarr.Cli.Tests.Pipelines.Tags.PipelinePhases; namespace Recyclarr.Cli.Tests.Pipelines.Tags.PipelinePhases;
@ -20,7 +21,7 @@ public class TagTransactionPhaseTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo("one", "two"); context.TransactionOutput.Should().BeEquivalentTo("one", "two");
} }
@ -34,7 +35,7 @@ public class TagTransactionPhaseTest
ApiFetchOutput = Array.Empty<SonarrTag>() ApiFetchOutput = Array.Empty<SonarrTag>()
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEquivalentTo("one", "two", "three"); context.TransactionOutput.Should().BeEquivalentTo("one", "two", "three");
} }
@ -52,7 +53,7 @@ public class TagTransactionPhaseTest
} }
}; };
sut.Execute(context); sut.Execute(context, Substitute.For<IServiceConfiguration>());
context.TransactionOutput.Should().BeEmpty(); context.TransactionOutput.Should().BeEmpty();
} }

Loading…
Cancel
Save