Skip to content

Add automated per-plugin versioning (NBGV) with /version-bump + weekly backstop - #813

Merged
Evangelink merged 10 commits into
mainfrom
abhitejjohn/per-plugin-version-strategy
Jul 13, 2026
Merged

Add automated per-plugin versioning (NBGV) with /version-bump + weekly backstop#813
Evangelink merged 10 commits into
mainfrom
abhitejjohn/per-plugin-version-strategy

Conversation

@AbhitejJohn

@AbhitejJohn AbhitejJohn commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Draft for review. Opens the versioning strategy we discussed: per‑plugin semantic versions, materialized into the checked‑in manifests, with two low‑touch automations and no auto‑editing of contributor PRs.

Why

Every client that surfaces these skills — Copilot CLI, Claude Code, Codex, Cursor — reads a plugin's version directly from its checked‑in manifest (plugin.json / .codex-plugin/plugin.json). Today those versions are static, so:

  • A plugin's behavior can change while its advertised version stays flat, and consumers never get a signal to re‑pull.
  • There's no human‑readable record of what changed when.
  • Bumping by hand across 15 plugins is error‑prone and easy to forget.

We want correct, current versions in the repo with minimal manual work, without bloating the marketplace clone and without taking on third‑party/external plugins (out of scope for now).

What this adds

  • Per‑plugin SemVer via Nerdbank.GitVersioning (NBGV). Each plugin gets a version.json whose pathFilters exclude the generated manifests and version.json itself, so the computed version height tracks real content changes only (editing a manifest or the version file doesn't inflate the height).
  • Versions are materialized into the checked‑in manifests, so consumers read a current value with no build step on their side.
  • One workhorse scripteng/version/Sync-PluginVersions.ps1 — resolves the changed‑plugin set from a git diff, computes each version with nbgv (predicting the squash‑merge height for PRs), and either reports or stamps.

Automations (two, low‑touch by design)

Workflow Trigger What it does
/version-bump A maintainer comments /version-bump on a PR Stamps the affected plugins on the PR branch. Gated on collaborator permission (admin/write/maintain); forks rejected before any privileged step.
weekly-version-sync Mondays 09:00 UTC + workflow_dispatch Backstop: stamps any drift on main, opens/updates a single bot PR, and explains the per‑plugin reason. Self‑heals anything merged without a bump.

We deliberately did not auto‑edit contributor PRs or add a noisy advisory‑comment bot — maintainers stay in control and the signal stays clean. (No official skills repo we surveyed auto‑mutates contributor PRs for versioning; the opt‑in command + scheduled backstop pattern is the conservative norm.)

Security — multi‑model adversarial review (GPT‑5.5 + Gemini 3.1 Pro)

  • Supply‑chain RCE (High — flagged independently by both models). dotnet tool restore would have honored a nuget.config authored in the PR tree, letting an attacker remap the nbgv package source to a malicious feed and execute code in the privileged contents: write context. This was genuinely reachable — no nuget.config is tracked anywhere in the repo today, so a PR could add one. Fix: a trusted eng/version/nuget.config (<clear/> + nuget.org‑only + packageSourceMapping), overlaid from main and consumed via --configfile so PR‑supplied configs are ignored entirely.
  • TOCTOU (Medium). /version-bump now checks out the authorized head SHA rather than the mutable branch name; if the branch advances after authorization, the push fails non‑fast‑forward — the safe outcome.
  • Injection hardening. Set-ManifestVersion uses a MatchEvaluator (not a replacement string), so a $‑bearing version can't re‑expand, plus a strict ^\d+\.\d+\.\d+$ guard that throws on a malformed base and leaves manifests untouched.
  • Correctness. A base‑only version.json bump (0.1 → 0.2) is now detected and stamped.

Verification

Exercised end‑to‑end against a real NBGV git harness (the repo global.json pins an SDK that isn't installable locally, so testing uses an isolated harness):

  • content‑scoped predict → only the touched plugin bumps;
  • base‑only bump → x.y.0;
  • docs‑only change → [] (no bump);
  • weekly -OnlyChanged → stamps drift authoritatively;
  • malformed base → throws, manifest intact;
  • dotnet tool restore --configfile → exit 0.

actionlint passes on both workflows.

Files

  • eng/version/Sync-PluginVersions.ps1, eng/version/nuget.config, .config/dotnet-tools.json
  • .github/workflows/version-bump-command.yml, .github/workflows/weekly-version-sync.yml
  • plugins/*/version.json (×15), CONTRIBUTING.md

Notes for reviewers

  • The issue_comment/scheduled workflows run the YAML from main, so /version-bump and the weekly job only take effect once this is merged — expected, not a bootstrap bug.
  • Open question for discussion: cadence/branch‑protection interplay for the weekly bot PR.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

…y backstop

WHY
Tools that surface skills (Copilot CLI, Claude Code, Codex, Cursor) read a
plugin's version directly from its checked-in manifest. With no versioning
discipline, a plugin's behavior can change while its advertised version stays
flat, so clients never learn to re-pull, and there is no human-readable signal
of what changed. We want correct, current versions in the repo with minimal
manual work and without bloating the marketplace clone.

WHAT
- Per-plugin semantic versioning via Nerdbank.GitVersioning (NBGV). Each plugin
  owns a version.json whose pathFilters exclude the generated manifests and the
  version.json itself, so version height tracks real content changes only.
- The computed version is materialized into the checked-in manifests
  (plugin.json and .codex-plugin/plugin.json) so every consumer reads a current
  value with no build step on their side.
- eng/version/Sync-PluginVersions.ps1 is the single workhorse. It resolves the
  set of changed plugins from a git diff, computes each version with nbgv
  (predicting the squash-merge height for PRs), and either reports or stamps.

AUTOMATIONS (two, low-touch by design)
- /version-bump: an admin/maintainer comments the command on a PR and the
  affected plugins are stamped on the PR branch. Gated on collaborator
  permission (admin/write/maintain); forks are rejected before any privileged
  step. No other PRs are auto-modified.
- weekly-version-sync: a Monday backstop (and workflow_dispatch) that stamps any
  drift on main, opens/updates a single bot PR, and explains the per-plugin
  reason. This self-heals anything that merged without a bump.

We deliberately did NOT auto-edit contributor PRs or add a noisy advisory
comment bot; maintainers stay in control and the signal stays clean.

SECURITY (multi-model adversarial review: GPT-5.5 + Gemini 3.1 Pro)
- Supply chain (High, both models): dotnet tool restore would have honored a
  nuget.config authored in the PR tree, letting an attacker remap the nbgv
  package source to a malicious feed and run code in the privileged
  contents:write context. Mitigated with a trusted eng/version/nuget.config
  (clear + nuget.org-only + packageSourceMapping), overlaid from main and used
  via --configfile so PR-supplied configs are ignored. No nuget.config is
  tracked in the repo today, so this path was genuinely exploitable.
- TOCTOU (Medium): /version-bump now checks out the authorized head SHA rather
  than the mutable branch name; a racing push fails non-fast-forward, which is
  the safe outcome.
- Injection: Set-ManifestVersion uses a MatchEvaluator (not a replacement
  string) so a "$"-bearing version cannot re-expand, plus a strict
  major.minor.patch guard that throws on a malformed base, leaving manifests
  untouched.
- A base-only version.json bump (0.1 -> 0.2) is correctly detected and stamped.

VERIFIED
End-to-end against a real NBGV git harness: content-scoped predict, base-only
bump -> x.y.0, docs-only -> [], weekly drift stamping, malformed-base guard,
and --configfile restore (exit 0). actionlint passes on both workflows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Skill Coverage Report

Plugin Skill Covered Coverage
dotnet-experimental exp-mock-usage-analysis 12/13 92.3%
⚠️ dotnet-experimental exp-test-maintainability 10/18 55.6%
dotnet-nuget convert-to-cpm 16/16 100%
dotnet-template-engine template-authoring 5/16 31.2%
dotnet-template-engine template-comparison 8/10 80%
dotnet-template-engine template-discovery 10/12 83.3%
⚠️ dotnet-template-engine template-instantiation 11/16 68.8%
⚠️ dotnet-template-engine template-smart-defaults 6/8 75%
⚠️ dotnet-template-engine template-validation 5/10 50%
dotnet-test-migration migrate-mstest-v1v2-to-v3 13/16 81.2%
dotnet-test-migration migrate-mstest-v3-to-v4 38/41 92.7%
dotnet-test-migration migrate-vstest-to-mtp 21/25 84%
⚠️ dotnet-test-migration migrate-xunit-to-mstest 31/46 67.4%
dotnet-test-migration migrate-xunit-to-xunit-v3 14/16 87.5%
⚠️ dotnet-maui maui-collectionview 7/9 77.8%
⚠️ dotnet-maui maui-data-binding 6/10 60%
dotnet-maui maui-dependency-injection 0/1 0%
dotnet-maui maui-safe-area 0/2 0%
dotnet-maui maui-theming 0/1 0%
dotnet-data optimizing-ef-core-queries 4/17 23.5%
dotnet-test assertion-quality 22/22 100%
dotnet-test code-testing-agent 5/5 100%
dotnet-test crap-score 6/6 100%
dotnet-test detect-static-dependencies 15/15 100%
dotnet-test filter-syntax 1/1 100%
dotnet-test generate-testability-wrappers 22/22 100%
dotnet-test grade-tests 28/28 100%
dotnet-test migrate-static-to-wrapper 21/21 100%
dotnet-test mtp-hot-reload 16/16 100%
dotnet-test run-tests 16/16 100%
dotnet-test test-anti-patterns 21/21 100%
dotnet-test test-gap-analysis 24/24 100%
dotnet-test test-smell-detection 26/26 100%
dotnet-test test-tagging 28/28 100%
dotnet-test writing-mstest-tests 45/45 100%
⚠️ dotnet-advanced csharp-scripts 13/22 59.1%
dotnet-advanced dotnet-pinvoke 6/28 21.4%
⚠️ dotnet-diag analyzing-dotnet-performance 12/21 57.1%
dotnet-diag android-tombstone-symbolication 5/5 100%
dotnet-diag apple-crash-symbolication 5/5 100%
dotnet-diag clr-activation-debugging 16/19 84.2%
dotnet-diag dotnet-trace-collect 15/17 88.2%
dotnet-diag microbenchmarking 3/3 100%
dotnet-blazor author-component 0/1 0%
dotnet-blazor collect-user-input 0/4 0%
dotnet-blazor configure-auth 0/3 0%
dotnet-blazor coordinate-components 0/2 0%
dotnet-blazor fetch-and-send-data 1/5 20%
dotnet-blazor plan-ui-change 0/1 0%
dotnet-blazor support-prerendering 0/3 0%
dotnet-blazor use-js-interop 0/2 0%
⚠️ dotnet-msbuild check-bin-obj-clash 9/13 69.2%
dotnet-msbuild directory-build-organization 0/1 0%
dotnet-msbuild extension-points 0/1 0%
dotnet-msbuild msbuild-modernization 6/7 85.7%
⚠️ dotnet-msbuild msbuild-server 7/9 77.8%
dotnet-msbuild property-patterns 0/1 0%
dotnet-msbuild resolve-project-references 5/6 83.3%
⚠️ dotnet-ai mcp-csharp-create 18/25 72%
dotnet-ai mcp-csharp-debug 16/18 88.9%
⚠️ dotnet-ai mcp-csharp-publish 10/15 66.7%
⚠️ dotnet-ai mcp-csharp-test 11/18 61.1%
dotnet-ai technology-selection 20/24 83.3%
⚠️ dotnet-aspnetcore configuring-opentelemetry-dotnet 13/21 61.9%
⚠️ dotnet-aspnetcore convert-blazor-server-to-webapp 17/27 63%
dotnet-aspnetcore dotnet-webapi 38/43 88.4%
⚠️ dotnet-aspnetcore minimal-api-file-upload 4/8 50%
⚠️ dotnet-upgrade dotnet-aot-compat 6/10 60%
dotnet-upgrade migrate-dotnet10-to-dotnet11 6/6 100%
dotnet-upgrade migrate-dotnet8-to-dotnet9 6/6 100%
dotnet-upgrade migrate-dotnet9-to-dotnet10 6/6 100%
⚠️ dotnet-upgrade migrate-nullable-references 20/27 74.1%
dotnet-upgrade thread-abort-migration 21/22 95.5%
dotnet setup-local-sdk 3/8 37.5%
Uncovered: dotnet-experimental/exp-mock-usage-analysis
  • [Validation] Production code was read and execution paths were traced (not just test code reviewed) (line 86)
Uncovered: dotnet-experimental/exp-test-maintainability
  • [Validation] Every finding shows the actual duplicated code, not just a description (line 188)
  • [Validation] Every suggestion includes a concrete before/after example (line 189)
  • [Validation] Findings are filtered through the 3+ occurrence threshold (line 190)
  • [Validation] Simple constructors are not flagged (line 191)
  • [Validation] If tests are clean, the report says so upfront (line 193)
  • [Pitfall] Suggesting extraction for 2 occurrences (line 200)
  • [Pitfall] Flagging simple new X() as boilerplate (line 203)
  • [CodePattern] [TestMethod] (line 67)
Uncovered: dotnet-template-engine/template-authoring
  • [Validation] Template identity and shortName are unique and meaningful (line 102)
  • [Validation] All parameters have descriptions and appropriate defaults (line 103)
  • [Validation] Template can be installed, dry-run, and instantiated successfully (line 104)
  • [Validation] Created projects build cleanly with dotnet build (line 105)
  • [Validation] Conditional content produces correct output for all parameter combinations (line 106)
  • [Pitfall] Identity format issues (line 112)
  • [Pitfall] Missing parameter descriptions (line 114)
  • [Pitfall] Not testing all parameter combinations (line 115)
  • [Pitfall] Not setting classifications (line 117)
  • [WorkflowStep] Step 3: Refine the template (line 80)
  • [WorkflowStep] Step 4: Test the template locally (line 90)
Uncovered: dotnet-template-engine/template-comparison
  • [Validation] Differences relevant to the user's scenario are called out explicitly (line 90)
  • [WorkflowStep] Step 3: Recommend (line 81)
Uncovered: dotnet-template-engine/template-discovery
  • [Validation] User understands what the template produces before proceeding to creation (line 145)
  • [Pitfall] A dotnet new call fails with a "mutex"/"persistence" error and you return nothing (line 154)
Uncovered: dotnet-template-engine/template-instantiation
  • [Validation] If CPM is active, .csproj has no version attributes and Directory.Packages.props has matching entries (line 128)
  • [Pitfall] Creating projects without specifying the framework (line 137)
  • [WorkflowStep] Step 2: Analyze the workspace (line 50)
  • [WorkflowStep] Step 3: Preview the creation (line 59)
  • [WorkflowStep] Step 6: Template package management (line 109)
Uncovered: dotnet-template-engine/template-smart-defaults
  • [Validation] No parameter the user set explicitly was overridden (line 62)
  • [Validation] Only unset parameters were filled (line 63)
Uncovered: dotnet-template-engine/template-validation
  • [Pitfall] ShortName = "list" or "search" (line 150)
  • [Pitfall] Invalid datatype value (line 153)
  • [Pitfall] Parameter prefix collision (Auth vs AuthMode) (line 155)
  • [Pitfall] Source condition without parentheses (line 156)
  • [WorkflowStep] Step 1: Locate the template.json (line 124)
Uncovered: dotnet-test-migration/migrate-mstest-v1v2-to-v3
  • [Validation] Project builds with zero errors (line 185)
  • [Validation] All tests pass (dotnet test) -- compare pass/fail counts to pre-migration baseline (line 186)
  • [CodePattern] Assert.AreNotEqual (line 144)
Uncovered: dotnet-test-migration/migrate-mstest-v3-to-v4
  • [CodePattern] [Timeout] (line 212)
  • [CodePattern] [TestMethodAttribute] (line 172)
  • [CodePattern] [TestMethod] (line 265)
Uncovered: dotnet-test-migration/migrate-vstest-to-mtp
  • [Validation] dotnet build completes with zero errors (line 361)
  • [Validation] Test executable runs directly (e.g., ./bin/Debug/net8.0/MyTests.exe) (line 363)
  • [Validation] No vstest.console.exe invocations remain in CI scripts (line 366)
  • [CodePattern] [trait] (line 252)
Uncovered: dotnet-test-migration/migrate-xunit-to-mstest
  • [Validation] using Xunit; and using Xunit.Abstractions; removed (line 521)
  • [Validation] xunit.runner.json removed; equivalent config in .runsettings / [assembly: Parallelize] (line 522)
  • [Validation] Project builds with zero errors (line 524)
  • [CodePattern] Parallelize (line 405)
  • [CodePattern] [ClassInitialize] (line 277)
  • [CodePattern] [ClassCleanup] (line 277)
  • [CodePattern] readonly (line 262)
  • [CodePattern] DoNotParallelize (line 434)
  • [CodePattern] [DoNotParallelize] (line 434)
  • [CodePattern] [TestMethod] (line 320)
  • [CodePattern] [TestClass] (line 277)
  • [CodePattern] [Fact] (line 308)
  • [CodePattern] Assert.False (line 347)
  • [CodePattern] Assert.IsFalse (line 347)
  • [CodePattern] sealed (line 277)
Uncovered: dotnet-test-migration/migrate-xunit-to-xunit-v3
  • [WorkflowStep] Step 13: Build and verify (line 199)
  • [CodePattern] sealed (line 118)
Uncovered: dotnet-maui/maui-collectionview
  • [Pitfall] EmptyView doesn't render correctly (line 329)
  • [Pitfall] Poor scroll performance (line 330)
Uncovered: dotnet-maui/maui-data-binding
  • [Pitfall] Specifying redundant Mode=OneWay / Mode=TwoWay (line 375)
  • [Pitfall] Mutating ObservableCollection off the UI thread (line 377)
  • [Pitfall] Complex converter chains in hot paths (line 378)
  • [Pitfall] Binding to non-public properties (line 380)
Uncovered: dotnet-maui/maui-dependency-injection
  • [CodePattern] readonly (line 102)
Uncovered: dotnet-maui/maui-safe-area
  • [CodePattern] readonly (line 65)
  • [CodePattern] [Flags] (line 48)
Uncovered: dotnet-maui/maui-theming
  • [CodePattern] [Activity] (line 226)
Uncovered: dotnet-data/optimizing-ef-core-queries
  • [Validation] SQL logging shows expected number of queries (no N+1) (line 164)
  • [Validation] Read-only queries use AsNoTracking() (line 165)
  • [Validation] Hot-path queries use compiled queries (line 166)
  • [Validation] No client-side evaluation warnings in logs (line 167)
  • [Validation] Include/split strategy matches data shape (line 168)
  • [Pitfall] Global query filters forgotten in perf analysis (line 175)
  • [Pitfall] DbContext kept alive too long (line 176)
  • [Pitfall] String interpolation in FromSqlRaw (line 178)
  • [WorkflowStep] Step 1: Enable query logging to see the actual SQL (line 31)
  • [WorkflowStep] Step 4: Use compiled queries for hot paths (line 120)
  • [WorkflowStep] Step 5: Avoid common query traps (line 134)
  • [WorkflowStep] Step 6: Use raw SQL or FromSql for complex queries (line 144)
  • [CodePattern] readonly (line 122)
Uncovered: dotnet-advanced/csharp-scripts
  • [Validation] dotnet --version reports 10.0 or later (or fallback path is used) (line 274)
  • [Validation] The app compiles without errors (can be checked explicitly with dotnet build <file>.cs) (line 276)
  • [Validation] App files and cached artifacts are cleaned up after the session (line 279)
  • [Pitfall] #:package without a version (line 286)
  • [Pitfall] #:property with wrong syntax (line 287)
  • [Pitfall] Directives placed after C# code (line 288)
  • [Pitfall] Reflection-based JSON serialization fails (line 293)
  • [WorkflowStep] Step 5: Clean up (line 199)
  • [CodePattern] [MSBuild] (line 93)
Uncovered: dotnet-advanced/dotnet-pinvoke
  • [Validation] Calling convention specified if targeting Windows x86; omitted otherwise (line 424)
  • [Validation] String encoding is explicit — no reliance on defaults or CharSet.Auto (line 425)
  • [Validation] Memory ownership is documented and matched (who allocates, who frees, with what) (line 426)
  • [Validation] SafeHandle used for all native handles (no raw IntPtr escaping the interop layer) (line 427)
  • [Validation] Delegates passed as callbacks are rooted to prevent GC collection (line 428)
  • [Validation] SetLastError/SetLastPInvokeError set for APIs that use OS error codes (line 429)
  • [Validation] Struct layout matches native (packing, alignment, field order) (line 430)
  • [Validation] CLong/CULong used for C long/unsigned long in cross-platform code (line 431)
  • [Validation] If using CLong/CULong with LibraryImport, [assembly: DisableRuntimeMarshalling] is applied (line 432)
  • [Validation] No bool without explicit MarshalAs — always specify UnmanagedType.Bool (4-byte) or UnmanagedType.U1 (1-byte) to ensure normalization across the language boundary. (line 433)
  • [WorkflowStep] Step 5: Establish Memory Ownership (line 168)
  • [WorkflowStep] Step 6: Use SafeHandle for Native Handles (line 224)
  • [WorkflowStep] Step 7: Handle Errors (line 261)
  • [CodePattern] [DllImport] (line 93)
  • [CodePattern] [UnmanagedCallersOnly] (line 281)
  • [CodePattern] [LibraryImport] (line 101)
  • [CodePattern] [256] (line 176)
  • [CodePattern] [Out] (line 144)
  • [CodePattern] [UnmanagedFunctionPointer] (line 300)
  • [CodePattern] sealed (line 228)
  • [CodePattern] [UnmanagedCallConv] (line 111)
  • [CodePattern] [MarshalAs] (line 144)
Uncovered: dotnet-diag/analyzing-dotnet-performance
  • [Validation] All critical patterns were checked (from reference files or inline recipes) (line 178)
  • [Validation] Topic-specific recipes run only when matching signals detected (line 179)
  • [Validation] Each finding includes a concrete code fix (line 180)
  • [Validation] Scan execution checklist is complete (all recipes run) (line 181)
  • [Validation] Summary table included at end (line 182)
  • [Pitfall] Suggesting ConfigureAwait(false) in app code (line 191)
  • [Pitfall] Recommending ValueTask everywhere (line 192)
  • [Pitfall] Flagging new HttpClient() in DI services (line 193)
  • [Pitfall] Suggesting CollectionsMarshal.AsSpan broadly (line 195)
Uncovered: dotnet-diag/clr-activation-debugging
  • [Validation] The entry point for each problematic activation was identified (line 289)
  • [Validation] SEM_FAILCRITICALERRORS state was noted for FOD-related issues (line 292)
  • [Validation] Multiple activations within a single log were individually traced (line 293)
Uncovered: dotnet-diag/dotnet-trace-collect
  • [Validation] The recommended tool is compatible with the developer's runtime, OS, and deployment topology (line 235)
  • [Validation] The output file is generated in the expected location (line 237)
Uncovered: dotnet-blazor/author-component
  • [CodePattern] [Parameter] (line 31)
Uncovered: dotnet-blazor/collect-user-input
  • [CodePattern] [Range] (line 135)
  • [CodePattern] [Required] (line 135)
  • [CodePattern] [SupplyParameterFromForm] (line 31)
  • [CodePattern] [CascadingParameter] (line 162)
Uncovered: dotnet-blazor/configure-auth
  • [CodePattern] [ExcludeFromInteractiveRouting] (line 152)
  • [CodePattern] [Authorize] (line 101)
  • [CodePattern] [CascadingParameter] (line 51)
Uncovered: dotnet-blazor/coordinate-components
  • [CodePattern] [CascadingParameter] (line 63)
  • [CodePattern] readonly (line 137)
Uncovered: dotnet-blazor/fetch-and-send-data
  • [CodePattern] [PersistentState] (line 84)
  • [CodePattern] [StreamRendering] (line 74)
  • [CodePattern] [Parameter] (line 159)
  • [CodePattern] [SupplyParameterFromQuery] (line 159)
Uncovered: dotnet-blazor/plan-ui-change
  • [CodePattern] [Parameter] (line 64)
Uncovered: dotnet-blazor/support-prerendering
  • [CodePattern] [PersistentState] (line 39)
  • [CodePattern] [ExcludeFromInteractiveRouting] (line 148)
  • [CodePattern] [CascadingParameter] (line 159)
Uncovered: dotnet-blazor/use-js-interop
  • [CodePattern] readonly (line 118)
  • [CodePattern] sealed (line 118)
Uncovered: dotnet-msbuild/check-bin-obj-clash
  • [WorkflowStep] Step 2: Get an overview and list projects (line 48)
  • [WorkflowStep] Step 5: Check for double writes (line 62)
  • [WorkflowStep] Step 2: Replay the Binary Log to Text (line 78)
  • [WorkflowStep] Step 3: List All Projects (line 84)
Uncovered: dotnet-msbuild/directory-build-organization
  • [CodePattern] [MSBuild] (line 122)
Uncovered: dotnet-msbuild/extension-points
  • [CodePattern] [MSBuild] (line 195)
Uncovered: dotnet-msbuild/msbuild-modernization
  • [WorkflowStep] Step 6: Remove Unnecessary Boilerplate (line 217)
Uncovered: dotnet-msbuild/msbuild-server
  • [Validation] MSBUILDUSESERVER=1 is set in the shell (line 59)
  • [Validation] Second sequential build is faster than the first (line 60)
Uncovered: dotnet-msbuild/property-patterns
  • [CodePattern] [MSBuild] (line 33)
Uncovered: dotnet-msbuild/resolve-project-references
  • [Validation] ResolveProjectReferences was not set as the optimization target (line 64)
Uncovered: dotnet-ai/mcp-csharp-create
  • [Validation] Project builds with no errors (dotnet build) (line 232)
  • [Validation] HTTP: app.MapMcp() is called in Program.cs (line 237)
  • [Validation] Server starts successfully with dotnet run (line 238)
  • [Pitfall] WithToolsFromAssembly() fails in AOT (line 247)
  • [WorkflowStep] Step 5: Add prompts and resources (optional) (line 151)
  • [CodePattern] CancellationToken (line 90)
  • [CodePattern] [Description] (line 90)
Uncovered: dotnet-ai/mcp-csharp-debug
  • [Validation] Breakpoints hit when debugging in IDE (line 185)
  • [Pitfall] HTTP server returns 404 at MCP endpoint (line 195)
Uncovered: dotnet-ai/mcp-csharp-publish
  • [Validation] NuGet: Package installs and runs via dnx PackageId@version (line 243)
  • [Validation] Azure: Server is reachable and tools respond (line 245)
  • [Validation] MCP Registry: Server appears at registry.modelcontextprotocol.io (line 246)
  • [Validation] MCP client can connect and call tools on the deployed server (line 247)
  • [Pitfall] Docker container exits immediately (line 255)
Uncovered: dotnet-ai/mcp-csharp-test
  • [Validation] All tests pass: dotnet test (line 165)
  • [Validation] Tests run in CI without manual setup (line 166)
  • [Pitfall] Full test suite runs are slow (line 176)
  • [WorkflowStep] Step 4: Run tests (line 138)
  • [CodePattern] [Theory] (line 57)
  • [CodePattern] [InlineData] (line 57)
  • [CodePattern] [Fact] (line 57)
Uncovered: dotnet-ai/technology-selection
  • [Validation] Non-deterministic outputs have validation and fallback paths (line 319)
  • [Validation] dotnet build -c Release -warnaserror completes cleanly (line 320)
  • [Pitfall] Over-engineering with LLMs (line 348)
  • [Pitfall] Cold start latency on ML.NET models (line 354)
Uncovered: dotnet-aspnetcore/configuring-opentelemetry-dotnet
  • [Validation] Traces appear in the observability backend (Jaeger, Aspire dashboard, etc.) (line 272)
  • [Validation] HTTP requests automatically create spans with correct verb, URL, status code (line 273)
  • [Validation] Health check endpoints are filtered from traces (line 277)
  • [Validation] Exception details appear on error spans (line 278)
  • [Pitfall] Missing HTTP client spans (line 286)
  • [Pitfall] High cardinality tags (line 287)
  • [CodePattern] readonly (line 124)
  • [CodePattern] [key] (line 241)
Uncovered: dotnet-aspnetcore/convert-blazor-server-to-webapp
  • [Validation] No references to AddServerSideBlazor remain (line 261)
  • [Validation] No references to MapBlazorHub remain (line 262)
  • [Validation] No references to MapFallbackToPage("/_Host") remain (line 263)
  • [Validation] No references to blazor.server.js remain (line 264)
  • [Validation] Pages/_Host.cshtml has been deleted (line 265)
  • [Validation] App builds and runs successfully on the target framework (line 272)
  • [Pitfall] Not migrating AddServerSideBlazor circuit options (line 283)
  • [Pitfall] CSS isolation bundle link has wrong assembly name (line 285)
  • [WorkflowStep] Step 1: Update the project file (line 48)
  • [WorkflowStep] Step 6: Recommended improvements (optional) (line 234)
Uncovered: dotnet-aspnetcore/dotnet-webapi
  • [Validation] DELETE endpoints return 204 No Content (line 464)
  • [Validation] A .http file exists with a request for every new endpoint (line 474)
  • [Validation] dotnet build passes with zero errors and zero warnings (line 475)
  • [CodePattern] [Range] (line 147)
  • [CodePattern] [HttpGet] (line 248)
Uncovered: dotnet-aspnetcore/minimal-api-file-upload
  • [WorkflowStep] Step 1: CRITICAL — Understand IFormFile Binding in Minimal APIs (line 29)
  • [WorkflowStep] Step 5: CRITICAL — Streaming Large Files Without Buffering (line 170)
  • [CodePattern] [FromForm] (line 31)
  • [CodePattern] [RequestSizeLimit] (line 54)
Uncovered: dotnet-upgrade/dotnet-aot-compat
  • [CodePattern] [DynamicallyAccessedMembers] (line 119)
  • [CodePattern] [RequiresUnreferencedCode] (line 195)
  • [CodePattern] [MSBuild] (line 67)
  • [CodePattern] [JsonSerializerContext] (line 169)
Uncovered: dotnet-upgrade/migrate-nullable-references
  • [Validation] Project file(s) contain <Nullable>enable</Nullable> (or #nullable enable per-file for file-by-file strategy) (line 235)
  • [Validation] <WarningsAsErrors>nullable</WarningsAsErrors> added to project file to prevent regressions (line 237)
  • [Validation] No #nullable disable directives remain unless justified with a comment (line 239)
  • [Validation] Public API signatures accurately reflect null contracts (line 241)
  • [Validation] For public libraries: breaking changes documented in nullable-breaking-changes.md and reviewed by the user (line 242)
  • [Pitfall] Multi-target projects and older TFMs (line 265)
  • [Pitfall] Warnings reappear after upgrading a dependency (line 266)
Uncovered: dotnet-upgrade/thread-abort-migration
  • [Validation] No SYSLIB0006 pragma suppressions remain (line 117)
Uncovered: dotnet/setup-local-sdk
  • [Pitfall] paths ignored (line 382)
  • [Pitfall] dotnet app.dll wrong runtime (line 386)
  • [CodePattern] [pscustomobject] (line 301)
  • [CodePattern] [ordered] (line 301)
  • [CodePattern] [guid] (line 104)

@AbhitejJohn
AbhitejJohn requested a review from Evangelink June 24, 2026 17:12
@AbhitejJohn

Copy link
Copy Markdown
Collaborator Author

Curious to hear thoughts on this versioning strategy. Goal was to keep this with as less ceremony as possible. At the moment Claude code users do not really get updates if they've already pulled down a plugin earlier because we haven't changed our versions.

@AbhitejJohn
AbhitejJohn marked this pull request as ready for review June 24, 2026 17:14
Copilot AI review requested due to automatic review settings June 24, 2026 17:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces automated, per-plugin semantic versioning for the plugins/* tree using Nerdbank.GitVersioning (NBGV), and adds two GitHub Actions automations to materialize the computed versions into the checked-in plugin manifests (so downstream consumers read current versions directly from the repo).

Changes:

  • Add per-plugin plugins/<plugin>/version.json files to scope NBGV version height to each plugin subtree.
  • Add eng/version/Sync-PluginVersions.ps1 plus a locked-down eng/version/nuget.config and a local tool manifest for nbgv.
  • Add two workflows: /version-bump (issue_comment-driven, same-repo PRs) and a scheduled weekly backstop PR that stamps any drift on main.
Show a summary per file
File Description
plugins/dotnet11/version.json Adds NBGV per-plugin version configuration for dotnet11.
plugins/dotnet/version.json Adds NBGV per-plugin version configuration for dotnet.
plugins/dotnet-upgrade/version.json Adds NBGV per-plugin version configuration for dotnet-upgrade.
plugins/dotnet-test/version.json Adds NBGV per-plugin version configuration for dotnet-test.
plugins/dotnet-template-engine/version.json Adds NBGV per-plugin version configuration for dotnet-template-engine.
plugins/dotnet-nuget/version.json Adds NBGV per-plugin version configuration for dotnet-nuget.
plugins/dotnet-msbuild/version.json Adds NBGV per-plugin version configuration for dotnet-msbuild.
plugins/dotnet-maui/version.json Adds NBGV per-plugin version configuration for dotnet-maui.
plugins/dotnet-experimental/version.json Adds NBGV per-plugin version configuration for dotnet-experimental.
plugins/dotnet-diag/version.json Adds NBGV per-plugin version configuration for dotnet-diag.
plugins/dotnet-data/version.json Adds NBGV per-plugin version configuration for dotnet-data.
plugins/dotnet-blazor/version.json Adds NBGV per-plugin version configuration for dotnet-blazor.
plugins/dotnet-aspnetcore/version.json Adds NBGV per-plugin version configuration for dotnet-aspnetcore.
plugins/dotnet-ai/version.json Adds NBGV per-plugin version configuration for dotnet-ai.
eng/version/Sync-PluginVersions.ps1 Core PowerShell implementation to compute/stamp versions and emit a JSON report.
eng/version/nuget.config Locked-down NuGet config used by workflows to prevent PR-controlled feed remapping during tool restore.
.config/dotnet-tools.json Adds local nbgv tool dependency for consistent version computation in CI.
.github/workflows/version-bump-command.yml Implements the maintainer-triggered /version-bump workflow.
.github/workflows/weekly-version-sync.yml Implements the scheduled backstop that opens/updates a single “weekly sync” PR on drift.
CONTRIBUTING.md Documents the new per-plugin versioning model and contributor expectations.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 20/20 changed files
  • Comments generated: 4

Comment thread CONTRIBUTING.md Outdated
Comment thread CONTRIBUTING.md Outdated
Comment thread .github/workflows/weekly-version-sync.yml Outdated
Comment thread eng/version/Sync-PluginVersions.ps1
@github-actions github-actions Bot added the waiting-on-author PR state label label Jun 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

👋 @AbhitejJohn — this PR has 4 unresolved review thread(s). When you're ready, please address the feedback and push an update; the triage bot will pick up the next state automatically. (Add the no-stale label to silence further pings.)

- Add missing plugins/dotnet-test-migration/version.json so it participates
  in versioning (it was the only plugin without one; manifests are at 0.1.0).
- CONTRIBUTING: the two manifests are not byte-identical; say the version is
  duplicated across two manifest files instead.
- weekly-version-sync: include version.json in commit attribution so a
  base-only bump is explained rather than showing 'no attributable commits'.
- Get-NbgvInfo: capture nbgv stderr and include it in the thrown error so CI
  failures are diagnosable, while keeping stdout clean for JSON parsing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Evangelink
Evangelink enabled auto-merge (squash) June 25, 2026 07:57
@github-actions github-actions Bot added waiting-on-review PR state label and removed waiting-on-author PR state label labels Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Evaluation passed for 766115f. cc @webreidi @AbhitejJohn @ViktorHofer @JanKrivanek @dotnet/aspnet @Redth @jfversluis @dotnet/skills-maui-reviewers @dotnet/skills-msbuild-reviewers @dotnet/area-infrastructure-libraries @kartheekp-ms @YuliiaKovalova @dotnet/dotnet-testing @ManishJayaswal — please review.

@Evangelink Evangelink left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: per-plugin NBGV versioning

Really like the overall design — per-plugin pathFilters, materializing into the checked-in manifests, the opt-in /version-bump + weekly backstop split, and the security hardening on the privileged workflow (SHA-pinned actions, fail-closed permission gate, fork rejection before any privileged step, --configfile source-mapped NuGet, trusted-tooling overlay from main, injection-safe MatchEvaluator). The security posture of version-bump-command.yml looks sound to me.

My concern is that the privileged workflow's git plumbing and the tool runtime pin look like they'll prevent /version-bump (and likely the weekly sync) from actually running. Because both workflows are issue_comment/schedule-triggered they run from main and get no CI signal on this PR, so these can only be caught by review. Two of the inline findings below were reproduced in a scratch repo.

This was a combined pass (two independent reviewers); we converged on the same set with no contradictions. Inline comments have details + suggested fixes. Summary:

Blocking / CI-breaking

  • git fetch --depth=1 origin main makes the whole repo shallow → NBGV refuses to compute height. Reproduced: a depth-limited fetch writes .git/shallow and flips the entire repo to shallow even though the head was checked out with fetch-depth: 0, so every nbgv get-version in the ordinary-content path fails.
  • git merge-base $BASE_SHA $head returns empty when the PR is behind main. Reproduced (PR 3 commits behind → empty merge-base, exit 1 → script throws -PredictSquashMerge requires -BaseCommit). Fixed by the same full-fetch change, plus an empty-merge-base guard.
  • nbgv (net8) under rollForward: false on a net11-preview-only runtime. setup-dotnet installs only the global.json runtime; a net8-targeted tool won't run, and even rollForward: true won't pick a preview runtime without DOTNET_ROLL_FORWARD_TO_PRERELEASE=1. Best fix: explicitly install an 8.0.x runtime in both workflows.

Correctness

  • Squash prediction over-bumps on version.json-only (non-base) edits, then the weekly backstop computes the true (lower) height and corrects downward — a non-monotonic version regression visible to consumers.

Minor

  • Format guard validates the computed value but not the 2-part base shape in version.json (a malformed 3-part base slips through the weekly path).
  • Concurrent /version-bump on the same plugin can stamp colliding patch numbers until the weekly sync reconciles — worth a doc note.
  • PR description says version.json ×14; there are 15 (dotnet-test-migration was added in commit 2).

Comment thread .github/workflows/version-bump-command.yml Outdated
Comment thread .github/workflows/version-bump-command.yml
Comment thread .config/dotnet-tools.json
Comment thread eng/version/Sync-PluginVersions.ps1 Outdated
Comment thread eng/version/Sync-PluginVersions.ps1
@github-actions github-actions Bot added waiting-on-author PR state label and removed waiting-on-review PR state label labels Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

👋 @AbhitejJohn — this PR has 5 unresolved review thread(s). When you're ready, please address the feedback and push an update; the triage bot will pick up the next state automatically. (Add the no-stale label to silence further pings.)

Address @Evangelink's review on the per-plugin versioning workflows. These
issue_comment/schedule workflows run from main and get no CI signal on the PR,
so each fix is validated with a local NBGV git harness instead.

Workflow runtime/git plumbing (version-bump-command.yml, weekly-version-sync.yml):
- Drop --depth=1 from the "pin trusted tooling from main" fetch. A shallow fetch
  writes .git/shallow and flips the whole repo shallow (proven locally), and NBGV
  refuses to compute height on a shallow repo. fetch-depth: 0 already fetched main,
  so the full fetch is cheap and keeps the supply-chain pin intact.
- Add a guard that throws if `git merge-base BASE_SHA head` is empty, instead of
  letting nbgv fail with an opaque "-PredictSquashMerge requires -BaseCommit".
- setup-dotnet: install dotnet-version 8.0.x alongside global-json-file. nbgv
  targets net8.0; global.json pins an SDK that ships only a net11 preview runtime,
  onto which a release-targeted tool will not roll forward. setup-dotnet installs
  both inputs, giving nbgv a runtime to run on.

Prediction correctness (Sync-PluginVersions.ps1):
- Only add +1 to the predicted height when a height-bearing file actually changed.
  A version.json-only non-base edit is height-neutral, so predicting +1 over-bumps
  and the weekly sync would later correct it downward — a visible version
  regression. New Test-HeightBearingChange checks the diff with the canonical
  exclusions.
- Validate the version.json base is major.minor; a 3-part base (e.g. 0.1.0) was
  silently normalized by NBGV into a passing SimpleVersion on the weekly path.
- Reject non-canonical pathFilters (raised in cross-model review). The predict
  height math assumes version.json and the two stamped manifests are excluded and
  that the filter set is stable between base and head; a hand-edited pathFilters
  would silently diverge the post-merge height from the prediction. The
  height-excluded file list is now a single source of truth shared by the guard
  and Test-HeightBearingChange.

CONTRIBUTING.md: note that concurrently bumped PRs can predict the same patch and
that the weekly sync reconciles the collision.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added waiting-on-review PR state label and removed waiting-on-author PR state label labels Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

✅ Evaluation passed for 284695d. cc @webreidi @AbhitejJohn @ViktorHofer @JanKrivanek @dotnet/aspnet @Redth @jfversluis @dotnet/skills-maui-reviewers @dotnet/skills-msbuild-reviewers @dotnet/area-infrastructure-libraries @kartheekp-ms @YuliiaKovalova @dotnet/dotnet-testing @ManishJayaswal — please review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 21/21 changed files
  • Comments generated: 6

Comment thread plugins/dotnet/version.json
Comment thread plugins/dotnet-test/version.json
Comment thread eng/version/Sync-PluginVersions.ps1
Comment thread eng/version/Sync-PluginVersions.ps1
Comment thread eng/version/Sync-PluginVersions.ps1
Comment thread CONTRIBUTING.md Outdated
@github-actions github-actions Bot added waiting-on-author PR state label and removed waiting-on-review PR state label labels Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

👋 @AbhitejJohn — this PR has 6 unresolved review thread(s). When you're ready, please address the feedback and push an update; the triage bot will pick up the next state automatically. (Add the no-stale label to silence further pings.)

The main merge bumped dotnet, dotnet-test, and dotnet-advanced to 0.2.0 in
their manifests, but their NBGV bases hadn't followed — a mismatch the weekly
sync would have "corrected" downward into a version regression. Addresses the
Copilot review on the merge commit.

- plugins/dotnet, plugins/dotnet-test: version.json base 0.1 -> 0.2 to match
  the manifests. Verified with an NBGV harness: base 0.1 + manifest 0.2.0
  computes 0.1.1 (a downgrade); base 0.2 computes 0.2.0 (the base change resets
  git height to 0), so no regression.
- Add plugins/dotnet-advanced/version.json (base 0.2, canonical pathFilters);
  it shipped a plugin.json but had no version base, so automation skipped it.

Sync-PluginVersions.ps1:
- Require -HeadCommit whenever -PredictSquashMerge is set. Without it the script
  fell back to all plugins and defaulted bumps=1, predicting a +1 patch for
  every plugin. Also simplifies the now-unconditional bumps calculation.
- Set-Location to the repo root before running git, so the repo-root-relative
  pathspecs resolve correctly regardless of the caller's working directory.
- Weekly path now enumerates by plugin.json and fails fast if a plugin has no
  version.json, instead of silently skipping it. The predict path is made
  symmetric: a changed shipped plugin (has plugin.json) missing version.json
  throws, while a deleted/non-plugin dir is still skipped.

CONTRIBUTING: document that every plugin must carry its own version.json.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 16:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 22/22 changed files
  • Comments generated: 3

Comment thread .github/workflows/version-bump-command.yml
Comment thread .github/workflows/version-bump-command.yml Outdated
Comment thread eng/version/Sync-PluginVersions.ps1
…fail-fast

Resolves the 3 findings from the Copilot re-review of ebd957e.

version-bump-command.yml:
- After overlaying trusted tooling from main via `git checkout FETCH_HEAD --
  <paths>`, that checkout also STAGES those paths. Add `git reset -q HEAD --
  <same paths>` so the index returns to HEAD's copies while the working tree
  keeps the overlay: the script still runs main's tooling, but a later commit
  can never include the overlaid tooling even if cleanup is skipped/fails.
- Make the worktree-hygiene cleanup `git checkout HEAD -- <paths>` non-fatal
  (`|| true`) so an older PR branch whose HEAD predates a file (e.g. no
  global.json) doesn't fail on "pathspec did not match". Rewrote the comment to
  clarify the unstage — not this cleanup — is what prevents a tooling leak.

Sync-PluginVersions.ps1:
- Treat the Codex manifest (.codex-plugin/plugin.json) as required: throw fast
  if a shipped plugin is missing it, rather than silently stamping only
  plugin.json and shipping mismatched versions across consumers. Placed after
  the version.json/deleted-plugin guard so deletions still skip cleanly.
- Simplify $currentCodex to an unconditional read and $changed accordingly,
  since existence is now guaranteed.

Validated: actionlint clean; script parses; harness scenarios prove
codex-missing throws, both manifests stamp equally, and manifest drift is
detected. Cross-model (GPT-5.5) review found no issues.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 17:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 22/22 changed files
  • Comments generated: 3

Comment thread .github/workflows/version-bump-command.yml Outdated
Comment thread eng/version/Sync-PluginVersions.ps1 Outdated
Comment thread CONTRIBUTING.md Outdated
…rden /version-bump permission check

Resolves the 3 findings from the Copilot re-review of ebfc958.

Optional third manifest (.claude-plugin/plugin.json):
- One plugin (dotnet-msbuild, via #844) also carries
  plugins/<name>/.claude-plugin/plugin.json — Claude Code needs an inline
  mcpServers block where the Codex manifest uses a reference. It has its own
  "version" field, but the script only stamped plugin.json and
  .codex-plugin/plugin.json, so it would drift. The top-level marketplace.json
  files carry no version fields, so they stay out of scope.
- Sync-PluginVersions.ps1: add .claude-plugin/plugin.json to the universal
  $HeightExcludedFiles (so it's height-excluded and part of the canonical
  pathFilters set) and to Get-ChangedPlugins' output-manifest excludes. In the
  main loop, treat it as optional (stamp-if-present, keyed off Test-Path so a
  present-but-malformed manifest fails loudly instead of being skipped); codex
  stays required. Include it in the drift/$changed check and the write path.
- All 16 plugins/*/version.json: add ":!.claude-plugin/plugin.json" so they
  still match the now-4-entry canonical set. Excluding a manifest a plugin
  doesn't have is a harmless no-op and future-proofs any plugin that later adds
  one.
- CONTRIBUTING.md: document the optional third manifest.

version-bump-command.yml:
- The actor permission lookup returned a 404 for non-collaborators, which made
  `gh api` exit non-zero and (under the default `set -eo pipefail` shell)
  aborted the step before the friendly "requires write access" denial comment.
  Default to "none" on any API failure so the denial path always runs. This can
  only ever deny more, never grant.
- Add a non-fatal `git add plugins/*/.claude-plugin/plugin.json` so the new
  manifest is committed, and an empty glob (if no plugin has one in future)
  can't fail the step.

Validated: actionlint clean; script parses; harness scenarios prove all three
manifests stamp equally, the Claude manifest is height-excluded (no self-bump),
claude-only drift is detected, a plugin without one stamps only its two, a
present-but-malformed Claude manifest fails loudly, and the canonical guard
accepts the 4-exclusion set. Earlier codex/regression guard suites still pass.
Cross-model (GPT-5.5) review drove the Test-Path presence fix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 17:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 22/22 changed files
  • Comments generated: 2

Comment thread .github/workflows/weekly-version-sync.yml
Comment thread .github/workflows/weekly-version-sync.yml Outdated
…weekly sync

Resolves the 2 findings from the Copilot re-review of 65d79ce, both in the
weekly sync workflow (the /version-bump command was already updated in 65d79ce
but the weekly sync was missed).

weekly-version-sync.yml:
- The stamping script updates the optional .claude-plugin/plugin.json when a
  plugin has one, but the commit step only staged plugin.json and
  .codex-plugin/plugin.json — so for dotnet-msbuild the stamped Claude manifest
  would never be committed, causing persistent drift and a repeat sync PR every
  week. Add a non-fatal `git add plugins/*/.claude-plugin/plugin.json` (mirrors
  the /version-bump fix; empty glob can't fail the step).
- Update the generated PR body to say the sync also stamps
  .claude-plugin/plugin.json where present, so reviewers of the bot PR aren't
  confused.
- Exclude .claude-plugin/plugin.json from the per-plugin commit attribution
  (git log) too, consistent with the other two output manifests, so a manifest
  stamp is never listed as a reason for the bump.

actionlint clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 17:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 22/22 changed files
  • Comments generated: 0 new

@github-actions

Copy link
Copy Markdown
Contributor

👋 @AbhitejJohn — this PR has 1 unresolved review thread(s). When you're ready, please address the feedback and push an update; the triage bot will pick up the next state automatically. (Add the no-stale label to silence further pings.)

@JanKrivanek JanKrivanek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@Evangelink
Evangelink merged commit ca1b473 into main Jul 13, 2026
39 checks passed
@Evangelink
Evangelink deleted the abhitejjohn/per-plugin-version-strategy branch July 13, 2026 17:07
briancabello pushed a commit to Forked-Dev-Tools/.Net-Skills that referenced this pull request Aug 1, 2026
The header comment contained `--configfile`, i.e. a doubled hyphen `--`, which
XML forbids inside a comment. That made eng/version/nuget.config invalid XML, so
`dotnet tool restore --configfile eng/version/nuget.config` failed with
"NuGet.Config is not valid XML" on every run of BOTH versioning workflows
(weekly-version-sync and version-bump-command). As a result no automated version
bumps have ever been produced since the infra merged in dotnet#813.

Reword the comment to avoid any doubled-hyphen sequence and move it inside
<configuration>. Verified: the file now parses as XML and `dotnet tool restore`
succeeds; nbgv get-version computes correctly against the plugins.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 70b3727e-c27d-4a3e-aff9-f4eb65eaf25c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on-author PR state label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants