From b01fd495b5b6d0e12f4a1ef28a901762523703e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Feb 2026 00:14:35 +0000 Subject: [PATCH 1/2] Initial plan From 6ce0fefc21b961a94c47b2f4b4888c05efdc1805 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 21 Feb 2026 00:21:44 +0000 Subject: [PATCH 2/2] fix: address PR review feedback - validator tests, Issue init-only, IssueRepository, exception middleware, squad-ci Co-authored-by: mpaulosky <60372079+mpaulosky@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 10 +++------- src/Api/Data/IssueRepository.cs | 6 +++++- src/Api/Program.cs | 18 ++++++++++++++++++ src/Shared/Domain/Issue.cs | 12 ++++++------ .../ListIssuesQueryValidatorTests.cs | 4 ++-- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 42a433b..7684856 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -19,10 +19,6 @@ jobs: - name: Build and test run: | - # TODO: Add your dotnet build/test commands here - # Go: go test ./... - # Python: pip install -r requirements.txt && pytest - # .NET: dotnet test - # Java (Maven): mvn test - # Java (Gradle): ./gradlew test - echo "No build commands configured — update squad-ci.yml" + dotnet restore + dotnet build --no-restore --configuration Release + dotnet test --no-build --configuration Release diff --git a/src/Api/Data/IssueRepository.cs b/src/Api/Data/IssueRepository.cs index d7d02c7..c07a2ca 100644 --- a/src/Api/Data/IssueRepository.cs +++ b/src/Api/Data/IssueRepository.cs @@ -138,6 +138,8 @@ internal class IssueEntity [BsonElement("updatedAt")] public DateTime UpdatedAt { get; set; } public bool IsArchived { get; set; } + public string? ArchivedBy { get; set; } + public DateTime? ArchivedAt { get; set; } public List? Labels { get; set; } public static IssueEntity FromDomain(Issue issue) @@ -161,7 +163,9 @@ public Issue ToDomain() Id: Id, Title: Title, Description: Description, - Status: Enum.Parse(Status), + Status: Enum.TryParse(Status, ignoreCase: true, out var parsedStatus) + ? parsedStatus + : IssueStatus.Open, CreatedAt: CreatedAt, UpdatedAt: UpdatedAt, Labels: Labels?.Select(l => new Label(l.Name, l.Color)).ToList() diff --git a/src/Api/Program.cs b/src/Api/Program.cs index f326659..266e4d0 100644 --- a/src/Api/Program.cs +++ b/src/Api/Program.cs @@ -34,6 +34,24 @@ var app = builder.Build(); +app.UseExceptionHandler(errorApp => errorApp.Run(async context => +{ + var ex = context.Features.Get()?.Error; + if (ex is FluentValidation.ValidationException validationEx) + { + context.Response.StatusCode = StatusCodes.Status400BadRequest; + context.Response.ContentType = "application/problem+json"; + var errors = validationEx.Errors + .GroupBy(e => e.PropertyName) + .ToDictionary(g => g.Key, g => g.Select(e => e.ErrorMessage).ToArray()); + await context.Response.WriteAsJsonAsync(new { title = "Validation failed", errors }); + } + else + { + context.Response.StatusCode = StatusCodes.Status500InternalServerError; + } +})); + app.UseHttpsRedirection(); app.MapOpenApi(); diff --git a/src/Shared/Domain/Issue.cs b/src/Shared/Domain/Issue.cs index 6ab2001..2c1e70f 100644 --- a/src/Shared/Domain/Issue.cs +++ b/src/Shared/Domain/Issue.cs @@ -102,17 +102,17 @@ public Issue Update(string title, string? description) } /// - /// Gets or sets a value indicating whether the issue is archived (soft-deleted). + /// Gets a value indicating whether the issue is archived (soft-deleted). /// - public bool IsArchived { get; set; } = false; + public bool IsArchived { get; init; } = false; /// - /// Gets or sets the user who archived the issue. + /// Gets the user who archived the issue. /// - public string? ArchivedBy { get; set; } + public string? ArchivedBy { get; init; } /// - /// Gets or sets the timestamp when the issue was archived. + /// Gets the timestamp when the issue was archived. /// - public DateTime? ArchivedAt { get; set; } + public DateTime? ArchivedAt { get; init; } } diff --git a/tests/Unit/Validators/ListIssuesQueryValidatorTests.cs b/tests/Unit/Validators/ListIssuesQueryValidatorTests.cs index 8e32400..92512fa 100644 --- a/tests/Unit/Validators/ListIssuesQueryValidatorTests.cs +++ b/tests/Unit/Validators/ListIssuesQueryValidatorTests.cs @@ -62,7 +62,7 @@ public void ListIssuesQueryValidator_PageZero_ReturnsValidationError() result.IsValid.Should().BeFalse(); result.Errors.Should().HaveCount(1); result.Errors[0].PropertyName.Should().Be("Page"); - result.Errors[0].ErrorMessage.Should().Contain("greater than 0"); + result.Errors[0].ErrorMessage.Should().Contain("greater than or equal to 1"); } [Fact] @@ -100,7 +100,7 @@ public void ListIssuesQueryValidator_PageSizeZero_ReturnsValidationError() result.IsValid.Should().BeFalse(); result.Errors.Should().HaveCount(1); result.Errors[0].PropertyName.Should().Be("PageSize"); - result.Errors[0].ErrorMessage.Should().Contain("greater than 0"); + result.Errors[0].ErrorMessage.Should().Contain("between 1 and 100"); } [Fact]