diff --git a/src/ReleaseHistory.md b/src/ReleaseHistory.md index eb01b6dcd..3c02fd709 100644 --- a/src/ReleaseHistory.md +++ b/src/ReleaseHistory.md @@ -5,6 +5,7 @@ * DEPENDENCY BREAKING: SARIF now requires Newtonsoft.JSON 11.0.2 (rather than 10.0.3) * DEPENDENCY: SARIF TypeScript package now requires minimist 1.2.3 or later (rather than >=1.2.0) * FEATURE: Add a setter to `GitHelper.GitExePath`. [#2110](https://github.com/microsoft/sarif-sdk/pull/2110) +* FEATURE: `GitHelper` will search in %PATH% variable if `git.exe` isn't located in ProgramFiles folder ## **v2.3.6** [Sdk](https://www.nuget.org/packages/Sarif.Sdk/2.3.6) | [Driver](https://www.nuget.org/packages/Sarif.Driver/2.3.6) | [Converters](https://www.nuget.org/packages/Sarif.Converters/2.3.6) | [Multitool](https://www.nuget.org/packages/Sarif.Multitool/2.3.6) | [Multitool Library](https://www.nuget.org/packages/Sarif.Multitool.Library/2.3.6) * BUGFIX: Restore multitool client app package build. diff --git a/src/Sarif/FileSearcherHelper.cs b/src/Sarif/FileSearcherHelper.cs new file mode 100644 index 000000000..71d6cac64 --- /dev/null +++ b/src/Sarif/FileSearcherHelper.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.IO; + +namespace Microsoft.CodeAnalysis.Sarif +{ + internal static class FileSearcherHelper + { + /// + /// This method will search in the environment variable for a specific file name. + /// It will return the first file found. + /// + /// Environment variable that we will look for + /// Name of the file that we will look for in the environment variable + /// Path to the file name or empty string. + public static string SearchForFileInEnvironmentVariable(string environmentVariable, string fileName) + { + string variable = Environment.GetEnvironmentVariable(environmentVariable); + if (string.IsNullOrEmpty(variable)) + { + return null; + } + + string[] paths = variable.Split(';'); + foreach (string path in paths) + { + string returnedPath = SearchForFileNameInPath(path, fileName); + if (!string.IsNullOrEmpty(returnedPath)) + { + return returnedPath; + } + } + + return null; + } + + /// + /// This method will search for a file name in a specific path. + /// + /// Path where it will search. + /// Name of the file that it will search + /// Path to the file name or empty string. + public static string SearchForFileNameInPath(string path, string fileName) + { + string filePath = $@"{path}\{fileName}"; + return File.Exists(filePath) ? filePath : null; + } + } +} diff --git a/src/Sarif/GitHelper.cs b/src/Sarif/GitHelper.cs index 87b582cc6..648e5eb0d 100644 --- a/src/Sarif/GitHelper.cs +++ b/src/Sarif/GitHelper.cs @@ -73,8 +73,15 @@ public void Checkout(string repoPath, string commitSha) args: $"checkout {commitSha}"); } - private string GetGitExePath() - => this.fileSystem.FileExists(s_expectedGitExePath) ? s_expectedGitExePath : null; + internal string GetGitExePath() + { + if (this.fileSystem.FileExists(s_expectedGitExePath)) + { + return s_expectedGitExePath; + } + + return FileSearcherHelper.SearchForFileInEnvironmentVariable("PATH", "git.exe"); + } public string GetCurrentBranch(string repoPath) { diff --git a/src/Test.UnitTests.Sarif/GitHelperTests.cs b/src/Test.UnitTests.Sarif/GitHelperTests.cs index be9c544cf..d01181a8f 100644 --- a/src/Test.UnitTests.Sarif/GitHelperTests.cs +++ b/src/Test.UnitTests.Sarif/GitHelperTests.cs @@ -118,6 +118,49 @@ public void GetRepositoryRoot_WhenCalledOnTheDefaultInstanceWithCachingDisabled_ action.Should().NotThrow(); } + [Fact] + public void GetGitExePath_WhenPathExistsInProgramFiles() + { + var mockFileSystem = new Mock(); + + mockFileSystem.Setup(x => x.FileExists(It.IsAny())).Returns(true); + + var gitHelper = new GitHelper(mockFileSystem.Object); + + gitHelper.GetGitExePath().Should().NotBeNullOrEmpty(); + } + + [Fact] + public void GetGitExePath_WhenPathDoesNotExistInProgramFiles() + { + var mockFileSystem = new Mock(); + + mockFileSystem.Setup(x => x.FileExists(It.IsAny())).Returns(false); + + var gitHelper = new GitHelper(mockFileSystem.Object); + + gitHelper.GetGitExePath().Should().NotBeNull(); + } + + [Fact] + public void SearchForFileInEnvironmentVariable_WhenVariableDoesNotExist() + { + FileSearcherHelper.SearchForFileInEnvironmentVariable("PATH_THAT_DOES_NOT_EXIST", "filename.exe").Should().BeNull(); + } + + [Fact] + public void SearchForFileInEnvironmentVariable_WhenVariableExistsButFileDoesnt() + { + // The error in the ntdll name here is intentional. + FileSearcherHelper.SearchForFileInEnvironmentVariable("PATH", "ntdll.dlll").Should().BeNull(); + } + + [Fact] + public void SearchForFileInEnvironmentVariable_WhenVariableAndFileExists() + { + FileSearcherHelper.SearchForFileInEnvironmentVariable("PATH", "ntdll.dll").Should().NotBeNull(); + } + [Fact] public void GitExePath_WhenPathDoesntExist_SettingManuallyShouldWork() {