Skip to content

Commit 047ea5f

Browse files
authored
Process execution and parsing for easy integration of cli tools (#61)
* Add ProcessUtils library with process handling and execution APIs Introduce a new `CreativeCoders.ProcessUtils` library to provide process handling and execution abstractions. Features include `IProcess` interface, `DefaultProcess` implementation, process factories, executors, and output parsers (e.g., JSON, strings). Update solution file to include the new project. * Add comprehensive C# development guidelines and unit tests for ProcessUtils library - Introduced detailed C# coding standards and development practices, covering naming conventions, formatting, project structure, and more. - Included new unit tests for `ProcessExecutor` in the `CreativeCoders.ProcessUtils` library to validate synchronous and asynchronous process execution, output parsing, and proper disposal. - Updated test project references to include `CreativeCoders.ProcessUtils`. * Update C# testing guidelines and include new projects in solution - Add guidelines for using `AwesomeAssertions`, `xUnit`, and `FakeItEasy` in C# testing. - Update solution file to include new organizational folders (`__ai`, `copilot`, `junie`) and related Markdown files. * Add unit tests for ProcessExecutor and improve testing guidelines - Added tests for `ProcessExecutor` covering synchronous and asynchronous behavior, including output parsing and process disposal. - Updated C# testing guidelines to recommend the Arrange-Act-Assert pattern. * Remove `StringListOutputParser` and add unit tests for JSON, line-splitting, and passthrough output parsers - Deleted unused `StringListOutputParser` implementation. - Added `SplitLinesOutputParser` class for processing output into trimmed, split lines. - Added thorough unit tests for `JsonOutputParser`, `SplitLinesOutputParser`, and `PassThroughProcessOutputParser`. - Enhanced `ProcessExecutorBuilder` to automatically configure output parsing with improved exception handling. - Applied [PublicAPI] annotations across `IProcess`, `IProcessExecutor`, and related interfaces for better IDE support. * Update C# testing guidelines and refactor unit tests - Updated C# testing guidelines to enforce the Arrange-Act-Assert pattern and added comments for clarity. - Refactored `PassThroughProcessOutputParserTests`, `JsonOutputParserTests`, and `SplitLinesOutputParserTests` to adhere to the updated pattern. - Added annotations and suppression attributes for better IDE integration and readability. - Revised test inputs to improve consistency and maintainability. * Add `ProcessUtilsSampleApp` project and enhance DI extensions for `ProcessUtils` - Introduced the `ProcessUtilsSampleApp` project showcasing usage of `ProcessExecutor` and output parsers. - Updated `CreativeCoders.ProcessUtils` library with `AddProcessUtils` DI extensions for streamlined service registration. - Included the new sample application and references in the solution file. * Add extensive unit tests for `ProcessExecutor` and enhance `CreativeCoders.ProcessUtils` - Added comprehensive unit tests for `ProcessExecutor`, including synchronous and asynchronous methods, output parsing, exit code validation, and process disposal. - Introduced `ProcessExecutionResult` for encapsulating processes and results with proper disposal. - Refactored existing implementations to improve code readability and align with testing best practices. - Applied minor formatting updates across classes and sample projects for consistency. * Add unit tests for `AddProcessUtils` and update namespaces for `ProcessUtils` tests - Added comprehensive tests for `AddProcessUtils` to verify DI registrations, lifetimes, idempotency, and TryAdd semantics. - Refactored and updated namespaces for `ProcessUtils` tests to improve organizational structure and align with the project's conventions.
1 parent 9a5355f commit 047ea5f

33 files changed

Lines changed: 2362 additions & 2 deletions

.github/csharp.instructions.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
description: 'Guidelines for building C# applications'
3+
applyTo: '**/*.cs'
4+
---
5+
6+
# C# Development
7+
8+
## C# Instructions
9+
- Always use the latest version C#, currently C# 14 features.
10+
- Write clear and concise comments for each function.
11+
12+
## General Instructions
13+
- Make only high confidence suggestions when reviewing code changes.
14+
- Write code with good maintainability practices, including comments on why certain design decisions were made.
15+
- Handle edge cases and write clear exception handling.
16+
- For libraries or external dependencies, mention their usage and purpose in comments.
17+
18+
## Naming Conventions
19+
20+
- Follow PascalCase for component names, method names, and public members.
21+
- Use camelCase for private fields and local variables.
22+
- Prefix interface names with "I" (e.g., IUserService).
23+
24+
## Formatting
25+
26+
- Apply code-formatting style defined in `.editorconfig`.
27+
- Prefer file-scoped namespace declarations and single-line using directives.
28+
- Insert a newline before the opening curly brace of any code block (e.g., after `if`, `for`, `while`, `foreach`, `using`, `try`, etc.).
29+
- Ensure that the final return statement of a method is on its own line.
30+
- Use pattern matching and switch expressions wherever possible.
31+
- Use `nameof` instead of string literals when referring to member names.
32+
- Ensure that XML doc comments are created for any public APIs. When applicable, include `<example>` and `<code>` documentation in the comments.
33+
34+
## Project Setup and Structure
35+
36+
- Guide users through creating a new .NET project with the appropriate templates.
37+
- Explain the purpose of each generated file and folder to build understanding of the project structure.
38+
- Demonstrate how to organize code using feature folders or domain-driven design principles.
39+
- Show proper separation of concerns with models, services, and data access layers.
40+
- Explain the Program.cs and configuration system in ASP.NET Core 10 including environment-specific settings.
41+
42+
## Nullable Reference Types
43+
44+
- Declare variables non-nullable, and check for `null` at entry points.
45+
- Always use `is null` or `is not null` instead of `== null` or `!= null`.
46+
- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null.
47+
48+
## Data Access Patterns
49+
50+
- Guide the implementation of a data access layer using Entity Framework Core.
51+
- Explain different options (SQL Server, SQLite, In-Memory) for development and production.
52+
- Demonstrate repository pattern implementation and when it's beneficial.
53+
- Show how to implement database migrations and data seeding.
54+
- Explain efficient query patterns to avoid common performance issues.
55+
56+
## Authentication and Authorization
57+
58+
- Guide users through implementing authentication using JWT Bearer tokens.
59+
- Explain OAuth 2.0 and OpenID Connect concepts as they relate to ASP.NET Core.
60+
- Show how to implement role-based and policy-based authorization.
61+
- Demonstrate integration with Microsoft Entra ID (formerly Azure AD).
62+
- Explain how to secure both controller-based and Minimal APIs consistently.
63+
64+
## Validation and Error Handling
65+
66+
- Guide the implementation of model validation using data annotations and FluentValidation.
67+
- Explain the validation pipeline and how to customize validation responses.
68+
- Demonstrate a global exception handling strategy using middleware.
69+
- Show how to create consistent error responses across the API.
70+
- Explain problem details (RFC 7807) implementation for standardized error responses.
71+
72+
## API Versioning and Documentation
73+
74+
- Guide users through implementing and explaining API versioning strategies.
75+
- Demonstrate Swagger/OpenAPI implementation with proper documentation.
76+
- Show how to document endpoints, parameters, responses, and authentication.
77+
- Explain versioning in both controller-based and Minimal APIs.
78+
- Guide users on creating meaningful API documentation that helps consumers.
79+
80+
## Logging and Monitoring
81+
82+
- Guide the implementation of structured logging using Serilog or other providers.
83+
- Explain the logging levels and when to use each.
84+
- Demonstrate integration with Application Insights for telemetry collection.
85+
- Show how to implement custom telemetry and correlation IDs for request tracking.
86+
- Explain how to monitor API performance, errors, and usage patterns.
87+
88+
## Testing
89+
90+
- Always include test cases for critical paths of the application.
91+
- Guide users through creating unit tests.
92+
- Do not emit "Act", "Arrange" or "Assert" comments.
93+
- Copy existing style in nearby files for test method names and capitalization.
94+
- Explain integration testing approaches for API endpoints.
95+
- Demonstrate how to mock dependencies for effective testing.
96+
- Show how to test authentication and authorization logic.
97+
- Explain test-driven development principles as applied to API development.
98+
- Use awesomeassertions for asserting expected results.
99+
- Use xUnit for unit testing.
100+
- Use FakeItEasy for mocking dependencies.
101+
- Always separate a test method into the blocks Arrange, Act and Assert. Mark this blocks with comments.
102+
103+
## Performance Optimization
104+
105+
- Guide users on implementing caching strategies (in-memory, distributed, response caching).
106+
- Explain asynchronous programming patterns and why they matter for API performance.
107+
- Demonstrate pagination, filtering, and sorting for large data sets.
108+
- Show how to implement compression and other performance optimizations.
109+
- Explain how to measure and benchmark API performance.
110+
111+
## Deployment and DevOps
112+
113+
- Guide users through containerizing their API using .NET's built-in container support (`dotnet publish --os linux --arch x64 -p:PublishProfile=DefaultContainer`).
114+
- Explain the differences between manual Dockerfile creation and .NET's container publishing features.
115+
- Explain CI/CD pipelines for NET applications.
116+
- Demonstrate deployment to Azure App Service, Azure Container Apps, or other hosting options.
117+
- Show how to implement health checks and readiness probes.
118+
- Explain environment-specific configurations for different deployment stages.

.junie/guidelines.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
description: 'Guidelines for building C# applications'
3+
applyTo: '**/*.cs'
4+
---
5+
6+
# C# Development
7+
8+
## C# Instructions
9+
- Always use the latest version C#, currently C# 14 features.
10+
- Write clear and concise comments for each function.
11+
12+
## General Instructions
13+
- Make only high confidence suggestions when reviewing code changes.
14+
- Write code with good maintainability practices, including comments on why certain design decisions were made.
15+
- Handle edge cases and write clear exception handling.
16+
- For libraries or external dependencies, mention their usage and purpose in comments.
17+
18+
## Naming Conventions
19+
20+
- Follow PascalCase for component names, method names, and public members.
21+
- Use camelCase for private fields and local variables.
22+
- Prefix interface names with "I" (e.g., IUserService).
23+
24+
## Formatting
25+
26+
- Apply code-formatting style defined in `.editorconfig`.
27+
- Prefer file-scoped namespace declarations and single-line using directives.
28+
- Insert a newline before the opening curly brace of any code block (e.g., after `if`, `for`, `while`, `foreach`, `using`, `try`, etc.).
29+
- Ensure that the final return statement of a method is on its own line.
30+
- Use pattern matching and switch expressions wherever possible.
31+
- Use `nameof` instead of string literals when referring to member names.
32+
- Ensure that XML doc comments are created for any public APIs. When applicable, include `<example>` and `<code>` documentation in the comments.
33+
34+
## Project Setup and Structure
35+
36+
- Guide users through creating a new .NET project with the appropriate templates.
37+
- Explain the purpose of each generated file and folder to build understanding of the project structure.
38+
- Demonstrate how to organize code using feature folders or domain-driven design principles.
39+
- Show proper separation of concerns with models, services, and data access layers.
40+
- Explain the Program.cs and configuration system in ASP.NET Core 10 including environment-specific settings.
41+
42+
## Nullable Reference Types
43+
44+
- Declare variables non-nullable, and check for `null` at entry points.
45+
- Always use `is null` or `is not null` instead of `== null` or `!= null`.
46+
- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null.
47+
48+
## Data Access Patterns
49+
50+
- Guide the implementation of a data access layer using Entity Framework Core.
51+
- Explain different options (SQL Server, SQLite, In-Memory) for development and production.
52+
- Demonstrate repository pattern implementation and when it's beneficial.
53+
- Show how to implement database migrations and data seeding.
54+
- Explain efficient query patterns to avoid common performance issues.
55+
56+
## Authentication and Authorization
57+
58+
- Guide users through implementing authentication using JWT Bearer tokens.
59+
- Explain OAuth 2.0 and OpenID Connect concepts as they relate to ASP.NET Core.
60+
- Show how to implement role-based and policy-based authorization.
61+
- Demonstrate integration with Microsoft Entra ID (formerly Azure AD).
62+
- Explain how to secure both controller-based and Minimal APIs consistently.
63+
64+
## Validation and Error Handling
65+
66+
- Guide the implementation of model validation using data annotations and FluentValidation.
67+
- Explain the validation pipeline and how to customize validation responses.
68+
- Demonstrate a global exception handling strategy using middleware.
69+
- Show how to create consistent error responses across the API.
70+
- Explain problem details (RFC 7807) implementation for standardized error responses.
71+
72+
## API Versioning and Documentation
73+
74+
- Guide users through implementing and explaining API versioning strategies.
75+
- Demonstrate Swagger/OpenAPI implementation with proper documentation.
76+
- Show how to document endpoints, parameters, responses, and authentication.
77+
- Explain versioning in both controller-based and Minimal APIs.
78+
- Guide users on creating meaningful API documentation that helps consumers.
79+
80+
## Logging and Monitoring
81+
82+
- Guide the implementation of structured logging using Serilog or other providers.
83+
- Explain the logging levels and when to use each.
84+
- Demonstrate integration with Application Insights for telemetry collection.
85+
- Show how to implement custom telemetry and correlation IDs for request tracking.
86+
- Explain how to monitor API performance, errors, and usage patterns.
87+
88+
## Testing
89+
90+
- Always include test cases for critical paths of the application.
91+
- Guide users through creating unit tests.
92+
- Do not emit "Act", "Arrange" or "Assert" comments.
93+
- Copy existing style in nearby files for test method names and capitalization.
94+
- Explain integration testing approaches for API endpoints.
95+
- Demonstrate how to mock dependencies for effective testing.
96+
- Show how to test authentication and authorization logic.
97+
- Explain test-driven development principles as applied to API development.
98+
- Use awesomeassertions for asserting expected results.
99+
- Use xUnit for unit testing.
100+
- Use FakeItEasy for mocking dependencies.
101+
- Always separate a test method into the blocks Arrange, Act and Assert. Mark this blocks with comments.
102+
103+
## Performance Optimization
104+
105+
- Guide users on implementing caching strategies (in-memory, distributed, response caching).
106+
- Explain asynchronous programming patterns and why they matter for API performance.
107+
- Demonstrate pagination, filtering, and sorting for large data sets.
108+
- Show how to implement compression and other performance optimizations.
109+
- Explain how to measure and benchmark API performance.
110+
111+
## Deployment and DevOps
112+
113+
- Guide users through containerizing their API using .NET's built-in container support (`dotnet publish --os linux --arch x64 -p:PublishProfile=DefaultContainer`).
114+
- Explain the differences between manual Dockerfile creation and .NET's container publishing features.
115+
- Explain CI/CD pipelines for NET applications.
116+
- Demonstrate deployment to Azure App Service, Azure Container Apps, or other hosting options.
117+
- Show how to implement health checks and readiness probes.
118+
- Explain environment-specific configurations for different deployment stages.

Core.sln

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,24 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreativeCoders.Options.Stor
219219
EndProject
220220
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreativeCoders.Options.Serializers", "source\Options\CreativeCoders.Options.Serializers\CreativeCoders.Options.Serializers.csproj", "{3140873A-7C79-408F-B7F2-C51980EFF0C4}"
221221
EndProject
222+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProcessUtils", "ProcessUtils", "{DD74AD8A-E88F-479A-82CE-32F818BE438D}"
223+
EndProject
224+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreativeCoders.ProcessUtils", "source\ProcessUtils\CreativeCoders.ProcessUtils\CreativeCoders.ProcessUtils.csproj", "{A26B77F8-EA82-4E04-ABE4-2CFB660CA323}"
225+
EndProject
226+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__ai", "__ai", "{FCD8D558-7F1F-4D2E-B2EA-DE412BCEE1F7}"
227+
EndProject
228+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "copilot", "copilot", "{7EA4E4D9-BC5F-401A-A143-99816D46ABC2}"
229+
ProjectSection(SolutionItems) = preProject
230+
.github\csharp.instructions.md = .github\csharp.instructions.md
231+
EndProjectSection
232+
EndProject
233+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "junie", "junie", "{6CAB0BC8-210F-4AFF-902F-91F3BFF64CC8}"
234+
ProjectSection(SolutionItems) = preProject
235+
.junie\guidelines.md = .junie\guidelines.md
236+
EndProjectSection
237+
EndProject
238+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessUtilsSampleApp", "samples\ProcessUtilsSampleApp\ProcessUtilsSampleApp.csproj", "{58E94E6E-9A9A-4E3F-ACB5-89E47CE67C39}"
239+
EndProject
222240
Global
223241
GlobalSection(SolutionConfigurationPlatforms) = preSolution
224242
Debug|Any CPU = Debug|Any CPU
@@ -519,6 +537,14 @@ Global
519537
{3140873A-7C79-408F-B7F2-C51980EFF0C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
520538
{3140873A-7C79-408F-B7F2-C51980EFF0C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
521539
{3140873A-7C79-408F-B7F2-C51980EFF0C4}.Release|Any CPU.Build.0 = Release|Any CPU
540+
{A26B77F8-EA82-4E04-ABE4-2CFB660CA323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
541+
{A26B77F8-EA82-4E04-ABE4-2CFB660CA323}.Debug|Any CPU.Build.0 = Debug|Any CPU
542+
{A26B77F8-EA82-4E04-ABE4-2CFB660CA323}.Release|Any CPU.ActiveCfg = Release|Any CPU
543+
{A26B77F8-EA82-4E04-ABE4-2CFB660CA323}.Release|Any CPU.Build.0 = Release|Any CPU
544+
{58E94E6E-9A9A-4E3F-ACB5-89E47CE67C39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
545+
{58E94E6E-9A9A-4E3F-ACB5-89E47CE67C39}.Debug|Any CPU.Build.0 = Debug|Any CPU
546+
{58E94E6E-9A9A-4E3F-ACB5-89E47CE67C39}.Release|Any CPU.ActiveCfg = Release|Any CPU
547+
{58E94E6E-9A9A-4E3F-ACB5-89E47CE67C39}.Release|Any CPU.Build.0 = Release|Any CPU
522548
EndGlobalSection
523549
GlobalSection(SolutionProperties) = preSolution
524550
HideSolutionNode = FALSE
@@ -617,6 +643,11 @@ Global
617643
{70C54624-CAE5-4ED6-A087-88CD1470E2B7} = {23126211-23BF-4399-A227-6C609FB7505E}
618644
{83F2F98D-4C23-404F-9D06-B744C87E6EF1} = {23126211-23BF-4399-A227-6C609FB7505E}
619645
{3140873A-7C79-408F-B7F2-C51980EFF0C4} = {23126211-23BF-4399-A227-6C609FB7505E}
646+
{DD74AD8A-E88F-479A-82CE-32F818BE438D} = {2A7105AA-05B6-469A-93F5-719723A4D90D}
647+
{A26B77F8-EA82-4E04-ABE4-2CFB660CA323} = {DD74AD8A-E88F-479A-82CE-32F818BE438D}
648+
{7EA4E4D9-BC5F-401A-A143-99816D46ABC2} = {FCD8D558-7F1F-4D2E-B2EA-DE412BCEE1F7}
649+
{6CAB0BC8-210F-4AFF-902F-91F3BFF64CC8} = {FCD8D558-7F1F-4D2E-B2EA-DE412BCEE1F7}
650+
{58E94E6E-9A9A-4E3F-ACB5-89E47CE67C39} = {72E179CA-7AE6-412A-856D-7BD13838E8E3}
620651
EndGlobalSection
621652
GlobalSection(ExtensibilityGlobals) = postSolution
622653
SolutionGuid = {EE24476B-9A4C-4146-B982-3461FAF8B3B0}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0"/>
11+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0"/>
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<ProjectReference Include="..\..\source\DependencyInjection\CreativeCoders.DependencyInjection\CreativeCoders.DependencyInjection.csproj"/>
16+
<ProjectReference Include="..\..\source\ProcessUtils\CreativeCoders.ProcessUtils\CreativeCoders.ProcessUtils.csproj"/>
17+
</ItemGroup>
18+
19+
</Project>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using CreativeCoders.Core.Collections;
2+
using CreativeCoders.DependencyInjection;
3+
using CreativeCoders.ProcessUtils;
4+
using CreativeCoders.ProcessUtils.Execution;
5+
using CreativeCoders.ProcessUtils.Execution.Parsers;
6+
using Microsoft.Extensions.DependencyInjection;
7+
8+
namespace ProcessUtilsSampleApp;
9+
10+
internal static class Program
11+
{
12+
private static void Main(string[] args)
13+
{
14+
var services = new ServiceCollection() as IServiceCollection;
15+
16+
services.AddObjectFactory();
17+
18+
services.AddProcessUtils();
19+
20+
var sp = services.BuildServiceProvider();
21+
22+
var factory = sp.GetRequiredService<IObjectFactory>();
23+
24+
var builder = factory.GetInstance<IProcessExecutorBuilder<string[]>>();
25+
26+
var executor = builder
27+
.SetFileName("defaults")
28+
.SetArguments(["domains"])
29+
.SetOutputParser<SplitLinesOutputParser>(x =>
30+
{
31+
x.SplitOptions = StringSplitOptions.RemoveEmptyEntries;
32+
x.Separators = [","];
33+
x.TrimLines = true;
34+
})
35+
.Build();
36+
37+
var lines = executor.Execute();
38+
39+
lines?.Order().ForEach(x => Console.WriteLine(x));
40+
41+
Console.ReadLine();
42+
}
43+
}

source/DependencyInjection/CreativeCoders.DependencyInjection/DefaultObjectFactory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ internal class DefaultObjectFactory<T> : IObjectFactory<T>
88

99
public DefaultObjectFactory(IObjectFactory objectFactory)
1010
{
11-
_objectFactory = Ensure.NotNull(objectFactory, nameof(objectFactory));
11+
_objectFactory = Ensure.NotNull(objectFactory);
1212
}
1313

1414
public T GetInstance()
@@ -28,7 +28,7 @@ internal class DefaultObjectFactory : IObjectFactory
2828

2929
public DefaultObjectFactory(IServiceProvider serviceProvider)
3030
{
31-
_serviceProvider = Ensure.NotNull(serviceProvider, nameof(serviceProvider));
31+
_serviceProvider = Ensure.NotNull(serviceProvider);
3232
}
3333

3434
public T GetInstance<T>()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<ProjectReference Include="..\..\Core\CreativeCoders.Core\CreativeCoders.Core.csproj" />
11+
</ItemGroup>
12+
13+
</Project>

0 commit comments

Comments
 (0)