Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .agents/agents/sdk-consumer-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ Help a consuming repository adopt or troubleshoot `Purview.BuildSdk` correctly,
variables, `.git` root, or a nearby `package.json`. `UsePackageJsonVersion=Strict` fails fast instead of
silently skipping resolution.
4. If the bundled `.agents/**` content isn't appearing in the repo root, check `EnableAgentFolderInPackage`
(default `true`) and `AgentPackDestinationFolder` (default `.agents`) — the copy runs before build via
(default `true`) and `AgentPackDestinationFolder` (default `.agents`) - the copy runs before build via
`EnsureAgentFolderInPackageTarget`.
5. For test-framework or project-shape questions, confirm the project follows repo naming and placement
conventions the SDK expects, rather than introducing bespoke structure.
6. Re-run `dotnet build` (or the repo's canonical build command) after each configuration change to confirm
6. For naming, layout, and test readability questions, start from the engineering principles: naming and
placement are configuration, short project names are preferred, the detected test type becomes the baseline
category, and subject-based tests should be named for the subject they own.
7. Re-run `dotnet build` (or the repo's canonical build command) after each configuration change to confirm
the fix.

## Constraints
Expand All @@ -32,3 +35,4 @@ Help a consuming repository adopt or troubleshoot `Purview.BuildSdk` correctly,
## Related skill

See `../skills/sdk-configuration-reference/SKILL.md` for the full property reference.
See `../skills/sdk-engineering-principles/SKILL.md` for the higher-level repository conventions.
38 changes: 38 additions & 0 deletions .agents/agents/sdk-repository-rationaliser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# sdk-repository-rationaliser (generic agent spec)

## Goal

Help a repository move toward `Purview.BuildSdk` conventions without unnecessary churn.

## Workflow

1. Start by reading the repo's `Directory.Build.props`, `Directory.Build.targets`, solution entry point,
and current project layout.
2. Identify the current `NamespacePrefix`, project naming scheme, and test project suffixes in use.
3. Compare the repo's structure against the engineering principles:
- short project names
- source/test split where practical
- exact shared/shared-testing names when SDK behavior is expected
- readable, scalable test naming
4. Separate findings into three groups:
- already aligned
- misaligned but harmless
- misaligned and blocking SDK automatic behavior
5. Prefer the smallest sequence of changes that improves predictability without forcing broad renames.
6. When recommending test changes, preserve readable behavior-oriented suites while tightening subject-based
suites toward `{SubjectName}Tests` and `{SubjectOrMemberUnderTest}_{Scenario}_{Expectation}`.
7. Confirm whether specialized dependencies such as `TUnit.Aspire` or `Testcontainers` are genuinely needed
rather than treating them as universal defaults.

## Constraints

- Do not assume every older repo should be renamed wholesale.
- Preserve meaningful established structure unless it interferes with SDK inference.
- Prefer explaining the effect on `RootNamespace`, `AssemblyName`, `PackageId`, `TestingType`, and
`TargetProjectName` instead of arguing from taste.

## Related skills

- `../skills/sdk-engineering-principles/SKILL.md`
- `../skills/project-placement-defaults/SKILL.md`
- `../skills/sdk-project-behavior-and-detection/SKILL.md`
33 changes: 33 additions & 0 deletions .agents/prompts/sdk-review-repository-shape.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# sdk-review-repository-shape (generic prompt spec)

Review a repository that uses `Purview.BuildSdk` for naming, placement, and test-structure alignment.

## Required behaviour

1. Inspect the repository's `Directory.Build.props`, `Directory.Build.targets`, solution entry point, and
project layout before making assumptions.
2. Identify whether the repository follows the SDK-friendly structure:
- source projects under `src/`
- test projects under `tests/`
- `.csproj` filenames matching directory names
- short project names with `NamespacePrefix` carrying the repo identity
3. Check whether test project names use recognised `*Tests` suffixes and whether shared/shared-testing
projects use exact SDK-recognised names.
4. Explain the consequences of deviations in terms of automatic `RootNamespace`, `AssemblyName`,
`PackageId`, `TargetProjectName`, and automatic project references.
5. Review test readability conventions:
- subject-based `{SubjectName}Tests`
- subject-based `{SubjectOrMemberUnderTest}_{Scenario}_{Expectation}` method names
- non-subject-based suites named clearly for their broader role
- appropriate use of TUnit categories and display names
6. Distinguish between:
- acceptable existing variance worth preserving
- structural debt that blocks the SDK's automatic behavior
- incremental rationalisation opportunities

## Suggested output

- A concise summary of whether the repo broadly fits the SDK conventions.
- A list of concrete mismatches, ordered by impact.
- A list of low-risk rationalisation steps for naming, placement, identity, or test readability.
- Explicit note of which behaviors are already automatic defaults and which require manual configuration.
8 changes: 8 additions & 0 deletions .agents/skills/sdk-engineering-principles/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Ignore all files
*

# Don't ignore directories, so Git can traverse them
!*/

# Keep this file
!.gitignore
6 changes: 6 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# actionlint configuration. The WSLC integration workflow targets a self-hosted runner with a custom
# `wslc` label (a Windows x64 host with WSL Containers installed); declaring it here lets actionlint
# validate .github/workflows/integration-wsl.yml.
self-hosted-runner:
labels:
- wslc
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Keep product, architecture, and general engineering standards centralized in `AG
- Never weaken the WSLC session/store invariants (single shared session, serialised session mutations, the
shared-store fallback, `Secret` redaction) to make a test pass.
- Treat the published consumer contract as an invariant too: `.NET 11` + a Windows target framework,
the `buildTransitive` defaults, and the `PWC0001`/`PWC0002` guards documented in
the `buildTransitive` defaults, and the `PCC0001`/`PCC0002` guards documented in
`docs/wiki/Consumer-Requirements.md`. `just verify-consumers` must pass before a consumer-facing change
is complete.
- Consult the repository `.agents/` folder for additional skills/workflows that may improve execution
Expand Down
89 changes: 89 additions & 0 deletions .github/workflows/integration-wsl.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Integration (WSL Containers)

# Manual-only. The WSLC integration suites need a Windows host with WSL Containers installed, which no
# GitHub-hosted runner provides, so this job runs on a self-hosted Windows runner carrying the custom
# `wslc` label. It is deliberately not attached to pull_request or push: it is the deliberate, manual
# proof that the WSLC backend and every service module run on WSL Containers. The Docker half of the
# matrix runs on every pull request instead (see pr.yml, the `integration-docker` job) because it needs
# only a daemon and therefore works on a hosted Linux runner.
#
# Runner prerequisites are documented in docs/wiki/Testing.md.
on:
workflow_dispatch:
inputs:
ref:
description: Git ref (branch, tag or SHA) to test. Defaults to the ref this workflow is dispatched from.
required: false
default: ""
filter:
description: TUnit treenode filter. Defaults to every test.
required: false
default: "/*/*/*/*"

concurrency:
# Never cancel a WSLC run in flight: it owns a session and its image store.
group: ${{ github.workflow }}-${{ inputs.ref || github.ref }}
cancel-in-progress: false

jobs:
integration-wsl:
name: Integration (WSL Containers)
# A self-hosted Windows x64 runner with WSL Containers installed and the custom `wslc` label.
runs-on: [self-hosted, wslc]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}

- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
# Keep in sync with `sdk.version` in global.json (and the other workflows).
dotnet-version: "11.0.100-rc.1.26425.128"

- name: Verify the WSL Containers host
shell: pwsh
run: |
wsl --version
wslc version

- name: Restore
run: dotnet restore src/WSLTestContainers.slnx

- name: Build
run: dotnet build src/WSLTestContainers.slnx --configuration Release --no-restore

- name: WSLC backend contract
# Real containers on a shared WSLC session; ~27 tests and ~4 minutes.
run: dotnet test src/tests/Wsl.IntegrationTests/Wsl.IntegrationTests.csproj --configuration Release --no-build --treenode-filter '${{ inputs.filter }}'

- name: Service modules on WSLC
# Each module pulls its image and starts a real service. One project at a time keeps the shared
# WSLC image store uncontended (parallel sessions fail with 0x80070020). Every project runs so a
# single failure does not hide the rest, and the step fails at the end if any of them did.
shell: pwsh
run: |
$projects = @(
'src/tests/PostgreSql.IntegrationTests/PostgreSql.IntegrationTests.csproj',
'src/tests/Redis.IntegrationTests/Redis.IntegrationTests.csproj',
'src/tests/MsSql.IntegrationTests/MsSql.IntegrationTests.csproj',
'src/tests/MySql.IntegrationTests/MySql.IntegrationTests.csproj',
'src/tests/RabbitMq.IntegrationTests/RabbitMq.IntegrationTests.csproj',
'src/tests/Azurite.IntegrationTests/Azurite.IntegrationTests.csproj',
'src/tests/Nats.IntegrationTests/Nats.IntegrationTests.csproj'
)

$failed = @()
foreach ($project in $projects) {
Write-Host "::group::$project"
dotnet test $project --configuration Release --no-build --treenode-filter '${{ inputs.filter }}'
if ($LASTEXITCODE -ne 0) {
$failed += $project
}
Write-Host "::endgroup::"
}

if ($failed.Count -gt 0) {
throw "WSLC integration suites failed: $($failed -join ', ')"
}
19 changes: 19 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,22 @@ jobs:
run-pack: true
validate-pack: true
secrets: inherit

# The shared pipeline filters to [Category=Unit] because the WSLC integration suites need a Windows
# host. The Docker integration suites need only a Docker daemon, so they run here on the same Linux
# runner a consumer would use - the standing proof that the library and every service module work off
# Windows/WSL. The suites skip themselves when no daemon is reachable, so a non-zero result is a real
# failure, not a missing runtime.
integration-docker:
name: Integration (Docker)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
# Keep in sync with `sdk.version` in global.json.
dotnet-version: "11.0.100-rc.1.26425.128"
- name: Docker backend
run: dotnet test src/tests/Docker.IntegrationTests/Docker.IntegrationTests.csproj --configuration Release --treenode-filter '/*/*/*/*'
- name: Service modules on Docker
run: dotnet test src/tests/Modules.DockerIntegrationTests/Modules.DockerIntegrationTests.csproj --configuration Release --treenode-filter '/*/*/*/*'
Loading
Loading