Skip to content

Conversation

KlausLoeffelmann
Copy link
Member

@KlausLoeffelmann KlausLoeffelmann commented Sep 17, 2025

Problem

During a recent servicing build, analyzer projects failed with version conflicts because they were excluded from standard versioning but had no alternative versioning strategy. This left analyzer assemblies with default 10.0.0.0 versions, causing build failures since Roslyn requires unique assembly versions for proper analyzer caching and side-by-side execution.

Solution

Implemented incremental versioning for all 5 analyzer projects in Directory.Build.targets. For official builds, the solution extracts the build number from Arcade SDK's OfficialBuildId (e.g., 20250917.12310.0.123.0). For local builds, it uses days since 2020-01-01 as the build number, ensuring unique versions while staying under .NET's 65535 component limit. Also fixed missing IsAnalyzerProject property in the Visual Basic analyzer project.

Result (Pending)

Analyzer assemblies now receive proper incremental versions (10.0.[BuildNumber].0), resolving servicing build failures while maintaining seamless local development. The solution leverages existing Arcade infrastructure and follows Microsoft's best practices for analyzer side-by-side loading.

Microsoft Reviewers: Open in CodeFlow

Copy link
Contributor

@Copilot 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

This PR fixes analyzer assembly versioning issues that were causing build failures in official servicing builds. The solution implements incremental versioning for analyzer projects to ensure unique assembly versions required for proper Roslyn analyzer caching and side-by-side execution.

Key changes:

  • Added automatic versioning logic for analyzer projects in Directory.Build.targets
  • Fixed missing IsAnalyzerProject property in the Visual Basic analyzer project
  • Implemented dual versioning strategy: official builds use Arcade SDK build numbers, local builds use timestamp-based numbering

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/System.Windows.Forms.Analyzers.VisualBasic/System.Windows.Forms.Analyzers.VisualBasic.vbproj Added missing IsAnalyzerProject property to enable versioning logic
Directory.Build.targets Implemented incremental versioning system for analyzer projects with fallback for local builds

-->
<PropertyGroup Condition="'$(IsAnalyzerProject)' == 'true'">
<!-- For official builds, extract build number from OfficialBuildId (format: yyyyMMdd.buildNumber) -->
<_AnalyzerBuildNumber Condition="'$(OfficialBuildId)' != '' and $(OfficialBuildId.Contains('.'))" >$(OfficialBuildId.Split('.')[1])</_AnalyzerBuildNumber>
Copy link
Preview

Copilot AI Sep 17, 2025

Choose a reason for hiding this comment

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

The condition uses $(OfficialBuildId.Contains('.')) which is invalid MSBuild syntax. MSBuild property functions should be called using $([String]::method()) format. Change to $([System.String]::IsNullOrEmpty('$(OfficialBuildId)')) == 'false' and $(OfficialBuildId.Contains('.')).

Suggested change
<_AnalyzerBuildNumber Condition="'$(OfficialBuildId)' != '' and $(OfficialBuildId.Contains('.'))" >$(OfficialBuildId.Split('.')[1])</_AnalyzerBuildNumber>
<_AnalyzerBuildNumber Condition="$([System.String]::IsNullOrEmpty('$(OfficialBuildId)')) == 'false' and $([System.String]::Contains('$(OfficialBuildId)', '.'))">$(OfficialBuildId.Split('.')[1])</_AnalyzerBuildNumber>

Copilot uses AI. Check for mistakes.

<!-- For official builds, extract build number from OfficialBuildId (format: yyyyMMdd.buildNumber) -->
<_AnalyzerBuildNumber Condition="'$(OfficialBuildId)' != '' and $(OfficialBuildId.Contains('.'))" >$(OfficialBuildId.Split('.')[1])</_AnalyzerBuildNumber>
<!-- For local builds, generate a build number from days since 2020-01-01 (keeps it under 65535) -->
<_AnalyzerBuildNumber Condition="'$(_AnalyzerBuildNumber)' == ''">$([MSBuild]::Subtract($([System.DateTime]::Now.Subtract($([System.DateTime]::new(2020,1,1))).Days), 0))</_AnalyzerBuildNumber>
Copy link
Preview

Copilot AI Sep 17, 2025

Choose a reason for hiding this comment

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

The $([MSBuild]::Subtract(..., 0)) operation is unnecessary since subtracting 0 doesn't change the value. Simply use $([System.DateTime]::Now.Subtract($([System.DateTime]::new(2020,1,1))).Days) directly.

Suggested change
<_AnalyzerBuildNumber Condition="'$(_AnalyzerBuildNumber)' == ''">$([MSBuild]::Subtract($([System.DateTime]::Now.Subtract($([System.DateTime]::new(2020,1,1))).Days), 0))</_AnalyzerBuildNumber>
<_AnalyzerBuildNumber Condition="'$(_AnalyzerBuildNumber)' == ''">$([System.DateTime]::Now.Subtract($([System.DateTime]::new(2020,1,1))).Days)</_AnalyzerBuildNumber>

Copilot uses AI. Check for mistakes.

Copy link

codecov bot commented Sep 17, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.11899%. Comparing base (3c5b282) to head (45744b1).
⚠️ Report is 53 commits behind head on main.

Additional details and impacted files
@@                 Coverage Diff                 @@
##                main      #13879         +/-   ##
===================================================
+ Coverage   77.07981%   77.11899%   +0.03918%     
===================================================
  Files           3271        3273          +2     
  Lines         644397      644919        +522     
  Branches       47665       47692         +27     
===================================================
+ Hits          496700      497355        +655     
+ Misses        144017      143895        -122     
+ Partials        3680        3669         -11     
Flag Coverage Δ
Debug 77.11899% <ø> (+0.03918%) ⬆️
integration 18.99321% <ø> (+0.00417%) ⬆️
production 51.95129% <ø> (+0.06774%) ⬆️
test 97.41256% <ø> (-0.00352%) ⬇️
unit 49.36659% <ø> (+0.07191%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ericstj
Copy link
Member

ericstj commented Sep 17, 2025

@KlausLoeffelmann Do we need to make it this complex? Couldn't we just use the <ProductVersion> -- that seems to be what was happening in 9.0:
image

Did you find out what was different in 10.0 that made this not work? Maybe it's just that some properties didn't get changed in the way you might normally change them in servicing? Maybe something in arcade changed to break it?

@KlausLoeffelmann
Copy link
Member Author

Honestly, I think it was not caught in 9.
One Analyzer wasn't even tagged correctly as such.

But no - I don't know what could have changed.

Let me try you're suggestion!

-->
<PropertyGroup Condition="'$(IsAnalyzerProject)' == 'true'">
<!-- For official builds, extract build number from OfficialBuildId (format: yyyyMMdd.buildNumber) -->
<_AnalyzerBuildNumber Condition="'$(OfficialBuildId)' != '' and $(OfficialBuildId.Contains('.'))" >$(OfficialBuildId.Split('.')[1])</_AnalyzerBuildNumber>
Copy link
Member

Choose a reason for hiding this comment

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

This will produce build numbers that overlap over a given release. The .buildNumber will be .1 starting with the first build each day, and then will increment after that.

What's the intended version progression you want? Or is there a progression? Is it just important that they don't overlap?

Arcade has a property for this: <AutoGenerateAssemblyVersion>true</AutoGenerateAssemblyVersion>

Copy link
Member Author

@KlausLoeffelmann KlausLoeffelmann Sep 22, 2025

Choose a reason for hiding this comment

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

I inherited the build/pipeline maintenance from a colleague, who is no longer here - so I am still ramping up on this.

The service exercise showed that the service build failed, since analyzer assemblies weren't incrementally versioned. I failed to figure out yet, what Arcade would provide ideally for this scenario.

@KlausLoeffelmann
Copy link
Member Author

Closing, since it was replaced by #13892.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants