Skip to content

Instantly share code, notes, and snippets.

@DamianEdwards
Created October 18, 2022 17:35
Show Gist options
  • Save DamianEdwards/deaec4fa1ef6bf5ad3caa0cc685827d6 to your computer and use it in GitHub Desktop.
Save DamianEdwards/deaec4fa1ef6bf5ad3caa0cc685827d6 to your computer and use it in GitHub Desktop.
Example of .NET console app (that could be made into a cmd line tool) that uses MSBuild to extract project version
<!-- Put this in sub-directory of the project named 'assets' -->
<Project>
<Target Name="_ExtractVersionMetadata">
<WriteLinesToFile File="$(_ProjectVersionMetadataFile)" Lines="$(Version)" />
</Target>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<VersionPrefix>1.2.0</VersionPrefix>
</PropertyGroup>
<ItemGroup>
<None Update="assets\GetProjectVersion.targets">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
using System.Diagnostics;
string? projectFilePath = null;
if (args.Length > 0)
{
projectFilePath = args[0];
if (!File.Exists(projectFilePath))
{
WriteError($"The specified project file '{projectFilePath}' was not found.");
Environment.Exit(1);
}
}
else
{
var projectFiles = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.csproj");
if (projectFiles.Length == 1)
{
projectFilePath = projectFiles[0];
}
else if (projectFiles.Length > 1)
{
WriteError("More than one .csproj file found. Please specify a project file, e.g.: dotnet version MyProjectFile.csproj");
Environment.Exit(1);
}
else
{
WriteError("No project file found. Please run this command in the project directory or specify a project file, e.g.: dotnet version MyProjectFile.csproj");
Environment.Exit(1);
}
}
var configuration = "Debug";
var targetsFile = FindTargetsFile();
if (targetsFile is null)
{
Environment.Exit(1);
}
var outputFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
try
{
var psi = new ProcessStartInfo
{
FileName = "dotnet.exe",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
ArgumentList =
{
"msbuild",
projectFilePath,
"/nologo",
"/t:_ExtractVersionMetadata", // defined in GetProjectVersion.targets
"/p:_ProjectVersionMetadataFile=" + outputFile,
"/p:Configuration=" + configuration,
"/p:CustomAfterMicrosoftCommonTargets=" + targetsFile,
"/p:CustomAfterMicrosoftCommonCrossTargetingTargets=" + targetsFile,
"-verbosity:detailed",
}
};
using var process = new Process()
{
StartInfo = psi,
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
if (process.ExitCode != 0)
{
WriteError($"Exit code: {process.ExitCode}");
}
if (!File.Exists(outputFile))
{
WriteError("Output file not found");
Environment.Exit(1);
}
var version = File.ReadAllText(outputFile)?.Trim();
if (string.IsNullOrEmpty(version))
{
WriteError("Output file was empty");
}
Console.WriteLine($"Project version: {version}");
}
catch (Exception ex)
{
WriteError(ex.ToString());
Environment.Exit(1);
}
void WriteError(string value)
{
WriteLine(value, ConsoleColor.Red);
}
void WriteLine(string value, ConsoleColor color)
{
Write(value, color);
Console.WriteLine();
}
void Write(string value, ConsoleColor color)
{
var originalForegroundColor = Console.ForegroundColor;
Console.ForegroundColor = color;
Console.Write(value);
Console.ForegroundColor = originalForegroundColor;
}
string? FindTargetsFile()
{
var assemblyDir = Path.GetDirectoryName(typeof(Program).Assembly.Location);
var searchPaths = new[]
{
Path.Combine(AppContext.BaseDirectory, "assets"),
Path.Combine(assemblyDir, "assets"),
AppContext.BaseDirectory,
assemblyDir,
};
var targetPath = searchPaths.Select(p => Path.Combine(p, "GetProjectVersion.targets")).FirstOrDefault(File.Exists);
if (targetPath == null)
{
WriteError("Fatal error: could not find GetProjectVersion.targets");
return null;
}
return targetPath;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment