mirror of
https://github.com/okieselbach/AutopilotMonitor.git
synced 2026-10-24 12:42:38 +00:00
added version info to backend
This commit is contained in:
+1
-1
Submodule .claude/commands updated: a3970d474c...c506bb75e0
@@ -25,10 +25,10 @@ jobs:
|
||||
run: dotnet restore src/Backend/AutopilotMonitor.Functions/AutopilotMonitor.Functions.csproj
|
||||
|
||||
- name: Build
|
||||
run: dotnet build src/Backend/AutopilotMonitor.Functions/AutopilotMonitor.Functions.csproj --configuration Release --no-restore
|
||||
run: dotnet build src/Backend/AutopilotMonitor.Functions/AutopilotMonitor.Functions.csproj --configuration Release --no-restore -p:SourceRevisionId=${{ github.sha }}
|
||||
|
||||
- name: Publish
|
||||
run: dotnet publish src/Backend/AutopilotMonitor.Functions/AutopilotMonitor.Functions.csproj --configuration Release --output ./publish --no-build
|
||||
run: dotnet publish src/Backend/AutopilotMonitor.Functions/AutopilotMonitor.Functions.csproj --configuration Release --output ./publish --no-build -p:SourceRevisionId=${{ github.sha }}
|
||||
|
||||
- name: Deploy to Azure Functions
|
||||
uses: Azure/functions-action@v1
|
||||
|
||||
@@ -1 +1 @@
|
||||
111
|
||||
113
|
||||
|
||||
@@ -1 +1 @@
|
||||
1078
|
||||
1079
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
using AutopilotMonitor.Functions.Services;
|
||||
|
||||
namespace AutopilotMonitor.Functions.Tests;
|
||||
|
||||
public class BackendBuildInfoTests
|
||||
{
|
||||
[Fact]
|
||||
public void Parse_VersionWithLongSha_TrimsTo7Chars()
|
||||
{
|
||||
var (version, commit) = BackendBuildInfo.ParseInformationalVersion(
|
||||
"1.0.0+2e82dd2bdeadbeefcafe1234567890abcdef1234");
|
||||
|
||||
Assert.Equal("1.0.0", version);
|
||||
Assert.Equal("2e82dd2", commit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_VersionWithoutSha_ReturnsEmptyCommit()
|
||||
{
|
||||
var (version, commit) = BackendBuildInfo.ParseInformationalVersion("1.0.0");
|
||||
|
||||
Assert.Equal("1.0.0", version);
|
||||
Assert.Equal(string.Empty, commit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_ShortShaBelowSeven_PreservedAsIs()
|
||||
{
|
||||
var (version, commit) = BackendBuildInfo.ParseInformationalVersion("1.0.0+abc12");
|
||||
|
||||
Assert.Equal("1.0.0", version);
|
||||
Assert.Equal("abc12", commit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_Empty_ReturnsFallback()
|
||||
{
|
||||
var (version, commit) = BackendBuildInfo.ParseInformationalVersion("");
|
||||
|
||||
Assert.Equal("0.0.0", version);
|
||||
Assert.Equal(string.Empty, commit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parse_NullSafe()
|
||||
{
|
||||
var (version, commit) = BackendBuildInfo.ParseInformationalVersion(null!);
|
||||
|
||||
Assert.Equal("0.0.0", version);
|
||||
Assert.Equal(string.Empty, commit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_ReadsCurrentAssembly_ProducesNonEmptyVersion()
|
||||
{
|
||||
var info = new BackendBuildInfo();
|
||||
|
||||
// Version comes from <Version> in .csproj via generated AssemblyInformationalVersion.
|
||||
// Test asserts only that the parser wired to the assembly produces something — we
|
||||
// don't hardcode the version string here to avoid coupling tests to every bump.
|
||||
Assert.False(string.IsNullOrWhiteSpace(info.Version));
|
||||
Assert.NotEqual(default, info.BuildUtc);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,12 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<!-- Backend version surfaced via /api/health. CommitHash is injected at CI time
|
||||
through -p:SourceRevisionId=<github.sha> and appended to InformationalVersion. -->
|
||||
<Version>1.0.0</Version>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<IncludeSourceRevisionInInformationalVersion>true</IncludeSourceRevisionInInformationalVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+12
-3
@@ -12,6 +12,7 @@ namespace AutopilotMonitor.Functions.Functions.Infrastructure
|
||||
private readonly ILogger<HealthCheckFunction> _logger;
|
||||
private readonly HealthCheckService _healthCheckService;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly BackendBuildInfo _buildInfo;
|
||||
|
||||
private const int MaxRequestsPerMinute = 30;
|
||||
private static readonly TimeSpan RateWindow = TimeSpan.FromMinutes(1);
|
||||
@@ -19,11 +20,13 @@ namespace AutopilotMonitor.Functions.Functions.Infrastructure
|
||||
public HealthCheckFunction(
|
||||
ILogger<HealthCheckFunction> logger,
|
||||
HealthCheckService healthCheckService,
|
||||
IMemoryCache cache)
|
||||
IMemoryCache cache,
|
||||
BackendBuildInfo buildInfo)
|
||||
{
|
||||
_logger = logger;
|
||||
_healthCheckService = healthCheckService;
|
||||
_cache = cache;
|
||||
_buildInfo = buildInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,7 +74,10 @@ namespace AutopilotMonitor.Functions.Functions.Infrastructure
|
||||
{
|
||||
status = "healthy",
|
||||
service = "Autopilot Monitor API",
|
||||
timestamp = DateTime.UtcNow
|
||||
timestamp = DateTime.UtcNow,
|
||||
version = _buildInfo.Version,
|
||||
commitHash = _buildInfo.CommitHash,
|
||||
buildUtc = _buildInfo.BuildUtc
|
||||
});
|
||||
|
||||
return response;
|
||||
@@ -101,7 +107,10 @@ namespace AutopilotMonitor.Functions.Functions.Infrastructure
|
||||
service = "Autopilot Monitor API",
|
||||
timestamp = healthCheckResult.Timestamp,
|
||||
overallStatus = healthCheckResult.OverallStatus,
|
||||
checks = healthCheckResult.Checks
|
||||
checks = healthCheckResult.Checks,
|
||||
version = _buildInfo.Version,
|
||||
commitHash = _buildInfo.CommitHash,
|
||||
buildUtc = _buildInfo.BuildUtc
|
||||
});
|
||||
|
||||
return response;
|
||||
|
||||
@@ -146,6 +146,7 @@ builder.Services.AddSingleton<McpUserService>();
|
||||
builder.Services.AddSingleton<PreviewWhitelistService>();
|
||||
builder.Services.AddSingleton<TenantAdminsService>();
|
||||
builder.Services.AddSingleton<HealthCheckService>();
|
||||
builder.Services.AddSingleton<BackendBuildInfo>();
|
||||
builder.Services.AddSingleton<GatherRuleService>();
|
||||
builder.Services.AddSingleton<AnalyzeRuleService>();
|
||||
builder.Services.AddSingleton<ImeLogPatternService>();
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace AutopilotMonitor.Functions.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes the backend build identity (version, commit hash, build time) surfaced
|
||||
/// via /api/health and /api/health/detailed. Values come from the assembly's
|
||||
/// InformationalVersion attribute which MSBuild populates from <Version> and
|
||||
/// -p:SourceRevisionId (the latter is set by the deploy workflow to github.sha).
|
||||
/// </summary>
|
||||
public sealed class BackendBuildInfo
|
||||
{
|
||||
public string Version { get; }
|
||||
public string CommitHash { get; }
|
||||
public DateTime BuildUtc { get; }
|
||||
|
||||
public BackendBuildInfo()
|
||||
{
|
||||
var asm = typeof(BackendBuildInfo).Assembly;
|
||||
var info = asm.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion
|
||||
?? "0.0.0";
|
||||
|
||||
(Version, CommitHash) = ParseInformationalVersion(info);
|
||||
|
||||
try
|
||||
{
|
||||
var path = asm.Location;
|
||||
BuildUtc = !string.IsNullOrEmpty(path) && File.Exists(path)
|
||||
? File.GetLastWriteTimeUtc(path)
|
||||
: DateTime.UtcNow;
|
||||
}
|
||||
catch
|
||||
{
|
||||
BuildUtc = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits an InformationalVersion ("1.0.0+abc1234567...") into a semver part
|
||||
/// and a 7-char short commit hash. No '+' → empty commit hash.
|
||||
/// </summary>
|
||||
internal static (string Version, string CommitHash) ParseInformationalVersion(string informationalVersion)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(informationalVersion))
|
||||
{
|
||||
return ("0.0.0", string.Empty);
|
||||
}
|
||||
|
||||
var plus = informationalVersion.IndexOf('+');
|
||||
if (plus < 0)
|
||||
{
|
||||
return (informationalVersion, string.Empty);
|
||||
}
|
||||
|
||||
var version = informationalVersion.Substring(0, plus);
|
||||
var sha = informationalVersion.Substring(plus + 1);
|
||||
var shortSha = sha.Length > 7 ? sha.Substring(0, 7) : sha;
|
||||
return (version, shortSha);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ interface HealthCheckResult {
|
||||
timestamp: string;
|
||||
overallStatus: string;
|
||||
checks: HealthCheck[];
|
||||
version?: string;
|
||||
commitHash?: string;
|
||||
buildUtc?: string;
|
||||
}
|
||||
|
||||
export default function HealthCheckPage() {
|
||||
@@ -182,6 +185,44 @@ export default function HealthCheckPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Backend Build (Global Admin only) */}
|
||||
{user?.isGlobalAdmin && healthResult?.version && (
|
||||
<div className="mb-6">
|
||||
<h2 className="text-sm font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3">Backend Build</h2>
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow border-l-4 border-indigo-500">
|
||||
<div className="p-4 grid grid-cols-1 sm:grid-cols-3 gap-4 text-sm">
|
||||
<div>
|
||||
<dt className="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase">Version</dt>
|
||||
<dd className="mt-1 font-mono text-gray-900 dark:text-gray-100">{healthResult.version}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase">Commit</dt>
|
||||
<dd className="mt-1 font-mono text-gray-900 dark:text-gray-100">
|
||||
{healthResult.commitHash ? (
|
||||
<a
|
||||
href={`https://github.com/okieselbach/Autopilot-Monitor/commit/${healthResult.commitHash}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-indigo-600 dark:text-indigo-400 hover:underline"
|
||||
>
|
||||
{healthResult.commitHash}
|
||||
</a>
|
||||
) : (
|
||||
<span className="text-gray-400">unknown</span>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase">Built</dt>
|
||||
<dd className="mt-1 text-gray-900 dark:text-gray-100">
|
||||
{healthResult.buildUtc ? new Date(healthResult.buildUtc).toLocaleString() : '—'}
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Real-Time Connection Status */}
|
||||
<div className="mb-6">
|
||||
<h2 className="text-sm font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-3">Real-Time Connection</h2>
|
||||
|
||||
Reference in New Issue
Block a user