From c0dac1b36b60cff724b6ba8d08df0fdad95672ae Mon Sep 17 00:00:00 2001 From: Logan Bussell Date: Mon, 6 Apr 2026 13:55:44 -0700 Subject: [PATCH 1/4] Add basic agent skill validation setup --- .github/skills/AGENTS.md | 24 ++++++++ .github/skills/ValidateSkill.cs | 100 ++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 .github/skills/AGENTS.md create mode 100755 .github/skills/ValidateSkill.cs diff --git a/.github/skills/AGENTS.md b/.github/skills/AGENTS.md new file mode 100644 index 000000000000..0b022c9eba26 --- /dev/null +++ b/.github/skills/AGENTS.md @@ -0,0 +1,24 @@ +# Agent Skills + +When creating skills, follow: +- Agent skills specification: https://agentskills.io/specification.md +- Best practices: https://agentskills.io/skill-creation/best-practices.md + +## Structure + +``` +.github/skills/skill-name/ +├── SKILL.md # Required: metadata + instructions +├── scripts/ # Optional: executable code +├── references/ # Optional: documentation +├── assets/ # Optional: templates, resources +└── ... # Any additional files or directories +``` + +## Quick Checklist + +- [ ] Run `dotnet .github/skills/ValidateSkill.cs ` to validate format. +- [ ] `description` describes what the skill does and when to use it. Skill body does not include "When to use this skill". +- [ ] Skill does not explain things the agent already knows. Focus on what's specific to the task at hand. +- [ ] Deterministic processes use scripts (for example, to fetch and format data from an API). +- [ ] Scripts use PowerShell or .NET file-based apps, not bash. diff --git a/.github/skills/ValidateSkill.cs b/.github/skills/ValidateSkill.cs new file mode 100755 index 000000000000..52809ef48e90 --- /dev/null +++ b/.github/skills/ValidateSkill.cs @@ -0,0 +1,100 @@ +#!/usr/bin/env dotnet +#:property ManagePackageVersionsCentrally=false +#:property PublishAot=false +#:package YamlDotNet@16.3.0 + +using YamlDotNet.Serialization; +using System.Text.RegularExpressions; + +if (args.Length == 0) +{ + Console.Error.WriteLine("Usage: dotnet ValidateSkill.cs "); + return 1; +} + +string skillDir = Path.GetFullPath(args[0]); +string skillName = Path.GetFileName(skillDir); +string skillFile = Path.Combine(skillDir, "SKILL.md"); + +// SKILL.md must exist in the skill directory +if (!File.Exists(skillFile)) +{ + Console.Error.WriteLine($"SKILL.md not found in {skillDir}"); + return 1; +} + +string text = File.ReadAllText(skillFile); + +// SKILL.md must begin with YAML frontmatter delimited by --- +if (!text.StartsWith("---")) +{ + Console.Error.WriteLine("No YAML frontmatter found."); + return 1; +} + +int endIndex = text.IndexOf("---", 3); +if (endIndex < 0) +{ + Console.Error.WriteLine("Unterminated YAML frontmatter."); + return 1; +} + +string yaml = text.Substring(3, endIndex - 3).Trim(); + +IDeserializer deserializer = new DeserializerBuilder().Build(); +Dictionary frontmatter = deserializer.Deserialize>(yaml); + +// name is required +if (!frontmatter.TryGetValue("name", out object? nameValue) || nameValue is not string frontmatterName) +{ + Console.Error.WriteLine("Frontmatter missing 'name' field."); + return 1; +} + +// name must be 1-64 characters +if (frontmatterName.Length == 0 || frontmatterName.Length > 64) +{ + Console.Error.WriteLine($"Name is {frontmatterName.Length} chars (must be 1-64)."); + return 1; +} + +// name: lowercase alphanumeric and hyphens only, no leading/trailing/consecutive hyphens +if (!Regex.IsMatch(frontmatterName, @"^[a-z0-9]([a-z0-9-]*[a-z0-9])?$") + || frontmatterName.Contains("--")) +{ + Console.Error.WriteLine($"Invalid name '{frontmatterName}'. Must be lowercase letters, numbers, and hyphens only. Must not start/end with a hyphen or contain consecutive hyphens."); + return 1; +} + +// name must match the parent directory name +if (!string.Equals(skillName, frontmatterName, StringComparison.Ordinal)) +{ + Console.Error.WriteLine($"Name mismatch: directory is '{skillName}' but SKILL.md name is '{frontmatterName}'."); + return 1; +} + +// description is required +if (!frontmatter.TryGetValue("description", out object? descValue) || descValue is not string description) +{ + Console.Error.WriteLine("Frontmatter missing 'description' field."); + return 1; +} + +// description must be 1-1024 characters +if (description.Length > 1024) +{ + Console.Error.WriteLine($"Description is {description.Length} chars (max 1024)."); + return 1; +} + +// Keep SKILL.md under 500 lines; move detailed content to references/ or scripts/ +// See "Progressive Disclosure" at https://agentskills.io/specification.md +int lineCount = text.Split('\n').Length; +if (lineCount > 500) +{ + Console.Error.WriteLine($"SKILL.md is {lineCount} lines (max 500). See \"Progressive Disclosure\" at https://agentskills.io/specification.md"); + return 1; +} + +Console.WriteLine($"Skill '{frontmatterName}' is valid."); +return 0; From 63b07552eaa680926a3f6357f65e427c71ee0c3d Mon Sep 17 00:00:00 2001 From: Logan Bussell Date: Mon, 6 Apr 2026 14:04:57 -0700 Subject: [PATCH 2/4] Rework incremental-test skill --- .github/copilot-instructions.md | 4 +- .github/copilot/skills/incremental-test.md | 104 ------------------ .github/skills/incremental-test/SKILL.md | 65 +++++++++++ .../scripts/Copy-ToRedist.ps1 | 88 +++++++++++++++ 4 files changed, 155 insertions(+), 106 deletions(-) delete mode 100644 .github/copilot/skills/incremental-test.md create mode 100644 .github/skills/incremental-test/SKILL.md create mode 100644 .github/skills/incremental-test/scripts/Copy-ToRedist.ps1 diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 5cb5d96045cd..54b0cbfa788d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -21,10 +21,10 @@ Testing: - Examples: - `dotnet test test/dotnet.Tests/dotnet.Tests.csproj --filter "Name~ItShowsTheAppropriateMessageToTheUser"` - `dotnet exec artifacts/bin/redist/Debug/dotnet.Tests.dll -method "*ItShowsTheAppropriateMessageToTheUser*"` -- For incremental test runs of `dotnet.Tests` (avoids slow full `build.cmd`), see the skill at `.github/copilot/skills/incremental-test.md`. In short: build only the modified projects, copy their output DLLs into the redist SDK layout, then run the tests. +- For incremental test runs of `dotnet.Tests` (avoids slow full `build.cmd`), use the `incremental-test` skill. - To test CLI command changes: - Build the redist SDK: `./build.sh` from repo root - - Create a dogfood environment: `source eng/dogfood.sh` + - Create a dogfood environment: `source eng/dogfood.sh` - Test commands in the dogfood shell (e.g., `dnx --help`, `dotnet tool install --help`) - The dogfood script sets up PATH and environment to use the newly built SDK diff --git a/.github/copilot/skills/incremental-test.md b/.github/copilot/skills/incremental-test.md deleted file mode 100644 index a15c42f6cd28..000000000000 --- a/.github/copilot/skills/incremental-test.md +++ /dev/null @@ -1,104 +0,0 @@ -# Incremental Test Runner for dotnet.Tests - -This skill enables fast incremental test runs of `dotnet.Tests` without a full `build.cmd` rebuild. -Use it after making source code changes to quickly build only the modified projects and deploy their outputs into the redist SDK layout so tests can run against them. - -## Prerequisites - -- A full build must have been completed at least once (via `build.cmd` or `build.sh`) so that the redist SDK layout exists at `artifacts\bin\redist\Debug\dotnet\sdk\\`. -- This workflow uses Windows/PowerShell commands and paths. On macOS/Linux, substitute forward slashes and use `cp` instead of `Copy-Item`. - -## When to use - -Use this skill when you need to run `dotnet.Tests` after modifying source code in one or more SDK projects. It avoids the slow full `build.cmd` by only rebuilding the changed projects and copying their output DLLs into the redist layout. - -## Workflow - -### Step 1: Identify modified projects - -Determine which projects have been modified. Use context from: -- The files you just edited in this session. -- Or `git status`/`git diff` to find changed `.cs` files and map them to their `.csproj` projects. - -### Step 2: Build modified projects - -Build each modified project individually using the repo-local dotnet: - -``` -.\.dotnet\dotnet build -c Debug -``` - -For example: -``` -.\.dotnet\dotnet build src\Cli\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj -c Debug -``` - -If the `dotnet` CLI project itself was modified, build it: -``` -.\.dotnet\dotnet build src\Cli\dotnet\dotnet.csproj -c Debug -``` - -### Step 3: Copy output DLLs to the redist SDK layout - -Discover the SDK version directory name: -```powershell -$sdkVersion = (Get-ChildItem artifacts\bin\redist\Debug\dotnet\sdk -Directory | Sort-Object LastWriteTime -Descending | Select-Object -First 1).Name -``` - -For each modified project, copy its output DLL (and any satellite assemblies) from the project's build output to the redist SDK directory: - -``` -Source: artifacts\bin\\Debug\net10.0\.dll -Target: artifacts\bin\redist\Debug\dotnet\sdk\\ -``` - -For example: -```powershell -Copy-Item artifacts\bin\Microsoft.DotNet.ProjectTools\Debug\net10.0\Microsoft.DotNet.ProjectTools.dll artifacts\bin\redist\Debug\dotnet\sdk\$sdkVersion\ -Copy-Item artifacts\bin\Microsoft.DotNet.Cli.Utils\Debug\net10.0\Microsoft.DotNet.Cli.Utils.dll artifacts\bin\redist\Debug\dotnet\sdk\$sdkVersion\ -``` - -The `dotnet` project is special — it builds into `artifacts\bin\dotnet\Debug\net10.0\` and its `dotnet.dll` must be copied to the SDK directory: -```powershell -Copy-Item artifacts\bin\dotnet\Debug\net10.0\dotnet.dll artifacts\bin\redist\Debug\dotnet\sdk\$sdkVersion\ -``` - -**Important notes:** -- For typical incremental edits, only copy DLLs that are **already present** in the target directory. If your change introduces a new shipped assembly or moves assemblies, you will need a full `build.cmd`/`build.sh` to update the layout correctly. -- Some projects multi-target (e.g., `net10.0` and `net472`). Always use the `net10.0` output. -- If localization resource DLLs were changed (in subdirectories like `cs\`, `de\`, etc.), copy those too. - -### Step 4: Build the test project (if test code was modified) - -The test project `test\dotnet.Tests\dotnet.Tests.csproj` outputs directly to `artifacts\bin\redist\Debug\` (via `TestHostFolder`), so just build it: - -``` -.\.dotnet\dotnet build test\dotnet.Tests\dotnet.Tests.csproj -``` - -### Step 5: Run the tests - -Run specific tests: -``` -.\.dotnet\dotnet exec artifacts\bin\redist\Debug\dotnet.Tests.dll -method "*TestMethodName*" -``` - -Or run filtered tests via `dotnet test`: -``` -.\.dotnet\dotnet test test\dotnet.Tests\dotnet.Tests.csproj --no-build --filter "Name~TestMethodName" -``` - -## Common project paths - -| Assembly | Project Path | -|---|---| -| `dotnet.dll` | `src\Cli\dotnet\dotnet.csproj` | -| `Microsoft.DotNet.Cli.Utils.dll` | `src\Cli\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj` | -| `Microsoft.DotNet.Cli.Definitions.dll` | `src\Cli\Microsoft.DotNet.Cli.Definitions\Microsoft.DotNet.Cli.Definitions.csproj` | -| `Microsoft.DotNet.Cli.CoreUtils.dll` | `src\Cli\Microsoft.DotNet.Cli.CoreUtils\Microsoft.DotNet.Cli.CoreUtils.csproj` | -| `Microsoft.DotNet.Configurer.dll` | `src\Cli\Microsoft.DotNet.Configurer\Microsoft.DotNet.Configurer.csproj` | -| `Microsoft.DotNet.ProjectTools.dll` | `src\Microsoft.DotNet.ProjectTools\Microsoft.DotNet.ProjectTools.csproj` | -| `Microsoft.DotNet.NativeWrapper.dll` | `src\Resolvers\Microsoft.DotNet.NativeWrapper\Microsoft.DotNet.NativeWrapper.csproj` | -| `Microsoft.DotNet.TemplateLocator.dll` | `src\Microsoft.DotNet.TemplateLocator\Microsoft.DotNet.TemplateLocator.csproj` | -| `Microsoft.DotNet.InternalAbstractions.dll` | `src\Cli\Microsoft.DotNet.InternalAbstractions\Microsoft.DotNet.InternalAbstractions.csproj` | -| `dotnet.Tests.dll` | `test\dotnet.Tests\dotnet.Tests.csproj` | diff --git a/.github/skills/incremental-test/SKILL.md b/.github/skills/incremental-test/SKILL.md new file mode 100644 index 000000000000..24d40bc57a60 --- /dev/null +++ b/.github/skills/incremental-test/SKILL.md @@ -0,0 +1,65 @@ +--- +name: incremental-test +description: >- + Run dotnet.Tests incrementally without a full build.cmd rebuild. Use after + modifying source code in SDK projects to quickly build only changed projects, + deploy their outputs into the redist SDK layout, and run tests against them. +--- + +# Incremental Test Runner for dotnet.Tests + +## Prerequisites + +A full build must have been completed at least once (`build.cmd` or `build.sh`) so the redist SDK layout exists at `artifacts/bin/redist/Debug/dotnet/sdk//`. + +## Workflow + +### Step 1: Build modified projects + +Build each modified project using the repo-local dotnet: + +``` +./.dotnet/dotnet build -c Debug +``` + +### Step 2: Copy outputs to the redist SDK layout + +Run the copy script with the project names (matching the directory names under `artifacts/bin/`): + +```pwsh +scripts/Copy-ToRedist.ps1 [ ...] +``` + +For example, after modifying `Microsoft.DotNet.Cli.Utils` and `dotnet`: + +```pwsh +scripts/Copy-ToRedist.ps1 Microsoft.DotNet.Cli.Utils dotnet +``` + +The script discovers the SDK version directory, copies only DLLs that are already present in the redist layout, and handles satellite resource assemblies. + +### Step 3: Build the test project (if test code was modified) + +``` +./.dotnet/dotnet build test/dotnet.Tests/dotnet.Tests.csproj +``` + +This project outputs directly to `artifacts/bin/redist/Debug/` via `TestHostFolder`. + +### Step 4: Run the tests + +``` +./.dotnet/dotnet exec artifacts/bin/redist/Debug/dotnet.Tests.dll -method "*TestMethodName*" +``` + +Or via `dotnet test`: + +``` +./.dotnet/dotnet test test/dotnet.Tests/dotnet.Tests.csproj --no-build --filter "Name~TestMethodName" +``` + +## Gotchas + +- Only DLLs **already present** in the redist layout are copied. If your change introduces a new shipped assembly, run a full `build.cmd`/`build.sh` instead. +- Multi-targeting projects (e.g., `net10.0` and `net472`): always use the `net10.0` output. +- The `dotnet` project builds into `artifacts/bin/dotnet/Debug/net10.0/`, not `artifacts/bin/Cli/dotnet/...`. diff --git a/.github/skills/incremental-test/scripts/Copy-ToRedist.ps1 b/.github/skills/incremental-test/scripts/Copy-ToRedist.ps1 new file mode 100644 index 000000000000..a9b5b2d6cf44 --- /dev/null +++ b/.github/skills/incremental-test/scripts/Copy-ToRedist.ps1 @@ -0,0 +1,88 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Copies build output DLLs into the redist SDK layout for incremental testing. + +.DESCRIPTION + After building modified projects with `dotnet build`, this script copies their + output assemblies into the redist SDK layout so that dotnet.Tests can run against them. + +.PARAMETER Projects + One or more project names whose output DLLs should be copied. + Use the directory name under artifacts/bin/ (e.g., "Microsoft.DotNet.Cli.Utils", "dotnet"). + +.EXAMPLE + ./Copy-ToRedist.ps1 Microsoft.DotNet.Cli.Utils dotnet +#> + +param( + [Parameter(Mandatory, Position = 0, ValueFromRemainingArguments)] + [string[]]$Projects +) + +$ErrorActionPreference = 'Stop' + +$repoRoot = git rev-parse --show-toplevel +if ($LASTEXITCODE -ne 0) { throw "Not inside a git repository." } + +$redistSdkBase = Join-Path $repoRoot 'artifacts' 'bin' 'redist' 'Debug' 'dotnet' 'sdk' + +if (-not (Test-Path $redistSdkBase)) { + throw "Redist SDK layout not found at '$redistSdkBase'. Run a full build first (build.cmd / build.sh)." +} + +$sdkVersionDir = Get-ChildItem $redistSdkBase -Directory | + Sort-Object LastWriteTime -Descending | + Select-Object -First 1 + +if (-not $sdkVersionDir) { + throw "No SDK version directory found under '$redistSdkBase'." +} + +$targetDir = $sdkVersionDir.FullName +Write-Host "Target SDK directory: $targetDir" + +foreach ($project in $Projects) { + $outputDir = Join-Path $repoRoot 'artifacts' 'bin' $project 'Debug' 'net10.0' + + if (-not (Test-Path $outputDir)) { + Write-Warning "Build output not found: $outputDir — skipping '$project'." + continue + } + + # Find DLLs in the project output + $dlls = Get-ChildItem $outputDir -Filter '*.dll' -File + + foreach ($dll in $dlls) { + $targetPath = Join-Path $targetDir $dll.Name + + # Safety: only copy DLLs that already exist in the redist layout + if (-not (Test-Path $targetPath)) { + continue + } + + Copy-Item $dll.FullName $targetPath -Force + Write-Host " Copied $($dll.Name)" + } + + # Copy satellite resource assemblies (e.g., cs/, de/, etc.) + $cultureDirs = Get-ChildItem $outputDir -Directory | Where-Object { + Test-Path (Join-Path $_.FullName '*.resources.dll') + } + + foreach ($cultureDir in $cultureDirs) { + $targetCultureDir = Join-Path $targetDir $cultureDir.Name + if (-not (Test-Path $targetCultureDir)) { continue } + + $resourceDlls = Get-ChildItem $cultureDir.FullName -Filter '*.resources.dll' -File + foreach ($resDll in $resourceDlls) { + $resTarget = Join-Path $targetCultureDir $resDll.Name + if (-not (Test-Path $resTarget)) { continue } + + Copy-Item $resDll.FullName $resTarget -Force + Write-Host " Copied $($cultureDir.Name)/$($resDll.Name)" + } + } +} + +Write-Host "Done." From 76645887e2315a4c8f997342d29e69dbd2a99232 Mon Sep 17 00:00:00 2001 From: Logan Bussell Date: Tue, 7 Apr 2026 08:35:58 -0700 Subject: [PATCH 3/4] Revert most incremental-test skill content changes --- .github/skills/incremental-test/SKILL.md | 88 ++++++++++++++----- .../scripts/Copy-ToRedist.ps1 | 88 ------------------- 2 files changed, 64 insertions(+), 112 deletions(-) delete mode 100644 .github/skills/incremental-test/scripts/Copy-ToRedist.ps1 diff --git a/.github/skills/incremental-test/SKILL.md b/.github/skills/incremental-test/SKILL.md index 24d40bc57a60..88ae6832926c 100644 --- a/.github/skills/incremental-test/SKILL.md +++ b/.github/skills/incremental-test/SKILL.md @@ -10,56 +10,96 @@ description: >- ## Prerequisites -A full build must have been completed at least once (`build.cmd` or `build.sh`) so the redist SDK layout exists at `artifacts/bin/redist/Debug/dotnet/sdk//`. +- A full build must have been completed at least once (via `build.cmd` or `build.sh`) so that the redist SDK layout exists at `artifacts\bin\redist\Debug\dotnet\sdk\\`. +- This workflow uses Windows/PowerShell commands and paths. On macOS/Linux, substitute forward slashes and use `cp` instead of `Copy-Item`. ## Workflow -### Step 1: Build modified projects +### Step 1: Identify modified projects -Build each modified project using the repo-local dotnet: +Determine which projects have been modified. Use context from: +- The files you just edited in this session. +- Or `git status`/`git diff` to find changed `.cs` files and map them to their `.csproj` projects. + +### Step 2: Build modified projects + +Build each modified project individually using the repo-local dotnet: ``` -./.dotnet/dotnet build -c Debug +.\.dotnet\dotnet build -c Debug ``` -### Step 2: Copy outputs to the redist SDK layout - -Run the copy script with the project names (matching the directory names under `artifacts/bin/`): +For example: +``` +.\.dotnet\dotnet build src\Cli\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj -c Debug +``` -```pwsh -scripts/Copy-ToRedist.ps1 [ ...] +If the `dotnet` CLI project itself was modified, build it: +``` +.\.dotnet\dotnet build src\Cli\dotnet\dotnet.csproj -c Debug ``` -For example, after modifying `Microsoft.DotNet.Cli.Utils` and `dotnet`: +### Step 3: Copy output DLLs to the redist SDK layout -```pwsh -scripts/Copy-ToRedist.ps1 Microsoft.DotNet.Cli.Utils dotnet +Discover the SDK version directory name: +```powershell +$sdkVersion = (Get-ChildItem artifacts\bin\redist\Debug\dotnet\sdk -Directory | Sort-Object LastWriteTime -Descending | Select-Object -First 1).Name ``` -The script discovers the SDK version directory, copies only DLLs that are already present in the redist layout, and handles satellite resource assemblies. +For each modified project, copy its output DLL (and any satellite assemblies) from the project's build output to the redist SDK directory: -### Step 3: Build the test project (if test code was modified) +``` +Source: artifacts\bin\\Debug\net10.0\.dll +Target: artifacts\bin\redist\Debug\dotnet\sdk\\ +``` +For example: +```powershell +Copy-Item artifacts\bin\Microsoft.DotNet.ProjectTools\Debug\net10.0\Microsoft.DotNet.ProjectTools.dll artifacts\bin\redist\Debug\dotnet\sdk\$sdkVersion\ +Copy-Item artifacts\bin\Microsoft.DotNet.Cli.Utils\Debug\net10.0\Microsoft.DotNet.Cli.Utils.dll artifacts\bin\redist\Debug\dotnet\sdk\$sdkVersion\ ``` -./.dotnet/dotnet build test/dotnet.Tests/dotnet.Tests.csproj + +The `dotnet` project is special — it builds into `artifacts\bin\dotnet\Debug\net10.0\` and its `dotnet.dll` must be copied to the SDK directory: +```powershell +Copy-Item artifacts\bin\dotnet\Debug\net10.0\dotnet.dll artifacts\bin\redist\Debug\dotnet\sdk\$sdkVersion\ ``` -This project outputs directly to `artifacts/bin/redist/Debug/` via `TestHostFolder`. +**Important notes:** +- For typical incremental edits, only copy DLLs that are **already present** in the target directory. If your change introduces a new shipped assembly or moves assemblies, you will need a full `build.cmd`/`build.sh` to update the layout correctly. +- Some projects multi-target (e.g., `net10.0` and `net472`). Always use the `net10.0` output. +- If localization resource DLLs were changed (in subdirectories like `cs\`, `de\`, etc.), copy those too. -### Step 4: Run the tests +### Step 4: Build the test project (if test code was modified) + +The test project `test\dotnet.Tests\dotnet.Tests.csproj` outputs directly to `artifacts\bin\redist\Debug\` (via `TestHostFolder`), so just build it: ``` -./.dotnet/dotnet exec artifacts/bin/redist/Debug/dotnet.Tests.dll -method "*TestMethodName*" +.\.dotnet\dotnet build test\dotnet.Tests\dotnet.Tests.csproj ``` -Or via `dotnet test`: +### Step 5: Run the tests +Run specific tests: ``` -./.dotnet/dotnet test test/dotnet.Tests/dotnet.Tests.csproj --no-build --filter "Name~TestMethodName" +.\.dotnet\dotnet exec artifacts\bin\redist\Debug\dotnet.Tests.dll -method "*TestMethodName*" ``` -## Gotchas +Or run filtered tests via `dotnet test`: +``` +.\.dotnet\dotnet test test\dotnet.Tests\dotnet.Tests.csproj --no-build --filter "Name~TestMethodName" +``` -- Only DLLs **already present** in the redist layout are copied. If your change introduces a new shipped assembly, run a full `build.cmd`/`build.sh` instead. -- Multi-targeting projects (e.g., `net10.0` and `net472`): always use the `net10.0` output. -- The `dotnet` project builds into `artifacts/bin/dotnet/Debug/net10.0/`, not `artifacts/bin/Cli/dotnet/...`. +## Common project paths + +| Assembly | Project Path | +|---|---| +| `dotnet.dll` | `src\Cli\dotnet\dotnet.csproj` | +| `Microsoft.DotNet.Cli.Utils.dll` | `src\Cli\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj` | +| `Microsoft.DotNet.Cli.Definitions.dll` | `src\Cli\Microsoft.DotNet.Cli.Definitions\Microsoft.DotNet.Cli.Definitions.csproj` | +| `Microsoft.DotNet.Cli.CoreUtils.dll` | `src\Cli\Microsoft.DotNet.Cli.CoreUtils\Microsoft.DotNet.Cli.CoreUtils.csproj` | +| `Microsoft.DotNet.Configurer.dll` | `src\Cli\Microsoft.DotNet.Configurer\Microsoft.DotNet.Configurer.csproj` | +| `Microsoft.DotNet.ProjectTools.dll` | `src\Microsoft.DotNet.ProjectTools\Microsoft.DotNet.ProjectTools.csproj` | +| `Microsoft.DotNet.NativeWrapper.dll` | `src\Resolvers\Microsoft.DotNet.NativeWrapper\Microsoft.DotNet.NativeWrapper.csproj` | +| `Microsoft.DotNet.TemplateLocator.dll` | `src\Microsoft.DotNet.TemplateLocator\Microsoft.DotNet.TemplateLocator.csproj` | +| `Microsoft.DotNet.InternalAbstractions.dll` | `src\Cli\Microsoft.DotNet.InternalAbstractions\Microsoft.DotNet.InternalAbstractions.csproj` | +| `dotnet.Tests.dll` | `test\dotnet.Tests\dotnet.Tests.csproj` | diff --git a/.github/skills/incremental-test/scripts/Copy-ToRedist.ps1 b/.github/skills/incremental-test/scripts/Copy-ToRedist.ps1 deleted file mode 100644 index a9b5b2d6cf44..000000000000 --- a/.github/skills/incremental-test/scripts/Copy-ToRedist.ps1 +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env pwsh -<# -.SYNOPSIS - Copies build output DLLs into the redist SDK layout for incremental testing. - -.DESCRIPTION - After building modified projects with `dotnet build`, this script copies their - output assemblies into the redist SDK layout so that dotnet.Tests can run against them. - -.PARAMETER Projects - One or more project names whose output DLLs should be copied. - Use the directory name under artifacts/bin/ (e.g., "Microsoft.DotNet.Cli.Utils", "dotnet"). - -.EXAMPLE - ./Copy-ToRedist.ps1 Microsoft.DotNet.Cli.Utils dotnet -#> - -param( - [Parameter(Mandatory, Position = 0, ValueFromRemainingArguments)] - [string[]]$Projects -) - -$ErrorActionPreference = 'Stop' - -$repoRoot = git rev-parse --show-toplevel -if ($LASTEXITCODE -ne 0) { throw "Not inside a git repository." } - -$redistSdkBase = Join-Path $repoRoot 'artifacts' 'bin' 'redist' 'Debug' 'dotnet' 'sdk' - -if (-not (Test-Path $redistSdkBase)) { - throw "Redist SDK layout not found at '$redistSdkBase'. Run a full build first (build.cmd / build.sh)." -} - -$sdkVersionDir = Get-ChildItem $redistSdkBase -Directory | - Sort-Object LastWriteTime -Descending | - Select-Object -First 1 - -if (-not $sdkVersionDir) { - throw "No SDK version directory found under '$redistSdkBase'." -} - -$targetDir = $sdkVersionDir.FullName -Write-Host "Target SDK directory: $targetDir" - -foreach ($project in $Projects) { - $outputDir = Join-Path $repoRoot 'artifacts' 'bin' $project 'Debug' 'net10.0' - - if (-not (Test-Path $outputDir)) { - Write-Warning "Build output not found: $outputDir — skipping '$project'." - continue - } - - # Find DLLs in the project output - $dlls = Get-ChildItem $outputDir -Filter '*.dll' -File - - foreach ($dll in $dlls) { - $targetPath = Join-Path $targetDir $dll.Name - - # Safety: only copy DLLs that already exist in the redist layout - if (-not (Test-Path $targetPath)) { - continue - } - - Copy-Item $dll.FullName $targetPath -Force - Write-Host " Copied $($dll.Name)" - } - - # Copy satellite resource assemblies (e.g., cs/, de/, etc.) - $cultureDirs = Get-ChildItem $outputDir -Directory | Where-Object { - Test-Path (Join-Path $_.FullName '*.resources.dll') - } - - foreach ($cultureDir in $cultureDirs) { - $targetCultureDir = Join-Path $targetDir $cultureDir.Name - if (-not (Test-Path $targetCultureDir)) { continue } - - $resourceDlls = Get-ChildItem $cultureDir.FullName -Filter '*.resources.dll' -File - foreach ($resDll in $resourceDlls) { - $resTarget = Join-Path $targetCultureDir $resDll.Name - if (-not (Test-Path $resTarget)) { continue } - - Copy-Item $resDll.FullName $resTarget -Force - Write-Host " Copied $($cultureDir.Name)/$($resDll.Name)" - } - } -} - -Write-Host "Done." From 735901bf032a08f83c59cf1d41ea802be324547f Mon Sep 17 00:00:00 2001 From: Logan Bussell Date: Tue, 7 Apr 2026 08:42:48 -0700 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/skills/ValidateSkill.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/skills/ValidateSkill.cs b/.github/skills/ValidateSkill.cs index 52809ef48e90..12d1e0b51342 100755 --- a/.github/skills/ValidateSkill.cs +++ b/.github/skills/ValidateSkill.cs @@ -13,7 +13,7 @@ } string skillDir = Path.GetFullPath(args[0]); -string skillName = Path.GetFileName(skillDir); +string skillName = Path.GetFileName(Path.TrimEndingDirectorySeparator(skillDir)); string skillFile = Path.Combine(skillDir, "SKILL.md"); // SKILL.md must exist in the skill directory @@ -32,14 +32,17 @@ return 1; } -int endIndex = text.IndexOf("---", 3); -if (endIndex < 0) +Match frontmatterMatch = Regex.Match( + text, + @"\A---\r?\n(?.*?)(?:\r?\n)---(?:\r?\n|$)", + RegexOptions.Singleline); +if (!frontmatterMatch.Success) { Console.Error.WriteLine("Unterminated YAML frontmatter."); return 1; } -string yaml = text.Substring(3, endIndex - 3).Trim(); +string yaml = frontmatterMatch.Groups["yaml"].Value.Trim(); IDeserializer deserializer = new DeserializerBuilder().Build(); Dictionary frontmatter = deserializer.Deserialize>(yaml); @@ -81,9 +84,9 @@ } // description must be 1-1024 characters -if (description.Length > 1024) +if (description.Length == 0 || description.Length > 1024) { - Console.Error.WriteLine($"Description is {description.Length} chars (max 1024)."); + Console.Error.WriteLine($"Description is {description.Length} chars (must be 1-1024)."); return 1; }