From be38a85539208612fa4b64d44a9d2e5201a61d53 Mon Sep 17 00:00:00 2001 From: Ryan Shepherd Date: Wed, 23 Oct 2024 13:23:24 -0700 Subject: [PATCH] Telemetry for detecting git (#3950) * Add telemetry to store where and which version of git.exe was detected * Strip trailing newline from git version --- .../GitExtension/GitDetectEvent.cs | 47 ++++++++++++++++ .../Models/GitDetect.cs | 53 ++++++++++++------- 2 files changed, 82 insertions(+), 18 deletions(-) create mode 100644 common/TelemetryEvents/GitExtension/GitDetectEvent.cs diff --git a/common/TelemetryEvents/GitExtension/GitDetectEvent.cs b/common/TelemetryEvents/GitExtension/GitDetectEvent.cs new file mode 100644 index 0000000000..5372b3d9e4 --- /dev/null +++ b/common/TelemetryEvents/GitExtension/GitDetectEvent.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Diagnostics.Tracing; +using DevHome.Telemetry; +using Microsoft.Diagnostics.Telemetry; +using Microsoft.Diagnostics.Telemetry.Internal; + +namespace DevHome.Common.TelemetryEvents.GitExtension; + +// How git.exe was located +public enum GitDetectStatus +{ + // git.exe was not found on the system + NotFound, + + // In the PATH environment variable + PathEnvironmentVariable, + + // Probed well-known registry keys to find a Git install location + RegistryProbe, + + // Probed well-known folders under Program Files [(x86)] + ProgramFiles, +} + +[EventData] +public class GitDetectEvent : EventBase +{ + public override PartA_PrivTags PartA_PrivTags => PrivTags.ProductAndServicePerformance; + + public string Status { get; } + + public string Version { get; } + + public GitDetectEvent(GitDetectStatus status, string version) + { + Status = status.ToString(); + Version = version; + } + + public override void ReplaceSensitiveStrings(Func replaceSensitiveStrings) + { + // This event so far has no sensitive strings + } +} diff --git a/extensions/GitExtension/FileExplorerGitIntegration/Models/GitDetect.cs b/extensions/GitExtension/FileExplorerGitIntegration/Models/GitDetect.cs index 28b1e0df5b..5ba26c8c46 100644 --- a/extensions/GitExtension/FileExplorerGitIntegration/Models/GitDetect.cs +++ b/extensions/GitExtension/FileExplorerGitIntegration/Models/GitDetect.cs @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using DevHome.Common.TelemetryEvents.GitExtension; +using DevHome.Common.TelemetryEvents.SourceControlIntegration; +using DevHome.Telemetry; using Microsoft.Win32; using Microsoft.Windows.DevHome.SDK; using Serilog; @@ -13,6 +16,12 @@ public class GitDetect private readonly ILogger _log = Log.ForContext(); + private struct DetectInfo + { + public bool Found; + public string Version; + } + public GitDetect() { GitConfiguration = new GitConfiguration(null); @@ -20,19 +29,21 @@ public GitDetect() public bool DetectGit() { - var gitExeFound = false; + var detect = new DetectInfo { Found = false, Version = string.Empty }; + var status = GitDetectStatus.NotFound; - if (!gitExeFound) + if (!detect.Found) { // Check if git.exe is present in PATH environment variable - gitExeFound = ValidateGitConfigurationPath("git.exe"); - if (gitExeFound) + detect = ValidateGitConfigurationPath("git.exe"); + if (detect.Found) { + status = GitDetectStatus.PathEnvironmentVariable; GitConfiguration.StoreGitExeInstallPath("git.exe"); } } - if (!gitExeFound) + if (!detect.Found) { // Check execution of git.exe by finding install location in registry keys string[] registryPaths = { "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Git_is1" }; @@ -43,25 +54,31 @@ public bool DetectGit() if (!string.IsNullOrEmpty(gitPath)) { var paths = FindSubdirectories(gitPath); - gitExeFound = CheckForExeInPaths(paths); - if (gitExeFound) + detect = CheckForExeInPaths(paths); + if (detect.Found) { + status = GitDetectStatus.RegistryProbe; break; } } } } - if (!gitExeFound) + if (!detect.Found) { // Search for git.exe in common file paths var programFiles = Environment.GetEnvironmentVariable("ProgramFiles"); var programFilesX86 = Environment.GetEnvironmentVariable("ProgramFiles(x86)"); string[] possiblePaths = { $"{programFiles}\\Git\\bin", $"{programFilesX86}\\Git\\bin", $"{programFiles}\\Git\\cmd", $"{programFilesX86}\\Git\\cmd" }; - gitExeFound = CheckForExeInPaths(possiblePaths); + detect = CheckForExeInPaths(possiblePaths); + if (detect.Found) + { + status = GitDetectStatus.ProgramFiles; + } } - return gitExeFound; + TelemetryFactory.Get().Log("GitDetect_Event", LogLevel.Critical, new GitDetectEvent(status, detect.Version)); + return detect.Found; } private string[] FindSubdirectories(string installLocation) @@ -85,35 +102,35 @@ private string[] FindSubdirectories(string installLocation) } } - private bool CheckForExeInPaths(string[] possiblePaths) + private DetectInfo CheckForExeInPaths(string[] possiblePaths) { // Iterate through the possible paths to find the git.exe file foreach (var path in possiblePaths.Where(x => !string.IsNullOrEmpty(x))) { var gitPath = Path.Combine(path, "git.exe"); - var isValid = ValidateGitConfigurationPath(gitPath); + var detect = ValidateGitConfigurationPath(gitPath); // If the git.exe file is found, store the install path and log the information - if (isValid) + if (detect.Found) { GitConfiguration.StoreGitExeInstallPath(gitPath); _log.Information("Git Exe Install Path found"); - return true; + return detect; } } _log.Debug("Git.exe not found in paths examined"); - return false; + return new DetectInfo { Found = false, Version = string.Empty }; } - public bool ValidateGitConfigurationPath(string path) + private DetectInfo ValidateGitConfigurationPath(string path) { var result = GitExecute.ExecuteGitCommand(path, string.Empty, "--version"); if (result.Status == ProviderOperationStatus.Success && result.Output != null && result.Output.Contains("git version")) { - return true; + return new DetectInfo { Found = true, Version = result.Output.Replace("git version", string.Empty).TrimEnd() }; } - return false; + return new DetectInfo { Found = false, Version = string.Empty }; } }