|
| 1 | +using System.Reflection; |
| 2 | + |
| 3 | +namespace DiffViewer.Utility; |
| 4 | + |
| 5 | +/// <summary> |
| 6 | +/// Reads the running DiffViewer build's version for display in the |
| 7 | +/// UI (Settings → Updates section). Two-method shape so the |
| 8 | +/// reflection-based read is wrapped around a pure string-handling |
| 9 | +/// inner method that's testable in isolation. |
| 10 | +/// |
| 11 | +/// <para>Prefers <see cref="AssemblyInformationalVersionAttribute"/> |
| 12 | +/// because that's what <c>release.yml</c> stamps with the release |
| 13 | +/// tag (e.g. <c>1.6.0</c> or <c>1.6.0-rc1</c>), matching exactly |
| 14 | +/// what users see on the GitHub Releases page. SourceLink may |
| 15 | +/// append a <c>+gitHash</c> suffix to the informational version on |
| 16 | +/// dev builds; we strip it for display so the value matches a tag |
| 17 | +/// the user could navigate to.</para> |
| 18 | +/// </summary> |
| 19 | +public static class AppVersionInfo |
| 20 | +{ |
| 21 | + /// <summary> |
| 22 | + /// User-facing version string for the running DiffViewer build, |
| 23 | + /// e.g. <c>"1.6.0"</c> or <c>"1.6.0-rc1"</c>. Falls back to the |
| 24 | + /// raw <see cref="System.Reflection.AssemblyName.Version"/> shape |
| 25 | + /// (<c>"1.6.0.0"</c>) when no informational version is stamped, |
| 26 | + /// and to <c>"unknown"</c> when neither is available (defensive — |
| 27 | + /// should not happen in normal builds). |
| 28 | + /// </summary> |
| 29 | + public static string GetDisplayVersion() |
| 30 | + { |
| 31 | + var asm = Assembly.GetEntryAssembly(); |
| 32 | + var info = asm?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion; |
| 33 | + var fallback = asm?.GetName().Version?.ToString(); |
| 34 | + return GetDisplayVersionFromValues(info, fallback); |
| 35 | + } |
| 36 | + |
| 37 | + /// <summary> |
| 38 | + /// Testable inner overload. Takes the raw attribute values and |
| 39 | + /// produces the display string per the precedence rules |
| 40 | + /// described on the class. Public-internal (via |
| 41 | + /// <c>InternalsVisibleTo</c>) so the test project can drive it |
| 42 | + /// without round-tripping through reflection on a fake assembly. |
| 43 | + /// </summary> |
| 44 | + internal static string GetDisplayVersionFromValues(string? informationalVersion, string? assemblyVersion) |
| 45 | + { |
| 46 | + if (!string.IsNullOrWhiteSpace(informationalVersion)) |
| 47 | + { |
| 48 | + // Strip SourceLink's "+gitHash" suffix so the displayed |
| 49 | + // value matches a tag the user could navigate to. |
| 50 | + var plus = informationalVersion!.IndexOf('+'); |
| 51 | + return plus > 0 ? informationalVersion[..plus] : informationalVersion; |
| 52 | + } |
| 53 | + if (!string.IsNullOrWhiteSpace(assemblyVersion)) |
| 54 | + { |
| 55 | + return assemblyVersion!; |
| 56 | + } |
| 57 | + return "unknown"; |
| 58 | + } |
| 59 | +} |
0 commit comments