Add Skill: Convert to Central Package Management (convert-to-cpm)#75
Add Skill: Convert to Central Package Management (convert-to-cpm)#75ViktorHofer merged 48 commits intomainfrom
Conversation
Authoring process: - Researched the Agent Skills standard at agentskills.io and reviewed repo conventions - Studied the existing csharp-scripts skill and test structure as a reference implementation - Studied Microsoft's CPM documentation at learn.microsoft.com - Authored SKILL.md with a 9-step workflow covering scope determination through validation - Created 5 test scenarios across simple, moderate, and advanced tiers - Performed dry-run evaluation against all scenarios, identifying 15 findings - Applied all 15 fixes (4 gaps, 6 ambiguities, 5 improvements) to SKILL.md - Re-evaluated: 50 OK, 0 gaps, 0 ambiguities, 1 test fixture improvement - Updated test fixture to resolve the remaining finding - Final validation: 254 lines, 0 errors, 0 warnings Skill implementation (skills/convert-to-cpm/SKILL.md): - 9-step workflow: scope, CPM check, audit, create/update props, update projects, handle properties, restore/validate, cleanup, summary - Handles single projects, solutions, and full repositories - Audits packages with per-project detail table including version conflicts and security advisories - Flags CVE/security vulnerabilities and recommends patched versions - Supports MSBuild property-based versioning with inline vs keep decisions - Covers conditional PackageReference items across target frameworks - Discovers PackageReference in imported .props/.targets via Import chain scanning - Provides cross-platform commands (Unix and Windows/PowerShell) - Documents import order requirements for property references in Directory.Packages.props - Mentions dotnet new packagesprops as preferred creation method (.NET 8+) - Includes validation checklist and common pitfalls table Test scenarios (tests/convert-to-cpm/): - simple-single-project: 1 project, 3 packages, no conflicts - simple-solution: 3 projects via .sln, 5 packages, PrivateAssets preservation - moderate-version-conflicts: 4 projects, System.Text.Json version conflicts with CVE-2024-43485 advisory, AutoMapper major version conflict with VersionOverride - moderate-msbuild-properties: 2 projects using MSBuild properties for versioning in Directory.Build.props, inline vs keep decisions, property cleanup verification - advanced-multi-complexity: 5 projects combining version conflicts, MSBuild properties, conditional TFM PackageReference, shared Common.props imports, VersionOverride, and security advisory handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ison Condensed SKILL.md using progressive disclosure: - Reduced from 254 lines / ~3937 tokens to 120 lines / ~1778 tokens - Extracted detailed procedural instructions into 5 focused reference files - Main file retains workflow decision logic with links to references loaded on demand - Follows agentskills.io progressive disclosure pattern: metadata -> instructions -> resources Added baseline build verification (new Step 2): - Requires clean build (dotnet clean && dotnet build) before any changes - Captures baseline.binlog for structured build artifact - Captures baseline-packages.json via dotnet list package --format json - Blocks conversion if baseline build fails Added post-conversion baseline comparison (Steps 8 and 10): - Step 8 produces after-cpm.binlog and after-cpm-packages.json from clean build - Step 10 compares baseline vs post-conversion package lists per project - Changes table shows version bumps, VersionOverride entries, added/removed packages - Unchanged table confirms version-neutral conversion for unmodified packages - Binlog files produced as artifacts for user review in MSBuild Structured Log Viewer Reference files created: - references/audit-complexities.md: 7 complexity categories for package auditing - references/baseline-comparison.md: dotnet list package comparison procedure, binlog production, artifact guidance, table formats for changes and unchanged packages - references/directory-packages-props.md: File creation (dotnet new packagesprops), placement rules, conditional versions, VersionOverride patterns - references/msbuild-property-handling.md: Property usage search, inline vs keep decisions, import order requirements, cleanup verification - references/validation-and-errors.md: NuGet error codes (NU1008, NU1010, NU1507), clean build validation, multi-TFM guidance, common pitfalls Workflow is now 10 steps (was 9): 1. Determine scope 2. Establish baseline build (new) 3. Check for existing CPM 4. Audit package references 5. Create or update Directory.Packages.props 6. Update project files 7. Handle MSBuild version properties 8. Restore and validate (now with binlog + package list capture) 9. Clean up obsolete properties 10. Summary and baseline comparison (expanded with diff tables) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…/comparison steps, add .gitignore for test solutions Package replacements across all skill references and test scenarios: - Serilog.AspNetCore -> OpenTelemetry.Extensions.Hosting 1.15.0 - Serilog (standalone) -> OpenTelemetry.Extensions.Hosting 1.15.0 - Swashbuckle.AspNetCore -> Microsoft.AspNetCore.OpenApi 8.0.24 - SerilogVersion MSBuild property -> OTelVersion - DIVersion updated from 8.0.1 to 9.0.0 (DI/Abstractions alignment) - Microsoft.AspNetCore.OpenApi uses 8.0.24 (not 9.x) for net8.0 compat Test fixture improvements: - Added Step 2 (baseline build with binlog) to all 5 with-skill.md files - Added Step 10 (package comparison table + binlog artifact links) to all 5 with-skill.md files - Expanded simple-solution without-skill.md with more realistic agent behavior - Standardized security fix terminology: table markers cite CVEs, prose references CVE IDs - Removed space-padded table formatting in favor of compact markdown with emojis Test solution infrastructure: - Added tests/convert-to-cpm/.gitignore to exclude src/ build artifacts - Added generation prompt to test README for recreating buildable solutions - All 5 test solutions verified to restore and build successfully Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…racy - Rename Step 10 and validation checklist from 'binlog comparison' to 'package list comparison' - Rewrite baseline-comparison.md: title to 'Baseline Comparison', lead with dotnet list package as primary comparison mechanism, position binlogs as supplementary artifacts for manual review/troubleshooting - Add brief definition of binlogs before the artifacts section - Fix Directory.Packages.props placement guidance: use first common ancestor of all .NET projects instead of assuming repository root (.git), since many repos nest source under src/ or similar - Update SKILL.md scope input and Step 1 to reference directory-scoped conversion - Standardize security fix terminology: table markers cite CVEs, prose uses 'security fix for CVE-...' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nario, fix commands Review findings addressed: 1. Fixed BlobsVersion grep step description in advanced scenario 2. Sorted PackageVersion entries alphabetically in all Directory.Packages.props outputs 3. Consolidated baseline-comparison.md to single-table format 4. Added solution file arguments and multi-line commands in test fixtures 5. Added Directory.Packages.props placement question for single-project scenario 6. Created simple-packages-config test scenario (packages.config rejection) 7. Use dotnet new packagesprops in simple-single-project workflow 8. Fixed More Info link text to match reference file title Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use mix of .sln and .slnx across scenarios (simple-solution and moderate-msbuild-properties use .sln; moderate-version-conflicts and advanced-multi-complexity use .slnx) - Fix simple-solution package count from 5 to 6 - Fix advanced user response #2 to reference Azure.Storage.Blobs version - Add ImplicitUsings to advanced Directory.Build.props in audit and cleanup - Complete the advanced unchanged table with all expected package entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix 4 occurrences of Inventory.sln to Inventory.slnx in moderate-version-conflicts/with-skill.md for consistency with the scenario README and test solution - Update test README to only run skill evaluation when the user explicitly requests it Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove duplicated bash code blocks from Steps 2 and 8, linking to baseline-comparison.md instead - Merge Steps 7 (MSBuild property decisions) and 9 (cleanup) into a single step since both reference msbuild-property-handling.md - Condense Step 10 summary to reference baseline-comparison.md for procedure details - Reduces from 120 to 97 lines (10 steps to 9 steps) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address code review feedback: fix 4 occurrences of Enterprise.sln to Enterprise.slnx in advanced-multi-complexity/with-skill.md for consistency with the scenario README and test solution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t, fix links - Instruct Step 6 to retain each file's existing indentation style and blank lines to keep diffs minimal - Instruct Step 9 to save the full summary as convert-to-cpm.md alongside binlog and JSON artifacts, suggesting its contents for a PR description - Strip en-us/ from learn.microsoft.com links in SKILL.md and validation-and-errors.md to make them culture-agnostic - Update all with-skill.md test expectations to include the convert-to-cpm.md create step and artifact mention Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move skill from skills/convert-to-cpm/ to src/dotnet-msbuild/skills/convert-to-cpm/ and tests from tests/convert-to-cpm/ to src/dotnet-msbuild/tests/convert-to-cpm/ to match the repository layout established on main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace manual test approach (README.md + with-skill.md + without-skill.md) with automated eval.yaml scenarios containing assertions and rubric items. Add committed test fixture files (.csproj, .sln, .slnx, .props) for each scenario with copy_test_files setup, replacing the git-ignored generated solutions. 6 scenarios converted: - simple-single-project: basic single project CPM conversion - simple-solution: multi-project solution conversion - simple-packages-config: negative test (packages.config rejection) - moderate-version-conflicts: version conflict resolution - moderate-msbuild-properties: MSBuild property version handling - advanced-multi-complexity: combined complexities (conflicts, properties, conditionals, shared props) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This pull request introduces the convert-to-cpm skill for migrating .NET projects to NuGet Central Package Management (CPM). The skill provides comprehensive guidance for consolidating package versions from individual project files into a centralized Directory.Packages.props file. This is a replacement for PR #28, rebased on main with updates to match the new repository layout and adoption of the eval.yaml test approach.
Changes:
- Adds a new skill with detailed 9-step workflow covering scope determination, baseline capture, package auditing, conflict resolution, MSBuild property handling, and validation
- Includes 5 reference documentation files covering audit complexities, baseline comparison procedures, Directory.Packages.props creation, MSBuild property handling, and validation/error handling
- Provides 6 test scenarios across 3 difficulty levels (simple, moderate, advanced) demonstrating various CPM conversion challenges including version conflicts, MSBuild properties, conditional references, and packages.config detection
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/dotnet-msbuild/skills/convert-to-cpm/SKILL.md | Main skill definition with 9-step workflow, inputs, validation checklist, and references to supplementary documentation |
| src/dotnet-msbuild/skills/convert-to-cpm/references/audit-complexities.md | Documents 7 complexity types to check during package auditing (properties, conditionals, conflicts, security, imports) |
| src/dotnet-msbuild/skills/convert-to-cpm/references/baseline-comparison.md | Procedures for capturing baseline and post-conversion package lists, producing comparison tables, and using binlog artifacts |
| src/dotnet-msbuild/skills/convert-to-cpm/references/directory-packages-props.md | Guidance on file placement, creation via CLI or manual, PackageVersion entries, conditional versions, and VersionOverride |
| src/dotnet-msbuild/skills/convert-to-cpm/references/msbuild-property-handling.md | Decision workflow for handling MSBuild properties used in version attributes, including inline vs. keep decisions and cleanup procedures |
| src/dotnet-msbuild/skills/convert-to-cpm/references/validation-and-errors.md | NuGet error code reference (NU1008, NU1010, NU1507) and common pitfalls table with solutions |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-single-project/eval.yaml | Test scenario for converting a single project with 3 packages |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-single-project/MyApp/MyApp.csproj | Test fixture: simple SDK-style project with 3 package references |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-solution/eval.yaml | Test scenario for converting a multi-project solution with 6 unique packages |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-solution/MyApp.sln | Test fixture: solution file with 3 projects (Web, Core, Tests) |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-solution/Web/Web.csproj | Test fixture: Web project with OpenTelemetry and OpenApi packages |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-solution/Core/Core.csproj | Test fixture: Core library with System.Text.Json package |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-solution/Tests/Tests.csproj | Test fixture: Test project with xunit packages and PrivateAssets attribute |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-packages-config/eval.yaml | Test scenario verifying skill correctly declines to convert packages.config projects |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-packages-config/LegacyApp/LegacyApp.csproj | Test fixture: legacy .NET Framework project using packages.config format |
| src/dotnet-msbuild/tests/convert-to-cpm/simple-packages-config/LegacyApp/packages.config | Test fixture: packages.config file with Newtonsoft.Json reference |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-version-conflicts/eval.yaml | Test scenario for handling version conflicts across 4 projects (System.Text.Json 10.0.1 vs 8.0.4, Azure.Identity 1.13.2 vs 1.10.0) |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-version-conflicts/Inventory.slnx | Test fixture: XML-based solution file (.slnx format) |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-version-conflicts/Api/Api.csproj | Test fixture: Api project with System.Text.Json 10.0.1 and Azure.Identity 1.13.2 |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-version-conflicts/Worker/Worker.csproj | Test fixture: Worker project with System.Text.Json 8.0.4 (has security advisory) |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-version-conflicts/Shared/Shared.csproj | Test fixture: Shared library with conflicting Azure.Identity version |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-version-conflicts/Tests/Tests.csproj | Test fixture: Test project with System.Text.Json 10.0.1 |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-msbuild-properties/eval.yaml | Test scenario for handling MSBuild properties in package versions (OTelVersion, DIVersion) |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-msbuild-properties/Platform.sln | Test fixture: solution with 2 projects using property-based versioning |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-msbuild-properties/Directory.Build.props | Test fixture: defines OTelVersion, DIVersion, and OutputPath properties |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-msbuild-properties/Api/Api.csproj | Test fixture: uses $(OTelVersion) for package version |
| src/dotnet-msbuild/tests/convert-to-cpm/moderate-msbuild-properties/Data/Data.csproj | Test fixture: uses $(DIVersion) for multiple DI packages |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/eval.yaml | Test scenario combining 6 complexities: 3-way version conflict, property versions, conditional references, shared props imports |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/Enterprise.slnx | Test fixture: complex solution with 5 projects |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/Directory.Build.props | Test fixture: defines version properties and non-version properties (LangVersion, ImplicitUsings) |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/Common.props | Test fixture: shared props file with Microsoft.Extensions.Logging package reference |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/Web/Web.csproj | Test fixture: Web project with System.Text.Json 10.0.1 |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/Api/Api.csproj | Test fixture: Multi-targeting project (net8.0;net6.0) with conditional PackageReference for different TFMs |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/Core/Core.csproj | Test fixture: Core library with System.Text.Json 9.0.0 and $(HostingVersion) property |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/Legacy/Legacy.csproj | Test fixture: net6.0 project with System.Text.Json 8.0.4 and Azure.Storage.Blobs literal version |
| src/dotnet-msbuild/tests/convert-to-cpm/advanced-multi-complexity/Tests/Tests.csproj | Test fixture: Test project with System.Text.Json 10.0.1 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Move all 6 scenario definitions from individual subdirectory eval.yaml
files into a single src/dotnet-msbuild/tests/convert-to-cpm/eval.yaml
file, matching the skill-validator discovery convention that expects
{testsDir}/{skillname}/eval.yaml. Scenario prompts updated to reference
subdirectory-prefixed paths since copy_test_files now copies all fixture
subdirectories.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
thanks @jeffhandley. before we get more reviewers do we want to see if there is a nudge we can provide to improve outcomes for some of these scenarios? |
|
@jeffhandley please merge latest main into this branch. We now use a newer model and made some fixes to the validator. |
Convert 6 non-deterministic output_matches assertions to 8 file-based assertions (file_contains, file_not_contains) across conversion scenarios: - Scenario 5: Verify PrivateAssets preserved in Tests.csproj - Scenario 6: Verify OTelVersion/DIVersion removed from Directory.Build.props - Scenario 7: Verify System.Text.Json and Azure.Identity in Directory.Packages.props - Scenario 8: Verify System.Text.Json in Directory.Packages.props and BlobsVersion/HostingVersion removed from Directory.Build.props Recommendation-only scenarios and conversational assertions (conflict detection, conditionals, Common.props awareness) remain as output_matches. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restructure the description to improve activation reliability by adopting the USE FOR / DO NOT USE FOR pattern used by other skills in the repo (thread-abort-migration, binlog-failure-analysis). Key changes: - Front-load activation cues before capability list - Add explicit USE FOR / DO NOT USE FOR section markers - Add .sln/.slnx file extensions for solution-path matching - Move DO NOT USE exclusions into description (was only in body) - Use YAML folded scalar for multi-line readability All existing activation keywords preserved. Length reduced from 882 to 849 chars (max 1024). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment was marked as outdated.
This comment was marked as outdated.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 37 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
tests/dotnet-nuget/convert-to-cpm/moderate-msbuild-properties/Platform.sln
Outdated
Show resolved
Hide resolved
This comment has been minimized.
This comment has been minimized.
Set expect_activation: false on the packages.config eval scenario so non-activation is reported as expected rather than flagged as a warning. Add a packages.config guard in Step 1 of the skill workflow so that if the skill is activated for a packages.config project, it stops early and recommends migrating to PackageReference first. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ensures the agent explicitly loads and reads reference files rather than treating them as optional 'see also' links. This aligns with the repo convention of explicitly instructing agents to load reference content. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 37 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
tests/dotnet-nuget/convert-to-cpm/simple-solution/MyApp.sln:1
- The solution uses the legacy C# project type GUID (
{FAE04EC0-...}) for SDK-style.csproj. Moderndotnet new slntypically uses the SDK-style C# GUID ({9A19103F-16F7-4668-BE54-9A1E7A4F7556}), and some tools rely on this for accurate classification. Update the project type GUIDs to the modern C# SDK GUID to reduce tooling ambiguity (same concern applies totests/dotnet-nuget/convert-to-cpm/moderate-msbuild-properties/Platform.sln).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 37 out of 37 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
tests/dotnet-nuget/convert-to-cpm/moderate-version-conflicts/Worker/Worker.csproj
Show resolved
Hide resolved
tests/dotnet-nuget/convert-to-cpm/moderate-msbuild-properties/Api/Api.csproj
Show resolved
Hide resolved
tests/dotnet-nuget/convert-to-cpm/advanced-multi-complexity/Web/Web.csproj
Show resolved
Hide resolved
tests/dotnet-nuget/convert-to-cpm/advanced-multi-complexity/Api/Api.csproj
Show resolved
Hide resolved
tests/dotnet-nuget/convert-to-cpm/moderate-version-conflicts/Api/Api.csproj
Show resolved
Hide resolved
This comment has been minimized.
This comment has been minimized.
Test fixture projects using Microsoft.NET.Sdk.Web and Microsoft.NET.Sdk.Worker require a Program.cs entrypoint for dotnet build to succeed. The skill workflow instructs the agent to run dotnet restore and dotnet build for validation, so these fixtures must be buildable. Adds minimal entrypoints (with explicit using directives since ImplicitUsings is not enabled in these projects) to 6 projects: - simple-solution/Web - moderate-version-conflicts/Api, Worker - moderate-msbuild-properties/Api - advanced-multi-complexity/Api, Web Also adds Microsoft.Extensions.Hosting package reference to the Worker project, matching what the dotnet new worker template produces. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Skill Validation Results
Model: claude-opus-4.6 | Judge: claude-opus-4.6 |
Replaces #28 with a rebase on main, updating to the new repo layout, and adoption of the eval.yml test approach
Introduce the
convert-to-cpmskill, which guides the migration of .NET projects to NuGet Central Package Management (CPM). It provides detailed workflow steps, auditing guidance, validation procedures, error handling, and test scenarios for various conversion complexities.