Implement .NET UpdatePackageVersion#14482
Conversation
Add language-specific version update for .NET packages: - Try Update-PkgVersion.ps1 from the repo (follows SetPackageVersion pattern) - Fall back to direct .csproj <Version> update when script unavailable - Parse sdk/<service>/<package> layout for script arguments - 11 tests covering script path, fallback, errors, and edge cases Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Change -ReplaceLatestEntryTitle from $true to $false to prevent Update-PkgVersion.ps1 from modifying CHANGELOG.md, since the base LanguageService class already handles changelog updates. - Fix WhenNoCsprojFound test to create a src/ directory without .csproj files, so it actually tests the 'no .csproj in existing src/' code path instead of duplicating the WhenSrcDirMissing test. - Strengthen ScriptCalledWithCorrectServiceAndPackage test to verify the actual script arguments (ServiceDirectory, PackageName, version) rather than only checking the script path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace inline sdk/<service>/<package> path parsing in both DotnetLanguageService.VersionUpdate.cs and DotNetLanguageService.Checks.cs with the shared PackageInfoHelper.ParsePackagePathAsync helper, consistent with Java and other language services. - Remove GetServiceDirectoryFromPath and GetPackageNameFromPath private methods from Checks.cs (45 lines of duplicated logic) - Consolidate redundant gitHelper.DiscoverRepoRootAsync calls in CheckGeneratedCode and CheckAotCompat - Update tests to mock IPackageInfoHelper instead of IGitHelper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Call TryGetPackageInfoAsync to get the accurate package name from MSBuild project metadata when invoking Update-PkgVersion.ps1, since the folder name may not match the actual package name. Falls back to the folder name if MSBuild is unavailable. Add test proving MSBuild-derived name takes precedence over folder name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update DotNetLanguageSpecificChecksTests to use a proper IPackageInfoHelper mock with a dynamic callback that computes the correct relative path, matching the refactored Checks.cs code that now uses ParsePackagePathAsync instead of the removed GetServiceDirectoryFromPath/GetPackageNameFromPath methods. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use null-coalescing on relativePath from ParsePackagePathAsync in all call sites, so null values safely produce empty path parts that trigger the existing validation checks. This removes the need for a default mock setup in tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace (relativePath ?? string.Empty) with explicit null checks and early returns, making the null case immediately visible. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply TryGetPackageInfoAsync for package name resolution in CheckAotCompat and ValidateChangelog, consistent with VersionUpdate. Falls back to folder name if MSBuild is unavailable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When Update-PkgVersion.ps1 is available, the .NET override now bypasses the base class changelog logic and delegates everything to the script with -ReplaceLatestEntryTitle and -ReleaseDate. This enables the beta-to-stable version promotion workflow (e.g. 12.28.0-beta.2 -> 12.28.0) where the script renames the changelog entry title and updates version files in one step. When the script is not available, falls back to base.UpdateVersionAsync which handles changelog separately then calls the simplified UpdatePackageVersionInFilesAsync for direct .csproj updates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tion - Change -ReplaceLatestEntryTitle from 'True' to 'true'. PowerShell -File mode treats '\True' as a literal string; 'true' is correctly converted to boolean. - Add fail-fast validation that releaseType matches the version format: stable + pre-release suffix = error, beta + no suffix = error. Includes actionable next steps suggesting the correct combination. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PowerShell -File mode cannot convert any string to [bool] parameters. Switch to -Command mode with '& script.ps1' invocation so that \True is evaluated as a native PowerShell boolean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds .NET package version update support to azsdk-cli by implementing .NET-specific version file updates and aligning some .NET checks with the shared ParsePackagePathAsync parsing flow.
Changes:
- Add
DotnetLanguageServiceversion update implementation with a primary PowerShell script path (Update-PkgVersion.ps1) and a.csproj<Version>fallback. - Update
.NETlanguage checks to derive service/package names viaIPackageInfoHelper.ParsePackagePathAsync(and MSBuild metadata where available). - Add new unit tests covering script vs fallback behavior and edge cases.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| tools/azsdk-cli/Azure.Sdk.Tools.Cli/Services/Languages/DotnetLanguageService.VersionUpdate.cs | Implements .NET version update logic (script + fallback) and release-type validation. |
| tools/azsdk-cli/Azure.Sdk.Tools.Cli/Services/Languages/DotNetLanguageService.Checks.cs | Updates .NET checks to use repo-root/relative-path parsing and MSBuild package name. |
| tools/azsdk-cli/Azure.Sdk.Tools.Cli.Tests/Services/Languages/DotnetLanguageServiceVersionUpdateTests.cs | Adds coverage for script success/failure, fallback behavior, and version/tag edge cases. |
| tools/azsdk-cli/Azure.Sdk.Tools.Cli.Tests/Services/Languages/DotNetLanguageSpecificChecksTests.cs | Adjusts test setup to mock ParsePackagePathAsync for updated checks behavior. |
Switch TryUpdateVersionUsingScriptAsync from -Command mode to -File mode when invoking Update-PkgVersion.ps1. This prevents potential command injection through unescaped metacharacters in serviceDirectory, packageName, version, or releaseDate parameters. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refetch package info on the script-success path so the response reflects the updated version instead of the stale pre-update value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Return a failed PackageCheckResponse when packageName cannot be determined instead of passing null to ValidateChangelog. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The scriptPath was passed both as the first element of the args array and as the scriptPath parameter to PowershellOptions, resulting in pwsh -File <script> <script> -ServiceDirectory ... which breaks parameter binding. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds .NET-specific version update support to azsdk-cli by teaching DotnetLanguageService how to update package versions via the .NET repo’s Update-PkgVersion.ps1 script, with a .csproj-edit fallback when the script isn’t available. It also refactors .NET check workflows to derive service/package identity via IPackageInfoHelper.ParsePackagePathAsync, and introduces a dedicated test suite for the new version-update behavior.
Changes:
- Implemented
.NETversion update flow by overridingDotnetLanguageService.UpdateVersionAsyncandUpdatePackageVersionInFilesAsyncwith script-first +.csprojfallback logic. - Updated .NET checks to compute
serviceDirectory/packageNameviaParsePackagePathAsync(and MSBuild metadata when available), removing ad-hoc path parsing. - Added new unit tests covering script invocation, fallback behavior, and release-type/version edge cases.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| tools/azsdk-cli/Azure.Sdk.Tools.Cli/Services/Languages/DotnetLanguageService.VersionUpdate.cs | New .NET version update implementation (script-first with direct .csproj fallback). |
| tools/azsdk-cli/Azure.Sdk.Tools.Cli/Services/Languages/DotNetLanguageService.Checks.cs | Refactors service/package derivation to use ParsePackagePathAsync; fixes AOT script arg construction. |
| tools/azsdk-cli/Azure.Sdk.Tools.Cli.Tests/Services/Languages/DotnetLanguageServiceVersionUpdateTests.cs | New tests validating script/fallback behavior and release-type validation. |
| tools/azsdk-cli/Azure.Sdk.Tools.Cli.Tests/Services/Languages/DotNetLanguageSpecificChecksTests.cs | Updates test setup to mock ParsePackagePathAsync consistently. |
… add GA release guard - Remove TryUpdateVersionUsingScriptAsync and delegate to base class for changelog + version file updates, eliminating the PowerShell Boolean parameter issue entirely - Update ChangelogHelper.UpdateReleaseDate to always replace the latest entry title (matching Prepare-Release.ps1 ReplaceLatestEntryTitle behavior), fixing version promotion (e.g., 12.28.0-beta.2 -> 12.28.0) - Require explicit --release-type stable for GA releases to prevent accidental stable releases when releaseType defaults to beta - Reject relativePath '.' in Checks.cs guards alongside '..' to prevent invalid -ServiceDirectory when packagePath is the sdk/ root Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… add GA release guard - Remove TryUpdateVersionUsingScriptAsync and delegate to base class for changelog + version file updates, eliminating the PowerShell Boolean parameter issue entirely - Handle changelog version promotion (e.g., 12.28.0-beta.2 -> 12.28.0) in the .NET override by renaming the latest entry before the base class exact-match lookup, matching Prepare-Release.ps1 ReplaceLatestEntryTitle - Require explicit --release-type stable for GA releases to prevent accidental stable releases when releaseType defaults to beta - Reject relativePath '.' in Checks.cs guards alongside '..' to prevent invalid -ServiceDirectory when packagePath is the sdk/ root Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ure-sdk-tools into net-version-updates
Remove duplicated changelog entry title renaming logic (60 lines) from DotnetLanguageService.VersionUpdate.cs — now handled by ChangelogHelper.UpdateLatestEntryTitle in the base class (PR Azure#14768). Also remove redundant release date defaulting (already done by VersionUpdateTool). Keep .NET-specific stable release guard and .csproj version file updates. Update test constructor calls to include ICopilotAgentRunner parameter added in main branch merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply reviewer suggestion to clarify the next-steps message from 'Pass --release-type stable' to 'Re-run this tool with --release-type stable'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply reviewer suggestion to use consistent 'Re-run this tool with' phrasing in the prerelease version mismatch error message. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes #13832
Architecture: Version Update Flow
Why UpdateReleaseDate replaces the latest entry instead of doing an exact version lookup
In azure-sdk-for-net changelogs always have the latest entry at the top in this format by default:
The whole point of a version update tool is to handle the transition from one version to another — e.g., taking the default version 12.28.0-beta.2 to 12.28.0 for a GA release, or bumping 12.28.0-beta.2 to 12.28.0-beta.3. If the tool required the changelog to already have an entry matching the target version, the user would need to manually edit the changelog first.
The new behavior matches how Prepare-Release.ps1 works: it always sets $replaceLatestEntryTitle = $true, which takes the latest entry, replaces its title (version + release date), and preserves the content underneath. So
## 12.28.0-beta.2 (Unreleased)becomes## 12.28.0 (2025-06-15).Why we removed the Update-PkgVersion.ps1 dependency
The original implementation shelled out to the repo's Update-PkgVersion.ps1 PowerShell script. This had a fundamental problem: the script declares [Boolean]$ReplaceLatestEntryTitle, and PowerShell's -File mode cannot convert any string argument to [Boolean] — not $true, not 1, nothing. Using -Command mode would work around this but is injection-prone and explicitly discouraged in this repo. Since the C# base class already has all the functionality the script provides (changelog updates via ChangelogHelper and version file updates via UpdatePackageVersionInFilesAsync), the script dependency was unnecessary complexity.
Why stable (GA) releases require explicit --release-type stable
When neither --version nor --release-type is provided, the tool defaults releaseType to "beta". If a package's current version happens to be stable (e.g., 1.0.0), the version would be inferred as 1.0.0 and the tool would proceed with a GA release — which is a high-impact action that shouldn't happen by accident. The validation now requires --release-type stable to confirm intent for any stable version, whether explicitly passed or inferred from the package.