refactor: Add SonarCloud Analyzer and fix analysis warnings

pull/201/head
Robert Dailey 10 months ago
parent 8596168757
commit a6ceae65fc

@ -226,6 +226,12 @@ dotnet_diagnostic.ca1001.severity = none
dotnet_diagnostic.ca1032.severity = none
dotnet_diagnostic.ca1310.severity = none
# Jump statements should not be redundant
# https://rules.sonarsource.com/csharp/RSPEC-3626/
# Justification: Used by Resharper to separate local methods from logic
dotnet_diagnostic.s3626.severity = none
dotnet_diagnostic.s1751.severity = none
# ReSharper properties
resharper_accessor_owner_body = expression_body
resharper_alignment_tab_fill_style = use_spaces

@ -24,6 +24,7 @@
<PackageVersion Include="Serilog.Expressions" Version="3.4.1" />
<PackageVersion Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageVersion Include="SonarAnalyzer.CSharp" Version="9.7.0.75501" />
<PackageVersion Include="Spectre.Console" Version="0.47.0" />
<PackageVersion Include="Spectre.Console.Analyzer" Version="0.47.0" />
<PackageVersion Include="Spectre.Console.Cli" Version="0.47.0" />

@ -19,11 +19,11 @@ public class ProcessedCustomFormatCache : IPipelineCache
public CustomFormatData? LookupByTrashId(string trashId)
{
return _customFormats.FirstOrDefault(x => x.TrashId.EqualsIgnoreCase(trashId));
return _customFormats.Find(x => x.TrashId.EqualsIgnoreCase(trashId));
}
public CustomFormatData? LookupByServiceId(int id)
{
return _customFormats.FirstOrDefault(x => x.Id == id);
return _customFormats.Find(x => x.Id == id);
}
}

@ -37,12 +37,13 @@ public class QualityProfileStatCalculator
return stats;
}
private void ProfileUpdates(ProfileWithStats stats, QualityProfileDto newDto, QualityProfileDto oldDto)
private void ProfileUpdates(ProfileWithStats stats, QualityProfileDto oldDto, QualityProfileDto newDto)
{
Log("Upgrade Allowed", oldDto.UpgradeAllowed, newDto.UpgradeAllowed);
Log("Cutoff", oldDto.Items.FindCutoff(oldDto.Cutoff), newDto.Items.FindCutoff(newDto.Cutoff));
Log("Cutoff Score", oldDto.CutoffFormatScore, newDto.CutoffFormatScore);
Log("Minimum Score", oldDto.MinFormatScore, newDto.MinFormatScore);
return;
void Log<T>(string msg, T oldValue, T newValue)
@ -52,11 +53,10 @@ public class QualityProfileStatCalculator
}
}
private static void QualityUpdates(ProfileWithStats stats, QualityProfileDto newDto, QualityProfileDto oldDto)
private static void QualityUpdates(ProfileWithStats stats, QualityProfileDto oldDto, QualityProfileDto newDto)
{
var dtoQualities = JToken.FromObject(newDto.Items);
var updatedQualities = JToken.FromObject(oldDto.Items);
stats.QualitiesChanged = !JToken.DeepEquals(dtoQualities, updatedQualities);
stats.QualitiesChanged = !JToken.DeepEquals(
JToken.FromObject(oldDto.Items), JToken.FromObject(newDto.Items));
}
private void ScoreUpdates(

@ -52,7 +52,7 @@ public class ReleaseProfileTransactionPhase
.Where(sonarrProfile =>
{
return sonarrProfile.Name.StartsWithIgnoreCase("[Trash]") &&
!profiles.Any(profile => sonarrProfile.Name.EndsWithIgnoreCase(profile.Name));
!profiles.Exists(profile => sonarrProfile.Name.EndsWithIgnoreCase(profile.Name));
})
.ToList();
}

@ -14,8 +14,6 @@ public class TemplateConfigCreator : IConfigCreator
private readonly IConfigTemplateGuideService _templates;
private readonly IAppPaths _paths;
// private readonly IConfigManipulator _configManipulator;
// private readonly IAnsiConsole _console;
public TemplateConfigCreator(
ILogger log,
@ -25,8 +23,6 @@ public class TemplateConfigCreator : IConfigCreator
_log = log;
_templates = templates;
_paths = paths;
// _configManipulator = configManipulator;
// _console = console;
}
public bool CanHandle(ICreateConfigSettings settings)
@ -66,19 +62,6 @@ public class TemplateConfigCreator : IConfigCreator
{
_log.Information("Created configuration file: {Path}", destinationFile);
}
// -- See comment in ConfigManipulator.cs --
// _configManipulator.LoadAndSave(templateFile, destinationFile, (instanceName, config) =>
// {
// _console.MarkupLineInterpolated($"Enter configuration info for instance [green]{instanceName}[/]:");
// var baseUrl = _console.Prompt(new TextPrompt<string>("Base URL:"));
// var apiKey = _console.Prompt(new TextPrompt<string>("API Key:"));
// return config with
// {
// BaseUrl = baseUrl,
// ApiKey = apiKey
// };
// });
}
catch (FileExistsException e)
{

@ -13,6 +13,10 @@
<PackageReference Include="Serilog.Expressions" />
<PackageReference Include="Serilog.Sinks.Console" />
<PackageReference Include="Serilog.Sinks.File" />
<PackageReference Include="SonarAnalyzer.CSharp">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Spectre.Console.Analyzer" PrivateAssets="All" />
<PackageReference Include="Spectre.Console.Cli" />
<PackageReference Include="TestableIO.System.IO.Abstractions" />

@ -9,9 +9,8 @@ public class RuntimeValidationService : IRuntimeValidationService
private static Type? GetValidatorInterface(Type type)
{
return type.GetInterfaces()
.FirstOrDefault(i
=> i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>));
return Array.Find(type.GetInterfaces(),
i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IValidator<>));
}
public RuntimeValidationService(IEnumerable<IValidator> validators)

@ -1,7 +1,9 @@
using System.Diagnostics.CodeAnalysis;
using Flurl.Http.Configuration;
namespace Recyclarr.Common.Networking;
[SuppressMessage("SonarCloud", "S4830:Server certificates should be verified during SSL/TLS connections")]
public class UntrustedCertClientFactory : DefaultHttpClientFactory
{
public override HttpMessageHandler CreateMessageHandler()

@ -6,6 +6,10 @@
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Serilog" />
<PackageReference Include="SonarAnalyzer.CSharp">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Spectre.Console" />
<PackageReference Include="System.Reactive" />
<PackageReference Include="TestableIO.System.IO.Abstractions.Extensions" />

@ -5,7 +5,7 @@ namespace Recyclarr.Common;
public class ResourceDataReader : IResourceDataReader
{
private readonly Assembly? _assembly;
private readonly Assembly _assembly;
private readonly string? _namespace;
private readonly string _subdirectory;
@ -19,7 +19,8 @@ public class ResourceDataReader : IResourceDataReader
{
_subdirectory = subdirectory;
_namespace = typeWithNamespaceToUse.Namespace;
_assembly = Assembly.GetAssembly(typeWithNamespaceToUse);
_assembly = Assembly.GetAssembly(typeWithNamespaceToUse)
?? throw new ArgumentException("Cannot get assembly from type", nameof(typeWithNamespaceToUse));
}
public string ReadData(string filename)
@ -49,8 +50,7 @@ public class ResourceDataReader : IResourceDataReader
private string FindResourcePath(string resourcePath)
{
var foundResource = _assembly?.GetManifestResourceNames()
.FirstOrDefault(x => x.EndsWith(resourcePath));
var foundResource = Array.Find(_assembly.GetManifestResourceNames(), x => x.EndsWith(resourcePath));
if (foundResource is null)
{
throw new ArgumentException($"Embedded resource not found: {resourcePath}");
@ -61,7 +61,7 @@ public class ResourceDataReader : IResourceDataReader
private string GetResourceData(string resourcePath)
{
using var stream = _assembly?.GetManifestResourceStream(resourcePath);
using var stream = _assembly.GetManifestResourceStream(resourcePath);
if (stream is null)
{
throw new ArgumentException($"Unable to open embedded resource: {resourcePath}");

@ -14,6 +14,10 @@
<PackageReference Include="ReactiveUI.Blazor" />
<PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Sinks.File" />
<PackageReference Include="SonarAnalyzer.CSharp">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Recyclarr.Common;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
@ -5,6 +6,7 @@ using YamlDotNet.Serialization;
namespace Recyclarr.TrashLib.Config.EnvironmentVariables;
[SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty")]
public record EnvironmentVariableTag;
public class EnvironmentVariablesDeserializer : INodeDeserializer

@ -87,6 +87,7 @@ public record ReleaseProfileConfigYaml
// This is usually empty (or the same as ServiceConfigYaml) on purpose.
// If empty, it is kept around to make it clear that this one is dedicated to Radarr.
[SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty")]
public record RadarrConfigYaml : ServiceConfigYaml;
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]

@ -13,10 +13,6 @@ public class ServiceConfigYamlValidator : AbstractValidator<ServiceConfigYaml>
.WithMessage("{PropertyName} must start with 'http' or 'https'")
.WithName("base_url");
// RuleFor(x => x.BaseUrl)
// .When(x => x.BaseUrl is {Length: > 0}, ApplyConditionTo.CurrentValidator)
// .WithMessage("{PropertyName} must start with 'http' or 'https'");
RuleFor(x => x.ApiKey).NotEmpty().WithName("api_key");
RuleFor(x => x.CustomFormats)

@ -20,7 +20,7 @@ public sealed class SyntaxErrorHelper : INodeTypeResolver
// just says "no node type resolver could resolve the type", or something along those lines -- which isn't helpful!
private static void CheckSequenceAssignedToNonSequence(ParsingEvent? nodeEvent, MemberInfo currentType)
{
if (nodeEvent is SequenceStart && !CollectionKeywords.Any(x => currentType.Name.Contains(x)))
if (nodeEvent is SequenceStart && !Array.Exists(CollectionKeywords, x => currentType.Name.Contains(x)))
{
throw new YamlException(nodeEvent.Start, nodeEvent.End,
$"A list/array/sequence is not allowed for {currentType.Name}");

@ -1,9 +1,11 @@
using System.Diagnostics.CodeAnalysis;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Recyclarr.TrashLib.Config.Secrets;
[SuppressMessage("Minor Code Smell", "S2094:Classes should not be empty")]
public record SecretTag;
public class SecretsDeserializer : INodeDeserializer

@ -13,6 +13,10 @@
<PackageReference Include="JetBrains.Annotations" />
<PackageReference Include="Newtonsoft.Json.Schema" />
<PackageReference Include="Serilog" />
<PackageReference Include="SonarAnalyzer.CSharp">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="SuperLinq" />
<PackageReference Include="System.Data.HashFunction.FNV" />
<PackageReference Include="System.Private.Uri" />

Loading…
Cancel
Save