Skip to content

Implement .NET UpdatePackageVersion#14482

Merged
m-redding merged 25 commits intoAzure:mainfrom
m-redding:net-version-updates
Mar 31, 2026
Merged

Implement .NET UpdatePackageVersion#14482
m-redding merged 25 commits intoAzure:mainfrom
m-redding:net-version-updates

Conversation

@m-redding
Copy link
Copy Markdown
Member

@m-redding m-redding commented Mar 12, 2026

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:

   ## 12.28.0-beta.2 (Unreleased)
   
   ### Features Added
   - Feature A
   - Feature B
   
   ### Breaking Changes
   
   ### Bugs Fixed
   
   ### Other Changes

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.

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>
@github-actions github-actions Bot added the azsdk-cli Issues related to Azure/azure-sdk-tools::tools/azsdk-cli label Mar 12, 2026
m-redding and others added 8 commits March 18, 2026 10:41
- 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>
@m-redding m-redding changed the title Implement .NET UpdatePackageVersionInFilesAsync Implement .NET UpdatePackageVersion Mar 19, 2026
m-redding and others added 3 commits March 18, 2026 17:54
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>
@m-redding m-redding marked this pull request as ready for review March 19, 2026 01:28
@m-redding m-redding requested a review from a team as a code owner March 19, 2026 01:28
Copilot AI review requested due to automatic review settings March 19, 2026 01:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 DotnetLanguageService version update implementation with a primary PowerShell script path (Update-PkgVersion.ps1) and a .csproj <Version> fallback.
  • Update .NET language checks to derive service/package names via IPackageInfoHelper.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.

m-redding and others added 4 commits March 19, 2026 10:13
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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 .NET version update flow by overriding DotnetLanguageService.UpdateVersionAsync and UpdatePackageVersionInFilesAsync with script-first + .csproj fallback logic.
  • Updated .NET checks to compute serviceDirectory/packageName via ParsePackagePathAsync (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.

m-redding and others added 4 commits March 19, 2026 12:23
… 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>
@weshaggard weshaggard requested a review from m-nash March 27, 2026 16:49
m-redding and others added 2 commits March 30, 2026 14:34
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>
@m-redding m-redding requested a review from raych1 March 30, 2026 21:53
m-redding and others added 2 commits March 31, 2026 09:47
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>
@m-redding m-redding requested a review from raych1 March 31, 2026 16:49
@m-redding m-redding merged commit aecfda5 into Azure:main Mar 31, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

azsdk-cli Issues related to Azure/azure-sdk-tools::tools/azsdk-cli

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[.NET] Support version updates in language-specific package files

5 participants