diff --git a/CHANGELOG.md b/CHANGELOG.md index 20145ac6..58ce85a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove INF log that showed a total count of CFs without scores assigned. This log caused a lot of confusion in support channels. You can still see a list of CFs without scores in the debug logs. +- Relaxed validation rules for `trash_ids` and `quality_profiles` under `custom_formats`. Both of + these nodes may now be empty. This is mostly to make commenting out parts of configuration + templates easier. ## [5.4.2] - 2023-09-14 diff --git a/schemas/config/custom-formats.json b/schemas/config/custom-formats.json index f51e98a2..6164fd42 100644 --- a/schemas/config/custom-formats.json +++ b/schemas/config/custom-formats.json @@ -10,12 +10,16 @@ "required": ["trash_ids"], "properties": { "trash_ids": { - "$ref": "trash-ids.json" + "type": ["null", "array"], + "description": "A list of one or more Trash IDs taken from the Trash Guide JSON files.", + "uniqueItems": true, + "items": { + "type": "string" + } }, "quality_profiles": { - "type": "array", + "type": ["null", "array"], "description": "One or more quality profiles to update with the scores from the specified custom formats.", - "minItems": 1, "items": { "properties": { "name": { diff --git a/schemas/config/trash-ids.json b/schemas/config/trash-ids.json index f4555f38..82dacda8 100644 --- a/schemas/config/trash-ids.json +++ b/schemas/config/trash-ids.json @@ -2,14 +2,10 @@ "$schema": "http://json-schema.org/draft-07/schema", "$id": "https://raw.githubusercontent.com/recyclarr/recyclarr/master/schemas/config/trash-ids.json", "type": "array", - "description": "A list of one or more Trash IDs taken from the Trash Guide Sonarr JSON files.", + "description": "A list of one or more Trash IDs taken from the Trash Guide JSON files.", "minItems": 1, "uniqueItems": true, "items": { - "trash_id": { - "type": "string", - "minLength": 32, - "pattern": "^[0-9a-fA-F]+$" - } + "type": "string" } } diff --git a/src/Recyclarr.Cli/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhase.cs b/src/Recyclarr.Cli/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhase.cs index 35d8b3a5..7f938540 100644 --- a/src/Recyclarr.Cli/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhase.cs +++ b/src/Recyclarr.Cli/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhase.cs @@ -32,10 +32,9 @@ public class QualityProfileConfigPhase // 2. For each quality profile score config in that CF group // 3. For each CF in the group above, match it to a Guide CF object and pair it with the quality profile config var profileAndCfs = config.CustomFormats - .Where(x => x.QualityProfiles.IsNotEmpty()) .SelectMany(x => x.QualityProfiles - .Select(y => (Config: x, Profile: y))) - .SelectMany(x => x.Config.TrashIds + .Select(y => (Profile: y, x.TrashIds))) + .SelectMany(x => x.TrashIds .Select(_cache.LookupByTrashId) .NotNull() .Select(y => (x.Profile, Cf: y))); diff --git a/src/Recyclarr.TrashLib.Config/Parsing/ConfigYamlDataObjectsValidation.cs b/src/Recyclarr.TrashLib.Config/Parsing/ConfigYamlDataObjectsValidation.cs index 15ff7213..74e64345 100644 --- a/src/Recyclarr.TrashLib.Config/Parsing/ConfigYamlDataObjectsValidation.cs +++ b/src/Recyclarr.TrashLib.Config/Parsing/ConfigYamlDataObjectsValidation.cs @@ -40,14 +40,7 @@ public class CustomFormatConfigYamlValidator : AbstractValidator x.TrashIds).NotEmpty() - .When(x => x.TrashIds is not null) - .WithName("trash_ids") - .ForEach(x => x.Length(32).Matches(@"^[0-9a-fA-F]+$")); - - RuleForEach(x => x.QualityProfiles).NotEmpty() - .When(x => x.QualityProfiles is not null) - .WithName("quality_profiles") + RuleForEach(x => x.QualityProfiles) .SetValidator(new QualityScoreConfigYamlValidator()); } } diff --git a/src/tests/Recyclarr.Cli.Tests/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhaseTest.cs b/src/tests/Recyclarr.Cli.Tests/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhaseTest.cs index c7bb30f1..ac17634f 100644 --- a/src/tests/Recyclarr.Cli.Tests/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhaseTest.cs +++ b/src/tests/Recyclarr.Cli.Tests/Pipelines/QualityProfile/PipelinePhases/QualityProfileConfigPhaseTest.cs @@ -219,4 +219,49 @@ public class QualityProfileConfigPhaseTest }, o => o.Excluding(x => x.ShouldCreate)); } + + [Test, AutoMockData] + public void Empty_trash_ids_list_is_ignored( + [Frozen] ProcessedCustomFormatCache cache, + QualityProfileConfigPhase sut) + { + var config = SetupCfs(new CustomFormatConfig + { + TrashIds = Array.Empty(), + QualityProfiles = new List + { + new() + { + Name = "test_profile", + Score = 100 + } + } + }); + + var result = sut.Execute(config); + + result.Should().BeEmpty(); + } + + [Test, AutoMockData] + public void Empty_quality_profiles_is_ignored( + [Frozen] ProcessedCustomFormatCache cache, + QualityProfileConfigPhase sut) + { + cache.AddCustomFormats(new[] + { + NewCf.DataWithScore("", "id1", 101, 1), + NewCf.DataWithScore("", "id2", 201, 2) + }); + + var config = SetupCfs(new CustomFormatConfig + { + TrashIds = new[] {"id1", "id2"}, + QualityProfiles = Array.Empty() + }); + + var result = sut.Execute(config); + + result.Should().BeEmpty(); + } } diff --git a/src/tests/Recyclarr.TrashLib.Config.Tests/YamlConfigValidatorTest.cs b/src/tests/Recyclarr.TrashLib.Config.Tests/YamlConfigValidatorTest.cs index 06ce208d..9ebc2f43 100644 --- a/src/tests/Recyclarr.TrashLib.Config.Tests/YamlConfigValidatorTest.cs +++ b/src/tests/Recyclarr.TrashLib.Config.Tests/YamlConfigValidatorTest.cs @@ -144,39 +144,6 @@ public class YamlConfigValidatorTest : ConfigIntegrationFixture public static string FirstCf { get; } = $"{nameof(ServiceConfigYaml.CustomFormats)}[0]."; - [Test] - public void Validation_failure_when_cf_trash_ids_empty() - { - var config = new ServiceConfigYaml - { - ApiKey = "valid", - BaseUrl = "http://valid", - CustomFormats = new List - { - new() - { - TrashIds = Array.Empty(), - QualityProfiles = new List - { - new() - { - Name = "valid" - } - } - } - }, - QualityDefinition = new QualitySizeConfigYaml - { - Type = "valid" - } - }; - - var validator = Resolve(); - var result = validator.TestValidate(config); - - result.ShouldHaveValidationErrorFor(FirstCf + nameof(CustomFormatConfig.TrashIds)); - } - [Test] public void Validation_failure_when_quality_definition_type_empty() {