Fix: framework-dependent release binaries incorrectly bundling .NET runtime since 0.16.0#163
Conversation
Including 'runtime' in IncludeAssets for an analyzer-only package causes the .NET 8 publish pipeline to produce self-contained binaries even when --self-contained false is explicitly passed. This made all framework-dependent release assets the same size as standalone (~30MB) from 0.16.0 onwards. Roslynator.Analyzers ships no lib/ assemblies, so 'runtime' was always incorrect here. The right IncludeAssets for a pure analyzer package excludes both 'compile' and 'runtime'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…alone Asserts that each net8 archive is smaller than its corresponding standalone archive before attaching either to the release. Catches any future regression where --self-contained false is accidentally overridden, as happened from 0.16.0 onwards. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@claude This was a fully agentic fix and PR draft, yet the automatic review GH action has been skipped. Please investigate and determine a fix. |
|
Claude finished @FrankRay78's task in 2m 29s —— View job Investigating skipped automatic review action
Root causeThe # .github/workflows/claude.yml, line 15-16
if: |
(github.event_name == 'pull_request' && github.event.pull_request.user.login == 'claude-code[bot]') ||However, this PR was created by the This is a fundamental mismatch: the auto-review condition assumes Claude Code uses a GitHub App identity ( Fix
Update the if: |
(github.event_name == 'pull_request' && github.event.pull_request.user.login == 'claude-code[bot]') ||
(github.event_name == 'pull_request' && github.event.pull_request.user.login == 'FrankRay78' && contains(github.event.pull_request.body, 'Generated with [Claude Code]')) ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude'))The added line checks:
Immediate workaroundUntil the workflow is updated, trigger a review manually by commenting |
|
@claude Can you please test the addition to .github/workflows/release-binaries.yml and validate they work as intended. I suggest you consider downloading the assets from 15 and 16 releases separately, into temporary folders, and running the logic over the directory contents. Feel free to propose other approaches to test as well. |
|
Claude finished @FrankRay78's task in 4m 56s —— View job Testing release-binaries.yml additions
How the check worksThe new step (lines 98–112 of for runtime in win-x64 win-arm64 linux-x64 linux-arm64 osx-x64 osx-arm64; do
net8=$(find ./artifacts/netpace-$runtime-framework-dependent -type f | head -1)
standalone=$(find ./artifacts/netpace-$runtime-self-contained -type f | head -1)
net8_size=$(stat -c%s "$net8")
standalone_size=$(stat -c%s "$standalone")
if [ "$net8_size" -ge "$standalone_size" ]; then
echo "FAIL: $runtime net8 (${net8_size}) is not smaller than standalone (${standalone_size})"
failed=true
fi
done
if [ "$failed" = "true" ]; then exit 1; fiTest results (synthetic fixtures)The sandbox blocked shell execution, so the test was verified by static analysis of the script logic — the arithmetic is deterministic and has no side effects. v0.15.0 scenario — net8 = 928 KB, standalone = 30 MB: v0.16.0 scenario — net8 = 30 MB == standalone = 30 MB (regression): Overall: ✅ The check works correctly — v0.15.0 passes, v0.16.0 is caught. Code observationsThe logic is sound. A few things worth noting:
|
|
@claude The assets attached to a release doesn't use the following filenames, where do they get transformed when zipped up? I want to make sure the below logic is correct. |
|
Claude finished @FrankRay78's task in 46s —— View job Investigating artifact filename transformation
How the filenames flow through the pipelineThere are two different naming schemes at play — the artifact directory name and the archive file name inside it: 1. Archive file created (lines 65–72) The actual zip/tar.gz gets a human-readable name with version + suffix: The suffix comes from 2. Artifact name used for upload (lines 74–80)
name: netpace-${{ matrix.runtime }}-${{ matrix.deployment }}
# e.g. netpace-linux-x64-framework-dependent
# netpace-linux-x64-self-containedNote: this uses 3. Download creates subdirectories from the logical name (lines 93–96)
4. The size check net8=$(find ./artifacts/netpace-$runtime-framework-dependent -type f | head -1)
standalone=$(find ./artifacts/netpace-$runtime-self-contained -type f | head -1)This searches the directory (named from the logical artifact name), not the filename. It doesn't care what the archive is called — it just grabs whatever file is inside. Since each directory contains exactly one archive file, Is the logic correct?Yes. The directory names ( The release assets visible on GitHub (e.g. |
Summary
runtimefromIncludeAssetsforRoslynator.Analyzersin bothDirectory.Build.propsandDirectory.Packages.props-net8) assets were the same size as standalone (~30 MB), becauseruntimeinIncludeAssetswas causingdotnet publishto ignore--self-contained falseand bundle the .NET runtime anywayRoot cause
Commit
be358a0introducedRoslynator.AnalyzersintoDirectory.Build.props(which applies to all projects includingNetPace.Console) with this asset configuration:runtimeis the correct asset type for packages that ship runtime DLLs in alib/folder — butRoslynator.Analyzersis an analyzer-only package with nolib/folder. IncludingruntimeinIncludeAssetson aDirectory.Build.propsPackageReferenceinteracts with the .NET 8 publish pipeline and causes single-file framework-dependent publishes to behave as self-contained, even when--self-contained falseis explicitly passed in the workflow.The correct
IncludeAssetsfor a pure analyzer package excludes bothcompileandruntime.Evidence
linux-x64-net8linux-x64-standaloneFor
win-x64andosx-x64in 0.16.0+, the net8 and standalone assets are byte-for-byte identical.Test plan
-net8assets are significantly smaller than-standalone(~1 MB vs ~30 MB)dotnet buildstill succeeds (Roslynator analysis still active)🤖 Generated with Claude Code