diff --git a/Directory.Build.props b/Directory.Build.props
index db8bbd23..6e84452a 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -29,7 +29,6 @@ See https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-director
enable
true
true
- false
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 3660945f..def08789 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -19,7 +19,6 @@
-
diff --git a/README.md b/README.md
index a10138fc..950057e1 100644
--- a/README.md
+++ b/README.md
@@ -79,7 +79,7 @@ or
- `GenerateCoverageReport` - Code coverage is run during `DotnetTest` and this generates a report via [ReportGenerator](https://github.com/danielpalme/ReportGenerator).
- `ShowCoverageReport` - Shows the report generated in `GenerateCoverageReport`.
- `WatchTests` - Runs [dotnet watch](https://docs.microsoft.com/en-us/aspnet/core/tutorials/dotnet-watch?view=aspnetcore-3.0) with the test projects. Useful for rapid feedback loops.
-- `GenerateAssemblyInfo` - Generates [AssemblyInfo](https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.applicationservices.assemblyinfo?view=netframework-4.8) for libraries.
+- `GenerateAssemblyInfo` - Writes the version, the release date, the release channel and the git hash of the latest changelog entry into `src/AssemblyInfo.Build.props`, which `src/Directory.Build.props` imports, so that the SDK generates the assembly attributes of the libraries from it.
- `DotnetPack` - Runs [dotnet pack](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-pack). This includes running [Source Link](https://github.com/dotnet/sourcelink).
- `SourceLinkTest` - Runs a Source Link test tool to verify Source Links were properly generated.
- `PublishToNuGet` - Publishes the NuGet packages generated in `DotnetPack` to NuGet via [dotnet nuget push](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-push). Runs only from `Github Actions`.
diff --git a/build/build.fs b/build/build.fs
index 004a55b3..d9536a28 100644
--- a/build/build.fs
+++ b/build/build.fs
@@ -1,4 +1,5 @@
open System
+open System.Xml.Linq
open Fake.Core
open Fake.DotNet
open Fake.Tools
@@ -28,6 +29,9 @@ let rootDirectory = __SOURCE_DIRECTORY__ > ".."
let productName = "FSharp.Collections.Immutable"
+/// The assembly information of the release. `src/Directory.Build.props` imports it, so that the SDK generates the attributes.
+let assemblyInfoPropsPath = rootDirectory > "src" > "AssemblyInfo.Build.props"
+
let sln = rootDirectory > "FSharp.Collections.Immutable.slnf"
let srcCodeGlob =
@@ -432,47 +436,90 @@ let watchTests _ =
cancelEvent.Cancel <- true
+/// Writes the assembly information of the latest changelog entry in two places. `src/AssemblyInfo.Build.props` holds
+/// the properties and the `AssemblyMetadata` items from which the SDK generates the assembly attributes, and
+/// `src/Directory.Build.props` imports it, so a project sets only what is specific to it in its own project file.
+/// `AssemblyInfo.fs` of each F# project in `src` holds the literals of `AssemblyVersionInformation`, which the code can
+/// use at compile time. It has no attributes, because the SDK generates them.
let generateAssemblyInfo _ =
- 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
- | _ -> failwithf "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
- // The date is optional in a changelog entry
- match latestEntry.Date with
- | Some releaseDate -> AssemblyInfo.Metadata ("ReleaseDate", releaseDate.ToString ("o"))
+ // The date is optional in a changelog entry
+ let releaseDate = latestEntry.Date |> Option.map _.ToString("o")
+ let gitHash = Git.Information.getCurrentSHA1 (null)
+
+ let metadata = [
+ match releaseDate with
+ | Some date -> "ReleaseDate", date
| None -> ()
- AssemblyInfo.FileVersion latestEntry.AssemblyVersion
- AssemblyInfo.InformationalVersion latestEntry.AssemblyVersion
- AssemblyInfo.Metadata ("ReleaseChannel", releaseChannel)
- AssemblyInfo.Metadata ("GitHash", Git.Information.getCurrentSHA1 (null))
+ "ReleaseChannel", releaseChannel
+ "GitHash", gitHash
]
- let getProjectDetails (projectPath : string) =
- let projectName = IO.Path.GetFileNameWithoutExtension (projectPath)
+ let properties =
+ XElement (
+ "PropertyGroup",
+ XElement ("Product", productName),
+ XElement ("AssemblyVersion", latestEntry.AssemblyVersion),
+ XElement ("FileVersion", latestEntry.AssemblyVersion),
+ XElement ("InformationalVersion", latestEntry.AssemblyVersion),
+ // The git hash is in the metadata, so the SDK must not append the source revision to the informational version
+ XElement ("IncludeSourceRevisionInInformationalVersion", "false")
+ )
- (projectPath, projectName, IO.Path.GetDirectoryName (projectPath), (getAssemblyInfoAttributes projectName))
+ let items =
+ XElement (
+ "ItemGroup",
+ metadata
+ |> List.map (fun (key, value) ->
+ XElement ("AssemblyMetadata", XAttribute ("Include", key), XAttribute ("Value", value))
+ )
+ )
- !!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
- )
+ let props =
+ XDocument (XComment " Auto-Generated by FAKE; do not edit ", XElement ("Project", properties, items))
+
+ // XDocument breaks lines as the operating system does, and the other generated file has "\n" everywhere
+ let propsText = props.ToString().ReplaceLineEndings "\n"
+
+ File.writeString false assemblyInfoPropsPath $"%s{propsText}\n"
+
+ let versionInformation projectName =
+ let literals = [
+ "AssemblyTitle", projectName
+ "AssemblyProduct", productName
+ "AssemblyVersion", latestEntry.AssemblyVersion
+ match releaseDate with
+ | Some date -> "AssemblyMetadata_ReleaseDate", date
+ | None -> ()
+ "AssemblyFileVersion", latestEntry.AssemblyVersion
+ "AssemblyInformationalVersion", latestEntry.AssemblyVersion
+ "AssemblyMetadata_ReleaseChannel", releaseChannel
+ "AssemblyMetadata_GitHash", gitHash
+ ]
+
+ [
+ "// Auto-Generated by FAKE; do not edit"
+ "namespace System"
+ ""
+ "module internal AssemblyVersionInformation ="
+ yield!
+ literals
+ |> List.map (fun (name, value) -> $" let [] %s{name} = \"%s{value}\"")
+ ]
+ |> String.concat "\n"
+
+ let writeVersionInformation (projectPath : string) =
+ // The project path is not null, so neither is the name
+ let projectName = IO.Path.GetFileNameWithoutExtension projectPath |> nonNull
+ File.writeString false (Path.getDirectory projectPath > "AssemblyInfo.fs") $"%s{versionInformation projectName}\n"
+
+ !!(rootDirectory > "src/**/*.fsproj")
+ |> Seq.iter writeVersionInformation
let dotnetPack ctx =
// Get release notes with properly-linked version number
@@ -534,6 +581,7 @@ let gitRelease _ =
!!(rootDirectory > "src/**/AssemblyInfo.fs")
++ (rootDirectory > "tests/**/AssemblyInfo.fs")
+ ++ assemblyInfoPropsPath
|> Seq.iter (Git.Staging.stageFile "" >> ignore)
let msg = $"release: bump version to `%s{latestEntry.NuGetVersion}`\n\n%s{releaseNotesGitCommitFormat}"
diff --git a/build/build.fsproj b/build/build.fsproj
index 95ccdb3c..26c77382 100644
--- a/build/build.fsproj
+++ b/build/build.fsproj
@@ -25,7 +25,6 @@
-
diff --git a/src/AssemblyInfo.Build.props b/src/AssemblyInfo.Build.props
new file mode 100644
index 00000000..924e6532
--- /dev/null
+++ b/src/AssemblyInfo.Build.props
@@ -0,0 +1,15 @@
+
+
+
+ FSharp.Collections.Immutable
+ 1.0.0
+ 1.0.0
+ 1.0.0
+ false
+
+
+
+
+
+
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 5ea09a4f..59621c56 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,5 +1,7 @@
+
+
true
true
diff --git a/src/FSharp.Collections.Immutable/AssemblyInfo.fs b/src/FSharp.Collections.Immutable/AssemblyInfo.fs
index db10dac4..48935162 100644
--- a/src/FSharp.Collections.Immutable/AssemblyInfo.fs
+++ b/src/FSharp.Collections.Immutable/AssemblyInfo.fs
@@ -1,16 +1,5 @@
// Auto-Generated by FAKE; do not edit
namespace System
-open System.Reflection
-
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-[]
-do ()
module internal AssemblyVersionInformation =
let [] AssemblyTitle = "FSharp.Collections.Immutable"