Move template AssemblyInfo generation from FAKE files to MSBuild pack-time metadata#320
Move template AssemblyInfo generation from FAKE files to MSBuild pack-time metadata#320
Conversation
Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
|
@copilot add a test that verifies the assemblyinfo values are set in the dll after a dotnetpack |
There was a problem hiding this comment.
Pull request overview
This PR migrates the library template’s assembly metadata generation away from FAKE-generated AssemblyInfo.fs files and toward MSBuild-driven assembly info/metadata at pack time, with an added integration assertion to validate the resulting DLL metadata.
Changes:
- Add integration assertions to ensure
AssemblyInfo.fsis not generated and that key assembly attributes/metadata are present afterDotnetPack. - Remove
AssemblyInfo.fsfrom the library template project and introduce MSBuildDirectory.Build.props/targetsto generate assembly info + pack-timeAssemblyMetadata. - Update the library template FAKE build script to pass MSBuild properties during packing (and remove git staging of generated AssemblyInfo files).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/MiniScaffold.Tests/Tests.fs | Wires new asserts into the library template integration scenario. |
| tests/MiniScaffold.Tests/Asserts.fs | Adds assertions for missing AssemblyInfo.fs and for assembly attribute/metadata values. |
| Content/Library/src/MyLib.1/MyLib.1.fsproj | Stops compiling the template’s AssemblyInfo.fs. |
| Content/Library/src/MyLib.1/AssemblyInfo.fs | Removes FAKE-generated assembly info source file from the template. |
| Content/Library/src/Directory.Build.props | Enables MSBuild assembly info generation and sets Product. |
| Content/Library/src/Directory.Build.targets | Adds pack-time AssemblyMetadata items gated by IsPacking. |
| Content/Library/build/build.fs | Passes MSBuild version/metadata properties and no-ops the old assembly-info generation logic. |
|
@copilot address comments |
Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
| <AssemblyMetadata Include="ReleaseChannel" Value="$(AssemblyMetadataReleaseChannel)" Condition="'$(AssemblyMetadataReleaseChannel)' != ''" /> | ||
| <AssemblyMetadata Include="GitHash" Value="$(AssemblyMetadataGitHash)" Condition="'$(AssemblyMetadataGitHash)' != ''" /> | ||
| <ItemGroup> | ||
| <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute" Condition="'$(AssemblyMetadataReleaseDate)' != ''"> |
There was a problem hiding this comment.
@copilot Are these needed if we’re setting them via FAKE?
There was a problem hiding this comment.
Yes—these are still needed. FAKE is passing the values as MSBuild properties during pack, but MSBuild still needs the AssemblyAttribute items here to materialize those values into assembly metadata attributes in the compiled DLL. No UI changes in this PR.
Implemented in 1364acb. I added a targeted integration assertion that reads the packed DLL from the generated .nupkg after DotnetPack and verifies assembly/version metadata values. No UI changes in this PR.
Addressed in 1364acb. The review comments were applied: per-project Product metadata, pack-time-only stamping behavior in build flow, and a robust post-pack DLL metadata assertion with safe unload/cleanup. No UI changes in this PR. |
Content/Library/build/build.fs
Outdated
| let generateAssemblyInfo _ = | ||
| let isNoop = true | ||
|
|
||
| let (|Fsproj|Csproj|Vbproj|) (projFileName: string) = | ||
| match projFileName with | ||
| | f when f.EndsWith("fsproj") -> Fsproj | ||
| | f when f.EndsWith("csproj") -> Csproj | ||
| | f when f.EndsWith("vbproj") -> Vbproj | ||
| | _ -> | ||
| failwith (sprintf "Project file %s not supported. Unknown project type." projFileName) | ||
|
|
||
| let releaseChannel = | ||
| match latestEntry.SemVer.PreRelease with | ||
| | Some pr -> pr.Name | ||
| | _ -> "release" | ||
|
|
||
| let getAssemblyInfoAttributes projectName = [ | ||
| AssemblyInfo.Title(projectName) | ||
| AssemblyInfo.Product productName | ||
| AssemblyInfo.Version latestEntry.AssemblyVersion | ||
| AssemblyInfo.Metadata("ReleaseDate", latestEntry.Date.Value.ToString("o")) | ||
| AssemblyInfo.FileVersion latestEntry.AssemblyVersion | ||
| AssemblyInfo.InformationalVersion latestEntry.AssemblyVersion | ||
| AssemblyInfo.Metadata("ReleaseChannel", releaseChannel) | ||
| AssemblyInfo.Metadata("GitHash", Git.Information.getCurrentSHA1 (null)) | ||
| ] | ||
|
|
||
| let getProjectDetails (projectPath: string) = | ||
| let projectName = IO.Path.GetFileNameWithoutExtension(projectPath) | ||
|
|
||
| (projectPath, | ||
| projectName, | ||
| IO.Path.GetDirectoryName(projectPath), | ||
| (getAssemblyInfoAttributes projectName)) | ||
|
|
||
| !!srcGlob | ||
| |> Seq.map getProjectDetails | ||
| |> Seq.iter (fun (projFileName, _, folderName, attributes) -> | ||
| match projFileName with | ||
| | Fsproj -> | ||
| AssemblyInfoFile.createFSharp | ||
| (folderName | ||
| </> "AssemblyInfo.fs") | ||
| attributes | ||
| | Csproj -> | ||
| AssemblyInfoFile.createCSharp | ||
| ((folderName | ||
| </> "Properties") | ||
| </> "AssemblyInfo.cs") | ||
| attributes | ||
| | Vbproj -> | ||
| AssemblyInfoFile.createVisualBasic | ||
| ((folderName | ||
| </> "My Project") | ||
| </> "AssemblyInfo.vb") | ||
| attributes | ||
| ) | ||
| if isNoop then | ||
| () |
There was a problem hiding this comment.
@copilot This should just be deleted. What are you even doing.
There was a problem hiding this comment.
Done in c6c3c1a. I deleted the no-op GenerateAssemblyInfo target and removed its dependency wiring from Content/Library/build/build.fs, plus removed the stale GenerateAssemblyInfo target entry from Content/Library/README.md. No UI changes in this PR.
…graph Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
|
Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
Done in a37a01c. Applied the AssemblyInfo migration pattern to No UI changes in this PR (screenshot not applicable). |
| finally | ||
| assemblyContext.Unload() | ||
|
|
||
| extractedDllDir | ||
| |> Option.iter (fun path -> | ||
| if Directory.Exists path then | ||
| Directory.Delete(path, true) | ||
| ) |
There was a problem hiding this comment.
AssemblyLoadContext.Unload() does not guarantee immediate release of file handles; on Windows the extracted DLL can remain locked briefly, making Directory.Delete(path, true) flaky in CI. Consider loading the assembly from a stream (e.g., read bytes + LoadFromStream) or forcing unload completion (GC.Collect/WaitForPendingFinalizers loop) and/or retrying the directory delete to avoid intermittent failures.
|
@copilot address build failures |
Co-authored-by: TheAngryByrd <1490044+TheAngryByrd@users.noreply.github.com>
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.