diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 9adfa48..1e9786b 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -46,7 +46,8 @@ "Restore", "SetupTestcontainers", "Test", - "UnitTests" + "UnitTests", + "Verify" ] }, "Verbosity": { diff --git a/Directory.Build.props b/Directory.Build.props index ae80255..8702b6e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,9 +1,17 @@ - - - - true - + + + + $(WarningsNotAsErrors); + AL0025;AL0026;AL0039;AL0070;AL0081;AL0101;AL0114;AL0137; + RS0030; + CA1002;CA1032;CA1034;CA1052;CA1056;CA1307;CA1725;CA1819;CA1822;CA1823;CA1852;CA1859; + CA2000;CA2012;CA2201;CA5394; + IDE0370;IDE1006 + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 025dfae..783c3bd 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,6 +4,9 @@ true + + true @@ -36,9 +39,7 @@ - - - + @@ -73,6 +74,13 @@ + + + + diff --git a/Paperless.Contracts/Paperless.Contracts.csproj b/Paperless.Contracts/Paperless.Contracts.csproj index d7dbfaa..e18270b 100644 --- a/Paperless.Contracts/Paperless.Contracts.csproj +++ b/Paperless.Contracts/Paperless.Contracts.csproj @@ -1,10 +1,6 @@ - + - net10.0 - preview - enable - enable Paperless.Contracts diff --git a/PaperlessREST.Tests/Integration/DocumentRepositoryIntegrationTests.cs b/PaperlessREST.Tests/Integration/DocumentRepositoryIntegrationTests.cs index ce4e7d1..7698d0a 100644 --- a/PaperlessREST.Tests/Integration/DocumentRepositoryIntegrationTests.cs +++ b/PaperlessREST.Tests/Integration/DocumentRepositoryIntegrationTests.cs @@ -312,11 +312,11 @@ public async Task GetDocumentsPagedAsync_ReturnsNewestFirst() // Add documents with slight delays to ensure distinct GUIDv7s Document oldest = new DocumentBuilder().WithFileName($"{testPrefix}-old.pdf").Build(); await _repository.AddAsync(oldest, TestContext.Current.CancellationToken); - await Task.Delay(10); + await Task.Delay(10, TestContext.Current.CancellationToken); Document middle = new DocumentBuilder().WithFileName($"{testPrefix}-mid.pdf").Build(); await _repository.AddAsync(middle, TestContext.Current.CancellationToken); - await Task.Delay(10); + await Task.Delay(10, TestContext.Current.CancellationToken); Document newest = new DocumentBuilder().WithFileName($"{testPrefix}-new.pdf").Build(); await _repository.AddAsync(newest, TestContext.Current.CancellationToken); @@ -345,7 +345,7 @@ public async Task GetDocumentsPagedAsync_RespectsPageSize() await _repository.AddAsync( new DocumentBuilder().WithFileName($"{testPrefix}-{i}.pdf").Build(), TestContext.Current.CancellationToken); - await Task.Delay(5); // Ensure distinct GUIDv7s + await Task.Delay(5, TestContext.Current.CancellationToken); // Ensure distinct GUIDv7s } // Act @@ -369,7 +369,7 @@ public async Task GetDocumentsPagedAsync_WithCursor_ReturnsNextPage() Document doc = new DocumentBuilder().WithFileName($"{testPrefix}-{i}.pdf").Build(); Document added = await _repository.AddAsync(doc, TestContext.Current.CancellationToken); addedDocs.Add(added); - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); } // Act - Get first page @@ -400,7 +400,7 @@ public async Task GetDocumentsPagedAsync_LastPage_HasMoreIsFalse() await _repository.AddAsync( new DocumentBuilder().WithFileName($"{testPrefix}-{i}.pdf").Build(), TestContext.Current.CancellationToken); - await Task.Delay(5); + await Task.Delay(5, TestContext.Current.CancellationToken); } // Act - Request more than available diff --git a/PaperlessREST.Tests/PaperlessREST.Tests.csproj b/PaperlessREST.Tests/PaperlessREST.Tests.csproj index fe6afbc..4602ec5 100644 --- a/PaperlessREST.Tests/PaperlessREST.Tests.csproj +++ b/PaperlessREST.Tests/PaperlessREST.Tests.csproj @@ -1,30 +1,22 @@ - + - net10.0 - preview - enable - enable - Exe - false + true + + true PaperlessREST.Tests true - true - - true - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/PaperlessREST.Tests/Unit/DocumentServiceErrorMappingTests.cs b/PaperlessREST.Tests/Unit/DocumentServiceErrorMappingTests.cs index 9cf3226..9a9993c 100644 --- a/PaperlessREST.Tests/Unit/DocumentServiceErrorMappingTests.cs +++ b/PaperlessREST.Tests/Unit/DocumentServiceErrorMappingTests.cs @@ -37,7 +37,7 @@ public async Task UploadDocumentAsync_StorageTimeout_ReturnsStorageTimeoutError( DocumentService sut = CreateSut(); // Act - ErrorOr result = await sut.UploadDocumentAsync(request); + ErrorOr result = await sut.UploadDocumentAsync(request, TestContext.Current.CancellationToken); // Assert result.IsError.Should().BeTrue(); @@ -57,7 +57,7 @@ public async Task UploadDocumentAsync_Storage500_ReturnsStorageServerError() DocumentService sut = CreateSut(); // Act - ErrorOr result = await sut.UploadDocumentAsync(request); + ErrorOr result = await sut.UploadDocumentAsync(request, TestContext.Current.CancellationToken); // Assert result.IsError.Should().BeTrue(); @@ -80,7 +80,7 @@ public async Task UploadDocumentAsync_StorageConnectionRefused_ReturnsStorageCon DocumentService sut = CreateSut(); // Act - ErrorOr result = await sut.UploadDocumentAsync(request); + ErrorOr result = await sut.UploadDocumentAsync(request, TestContext.Current.CancellationToken); // Assert result.IsError.Should().BeTrue(); diff --git a/PaperlessREST/Features/BatchProcessing/Application/ReportProcessor.cs b/PaperlessREST/Features/BatchProcessing/Application/ReportProcessor.cs index 6ce11ff..455989f 100644 --- a/PaperlessREST/Features/BatchProcessing/Application/ReportProcessor.cs +++ b/PaperlessREST/Features/BatchProcessing/Application/ReportProcessor.cs @@ -6,7 +6,7 @@ public sealed class ReportProcessor( ILogger logger) : IReportProcessor { private const string SchemaFileName = "accessReport.xsd"; - private static readonly XmlSerializer Serializer = new(typeof(AccessReportDto)); + private static readonly XmlSerializer s_serializer = new(typeof(AccessReportDto)); private XmlSchemaSet Schemas => field ??= LoadSchemas(); @@ -89,7 +89,7 @@ private XmlSchemaSet LoadSchemas() }; using XmlReader reader = XmlReader.Create(stream, settings); - AccessReportDto dto = (AccessReportDto)Serializer.Deserialize(reader)!; + AccessReportDto dto = (AccessReportDto)s_serializer.Deserialize(reader)!; if (validationErrors.Count > 0) { diff --git a/PaperlessREST/Features/DocumentManagement/Application/Document.cs b/PaperlessREST/Features/DocumentManagement/Application/Document.cs index 0553cd7..d79e24b 100644 --- a/PaperlessREST/Features/DocumentManagement/Application/Document.cs +++ b/PaperlessREST/Features/DocumentManagement/Application/Document.cs @@ -77,6 +77,7 @@ public sealed class Document /// Creates a new instance from an uploaded file. /// /// The original filename of the uploaded PDF. + /// Provides the UTC timestamp recorded on ; inject for testability. /// A new in status. /// /// This factory method initializes a document with: diff --git a/PaperlessREST/Features/DocumentManagement/Application/DocumentService.cs b/PaperlessREST/Features/DocumentManagement/Application/DocumentService.cs index 3245c7a..ba50d6d 100644 --- a/PaperlessREST/Features/DocumentManagement/Application/DocumentService.cs +++ b/PaperlessREST/Features/DocumentManagement/Application/DocumentService.cs @@ -245,6 +245,6 @@ await Task.WhenAll( "Document.StorageConnectionFailed", $"Cannot connect to storage service for {storagePath}"), - _ => null! + _ => null }; } diff --git a/PaperlessREST/Host/Extensions/ServiceCollectionExtensions.cs b/PaperlessREST/Host/Extensions/ServiceCollectionExtensions.cs index a569f66..7f57ab0 100644 --- a/PaperlessREST/Host/Extensions/ServiceCollectionExtensions.cs +++ b/PaperlessREST/Host/Extensions/ServiceCollectionExtensions.cs @@ -220,7 +220,7 @@ private IServiceCollection AddInfrastructure(IConfiguration config) private IServiceCollection AddPostgres(IConfiguration config) { - NpgsqlDataSource dataSource = new NpgsqlDataSourceBuilder(config.GetConnectionString("PaperlessDb")!) + NpgsqlDataSource dataSource = new NpgsqlDataSourceBuilder(config.GetConnectionString("PaperlessDb")) .MapEnum("document_status") .Build(); diff --git a/PaperlessREST/Host/Extensions/TypedErrorOrAsyncExtensions.cs b/PaperlessREST/Host/Extensions/TypedErrorOrAsyncExtensions.cs index ea1bfd4..b3705ae 100644 --- a/PaperlessREST/Host/Extensions/TypedErrorOrAsyncExtensions.cs +++ b/PaperlessREST/Host/Extensions/TypedErrorOrAsyncExtensions.cs @@ -5,9 +5,6 @@ namespace PaperlessREST.Host.Extensions; /// public static class TypedErrorOrAsyncExtensions { - private static readonly NotFound NotFound = TypedResults.NotFound(); - private static readonly NoContent NoContent = TypedResults.NoContent(); - private static ValidationProblem CreateValidationProblem(IReadOnlyList errors) => TypedResults.ValidationProblem( errors.Where(e => e.Type == ErrorType.Validation) @@ -79,7 +76,7 @@ public async Task, NotFound>> ToOkOr404( } return result.FirstError.Type == ErrorType.NotFound - ? NotFound + ? TypedResults.NotFound() : throw ContractViolationException.ForNotFoundOnly(result.FirstError, result.Errors, callerName); } @@ -126,11 +123,11 @@ public async Task> ToNoContentOr404([CallerMemberNa if (!result.IsError) { - return NoContent; + return TypedResults.NoContent(); } return result.FirstError.Type == ErrorType.NotFound - ? NotFound + ? TypedResults.NotFound() : throw ContractViolationException.ForNotFoundOnly(result.FirstError, result.Errors, callerName); } } diff --git a/PaperlessREST/PaperlessREST.csproj b/PaperlessREST/PaperlessREST.csproj index 2c553e9..dcd9e21 100644 --- a/PaperlessREST/PaperlessREST.csproj +++ b/PaperlessREST/PaperlessREST.csproj @@ -1,17 +1,8 @@ - + - net10.0 - enable - enable - true - preview Linux - true - true - latest - true - $(NoWarn);1591 + false diff --git a/PaperlessServices.Tests/PaperlessServices.Tests.csproj b/PaperlessServices.Tests/PaperlessServices.Tests.csproj index 3062150..a395a45 100644 --- a/PaperlessServices.Tests/PaperlessServices.Tests.csproj +++ b/PaperlessServices.Tests/PaperlessServices.Tests.csproj @@ -1,23 +1,14 @@ - + - net10.0 - preview - enable - enable + + true Exe - false - true - - true - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/PaperlessServices/Features/OcrProcessing/Infrastructure/Search/SearchIndexService.cs b/PaperlessServices/Features/OcrProcessing/Infrastructure/Search/SearchIndexService.cs index 4d18e00..5f6fa04 100644 --- a/PaperlessServices/Features/OcrProcessing/Infrastructure/Search/SearchIndexService.cs +++ b/PaperlessServices/Features/OcrProcessing/Infrastructure/Search/SearchIndexService.cs @@ -17,8 +17,8 @@ public class SearchIndexService( ILogger logger) : ISearchIndexService { - private static readonly SemaphoreSlim SInitLock = new(1, 1); - private static readonly ConcurrentDictionary SInitializedIndices = new(); + private static readonly SemaphoreSlim s_initLock = new(1, 1); + private static readonly ConcurrentDictionary s_initializedIndices = new(); /// /// Indexes a document in Elasticsearch after OCR processing completes. @@ -77,16 +77,16 @@ private async Task InitializeAsync(CancellationToken cancellationToken = default string indexName = options.Value.DefaultIndex; // Fast path: index already initialized - if (SInitializedIndices.ContainsKey(indexName)) + if (s_initializedIndices.ContainsKey(indexName)) { return; } - await SInitLock.WaitAsync(cancellationToken); + await s_initLock.WaitAsync(cancellationToken); try { // Double-check after acquiring lock - if (SInitializedIndices.ContainsKey(indexName)) + if (s_initializedIndices.ContainsKey(indexName)) { return; } @@ -94,7 +94,7 @@ private async Task InitializeAsync(CancellationToken cancellationToken = default ExistsResponse existsResponse = await elastic.Indices.ExistsAsync(indexName, cancellationToken); if (existsResponse.Exists) { - SInitializedIndices.TryAdd(indexName, true); + s_initializedIndices.TryAdd(indexName, true); return; } @@ -113,11 +113,11 @@ private async Task InitializeAsync(CancellationToken cancellationToken = default logger.LogInformation("Created Elasticsearch index: {IndexName}", indexName); } - SInitializedIndices.TryAdd(indexName, true); + s_initializedIndices.TryAdd(indexName, true); } finally { - SInitLock.Release(); + s_initLock.Release(); } } } diff --git a/PaperlessServices/PaperlessServices.csproj b/PaperlessServices/PaperlessServices.csproj index 3a6ce16..145c700 100644 --- a/PaperlessServices/PaperlessServices.csproj +++ b/PaperlessServices/PaperlessServices.csproj @@ -1,17 +1,23 @@ - + - net10.0 - enable - enable + Exe paperless-services - true - preview + false + + + + + + + + diff --git a/PaperlessUI.Angular/PaperlessUI.Angular.esproj b/PaperlessUI.Angular/PaperlessUI.Angular.esproj index 83b6915..31323fc 100644 --- a/PaperlessUI.Angular/PaperlessUI.Angular.esproj +++ b/PaperlessUI.Angular/PaperlessUI.Angular.esproj @@ -1,11 +1,49 @@ - + + + + - pnpm run start - src\ - Jasmine - - false - - $(MSBuildProjectDirectory)\dist\paperless-ui-angular + $(MSBuildProjectDirectory)/ + pnpm + $(FrontendRoot)dist/paperless-ui-angular + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PaperlessUI.Blazor/PaperlessUI.Blazor.csproj b/PaperlessUI.Blazor/PaperlessUI.Blazor.csproj index b5f6af0..c349c29 100644 --- a/PaperlessUI.Blazor/PaperlessUI.Blazor.csproj +++ b/PaperlessUI.Blazor/PaperlessUI.Blazor.csproj @@ -1,10 +1,8 @@ - + - net10.0 - enable - enable true + false diff --git a/PaperlessUI.React/PaperlessUI.React.esproj b/PaperlessUI.React/PaperlessUI.React.esproj index 6e996bb..2c91422 100644 --- a/PaperlessUI.React/PaperlessUI.React.esproj +++ b/PaperlessUI.React/PaperlessUI.React.esproj @@ -1,11 +1,50 @@ - + + + + - pnpm run dev - src\ - Vitest - - false - - $(MSBuildProjectDirectory)\dist + $(MSBuildProjectDirectory)/ + pnpm + $(FrontendRoot)dist + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pipeline/Build.csproj b/Pipeline/Build.csproj index 1662874..91e0794 100644 --- a/Pipeline/Build.csproj +++ b/Pipeline/Build.csproj @@ -27,6 +27,11 @@ + + + diff --git a/global.json b/global.json index 400edd5..8b810e1 100644 --- a/global.json +++ b/global.json @@ -3,6 +3,11 @@ "version": "10.0.203", "rollForward": "latestFeature" }, + "msbuild-sdks": { + "ANcpLua.NET.Sdk": "3.4.27", + "ANcpLua.NET.Sdk.Web": "3.4.27", + "ANcpLua.NET.Sdk.Test": "3.4.27" + }, "test": { "runner": "Microsoft.Testing.Platform" }