├── .github ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── create-release.yml │ └── dotnet.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── LinkDotNet.BuildInformation.Sample ├── LinkDotNet.BuildInformation.Sample.csproj └── Program.cs ├── LinkDotNet.BuildInformation.sln ├── LinkDotNet.BuildInformation ├── GitInformationInfo.cs ├── GitRetriever.cs ├── IncrementalBuildInformationGenerator.cs └── LinkDotNet.BuildInformation.csproj ├── README.md └── logo.png /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: "daily" 17 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | schedule: 5 | # ┌───────────── minute (0 - 59) 6 | # │ ┌───────────── hour (0 - 23) 7 | # │ │ ┌───────────── day of the month (1 - 31) 8 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) 9 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) 10 | # │ │ │ │ │ 11 | # │ │ │ │ │ 12 | # │ │ │ │ │ 13 | # * * * * * 14 | - cron: '30 1 * * 0' 15 | 16 | jobs: 17 | CodeQL-Build: 18 | runs-on: ubuntu-latest 19 | 20 | permissions: 21 | security-events: write 22 | 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@v4.2.2 26 | 27 | - uses: actions/setup-dotnet@v4.3.1 28 | with: 29 | dotnet-version: | 30 | 8.0.x 31 | 9.0.x 32 | 33 | - name: Initialize CodeQL 34 | uses: github/codeql-action/init@v3 35 | 36 | - name: Autobuild 37 | uses: github/codeql-action/autobuild@v3 38 | 39 | - name: Perform CodeQL Analysis 40 | uses: github/codeql-action/analyze@v3 41 | -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: Create new Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | versionIncrement: 7 | description: 'The new version. For example: 1.1.0' 8 | required: true 9 | default: '' 10 | prerelease: 11 | description: 'Is this a pre-release?' 12 | type: boolean 13 | required: false 14 | default: false 15 | 16 | jobs: 17 | release: 18 | name: Publish new release 19 | runs-on: ubuntu-latest 20 | steps: 21 | 22 | - name: Checkout repository 23 | uses: actions/checkout@v4.2.2 24 | with: 25 | token: ${{ secrets.PAT }} 26 | persist-credentials: true 27 | fetch-depth: 0 28 | 29 | - name: Get changelog entries 30 | id: changelog 31 | uses: mindsers/changelog-reader-action@v2.2.3 32 | with: 33 | version: Unreleased 34 | path: ./CHANGELOG.md 35 | 36 | - name: Setup dotnet 37 | uses: actions/setup-dotnet@v4.3.1 38 | with: 39 | dotnet-version: | 40 | 8.0.x 41 | 9.0.x 42 | 43 | - name: Update CHANGELOG file 44 | uses: thomaseizinger/keep-a-changelog-new-release@3.1.0 45 | with: 46 | version: ${{ github.event.inputs.versionIncrement }} 47 | 48 | - name: Set git config 49 | run: | 50 | git config --local user.email "linkdotnet@action.com" 51 | git config --local user.name "LinkDotNet Bot" 52 | 53 | - name: Commit changes and push changes 54 | run: | 55 | git add CHANGELOG.md 56 | git commit -m "Update Changelog.md for ${{github.event.inputs.versionIncrement}} release" 57 | git push origin main 58 | 59 | - name: Create release on GitHub 60 | uses: thomaseizinger/create-release@2.0.0 61 | env: 62 | GITHUB_TOKEN: ${{ secrets.PAT }} 63 | with: 64 | tag_name: v${{ github.event.inputs.versionIncrement }} 65 | target_commitish: ${{ env.RELEASE_COMMIT_HASH }} 66 | name: v${{ github.event.inputs.versionIncrement }} 67 | body: ${{ steps.changelog.outputs.changes }} 68 | draft: false 69 | prerelease: ${{ github.event.inputs.prerelease }} 70 | 71 | - name: Create release package 72 | run: | 73 | dotnet pack -c RELEASE -p:PackageVersion=${{ github.event.inputs.versionIncrement }} --property:PackageOutputPath=${GITHUB_WORKSPACE}/packages /p:ContinuousIntegrationBuild=true --nologo 74 | 75 | - name: Upload to nuget 76 | run: | 77 | dotnet nuget push ${GITHUB_WORKSPACE}/packages/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate 78 | 79 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4.2.2 16 | - name: Setup .NET 17 | uses: actions/setup-dotnet@v4.3.1 18 | with: 19 | dotnet-version: | 20 | 8.0.x 21 | 9.0.x 22 | - name: Setup color 23 | run: | 24 | echo "DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION=1" >> $GITHUB_ENV 25 | echo "TERM=xterm" >> $GITHUB_ENV 26 | - name: Restore dependencies 27 | run: dotnet restore 28 | - name: Build 29 | run: dotnet build --no-restore -c Release /p:ContinuousIntegrationBuild=true 30 | - name: Test 31 | run: dotnet test -c Release --no-build 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /packages/ 4 | riderModule.iml 5 | /_ReSharper.Caches/ 6 | 7 | appsettings.Development.json 8 | appsettings.Production.json 9 | 10 | *.[Pp]ublish.xml 11 | *.azurePubxml 12 | *.pubxml 13 | *.pubxml.user 14 | *.publishproj 15 | *.suo 16 | sitemap.xml 17 | robots.txt 18 | .vs/ 19 | .idea/ 20 | *.csproj.user 21 | *.dotsettings.user 22 | 23 | # Coverage files and reports 24 | /**/TestResults/* 25 | /**/coverage*.xml 26 | /CoverageReport/ 27 | 28 | # MacOS 29 | .DS_Store -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to **ValueStringBuilder** will be documented in this file. The project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 4 | 5 | 6 | 7 | ## [Unreleased] 8 | 9 | ## [1.3.0] - 2024-10-11 10 | 11 | ### Added 12 | 13 | - Added support for git information. Please see the README.md for more details and how to activate it. 14 | 15 | ## [1.2.1] - 2024-05-02 16 | 17 | ### Changed 18 | 19 | - Fixed a wrong example tag which shows a language version instead of the language itself 20 | 21 | ## [1.2.0] - 2024-04-25 22 | 23 | ### Added 24 | 25 | - Language and LanguageVersion properties to the BuildInformation (i.e. C# 12.0) 26 | 27 | ## [1.1.2] - 2024-04-20 28 | 29 | ### Added 30 | 31 | - Added logo for nuget package 32 | 33 | ## [1.1.1] - 2024-04-19 34 | 35 | ### Changed 36 | 37 | - Minor version bump because of failed deployment 38 | 39 | ## [1.1.0] - 2024-04-19 40 | 41 | ### Added 42 | 43 | The following options were added: 44 | 45 | - `AnalysisLevel` to represent the `` property in the project file 46 | - `ProjectDirectory` to represent the current path to the project file 47 | 48 | ## [1.0.0] - 2023-12-30 49 | 50 | ### Added 51 | 52 | - Option, to use the root namespace for the generated class (see README.md for more details) 53 | 54 | ### Changed 55 | 56 | - Use auto-generated header so analyzers don't complain 57 | - Made `BuildInformation` class internal if used across different assemblies 58 | 59 | ## [0.4.2] - 2023-08-29 60 | 61 | ### Changed 62 | 63 | - Used meta-package for analyzers to reduce dependency errors 64 | 65 | ## [0.4.1] - 2023-08-12 66 | 67 | ### Changed 68 | 69 | - `Configuration` also takes custom configuration into account 70 | 71 | ## [0.4.0] - 2023-06-15 72 | 73 | ### Added 74 | 75 | - Added support for nullability analysis level 76 | - Added support for deterministic builds 77 | 78 | ## [0.3.0] - 2023-03-24 79 | 80 | ### Added 81 | 82 | - Added framework moniker to the build information 83 | 84 | ## [0.2.0] - 2023-03-24 85 | 86 | ### Added 87 | 88 | - New assembly related objects 89 | 90 | [unreleased]: https://github.com/linkdotnet/BuildInformation/compare/1.3.0...HEAD 91 | [1.3.0]: https://github.com/linkdotnet/BuildInformation/compare/1.2.1...1.3.0 92 | [1.2.1]: https://github.com/linkdotnet/BuildInformation/compare/1.2.0...1.2.1 93 | [1.2.0]: https://github.com/linkdotnet/BuildInformation/compare/1.1.2...1.2.0 94 | [1.1.2]: https://github.com/linkdotnet/BuildInformation/compare/1.1.1...1.1.2 95 | [1.1.1]: https://github.com/linkdotnet/BuildInformation/compare/1.1.0...1.1.1 96 | [1.1.0]: https://github.com/linkdotnet/BuildInformation/compare/1.0.0...1.1.0 97 | [1.0.0]: https://github.com/linkdotnet/BuildInformation/compare/0.4.2...1.0.0 98 | [0.4.2]: https://github.com/linkdotnet/BuildInformation/compare/0.4.1...0.4.2 99 | [0.4.1]: https://github.com/linkdotnet/BuildInformation/compare/0.4.0...0.4.1 100 | [0.4.0]: https://github.com/linkdotnet/BuildInformation/compare/0.3.0...0.4.0 101 | [0.3.0]: https://github.com/linkdotnet/BuildInformation/compare/0.2.0...0.3.0 102 | [0.2.0]: https://github.com/linkdotnet/BuildInformation/compare/9866bfb38171ce0b36aae085d07d15f6e2bc6ff3...0.2.0 103 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Steven Giesel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LinkDotNet.BuildInformation.Sample/LinkDotNet.BuildInformation.Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net8.0 5 | enable 6 | enable 7 | false 8 | 1.0 9 | 1.2 10 | 11 | 12 | true 13 | true 14 | true 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /LinkDotNet.BuildInformation.Sample/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | using LinkDotNet.BuildInformation.Sample; 4 | 5 | Console.WriteLine($"Build at: {BuildInformation.BuildAt}"); 6 | Console.WriteLine($"Platform: {BuildInformation.Platform}"); 7 | Console.WriteLine($"Warning level: {BuildInformation.WarningLevel}"); 8 | Console.WriteLine($"Configuration: {BuildInformation.Configuration}"); 9 | Console.WriteLine($"Assembly version: {BuildInformation.AssemblyVersion}"); 10 | Console.WriteLine($"Assembly file version: {BuildInformation.AssemblyFileVersion}"); 11 | Console.WriteLine($"Assembly name: {BuildInformation.AssemblyName}"); 12 | Console.WriteLine($"Target framework moniker: {BuildInformation.TargetFrameworkMoniker}"); 13 | Console.WriteLine($"Analysis level: {BuildInformation.Nullability}"); 14 | Console.WriteLine($"Deterministic build: {BuildInformation.Deterministic}"); 15 | Console.WriteLine($"Analysis level: {BuildInformation.AnalysisLevel}"); 16 | Console.WriteLine($"Project directory: {BuildInformation.ProjectDirectory}"); 17 | Console.WriteLine($"Language: {BuildInformation.Language}"); 18 | Console.WriteLine($"Language version: {BuildInformation.LanguageVersion}"); 19 | 20 | Console.WriteLine(); 21 | Console.WriteLine("Git information:"); 22 | Console.WriteLine($"Branch: {GitInformation.Branch}"); 23 | Console.WriteLine($"Commit: {GitInformation.Commit}"); 24 | Console.WriteLine($"Short commit: {GitInformation.ShortCommit}"); 25 | Console.WriteLine($"Nearest tag: {GitInformation.NearestTag}"); 26 | Console.WriteLine($"Detailed tag description: {GitInformation.DetailedTagDescription}"); -------------------------------------------------------------------------------- /LinkDotNet.BuildInformation.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkDotNet.BuildInformation", "LinkDotNet.BuildInformation\LinkDotNet.BuildInformation.csproj", "{6D32EA91-61D4-4F8E-B1AF-4B0199EAF9A6}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkDotNet.BuildInformation.Sample", "LinkDotNet.BuildInformation.Sample\LinkDotNet.BuildInformation.Sample.csproj", "{B9A197AA-2580-4AC7-8E60-2ECF12F2A198}" 6 | EndProject 7 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".text", ".text", "{985BB5C0-64D5-44E5-849C-08D7CDADCD74}" 8 | ProjectSection(SolutionItems) = preProject 9 | CHANGELOG.md = CHANGELOG.md 10 | README.md = README.md 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {6D32EA91-61D4-4F8E-B1AF-4B0199EAF9A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {6D32EA91-61D4-4F8E-B1AF-4B0199EAF9A6}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {6D32EA91-61D4-4F8E-B1AF-4B0199EAF9A6}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {6D32EA91-61D4-4F8E-B1AF-4B0199EAF9A6}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {B9A197AA-2580-4AC7-8E60-2ECF12F2A198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {B9A197AA-2580-4AC7-8E60-2ECF12F2A198}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {B9A197AA-2580-4AC7-8E60-2ECF12F2A198}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {B9A197AA-2580-4AC7-8E60-2ECF12F2A198}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /LinkDotNet.BuildInformation/GitInformationInfo.cs: -------------------------------------------------------------------------------- 1 | namespace LinkDotNet.BuildInformation; 2 | 3 | public sealed class GitInformationInfo 4 | { 5 | public string Branch { get; init; } = string.Empty; 6 | public string Commit { get; init; } = string.Empty; 7 | public string ShortCommit => Commit.Length > 7 ? Commit[..7] : Commit; 8 | public string NearestTag { get; init; } = string.Empty; 9 | public string DetailedTagDescription { get; init; } = string.Empty; 10 | } -------------------------------------------------------------------------------- /LinkDotNet.BuildInformation/GitRetriever.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace LinkDotNet.BuildInformation; 4 | 5 | public static class GitRetriever 6 | { 7 | public static GitInformationInfo GetGitInformation(bool useGitInfo) 8 | { 9 | if (!useGitInfo) 10 | { 11 | return new GitInformationInfo(); 12 | } 13 | 14 | return new GitInformationInfo 15 | { 16 | Branch = GetGitInfoByCommand("rev-parse --abbrev-ref HEAD"), 17 | Commit = GetGitInfoByCommand("rev-parse HEAD"), 18 | NearestTag = GetGitInfoByCommand("describe --tags --abbrev=0"), 19 | DetailedTagDescription = GetGitInfoByCommand("describe --tags"), 20 | }; 21 | 22 | static string GetGitInfoByCommand(string command) 23 | { 24 | var processInfo = new ProcessStartInfo 25 | { 26 | FileName = "git", 27 | Arguments = command, 28 | RedirectStandardOutput = true, 29 | UseShellExecute = false, 30 | CreateNoWindow = true, 31 | }; 32 | 33 | var process = new Process { StartInfo = processInfo }; 34 | 35 | process.Start(); 36 | var result = process.StandardOutput.ReadToEnd().Trim(); 37 | process.WaitForExit(); 38 | return result; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /LinkDotNet.BuildInformation/IncrementalBuildInformationGenerator.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Reflection; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | 7 | namespace LinkDotNet.BuildInformation; 8 | 9 | [Generator] 10 | public sealed class IncrementalBuildInformationGenerator : IIncrementalGenerator 11 | { 12 | public void Initialize(IncrementalGeneratorInitializationContext context) 13 | { 14 | var compilationAndOptionsProvider = context 15 | .CompilationProvider 16 | .Combine(context.AnalyzerConfigOptionsProvider) 17 | .Select((s, _) => s); 18 | 19 | context.RegisterSourceOutput(compilationAndOptionsProvider, static (productionContext, options) => 20 | { 21 | var compiler = options.Left; 22 | var analyzer = options.Right; 23 | 24 | analyzer.GlobalOptions.TryGetValue("build_property.TargetFramework", out var targetFrameworkValue); 25 | var nullability = compiler.Options.NullableContextOptions.ToString(); 26 | var configuration = 27 | Assembly.GetExecutingAssembly().GetCustomAttribute()?.Configuration ?? 28 | compiler.Options.OptimizationLevel.ToString(); 29 | 30 | var assembly = compiler.Assembly; 31 | var rootNamespace = GetRootNamespace(analyzer); 32 | analyzer.GlobalOptions.TryGetValue("build_property.effectiveanalysislevelstyle", out var analysisLevel); 33 | var projectDirectory = GetProjectDirectory(analyzer); 34 | 35 | var buildInformation = new BuildInformationInfo 36 | { 37 | BuildAt = DateTime.UtcNow.ToString("O"), 38 | Platform = compiler.Options.Platform.ToString(), 39 | WarningLevel = compiler.Options.WarningLevel, 40 | Configuration = configuration, 41 | AssemblyVersion = GetAssemblyVersion(assembly) ?? string.Empty, 42 | AssemblyFileVersion = GetAssemblyFileVersion(assembly) ?? string.Empty, 43 | AssemblyName = assembly.Name, 44 | TargetFrameworkMoniker = targetFrameworkValue ?? string.Empty, 45 | Nullability = nullability, 46 | Deterministic = compiler.Options.Deterministic, 47 | RootNamespace = rootNamespace, 48 | AnalysisLevel = analysisLevel ?? string.Empty, 49 | ProjectDirectory = projectDirectory, 50 | Language = CSharpParseOptions.Default.Language, 51 | LanguageVersion = CSharpParseOptions.Default.LanguageVersion.ToDisplayString(), 52 | }; 53 | 54 | analyzer.GlobalOptions.TryGetValue("build_property.IncludeGitInformation", out var useGitInfoOption); 55 | var useGitInfo = useGitInfoOption?.Equals("true", StringComparison.InvariantCultureIgnoreCase) ?? false; 56 | 57 | var gitInfo = GitRetriever.GetGitInformation(useGitInfo); 58 | 59 | productionContext.AddSource("LinkDotNet.BuildInformation.g", GenerateBuildInformationClass(buildInformation, gitInfo)); 60 | }); 61 | } 62 | 63 | private static string? GetAssemblyFileVersion(ISymbol assembly) 64 | { 65 | var assemblyFileVersionAttribute = assembly.GetAttributes() 66 | .FirstOrDefault(attr => attr.AttributeClass?.Name == "AssemblyFileVersionAttribute"); 67 | var assemblyFileVersion = assemblyFileVersionAttribute is not null 68 | ? assemblyFileVersionAttribute.ConstructorArguments[0].Value!.ToString() 69 | : string.Empty; 70 | return assemblyFileVersion; 71 | } 72 | 73 | private static string? GetAssemblyVersion(ISymbol assembly) 74 | { 75 | var assemblyVersionAttribute = assembly.GetAttributes() 76 | .FirstOrDefault(attr => attr.AttributeClass?.Name == "AssemblyVersionAttribute"); 77 | var assemblyVersion = assemblyVersionAttribute is not null 78 | ? assemblyVersionAttribute.ConstructorArguments[0].Value!.ToString() 79 | : string.Empty; 80 | return assemblyVersion; 81 | } 82 | 83 | private static string GetRootNamespace(AnalyzerConfigOptionsProvider analyzer) 84 | { 85 | analyzer.GlobalOptions.TryGetValue("build_property.UseRootNamespaceForBuildInformation", out var useRootNamespaceValue); 86 | var useRootNamespace = useRootNamespaceValue?.Equals("true", StringComparison.InvariantCultureIgnoreCase) ?? false; 87 | if (!useRootNamespace) 88 | { 89 | return string.Empty; 90 | } 91 | 92 | if (!analyzer.GlobalOptions.TryGetValue("build_property.RootNamespace", out var rootNamespaceValue)) 93 | { 94 | analyzer.GlobalOptions.TryGetValue("build_property.MSBuildProjectName", out rootNamespaceValue); 95 | return rootNamespaceValue ?? string.Empty; 96 | } 97 | 98 | return rootNamespaceValue; 99 | } 100 | 101 | private static string GetProjectDirectory(AnalyzerConfigOptionsProvider analyzer) 102 | { 103 | analyzer.GlobalOptions.TryGetValue("build_property.AllowProjectDirectoryBuildOutput", out var allowOutput); 104 | if (!allowOutput?.Equals("true", StringComparison.InvariantCultureIgnoreCase) ?? true) 105 | { 106 | return string.Empty; 107 | } 108 | 109 | return !analyzer.GlobalOptions.TryGetValue("build_property.projectDir", out var projectDir) 110 | ? string.Empty 111 | : projectDir; 112 | } 113 | 114 | private static string GenerateBuildInformationClass( 115 | BuildInformationInfo buildInformation, 116 | GitInformationInfo gitInfo) 117 | { 118 | var rootNamespace = string.IsNullOrEmpty(buildInformation.RootNamespace) 119 | ? string.Empty 120 | : $"\nnamespace {buildInformation.RootNamespace};\n"; 121 | return $$""" 122 | // 123 | // This file was generated by the LinkDotNet.BuildInformation package. 124 | // 125 | // Changes to this file may cause incorrect behavior and will be lost if 126 | // the code is regenerated. 127 | // 128 | 129 | using System; 130 | using System.Globalization; 131 | {{rootNamespace}} 132 | internal static class BuildInformation 133 | { 134 | /// 135 | /// Returns the build date (UTC). 136 | /// 137 | /// Value is: {{buildInformation.BuildAt}} 138 | public static readonly DateTime BuildAt = DateTime.ParseExact("{{buildInformation.BuildAt}}", "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind); 139 | 140 | /// 141 | /// Returns the platform. 142 | /// 143 | /// Value is: {{buildInformation.Platform}} 144 | public const string Platform = "{{buildInformation.Platform}}"; 145 | 146 | /// 147 | /// Returns the warning level. 148 | /// 149 | /// Value is: {{buildInformation.WarningLevel}} 150 | public const int WarningLevel = {{buildInformation.WarningLevel}}; 151 | 152 | /// 153 | /// Returns the configuration. 154 | /// 155 | /// Value is: {{buildInformation.Configuration}} 156 | public const string Configuration = "{{buildInformation.Configuration}}"; 157 | 158 | /// 159 | /// Returns the assembly version. 160 | /// 161 | /// Value is: {{buildInformation.AssemblyVersion}} 162 | public const string AssemblyVersion = "{{buildInformation.AssemblyVersion}}"; 163 | 164 | /// 165 | /// Returns the assembly file version. 166 | /// 167 | /// Value is: {{buildInformation.AssemblyFileVersion}} 168 | public const string AssemblyFileVersion = "{{buildInformation.AssemblyFileVersion}}"; 169 | 170 | /// 171 | /// Returns the assembly name. 172 | /// 173 | /// Value is: {{buildInformation.AssemblyName}} 174 | public const string AssemblyName = "{{buildInformation.AssemblyName}}"; 175 | 176 | /// 177 | /// Returns the target framework moniker. 178 | /// 179 | /// Value is: {{buildInformation.TargetFrameworkMoniker}} 180 | public const string TargetFrameworkMoniker = "{{buildInformation.TargetFrameworkMoniker}}"; 181 | 182 | /// 183 | /// Returns the nullability level. 184 | /// 185 | /// Value is: {{buildInformation.Nullability}} 186 | public const string Nullability = "{{buildInformation.Nullability}}"; 187 | 188 | /// 189 | /// Returns whether the build is deterministic. 190 | /// 191 | /// Value is: {{buildInformation.Deterministic.ToString().ToLowerInvariant()}} 192 | public const bool Deterministic = {{buildInformation.Deterministic.ToString().ToLowerInvariant()}}; 193 | 194 | /// 195 | /// Returns the Analysis level of the application. 196 | /// 197 | /// Value is: {{buildInformation.AnalysisLevel}} 198 | public const string AnalysisLevel = "{{buildInformation.AnalysisLevel}}"; 199 | 200 | /// 201 | /// Returns the project directory. 202 | /// 203 | /// Value is: {{buildInformation.ProjectDirectory}} 204 | public const string ProjectDirectory = "{{buildInformation.ProjectDirectory}}"; 205 | 206 | /// 207 | /// Returns the language the code is compiled against (like C# or F#). 208 | /// 209 | /// C# 210 | /// Value is {{buildInformation.Language}} 211 | public const string Language = "{{buildInformation.Language}}"; 212 | 213 | /// 214 | /// Returns the language version the code is compiled against. This is only the version (like 12.0). 215 | /// 216 | /// 12.0 217 | /// Value is {{buildInformation.LanguageVersion}} 218 | public const string LanguageVersion = "{{buildInformation.LanguageVersion}}"; 219 | } 220 | 221 | internal static class GitInformation 222 | { 223 | /// 224 | /// Returns the branch of the git repository. 225 | /// 226 | /// Value is: {{gitInfo.Branch}} 227 | public const string Branch = "{{gitInfo.Branch}}"; 228 | 229 | /// 230 | /// Returns the commit hash of the git repository. 231 | /// 232 | /// Value is: {{gitInfo.Commit}} 233 | public const string Commit = "{{gitInfo.Commit}}"; 234 | 235 | /// 236 | /// Returns the short commit hash of the git repository. 237 | /// 238 | /// Value is: {{gitInfo.ShortCommit}} 239 | public const string ShortCommit = "{{gitInfo.ShortCommit}}"; 240 | 241 | /// 242 | /// Returns the nearest tag of the git repository. This uses git describe --tags --abbrev=0. 243 | /// 244 | /// Value is: {{gitInfo.NearestTag}} 245 | public const string NearestTag = "{{gitInfo.NearestTag}}"; 246 | 247 | /// 248 | /// Returns the detailed tag description of the git repository. This uses git describe --tags. 249 | /// 250 | /// Value is: {{gitInfo.DetailedTagDescription}} 251 | public const string DetailedTagDescription = "{{gitInfo.DetailedTagDescription}}"; 252 | } 253 | """; 254 | } 255 | 256 | private sealed class BuildInformationInfo 257 | { 258 | public string BuildAt { get; set; } = string.Empty; 259 | public string Platform { get; set; } = string.Empty; 260 | public int WarningLevel { get; set; } 261 | public string Configuration { get; set; } = string.Empty; 262 | public string AssemblyVersion { get; set; } = string.Empty; 263 | public string AssemblyFileVersion { get; set; } = string.Empty; 264 | public string AssemblyName { get; set; } = string.Empty; 265 | public string TargetFrameworkMoniker { get; set; } = string.Empty; 266 | public string Nullability { get; set; } = string.Empty; 267 | public bool Deterministic { get; set; } 268 | public string RootNamespace { get; set; } = string.Empty; 269 | public string AnalysisLevel { get; set; } = string.Empty; 270 | public string ProjectDirectory { get; set; } = string.Empty; 271 | public string Language { get; set; } = string.Empty; 272 | public string LanguageVersion { get; set; } = string.Empty; 273 | } 274 | } -------------------------------------------------------------------------------- /LinkDotNet.BuildInformation/LinkDotNet.BuildInformation.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | enable 6 | false 7 | enable 8 | latest 9 | true 10 | Generated 11 | true 12 | Steven Giesel 13 | Steven Giesel 14 | BuildInformation 15 | Supplies information about the build like build time. 16 | https://github.com/linkdotnet/BuildInformation 17 | https://github.com/linkdotnet/BuildInformation 18 | csharp,dotnet,msbuild,roslyn,git,build information 19 | README.md 20 | logo.png 21 | MIT 22 | 23 | 24 | 25 | 26 | all 27 | runtime; build; native; contentfiles; analyzers; buildtransitive 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | True 39 | \ 40 | 41 | 42 | True 43 | \ 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Incremental Build Information Generator 2 | 3 | [![.NET](https://github.com/linkdotnet/BuildInformation/actions/workflows/dotnet.yml/badge.svg)](https://github.com/linkdotnet/BuildInformation/actions/workflows/dotnet.yml) 4 | [![Nuget](https://img.shields.io/nuget/dt/LinkDotNet.BuildInformation)](https://www.nuget.org/packages/LinkDotNet.BuildInformation/) 5 | [![GitHub tag](https://img.shields.io/github/v/tag/linkdotnet/BuildInformation?include_prereleases&logo=github&style=flat-square)](https://github.com/linkdotnet/BuildInformation/releases) 6 | 7 | This project provides a simple and easy-to-use C# source generator that embeds build information, such as the build time, platform, warning level, and configuration, directly into your code. By using the `BuildInformation` class, you can quickly access and display these details. 8 | 9 | ## Features 10 | * Embeds build date (in UTC) in your code 11 | * Embeds platform (AnyCPU, x86, x64, ...) information in your code 12 | * Embeds compiler warning level in your code 13 | * Embeds build configuration (e.g., Debug, Release) in your code 14 | * Embeds the assembly version and assembly file version in your code 15 | * Embeds the target framework moniker in your code 16 | * Embeds the nullability analysis level in your code 17 | * Embeds the deterministic build flag in your code 18 | * Embeds the project path where the generator is running in your code 19 | * Embeds the language and language version (like "C#" and "12.0") 20 | 21 | ## Configuration 22 | By default the created class is `internal` and is not under any namespace. This can be changed by adding the following to your project file: 23 | ```xml 24 | 25 | true 26 | 27 | 28 | 29 | 30 | 31 | ``` 32 | 33 | This will use the root namespace of the project for the generated class. This is especially helpful if the generator is used in multiple projects, that might be visible to each other. 34 | 35 | The `AllowProjectDirectoryBuildOutput` property is used to allow the generator to write the project directory into the generated class. This is disabled by default, as it might leak sensitive information. 36 | ```xml 37 | 38 | true 39 | 40 | 41 | 42 | 43 | 44 | ``` 45 | 46 | ### Git Information 47 | By default, the generator does not include git information. If you want to include the git information, you can add the following to your project file: 48 | 49 | ```xml 50 | 51 | true 52 | 53 | 54 | 55 | 56 | 57 | ``` 58 | 59 | This will fill the `GitInformation` class with the following properties: 60 | ```csharp 61 | Console.WriteLine("Git information:"); 62 | Console.WriteLine($"Branch: {GitInformation.Branch}"); 63 | Console.WriteLine($"Commit: {GitInformation.Commit}"); 64 | Console.WriteLine($"Short commit: {GitInformation.ShortCommit}"); 65 | Console.WriteLine($"Nearest tag: {GitInformation.NearestTag}"); 66 | Console.WriteLine($"Detailed tag description: {GitInformation.DetailedTagDescription}"); 67 | ``` 68 | 69 | This will spawn a `git` process to get the information. 70 | Therefore, git has to be accessible from the command line. Be advised, that it will increase your build time slightly. 71 | 72 | ## Usage 73 | To use the `BuildInformation` class in your project, add the NuGet package: 74 | 75 | ```no-class 76 | dotnet add package LinkDotNet.BuildInformation 77 | ``` 78 | 79 | Here is some code how to use the class: 80 | ```csharp 81 | using System; 82 | 83 | Console.WriteLine($"Build at: {BuildInformation.BuildAt}"); 84 | Console.WriteLine($"Platform: {BuildInformation.Platform}"); 85 | Console.WriteLine($"Warning level: {BuildInformation.WarningLevel}"); 86 | Console.WriteLine($"Configuration: {BuildInformation.Configuration}"); 87 | Console.WriteLine($"Assembly version: {BuildInformation.AssemblyVersion}"); 88 | Console.WriteLine($"Assembly file version: {BuildInformation.AssemblyFileVersion}"); 89 | Console.WriteLine($"Assembly name: {BuildInformation.AssemblyName}"); 90 | Console.WriteLine($"Target framework moniker: {BuildInformation.TargetFrameworkMoniker}"); 91 | Console.WriteLine($"Nullability level: {BuildInformation.Nullability}"); 92 | Console.WriteLine($"Deterministic build: {BuildInformation.Deterministic}"); 93 | Console.WriteLine($"Analysis level: {BuildInformation.AnalysisLevel}"); 94 | Console.WriteLine($"Project directory: {BuildInformation.ProjectDirectory}"); 95 | Console.WriteLine($"Language: {BuildInformation.Language}"); 96 | Console.WriteLine($"Language version: {BuildInformation.LanguageVersion}"); 97 | ``` 98 | 99 | You can also hover over the properties to get the currently held value (xmldoc support). An example output could look like this: 100 | ```no-class 101 | Build at: 24.03.2024 21:32:17 102 | Platform: AnyCpu 103 | Warning level: 7 104 | Configuration: Debug 105 | Assembly version: 1.0 106 | Assembly file version: 1.2 107 | Assembly name: LinkDotNet.BuildInformation.Sample 108 | Target framework moniker: net7.0 109 | Nullability level: enabled 110 | Deterministic build: true 111 | Analysis level: 7.0 112 | Project directory: /Users/example/repo/this/Sample.csproj 113 | Language: C# 114 | Langugage version: 12.0 115 | ``` 116 | 117 | ## Contributing 118 | If you would like to contribute to the project, please submit a pull request or open an issue on the project's GitHub page. We welcome any feedback, bug reports, or feature requests. 119 | 120 | ## License 121 | This project is licensed under the MIT License. -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linkdotnet/BuildInformation/242892154edfbc358b8b899c14ab569b2e037088/logo.png --------------------------------------------------------------------------------