fix: Regression caused reset_unmatched_scores: false to not be respected

pull/201/head
Robert Dailey 11 months ago
parent fd8a2f570b
commit d799da385e

@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Recyclarr will now continue if `git fetch` fails for any repos, so long as there is an existing, - Recyclarr will now continue if `git fetch` fails for any repos, so long as there is an existing,
valid clone to use. valid clone to use.
### Fixed
- Address regression causing `reset_unmatched_scores: false` to not be respected.
## [5.0.0] - 2023-06-22 ## [5.0.0] - 2023-06-22
This release contains **BREAKING CHANGES**. See the [v5.0 Upgrade Guide][breaking5] for required This release contains **BREAKING CHANGES**. See the [v5.0 Upgrade Guide][breaking5] for required

@ -32,7 +32,12 @@ public class QualityProfileApiPersistencePhase
private void LogQualityProfileUpdates(QualityProfileTransactionData transactions) private void LogQualityProfileUpdates(QualityProfileTransactionData transactions)
{ {
var updatedScores = transactions.UpdatedProfiles var updatedScores = transactions.UpdatedProfiles
.Select(x => (x.UpdatedProfile.Name, x.UpdatedScores)) .Select(x => (
ProfileName: x.UpdatedProfile.Name,
Scores: x.UpdatedScores
.Where(y => y.Reason != FormatScoreUpdateReason.New && y.Dto.Score != y.NewScore)
.ToList()))
.Where(x => x.Scores.Any())
.ToList(); .ToList();
if (updatedScores.Count > 0) if (updatedScores.Count > 0)
@ -50,7 +55,7 @@ public class QualityProfileApiPersistencePhase
_log.Information("Updated {ProfileCount} profiles and a total of {ScoreCount} scores", _log.Information("Updated {ProfileCount} profiles and a total of {ScoreCount} scores",
transactions.UpdatedProfiles.Count, transactions.UpdatedProfiles.Count,
updatedScores.Sum(s => s.UpdatedScores.Count)); updatedScores.Sum(s => s.Scores.Count));
} }
else else
{ {

@ -26,7 +26,7 @@ public class QualityProfilePreviewPhase
.AddColumn("[bold]New[/]") .AddColumn("[bold]New[/]")
.AddColumn("[bold]Reason[/]"); .AddColumn("[bold]Reason[/]");
foreach (var updatedScore in updatedScores.Where(x => x.Reason != FormatScoreUpdateReason.NoChange)) foreach (var updatedScore in updatedScores.Where(x => x.Dto.Score != x.NewScore))
{ {
table.AddRow( table.AddRow(
updatedScore.Dto.Name, updatedScore.Dto.Name,

@ -71,28 +71,31 @@ public class QualityProfileTransactionPhase
.FullJoin(profileDto.FormatItems, .FullJoin(profileDto.FormatItems,
x => x.FormatId, x => x.FormatId,
x => x.Format, x => x.Format,
// Exists in config, but not in service (these are unusual and should be errors)
// See `FormatScoreUpdateReason` for reason why we need this (it's preview mode)
l => new UpdatedFormatScore l => new UpdatedFormatScore
{ {
Dto = new ProfileFormatItemDto {Format = l.FormatId, Name = l.CfName}, Dto = new ProfileFormatItemDto {Format = l.FormatId, Name = l.CfName},
NewScore = l.Score, NewScore = l.Score,
Reason = FormatScoreUpdateReason.New Reason = FormatScoreUpdateReason.New
}, },
// Exists in service, but not in config
r => new UpdatedFormatScore r => new UpdatedFormatScore
{ {
Dto = r, Dto = r,
NewScore = 0, NewScore = profileData.Profile.ResetUnmatchedScores ? 0 : r.Score,
Reason = FormatScoreUpdateReason.Reset Reason = FormatScoreUpdateReason.Reset
}, },
// Exists in both service and config
(l, r) => new UpdatedFormatScore (l, r) => new UpdatedFormatScore
{ {
Dto = r, Dto = r,
NewScore = l.Score, NewScore = l.Score,
Reason = FormatScoreUpdateReason.Updated Reason = FormatScoreUpdateReason.Updated
}) })
.Select(x => x.Dto.Score == x.NewScore ? x with {Reason = FormatScoreUpdateReason.NoChange} : x)
.ToList(); .ToList();
return scoreMap.Any(x => x.Reason != FormatScoreUpdateReason.NoChange) return scoreMap.Any(x => x.Dto.Score != x.NewScore)
? new UpdatedQualityProfile(profileDto) {UpdatedScores = scoreMap} ? new UpdatedQualityProfile(profileDto) {UpdatedScores = scoreMap}
: null; : null;
} }

@ -4,11 +4,6 @@ namespace Recyclarr.Cli.Pipelines.QualityProfile;
public enum FormatScoreUpdateReason public enum FormatScoreUpdateReason
{ {
/// <summary>
/// A score who's value did not change.
/// </summary>
NoChange,
/// <summary> /// <summary>
/// A score that is changed. /// A score that is changed.
/// </summary> /// </summary>

@ -47,6 +47,6 @@ public record QualityDefinitionConfig
public record QualityProfileConfig public record QualityProfileConfig
{ {
public bool? ResetUnmatchedScores { get; init; } public bool ResetUnmatchedScores { get; init; }
public string Name { get; init; } = ""; public string Name { get; init; } = "";
} }

@ -11,12 +11,12 @@ public static class NewQp
string profileName, string profileName,
params (string TrashId, int FormatId, int Score)[] scores) params (string TrashId, int FormatId, int Score)[] scores)
{ {
return Processed(profileName, null, scores); return Processed(profileName, false, scores);
} }
public static ProcessedQualityProfileData Processed( public static ProcessedQualityProfileData Processed(
string profileName, string profileName,
bool? resetUnmatchedScores, bool resetUnmatchedScores,
params (string TrashId, int FormatId, int Score)[] scores) params (string TrashId, int FormatId, int Score)[] scores)
{ {
return Processed(profileName, resetUnmatchedScores, return Processed(profileName, resetUnmatchedScores,
@ -25,7 +25,7 @@ public static class NewQp
public static ProcessedQualityProfileData Processed( public static ProcessedQualityProfileData Processed(
string profileName, string profileName,
bool? resetUnmatchedScores, bool resetUnmatchedScores,
params (string CfName, string TrashId, int FormatId, int Score)[] scores) params (string CfName, string TrashId, int FormatId, int Score)[] scores)
{ {
return new ProcessedQualityProfileData(new QualityProfileConfig return new ProcessedQualityProfileData(new QualityProfileConfig

@ -151,7 +151,7 @@ public class QualityProfileTransactionPhaseTest
} }
[Test, AutoMockData] [Test, AutoMockData]
public void Reset_scores( public void Reset_scores_with_reset_unmatched_true(
QualityProfileTransactionPhase sut) QualityProfileTransactionPhase sut)
{ {
var guideData = new[] var guideData = new[]
@ -194,4 +194,48 @@ public class QualityProfileTransactionPhaseTest
NewQp.UpdatedScore("quality4", 0, 500, FormatScoreUpdateReason.New) NewQp.UpdatedScore("quality4", 0, 500, FormatScoreUpdateReason.New)
}, o => o.Excluding(x => x.Dto.Format)); }, o => o.Excluding(x => x.Dto.Format));
} }
[Test, AutoMockData]
public void Reset_scores_with_reset_unmatched_false(QualityProfileTransactionPhase sut)
{
var guideData = new[]
{
NewQp.Processed("profile1", false, ("quality3", "id3", 3, 100), ("quality4", "id4", 4, 500))
};
var serviceData = new[]
{
new QualityProfileDto
{
Name = "profile1",
FormatItems = new[]
{
new ProfileFormatItemDto
{
Name = "quality1",
Format = 1,
Score = 200
},
new ProfileFormatItemDto
{
Name = "quality2",
Format = 2,
Score = 300
}
}
}
};
var result = sut.Execute(guideData, serviceData);
result.UpdatedProfiles.Should()
.ContainSingle().Which.UpdatedScores.Should()
.BeEquivalentTo(new[]
{
NewQp.UpdatedScore("quality1", 200, 200, FormatScoreUpdateReason.Reset),
NewQp.UpdatedScore("quality2", 300, 300, FormatScoreUpdateReason.Reset),
NewQp.UpdatedScore("quality3", 0, 100, FormatScoreUpdateReason.New),
NewQp.UpdatedScore("quality4", 0, 500, FormatScoreUpdateReason.New)
}, o => o.Excluding(x => x.Dto.Format));
}
} }

Loading…
Cancel
Save